From 28658aef39e1c9562eecbf9323034c4e0f399142 Mon Sep 17 00:00:00 2001 From: Jean-Marc ANDRE Date: Fri, 3 Feb 2023 18:36:09 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 +- Dockerfile | 9 - Dockerfile.deployment | 39 ---- LICENSE | 202 ----------------- Makefile | 23 +- backupsession/create.go | 82 +++++++ cmd/backupsession.go | 40 ++++ cmd/root.go | 46 ++++ go.mod | 82 +++++-- main.go | 16 +- manifests/formolcli-rbac.yaml | 69 ------ pkg/backup/root.go | 58 ----- pkg/cmd/backupsession.go | 67 ------ pkg/cmd/postgres.go | 106 --------- pkg/cmd/root.go | 91 -------- pkg/cmd/snapshot.go | 46 ---- pkg/cmd/target.go | 44 ---- pkg/cmd/volume.go | 70 ------ pkg/controllers/backupsession_controller.go | 225 ------------------- pkg/controllers/restoresession_controller.go | 158 ------------- pkg/restic/root.go | 111 --------- pkg/restore/root.go | 61 ----- pkg/server/root.go | 74 ------ pkg/session/root.go | 142 ------------ pkg/utils/root.go | 95 -------- 25 files changed, 246 insertions(+), 1713 deletions(-) delete mode 100644 Dockerfile delete mode 100644 Dockerfile.deployment create mode 100644 backupsession/create.go create mode 100644 cmd/backupsession.go create mode 100644 cmd/root.go delete mode 100644 manifests/formolcli-rbac.yaml delete mode 100644 pkg/backup/root.go delete mode 100644 pkg/cmd/backupsession.go delete mode 100644 pkg/cmd/postgres.go delete mode 100644 pkg/cmd/root.go delete mode 100644 pkg/cmd/snapshot.go delete mode 100644 pkg/cmd/target.go delete mode 100644 pkg/cmd/volume.go delete mode 100644 pkg/controllers/backupsession_controller.go delete mode 100644 pkg/controllers/restoresession_controller.go delete mode 100644 pkg/restic/root.go delete mode 100644 pkg/restore/root.go delete mode 100644 pkg/server/root.go delete mode 100644 pkg/session/root.go delete mode 100644 pkg/utils/root.go diff --git a/.gitignore b/.gitignore index c0e88cc..6a8579a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +*~ +bin/ go.sum -bin diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 15086dc..0000000 --- a/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -# Build a small image -FROM arm64v8/alpine:3.14 - -RUN apk add --no-cache su-exec restic postgresql-client -COPY bin/formolcli /usr/local/bin - -# Command to run -ENTRYPOINT ["/usr/local/bin/formolcli"] -CMD ["--help"] diff --git a/Dockerfile.deployment b/Dockerfile.deployment deleted file mode 100644 index 3e7b6e8..0000000 --- a/Dockerfile.deployment +++ /dev/null @@ -1,39 +0,0 @@ -FROM golang:alpine AS builder - -# Set necessary environmet variables needed for our image -ENV GO111MODULE=on \ - CGO_ENABLED=0 \ - GOOS=linux \ - GOARCH=arm \ - GOARM=7 - -# Move to working directory /build -WORKDIR /build - -# Copy and download dependency using go mod -COPY src/go.mod . -COPY src/go.sum . -RUN go mod download - -# Copy the code into the container -COPY src . - -# Build the application -RUN go build -o formolcli . - -# Move to /dist directory as the place for resulting binary folder -WORKDIR /dist - -# Copy binary from build to main folder -RUN cp /build/formolcli . - -# Build a small image -FROM arm32v7/alpine:3.12 - -RUN apk add --no-cache restic postgresql-client -#COPY bin/restic /usr/local/bin -COPY --from=builder /dist/formolcli /usr/local/bin - -# Command to run -ENTRYPOINT ["/usr/local/bin/formolcli"] -CMD ["--help"] diff --git a/LICENSE b/LICENSE index d645695..e69de29 100644 --- a/LICENSE +++ b/LICENSE @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Makefile b/Makefile index c64d981..8bd8afa 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,16 @@ -.PHONY: all formolcli docker docker-build docker-push - -IMG ?= desmo999r/formolcli:latest +GOARCH ?= arm64 +.PHONY: formolcli formolcli: fmt vet - GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o bin/formolcli main.go - -test: fmt vet - go test ./... -coverprofile cover.out + GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=$(GOARCH) go build -o bin/formolcli main.go +.PHONY: fmt fmt: go fmt ./... +.PHONY: vet vet: go vet ./... -docker-build: - buildah bud --disable-compression --format=docker -t ${IMG} . - -docker-push: - buildah push ${IMG} - -docker: formolcli docker-build docker-push - -all: docker +.PHONY: all +all: formolcli diff --git a/backupsession/create.go b/backupsession/create.go new file mode 100644 index 0000000..713e97e --- /dev/null +++ b/backupsession/create.go @@ -0,0 +1,82 @@ +package backupsession + +import ( + "context" + formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "os" + "path/filepath" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "strconv" + "strings" + "time" +) + +var ( + config *rest.Config + scheme *runtime.Scheme + cl client.Client + logger logr.Logger + ctx context.Context +) + +func init() { + logger = zap.New(zap.UseDevMode(true)) + ctx = context.Background() + log := logger.WithName("InitBackupSession") + ctrl.SetLogger(logger) + config, err := rest.InClusterConfig() + if err != nil { + config, err = clientcmd.BuildConfigFromFlags("", filepath.Join(os.Getenv("HOME"), ".kube", "config")) + if err != nil { + log.Error(err, "unable to get config") + os.Exit(1) + } + } + scheme = runtime.NewScheme() + _ = formolv1alpha1.AddToScheme(scheme) + _ = clientgoscheme.AddToScheme(scheme) + cl, err = client.New(config, client.Options{Scheme: scheme}) + if err != nil { + log.Error(err, "unable to get client") + os.Exit(1) + } +} + +func CreateBackupSession(ref corev1.ObjectReference) { + log := logger.WithName("CreateBackupSession") + log.V(0).Info("CreateBackupSession called") + backupConf := formolv1alpha1.BackupConfiguration{} + if err := cl.Get(ctx, types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + }, &backupConf); err != nil { + log.Error(err, "unable to get backupconf") + os.Exit(1) + } + log.V(0).Info("got backupConf", "backupConf", backupConf) + + backupSession := &formolv1alpha1.BackupSession{ + ObjectMeta: metav1.ObjectMeta{ + Name: strings.Join([]string{"backupsession", ref.Name, strconv.FormatInt(time.Now().Unix(), 10)}, "-"), + Namespace: ref.Namespace, + }, + Spec: formolv1alpha1.BackupSessionSpec{ + Ref: ref, + }, + } + log.V(1).Info("create backupsession", "backupSession", backupSession) + if err := cl.Create(ctx, backupSession); err != nil { + log.Error(err, "unable to create backupsession") + os.Exit(1) + } +} diff --git a/cmd/backupsession.go b/cmd/backupsession.go new file mode 100644 index 0000000..00ecbe6 --- /dev/null +++ b/cmd/backupsession.go @@ -0,0 +1,40 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "github.com/desmo999r/formolcli/backupsession" + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" +) + +var createBackupSessionCmd = &cobra.Command{ + Use: "create", + Short: "Create a backupsession", + Run: func(cmd *cobra.Command, args []string) { + name, _ := cmd.Flags().GetString("name") + namespace, _ := cmd.Flags().GetString("namespace") + fmt.Println("create backupsession called") + backupsession.CreateBackupSession(corev1.ObjectReference{ + Namespace: namespace, + Name: name, + }) + }, +} + +// backupsessionCmd represents the backupsession command +var backupSessionCmd = &cobra.Command{ + Use: "backupsession", + Short: "All the BackupSession related commands", +} + +func init() { + rootCmd.AddCommand(backupSessionCmd) + backupSessionCmd.AddCommand(createBackupSessionCmd) + createBackupSessionCmd.Flags().String("namespace", "", "The namespace of the BackupConfiguration containing the information about the backup.") + createBackupSessionCmd.Flags().String("name", "", "The name of the BackupConfiguration containing the information about the backup.") + createBackupSessionCmd.MarkFlagRequired("namespace") + createBackupSessionCmd.MarkFlagRequired("name") +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..cd47515 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,46 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "formolcli", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.formolcli.yaml)") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/go.mod b/go.mod index dd846cf..0a4d79d 100644 --- a/go.mod +++ b/go.mod @@ -1,21 +1,73 @@ module github.com/desmo999r/formolcli -go 1.14 +go 1.19 require ( - github.com/desmo999r/formol v0.7.1 - github.com/go-logr/logr v0.3.0 - github.com/go-logr/zapr v0.2.0 - github.com/mitchellh/go-homedir v1.1.0 - github.com/onsi/ginkgo v1.14.1 - github.com/onsi/gomega v1.10.2 - github.com/spf13/cobra v1.1.1 - github.com/spf13/viper v1.7.0 - go.uber.org/zap v1.15.0 - k8s.io/api v0.20.2 - k8s.io/apimachinery v0.20.2 - k8s.io/client-go v0.20.2 - sigs.k8s.io/controller-runtime v0.8.3 + github.com/desmo999r/formol v0.8.0 + github.com/go-logr/logr v1.2.3 + github.com/spf13/cobra v1.6.1 + k8s.io/api v0.26.1 + k8s.io/apimachinery v0.26.1 + k8s.io/client-go v0.26.1 + sigs.k8s.io/controller-runtime v0.14.2 ) -replace github.com/desmo999r/formol => /home/jandre/devel/golang/formol +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/zapr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/term v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect + golang.org/x/time v0.3.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.26.1 // indirect + k8s.io/component-base v0.26.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace github.com/desmo999r/formol => ../formol diff --git a/main.go b/main.go index 81f4c1a..74459e8 100644 --- a/main.go +++ b/main.go @@ -1,21 +1,9 @@ /* -Copyright © 2020 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +Copyright © 2023 NAME HERE */ package main -import "github.com/desmo999r/formolcli/pkg/cmd" +import "github.com/desmo999r/formolcli/cmd" func main() { cmd.Execute() diff --git a/manifests/formolcli-rbac.yaml b/manifests/formolcli-rbac.yaml deleted file mode 100644 index 51cb035..0000000 --- a/manifests/formolcli-rbac.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: backup ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: backupsession-creator - namespace: backup - labels: - app: backupsession-creator ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: backup-listener - labels: - app: backup-listener -rules: - - apiGroups: ["formol.desmojim.fr"] - resources: ["backupsessions", "backupconfigurations"] - verbs: ["get", "list", "watch"] - - apiGroups: ["formol.desmojim.fr"] - resources: ["backupsessions/status"] - verbs: ["update"] ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: backupsession-creator - labels: - app: backupsession-creator -rules: - - apiGroups: ["formol.desmojim.fr"] - resources: ["backupsessions"] - verbs: ["get", "list", "create", "delete"] ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: backupsession-creator - labels: - app: backupsession-creator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: backupsession-creator -subjects: - - name: backupsession-creator - namespace: backup - kind: ServiceAccount - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: backup-listener - labels: - app: backup-listener -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: backup-listener -subjects: - - name: default - namespace: default - kind: ServiceAccount - diff --git a/pkg/backup/root.go b/pkg/backup/root.go deleted file mode 100644 index c813036..0000000 --- a/pkg/backup/root.go +++ /dev/null @@ -1,58 +0,0 @@ -package backup - -import ( - "fmt" - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - "github.com/desmo999r/formolcli/pkg/restic" - "github.com/desmo999r/formolcli/pkg/session" - "github.com/go-logr/logr" - "github.com/go-logr/zapr" - "go.uber.org/zap" - "io/ioutil" - "os" - "os/exec" -) - -var ( - pg_dumpExec = "/usr/bin/pg_dump" - logger logr.Logger -) - -func init() { - zapLog, _ := zap.NewDevelopment() - logger = zapr.NewLogger(zapLog) -} - -func BackupVolume(tag string, paths []string) error { - log := logger.WithName("backup-volume") - state := formolv1alpha1.Success - output, err := restic.BackupPaths(tag, paths) - var snapshotId string - if err != nil { - log.Error(err, "unable to backup volume", "output", string(output)) - state = formolv1alpha1.Failure - } else { - snapshotId = restic.GetBackupResults(output) - } - session.BackupSessionUpdateTargetStatus(state, snapshotId) - return err -} - -func BackupPostgres(file string, hostname string, database string, username string, password string) error { - log := logger.WithName("backup-postgres") - pgpass := []byte(fmt.Sprintf("%s:*:%s:%s:%s", hostname, database, username, password)) - if err := ioutil.WriteFile("/output/.pgpass", pgpass, 0600); err != nil { - log.Error(err, "unable to write password to /output/.pgpass") - return err - } - defer os.Remove("/output/.pgpass") - cmd := exec.Command(pg_dumpExec, "--format=custom", "--clean", "--create", "--file", file, "--host", hostname, "--dbname", database, "--username", username, "--no-password") - cmd.Env = append(os.Environ(), "PGPASSFILE=/output/.pgpass") - output, err := cmd.CombinedOutput() - log.V(1).Info("postgres backup output", "output", string(output)) - if err != nil { - log.Error(err, "something went wrong during the backup") - return err - } - return nil -} diff --git a/pkg/cmd/backupsession.go b/pkg/cmd/backupsession.go deleted file mode 100644 index 12e3a26..0000000 --- a/pkg/cmd/backupsession.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright © 2020 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "github.com/desmo999r/formolcli/pkg/server" - "github.com/desmo999r/formolcli/pkg/session" - "github.com/spf13/cobra" -) - -var serverBackupSessionCmd = &cobra.Command{ - Use: "server", - Short: "A brief description of your command", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - server.Server() - }, -} - -var createBackupSessionCmd = &cobra.Command{ - Use: "create", - Short: "Creates a backupsession", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - name, _ := cmd.Flags().GetString("name") - namespace, _ := cmd.Flags().GetString("namespace") - session.CreateBackupSession(name, namespace) - }, -} - -var backupSessionCmd = &cobra.Command{ - Use: "backupsession", - Short: "backupsession related commands", -} - -func init() { - rootCmd.AddCommand(backupSessionCmd) - backupSessionCmd.AddCommand(createBackupSessionCmd) - backupSessionCmd.AddCommand(serverBackupSessionCmd) - createBackupSessionCmd.Flags().String("namespace", "", "The referenced BackupSessionConfiguration namespace") - createBackupSessionCmd.Flags().String("name", "", "The referenced BackupSessionConfiguration name") - createBackupSessionCmd.MarkFlagRequired("namespace") - createBackupSessionCmd.MarkFlagRequired("name") -} diff --git a/pkg/cmd/postgres.go b/pkg/cmd/postgres.go deleted file mode 100644 index 91bf264..0000000 --- a/pkg/cmd/postgres.go +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright © 2020 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "fmt" - - "github.com/desmo999r/formolcli/pkg/backup" - "github.com/desmo999r/formolcli/pkg/restore" - "github.com/spf13/cobra" -) - -// postgresCmd represents the postgres command -var postgresRestoreCmd = &cobra.Command{ - Use: "restore", - Short: "restore a PostgreSQL database", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("postgres called") - file, _ := cmd.Flags().GetString("file") - hostname, _ := cmd.Flags().GetString("hostname") - database, _ := cmd.Flags().GetString("database") - username, _ := cmd.Flags().GetString("username") - password, _ := cmd.Flags().GetString("password") - _ = restore.RestorePostgres(file, hostname, database, username, password) - }, -} - -var postgresBackupCmd = &cobra.Command{ - Use: "backup", - Short: "backup a PostgreSQL database", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("postgres called") - file, _ := cmd.Flags().GetString("file") - hostname, _ := cmd.Flags().GetString("hostname") - database, _ := cmd.Flags().GetString("database") - username, _ := cmd.Flags().GetString("username") - password, _ := cmd.Flags().GetString("password") - _ = backup.BackupPostgres(file, hostname, database, username, password) - }, -} - -var postgresCmd = &cobra.Command{ - Use: "postgres", - Short: "postgres actions", -} - -func init() { - rootCmd.AddCommand(postgresCmd) - postgresCmd.AddCommand(postgresBackupCmd) - postgresCmd.AddCommand(postgresRestoreCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // backupPostgresCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // backupPostgresCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - postgresBackupCmd.Flags().String("file", "", "The file the backup will be stored") - postgresBackupCmd.Flags().String("hostname", "", "The postgresql server host") - postgresBackupCmd.Flags().String("database", "", "The postgresql database") - postgresBackupCmd.Flags().String("username", "", "The postgresql username") - postgresBackupCmd.Flags().String("password", "", "The postgresql password") - postgresBackupCmd.MarkFlagRequired("path") - postgresBackupCmd.MarkFlagRequired("hostname") - postgresBackupCmd.MarkFlagRequired("database") - postgresBackupCmd.MarkFlagRequired("username") - postgresBackupCmd.MarkFlagRequired("password") - postgresRestoreCmd.Flags().String("file", "", "The file the database will be restored from") - postgresRestoreCmd.Flags().String("hostname", "", "The postgresql server host") - postgresRestoreCmd.Flags().String("database", "", "The postgresql database") - postgresRestoreCmd.Flags().String("username", "", "The postgresql username") - postgresRestoreCmd.Flags().String("password", "", "The postgresql password") - postgresRestoreCmd.MarkFlagRequired("path") - postgresRestoreCmd.MarkFlagRequired("hostname") - postgresRestoreCmd.MarkFlagRequired("database") - postgresRestoreCmd.MarkFlagRequired("username") - postgresRestoreCmd.MarkFlagRequired("password") -} diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go deleted file mode 100644 index 86f2468..0000000 --- a/pkg/cmd/root.go +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright © 2020 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "fmt" - "github.com/spf13/cobra" - "os" - - homedir "github.com/mitchellh/go-homedir" - "github.com/spf13/viper" -) - -var cfgFile string - -// rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ - Use: "formolcli", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, -} - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) - } -} - -func init() { - cobra.OnInitialize(initConfig) - - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.formolcli.yaml)") - - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} - -// initConfig reads in config file and ENV variables if set. -func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := homedir.Dir() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - // Search config in home directory with name ".formolcli" (without extension). - viper.AddConfigPath(home) - viper.SetConfigName(".formolcli") - } - - viper.AutomaticEnv() // read in environment variables that match - - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) - } -} diff --git a/pkg/cmd/snapshot.go b/pkg/cmd/snapshot.go deleted file mode 100644 index 0cadb76..0000000 --- a/pkg/cmd/snapshot.go +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright © 2020 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "os" - - "github.com/desmo999r/formolcli/pkg/restic" - "github.com/spf13/cobra" -) - -// snapshotCmd represents the snapshot command -var snapshotCmd = &cobra.Command{ - Use: "snapshot", - Short: "A brief description of your command", -} - -var snapshotDeleteCmd = &cobra.Command{ - Use: "delete", - Short: "delete a snapshot", - Run: func(cmd *cobra.Command, args []string) { - snapshot, _ := cmd.Flags().GetString("snapshot-id") - if err := restic.DeleteSnapshot(snapshot); err != nil { - os.Exit(1) - } - }, -} - -func init() { - rootCmd.AddCommand(snapshotCmd) - snapshotCmd.AddCommand(snapshotDeleteCmd) - snapshotDeleteCmd.Flags().String("snapshot-id", "", "The snapshot to delete") - snapshotDeleteCmd.MarkFlagRequired("snapshot-id") -} diff --git a/pkg/cmd/target.go b/pkg/cmd/target.go deleted file mode 100644 index f7a63c7..0000000 --- a/pkg/cmd/target.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright © 2021 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "fmt" - - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - "github.com/desmo999r/formolcli/pkg/session" - "github.com/spf13/cobra" -) - -// targetCmd represents the target command -var targetFinalizeCmd = &cobra.Command{ - Use: "finalize", - Short: "Update the session target status", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("target called") - session.RestoreSessionUpdateTargetStatus(formolv1alpha1.Success) - }, -} - -var targetCmd = &cobra.Command{ - Use: "target", - Short: "A brief description of your command", -} - -func init() { - rootCmd.AddCommand(targetCmd) - targetCmd.AddCommand(targetFinalizeCmd) -} diff --git a/pkg/cmd/volume.go b/pkg/cmd/volume.go deleted file mode 100644 index 4cd2e7f..0000000 --- a/pkg/cmd/volume.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright © 2020 NAME HERE - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "os" - - "github.com/desmo999r/formolcli/pkg/backup" - "github.com/desmo999r/formolcli/pkg/restore" - "github.com/spf13/cobra" -) - -var volumeRestoreCmd = &cobra.Command{ - Use: "restore", - Short: "restore a volume", - Run: func(cmd *cobra.Command, args []string) { - snapshotId, _ := cmd.Flags().GetString("snapshot-id") - if err := restore.RestoreVolume(snapshotId); err != nil { - os.Exit(1) - } - }, -} - -var volumeBackupCmd = &cobra.Command{ - Use: "backup", - Short: "backup a volume", - Run: func(cmd *cobra.Command, args []string) { - paths, _ := cmd.Flags().GetStringSlice("path") - tag, _ := cmd.Flags().GetString("tag") - if err := backup.BackupVolume(tag, paths); err != nil { - os.Exit(1) - } - }, -} - -var volumeCmd = &cobra.Command{ - Use: "volume", - Short: "volume actions", - Long: `A longer description that spans multiple lines and likely contains examples -and usage of using your command. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, -} - -func init() { - rootCmd.AddCommand(volumeCmd) - volumeCmd.AddCommand(volumeBackupCmd) - volumeCmd.AddCommand(volumeRestoreCmd) - - volumeBackupCmd.Flags().StringSlice("path", nil, "Path to the data to backup") - volumeBackupCmd.Flags().String("tag", "", "Tag associated to the backup") - volumeBackupCmd.MarkFlagRequired("path") - volumeRestoreCmd.Flags().String("snapshot-id", "", "snapshot id associated to the backup") - volumeRestoreCmd.MarkFlagRequired("snapshot-id") -} diff --git a/pkg/controllers/backupsession_controller.go b/pkg/controllers/backupsession_controller.go deleted file mode 100644 index faecf7c..0000000 --- a/pkg/controllers/backupsession_controller.go +++ /dev/null @@ -1,225 +0,0 @@ -package controllers - -import ( - "context" - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" - "os" - "regexp" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "time" - - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - "github.com/desmo999r/formolcli/pkg/restic" - formolcliutils "github.com/desmo999r/formolcli/pkg/utils" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// BackupSessionReconciler reconciles a BackupSession object -type BackupSessionReconciler struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme -} - -var _ reconcile.Reconciler = &BackupSessionReconciler{} - -func (r *BackupSessionReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - time.Sleep(2 * time.Second) - log := r.Log.WithValues("backupsession", req.NamespacedName) - - // your logic here - backupSession := &formolv1alpha1.BackupSession{} - if err := r.Get(ctx, req.NamespacedName, backupSession); err != nil { - log.Error(err, "unable to get backupsession") - return reconcile.Result{}, client.IgnoreNotFound(err) - } - backupConf := &formolv1alpha1.BackupConfiguration{} - if err := r.Get(ctx, client.ObjectKey{ - Namespace: backupSession.Namespace, - Name: backupSession.Spec.Ref.Name, - }, backupConf); err != nil { - log.Error(err, "unable to get backupConfiguration") - return reconcile.Result{}, client.IgnoreNotFound(err) - } - - deploymentName := os.Getenv(formolv1alpha1.TARGET_NAME) - for _, target := range backupConf.Spec.Targets { - switch target.Kind { - case formolv1alpha1.SidecarKind: - if target.Name == deploymentName { - // We are involved in that Backup, let's see if it's our turn - status := &(backupSession.Status.Targets[len(backupSession.Status.Targets)-1]) - if status.Name == deploymentName { - log.V(0).Info("It's for us!", "target", target) - switch status.SessionState { - case formolv1alpha1.New: - log.V(0).Info("New session, move to Initializing state") - status.SessionState = formolv1alpha1.Init - if err := r.Status().Update(ctx, backupSession); err != nil { - log.Error(err, "unable to update backupsession status") - return reconcile.Result{}, err - } - case formolv1alpha1.Init: - log.V(0).Info("Start to run the backup initializing steps if any") - result := formolv1alpha1.Running - for _, step := range target.Steps { - if step.Finalize != nil && *step.Finalize == true { - continue - } - function := &formolv1alpha1.Function{} - if err := r.Get(ctx, client.ObjectKey{ - Name: step.Name, - Namespace: backupConf.Namespace, - }, function); err != nil { - log.Error(err, "unable to get function", "function", step.Name) - return reconcile.Result{}, err - } - // TODO: check the command arguments for $(VAR_NAME) arguments. If some are found, try to expand them from - // the Function.Spec EnvFrom and Env in that order - pattern := regexp.MustCompile(`^\$\((\w+)\)$`) - for i, arg := range function.Spec.Command[1:] { - i++ - if match, _ := regexp.MatchString(`^\$\$`, arg); match { - continue - } - if pattern.MatchString(arg) { - arg = pattern.ReplaceAllString(arg, "$1") - // TODO: Find arg in EnvFrom key and replace it by the value in Command[i] - for _, envFrom := range function.Spec.EnvFrom { - if envFrom.SecretRef != nil { - secret := &corev1.Secret{} - if err := r.Get(ctx, client.ObjectKey{ - Name: envFrom.SecretRef.Name, - Namespace: backupConf.Namespace, - }, secret); err != nil { - log.Error(err, "unable to get secret", "secret", envFrom.SecretRef.Name) - return reconcile.Result{}, err - } - if val, ok := secret.Data[arg]; ok { - log.V(1).Info("Found EnvFrom value for arg", "arg", arg) - function.Spec.Command[i] = string(val) - } - - } - if envFrom.ConfigMapRef != nil { - configMap := &corev1.ConfigMap{} - if err := r.Get(ctx, client.ObjectKey{ - Name: envFrom.ConfigMapRef.Name, - Namespace: backupConf.Namespace, - }, configMap); err != nil { - log.Error(err, "unable to get configMap", "configMap", envFrom.ConfigMapRef.Name) - return reconcile.Result{}, err - } - if val, ok := configMap.Data[arg]; ok { - log.V(1).Info("Found EnvFrom value for arg", "arg", arg) - function.Spec.Command[i] = val - } - } - } - for _, env := range function.Spec.Env { - if env.Name == arg { - if env.Value == "" { - if env.ValueFrom != nil { - if env.ValueFrom.SecretKeyRef != nil { - secret := &corev1.Secret{} - if err := r.Get(ctx, client.ObjectKey{ - Name: env.ValueFrom.SecretKeyRef.Name, - Namespace: backupConf.Namespace, - }, secret); err != nil { - log.Error(err, "unable to get secret", "secret", env.ValueFrom.SecretKeyRef.Name) - return reconcile.Result{}, err - } - log.V(1).Info("Found Env value for arg", "arg", arg) - function.Spec.Command[i] = string(secret.Data[env.ValueFrom.SecretKeyRef.Key]) - } - } - } else { - function.Spec.Command[i] = env.Value - } - } - } - } - } - if err := formolcliutils.RunChroot(target.ContainerName != "", function.Spec.Command[0], function.Spec.Command[1:]...); err != nil { - log.Error(err, "unable to run function command", "command", function.Spec.Command) - result = formolv1alpha1.Failure - break - } - } - status.SessionState = result - - if err := r.Status().Update(ctx, backupSession); err != nil { - log.Error(err, "unable to update backupsession status") - return reconcile.Result{}, err - } - case formolv1alpha1.Running: - log.V(0).Info("Running session. Do the backup") - result := formolv1alpha1.Finalize - status.StartTime = &metav1.Time{Time: time.Now()} - output, err := restic.BackupPaths(backupSession.Name, target.Paths) - if err != nil { - log.Error(err, "unable to backup deployment", "output", string(output)) - result = formolv1alpha1.Failure - } else { - snapshotId := restic.GetBackupResults(output) - status.SnapshotId = snapshotId - status.Duration = &metav1.Duration{Duration: time.Now().Sub(status.StartTime.Time)} - } - status.SessionState = result - log.V(1).Info("current backupSession status", "status", backupSession.Status) - if err := r.Status().Update(ctx, backupSession); err != nil { - log.Error(err, "unable to update backupsession status") - return reconcile.Result{}, err - } - case formolv1alpha1.Finalize: - log.V(0).Info("Start to run the backup finalizing steps if any") - result := formolv1alpha1.Success - for _, step := range target.Steps { - if step.Finalize != nil && *step.Finalize == true { - function := &formolv1alpha1.Function{} - if err := r.Get(ctx, client.ObjectKey{ - Name: step.Name, - Namespace: backupConf.Namespace, - }, function); err != nil { - log.Error(err, "unable to get function", "function", step.Name) - return reconcile.Result{}, err - } - if err := formolcliutils.RunChroot(target.ContainerName != "", function.Spec.Command[0], function.Spec.Command[1:]...); err != nil { - log.Error(err, "unable to run function command", "command", function.Spec.Command) - result = formolv1alpha1.Failure - break - } - } - } - status.SessionState = result - - if err := r.Status().Update(ctx, backupSession); err != nil { - log.Error(err, "unable to update backupsession status") - return reconcile.Result{}, err - } - - case formolv1alpha1.Success, formolv1alpha1.Failure: - log.V(0).Info("Backup is over") - } - } - } - } - } - return reconcile.Result{}, nil -} - -func (r *BackupSessionReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&formolv1alpha1.BackupSession{}). - WithEventFilter(predicate.Funcs{ - CreateFunc: func(e event.CreateEvent) bool { return false }, - DeleteFunc: func(e event.DeleteEvent) bool { return false }, - }). - Complete(r) -} diff --git a/pkg/controllers/restoresession_controller.go b/pkg/controllers/restoresession_controller.go deleted file mode 100644 index 6cb7877..0000000 --- a/pkg/controllers/restoresession_controller.go +++ /dev/null @@ -1,158 +0,0 @@ -package controllers - -import ( - "context" - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - formolcliutils "github.com/desmo999r/formolcli/pkg/utils" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "os" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "strings" - "time" -) - -type RestoreSessionReconciler struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme -} - -var _ reconcile.Reconciler = &RestoreSessionReconciler{} - -func (r *RestoreSessionReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { - log := r.Log.WithValues("restoresession", req.NamespacedName) - - restoreSession := &formolv1alpha1.RestoreSession{} - if err := r.Get(ctx, req.NamespacedName, restoreSession); err != nil { - log.Error(err, "unable to get restoresession") - return reconcile.Result{}, client.IgnoreNotFound(err) - } - backupSession := &formolv1alpha1.BackupSession{} - if err := r.Get(ctx, client.ObjectKey{ - Namespace: restoreSession.Namespace, - Name: restoreSession.Spec.BackupSessionRef.Ref.Name, - }, backupSession); err != nil { - if errors.IsNotFound(err) { - backupSession = &formolv1alpha1.BackupSession{ - Spec: restoreSession.Spec.BackupSessionRef.Spec, - Status: restoreSession.Spec.BackupSessionRef.Status, - } - log.V(1).Info("generated backupsession", "backupsession", backupSession) - } else { - log.Error(err, "unable to get backupsession", "restoresession", restoreSession.Spec) - return reconcile.Result{}, client.IgnoreNotFound(err) - } - } - backupConf := &formolv1alpha1.BackupConfiguration{} - if err := r.Get(ctx, client.ObjectKey{ - Namespace: restoreSession.Namespace, // we use the BackupConfiguration in RestoreSession namespace. - Name: backupSession.Spec.Ref.Name, - }, backupConf); err != nil { - log.Error(err, "unable to get backupConfiguration") - return reconcile.Result{}, client.IgnoreNotFound(err) - } - deploymentName := os.Getenv(formolv1alpha1.TARGET_NAME) - currentTargetStatus := &(restoreSession.Status.Targets[len(restoreSession.Status.Targets)-1]) - currentTarget := backupConf.Spec.Targets[len(restoreSession.Status.Targets)-1] - switch currentTarget.Kind { - case formolv1alpha1.SidecarKind: - if currentTarget.Name == deploymentName { - switch currentTargetStatus.SessionState { - case formolv1alpha1.Finalize: - log.V(0).Info("It's for us!", "target", currentTarget.Name) - podName := os.Getenv(formolv1alpha1.POD_NAME) - podNamespace := os.Getenv(formolv1alpha1.POD_NAMESPACE) - pod := &corev1.Pod{} - if err := r.Get(ctx, client.ObjectKey{ - Namespace: podNamespace, - Name: podName, - }, pod); err != nil { - log.Error(err, "unable to get pod", "name", podName, "namespace", podNamespace) - return reconcile.Result{}, err - } - for _, containerStatus := range pod.Status.ContainerStatuses { - if !containerStatus.Ready { - log.V(0).Info("Not all the containers in the pod are ready. Reschedule", "name", containerStatus.Name) - return reconcile.Result{RequeueAfter: 10 * time.Second}, nil - } - } - log.V(0).Info("All the containers in the pod are ready. Time to run the restore steps (in reverse order)") - // We iterate through the steps in reverse order - result := formolv1alpha1.Success - for i := range currentTarget.Steps { - step := currentTarget.Steps[len(currentTarget.Steps)-1-i] - log.V(1).Info("current step", "step", step.Name) - backupFunction := &formolv1alpha1.Function{} - if err := r.Get(ctx, client.ObjectKey{ - Namespace: backupConf.Namespace, - Name: step.Name, - }, backupFunction); err != nil { - log.Error(err, "unable to get backup function") - return reconcile.Result{}, err - } - // We got the backup function corresponding to the step from the BackupConfiguration - // Now let's try to get the restore function is there is one - restoreFunction := &formolv1alpha1.Function{} - if restoreFunctionName, exists := backupFunction.Annotations[formolv1alpha1.RESTORE_ANNOTATION]; exists { - log.V(0).Info("got restore function", "name", restoreFunctionName) - if err := r.Get(ctx, client.ObjectKey{ - Namespace: backupConf.Namespace, - Name: restoreFunctionName, - }, restoreFunction); err != nil { - log.Error(err, "unable to get restore function") - continue - } - } else { - if strings.HasPrefix(backupFunction.Name, "backup-") { - log.V(0).Info("backupFunction starts with 'backup-'", "name", backupFunction.Name) - if err := r.Get(ctx, client.ObjectKey{ - Namespace: backupConf.Namespace, - Name: strings.Replace(backupFunction.Name, "backup-", "restore-", 1), - }, restoreFunction); err != nil { - log.Error(err, "unable to get restore function") - continue - } - } - log.V(1).Info("No associated restore function", "step", step.Name) - } - if len(restoreFunction.Spec.Command) > 1 { - log.V(0).Info("Running the restore function", "name", restoreFunction.Name, "command", restoreFunction.Spec.Command) - if err := formolcliutils.RunChroot(currentTarget.ContainerName != "", restoreFunction.Spec.Command[0], restoreFunction.Spec.Command[1:]...); err != nil { - log.Error(err, "unable to run function command", "command", restoreFunction.Spec.Command) - result = formolv1alpha1.Failure - break - } else { - log.V(0).Info("Restore command is successful") - } - } - } - // We are done with the restore of this target. We flag it as success or failure - // so that we can move to the next step - log.V(0).Info("Finalize is over", "target", currentTarget.Name) - currentTargetStatus.SessionState = result - if err := r.Status().Update(ctx, restoreSession); err != nil { - log.Error(err, "unable to update restoresession") - } - } - } - } - - return reconcile.Result{}, nil -} - -func (r *RestoreSessionReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&formolv1alpha1.RestoreSession{}). - WithEventFilter(predicate.Funcs{ - CreateFunc: func(e event.CreateEvent) bool { return false }, - DeleteFunc: func(e event.DeleteEvent) bool { return false }, - }). - Complete(r) -} diff --git a/pkg/restic/root.go b/pkg/restic/root.go deleted file mode 100644 index d4effe4..0000000 --- a/pkg/restic/root.go +++ /dev/null @@ -1,111 +0,0 @@ -package restic - -import ( - "bufio" - "bytes" - "encoding/json" - "github.com/go-logr/logr" - "github.com/go-logr/zapr" - "go.uber.org/zap" - "os" - "os/exec" - "time" -) - -var ( - repository string - passwordFile string - aws_access_key_id string - aws_secret_access_key string - resticExec = "/usr/bin/restic" - logger logr.Logger -) - -func init() { - zapLog, _ := zap.NewDevelopment() - logger = zapr.NewLogger(zapLog) - repository = os.Getenv("RESTIC_REPOSITORY") - passwordFile = os.Getenv("RESTIC_PASSWORD") - aws_access_key_id = os.Getenv("AWS_ACCESS_KEY_ID") - aws_secret_access_key = os.Getenv("AWS_SECRET_ACCESS_KEY") -} - -func checkRepo(repo string) error { - log := logger.WithValues("backup-checkrepo", repo) - cmd := exec.Command(resticExec, "unlock", "-r", repo) - if err := cmd.Run(); err != nil { - log.Error(err, "unable to unlock repo", "repo", repo) - } - cmd = exec.Command(resticExec, "check", "-r", repo) - output, err := cmd.CombinedOutput() - log.V(1).Info("restic check output", "output", string(output)) - if err != nil { - log.V(0).Info("initializing new repo", "repo", repo) - cmd = exec.Command(resticExec, "init", "-r", repo) - output, err = cmd.CombinedOutput() - log.V(1).Info("restic init repo", "output", string(output)) - if err != nil { - log.Error(err, "something went wrong during repo init") - return err - } - } - return err -} - -func GetBackupResults(output []byte) (snapshotId string) { - log := logger.WithName("backup-getbackupresults") - scanner := bufio.NewScanner(bytes.NewReader(output)) - var dat map[string]interface{} - for scanner.Scan() { - if err := json.Unmarshal(scanner.Bytes(), &dat); err != nil { - log.Error(err, "unable to unmarshal json", "msg", string(scanner.Bytes())) - continue - } - log.V(1).Info("message on stdout", "stdout", dat) - if message_type, ok := dat["message_type"]; ok && message_type == "summary" { - snapshotId = dat["snapshot_id"].(string) - //duration = time.Duration(dat["total_duration"].(float64)*1000) * time.Millisecond - } - } - return -} - -func GetRestoreResults(output []byte) time.Duration { - return 0 * time.Millisecond -} - -func BackupPaths(tag string, paths []string) ([]byte, error) { - log := logger.WithName("backup-deployment") - if err := checkRepo(repository); err != nil { - log.Error(err, "unable to setup newrepo", "newrepo", repository) - return []byte{}, err - } - cmd := exec.Command(resticExec, append([]string{"backup", "--json", "--tag", tag, "-r", repository}, paths...)...) - output, err := cmd.CombinedOutput() - return output, err -} - -func RestorePaths(snapshotId string) ([]byte, error) { - log := logger.WithName("restore-deployment") - if err := checkRepo(repository); err != nil { - log.Error(err, "unable to setup repo", "repo", repository) - return []byte{}, err - } - cmd := exec.Command(resticExec, "restore", "-r", repository, snapshotId, "--target", "/") - output, err := cmd.CombinedOutput() - log.V(1).Info("restic restore output", "output", string(output)) - return output, err -} - -func DeleteSnapshot(snapshot string) error { - log := logger.WithValues("delete-snapshot", snapshot) - cmd := exec.Command(resticExec, "forget", "-r", repository, "--prune", snapshot) - log.V(0).Info("deleting snapshot", "snapshot", snapshot) - output, err := cmd.CombinedOutput() - log.V(1).Info("delete snapshot output", "output", string(output)) - if err != nil { - log.Error(err, "unable to delete the snapshot") - return err - } - return nil -} diff --git a/pkg/restore/root.go b/pkg/restore/root.go deleted file mode 100644 index 3327ba0..0000000 --- a/pkg/restore/root.go +++ /dev/null @@ -1,61 +0,0 @@ -package restore - -import ( - "fmt" - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - "github.com/desmo999r/formolcli/pkg/restic" - "github.com/desmo999r/formolcli/pkg/session" - "github.com/go-logr/logr" - "github.com/go-logr/zapr" - "go.uber.org/zap" - "io/ioutil" - "os" - "os/exec" -) - -var ( - //psqlExec = "/usr/bin/psql" - pg_restoreExec = "/usr/bin/pg_restore" - logger logr.Logger -) - -func init() { - zapLog, _ := zap.NewDevelopment() - logger = zapr.NewLogger(zapLog) -} - -func RestoreVolume(snapshotId string) error { - log := logger.WithName("restore-volume") - if err := session.RestoreSessionUpdateTargetStatus(formolv1alpha1.Init); err != nil { - return err - } - state := formolv1alpha1.Waiting - output, err := restic.RestorePaths(snapshotId) - if err != nil { - log.Error(err, "unable to restore volume", "output", string(output)) - state = formolv1alpha1.Failure - } - log.V(1).Info("restic restore output", "output", string(output)) - session.RestoreSessionUpdateTargetStatus(state) - return err -} - -func RestorePostgres(file string, hostname string, database string, username string, password string) error { - log := logger.WithName("restore-postgres") - pgpass := []byte(fmt.Sprintf("%s:*:%s:%s:%s", hostname, database, username, password)) - if err := ioutil.WriteFile("/output/.pgpass", pgpass, 0600); err != nil { - log.Error(err, "unable to write password to /output/.pgpass") - return err - } - defer os.Remove("/output/.pgpass") - //cmd := exec.Command(psqlExec, "--file", file, "--host", hostname, "--dbname", database, "--username", username, "--no-password") - cmd := exec.Command(pg_restoreExec, "--format=custom", "--clean", "--host", hostname, "--dbname", database, "--username", username, "--no-password", file) - cmd.Env = append(os.Environ(), "PGPASSFILE=/output/.pgpass") - output, err := cmd.CombinedOutput() - log.V(1).Info("postgres restore output", "output", string(output)) - if err != nil { - log.Error(err, "something went wrong during the restore") - return err - } - return nil -} diff --git a/pkg/server/root.go b/pkg/server/root.go deleted file mode 100644 index e181019..0000000 --- a/pkg/server/root.go +++ /dev/null @@ -1,74 +0,0 @@ -package server - -import ( - // "flag" - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - "github.com/desmo999r/formolcli/pkg/controllers" - "k8s.io/apimachinery/pkg/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "os" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log/zap" -) - -var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("server") -) - -func init() { - _ = clientgoscheme.AddToScheme(scheme) - _ = formolv1alpha1.AddToScheme(scheme) -} - -func Server() { - // var metricsAddr string - // var enableLeaderElection bool - // flag.StringVar(&metricsAddr, "metrics-addr", ":8082", "The address the metric endpoint binds to.") - // flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, - // "Enable leader election for controller manager. "+ - // "Enabling this will ensure there is only one active controller manager.") - // flag.Parse() - - ctrl.SetLogger(zap.New(zap.UseDevMode(true))) - - config, err := ctrl.GetConfig() - mgr, err := ctrl.NewManager(config, ctrl.Options{ - Scheme: scheme, - // MetricsBindAddress: metricsAddr, - // Port: 9443, - // LeaderElection: enableLeaderElection, - // LeaderElectionID: "12345.desmojim.fr", - Namespace: os.Getenv("POD_NAMESPACE"), - }) - if err != nil { - setupLog.Error(err, "unable to create manager") - os.Exit(1) - } - - // BackupSession controller - if err = (&controllers.BackupSessionReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("BackupSession"), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "BackupSession") - os.Exit(1) - } - - // RestoreSession controller - if err = (&controllers.RestoreSessionReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("RestoreSession"), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "RestoreSession") - os.Exit(1) - } - - setupLog.Info("starting manager") - if err = mgr.Start(ctrl.SetupSignalHandler()); err != nil { - setupLog.Error(err, "problem running the manager") - os.Exit(1) - } -} diff --git a/pkg/session/root.go b/pkg/session/root.go deleted file mode 100644 index 43d8e8a..0000000 --- a/pkg/session/root.go +++ /dev/null @@ -1,142 +0,0 @@ -package session - -import ( - "context" - "errors" - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - "os" - "path/filepath" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "strconv" - "strings" - "time" -) - -var ( - config *rest.Config - scheme *runtime.Scheme - cl client.Client - logger logr.Logger - //backupSession *formolv1alpha1.BackupSession -) - -func init() { - logger = zap.New(zap.UseDevMode(true)) - log := logger.WithName("InitBackupSession") - ctrl.SetLogger(logger) - config, err := rest.InClusterConfig() - if err != nil { - config, err = clientcmd.BuildConfigFromFlags("", filepath.Join(os.Getenv("HOME"), ".kube", "config")) - if err != nil { - log.Error(err, "unable to get config") - os.Exit(1) - } - } - scheme = runtime.NewScheme() - _ = formolv1alpha1.AddToScheme(scheme) - _ = clientgoscheme.AddToScheme(scheme) - cl, err = client.New(config, client.Options{Scheme: scheme}) - if err != nil { - log.Error(err, "unable to get client") - os.Exit(1) - } -} - -func BackupSessionUpdateTargetStatus(state formolv1alpha1.SessionState, snapshotId string) error { - log := logger.WithName("BackupSessionUpdateStatus") - targetName := os.Getenv("TARGET_NAME") - backupSession := &formolv1alpha1.BackupSession{} - if err := cl.Get(context.Background(), client.ObjectKey{ - Namespace: os.Getenv("BACKUPSESSION_NAMESPACE"), - Name: os.Getenv("BACKUPSESSION_NAME"), - }, backupSession); err != nil { - log.Error(err, "unable to get backupsession", "BACKUPSESSION_NAME", os.Getenv("BACKUPSESSION_NAME"), "BACKUPSESSION_NAMESPACE", os.Getenv("BACKUPSESSION_NAMESPACE")) - return err - } - target := &(backupSession.Status.Targets[len(backupSession.Status.Targets)-1]) - if target.Name == targetName { - target.SessionState = state - target.SnapshotId = snapshotId - target.Duration = &metav1.Duration{Duration: time.Now().Sub(target.StartTime.Time)} - } - - if err := cl.Status().Update(context.Background(), backupSession); err != nil { - log.Error(err, "unable to update status", "backupsession", backupSession) - return err - } - return nil -} - -func RestoreSessionUpdateTargetStatus(state formolv1alpha1.SessionState) error { - log := logger.WithName("RestoreSessionUpdateStatus") - targetName := os.Getenv("TARGET_NAME") - restoreSession := &formolv1alpha1.RestoreSession{} - if err := cl.Get(context.Background(), client.ObjectKey{ - Namespace: os.Getenv("RESTORESESSION_NAMESPACE"), - Name: os.Getenv("RESTORESESSION_NAME"), - }, restoreSession); err != nil { - log.Error(err, "unable to get backupsession", "RESTORESESSION_NAME", os.Getenv("RESTORESESSION_NAME"), "RESTORESESSION_NAMESPACE", os.Getenv("RESTORESESSION_NAMESPACE")) - return err - } - for i, target := range restoreSession.Status.Targets { - if target.Name == targetName { - if target.SessionState == formolv1alpha1.Success { - return errors.New("the restore has already been done. Skipping") - } - restoreSession.Status.Targets[i].SessionState = state - if state == formolv1alpha1.Success || state == formolv1alpha1.Failure { - restoreSession.Status.Targets[i].Duration = &metav1.Duration{Duration: time.Now().Sub(restoreSession.Status.Targets[i].StartTime.Time)} - } - } - } - - if err := cl.Status().Update(context.Background(), restoreSession); err != nil { - log.Error(err, "unable to update restoresession status", "restoresession", restoreSession) - return err - } - return nil -} - -func CreateBackupSession(name string, namespace string) { - log := logger.WithName("CreateBackupSession") - log.V(0).Info("CreateBackupSession called") - backupConfList := &formolv1alpha1.BackupConfigurationList{} - if err := cl.List(context.TODO(), backupConfList, client.InNamespace(namespace)); err != nil { - log.Error(err, "unable to get backupconf") - os.Exit(1) - } - backupConf := &formolv1alpha1.BackupConfiguration{} - for _, bc := range backupConfList.Items { - if bc.Name == name { - *backupConf = bc - } - } - log.V(0).Info("got backupConf", "backupConf", backupConf) - - backupSession := &formolv1alpha1.BackupSession{ - ObjectMeta: metav1.ObjectMeta{ - Name: strings.Join([]string{"backupsession", name, strconv.FormatInt(time.Now().Unix(), 10)}, "-"), - Namespace: namespace, - }, - Spec: formolv1alpha1.BackupSessionSpec{ - Ref: corev1.ObjectReference{ - Name: name, - Namespace: namespace, - }, - }, - } - log.V(1).Info("create backupsession", "backupSession", backupSession) - if err := cl.Create(context.TODO(), backupSession); err != nil { - log.Error(err, "unable to create backupsession") - os.Exit(1) - } -} diff --git a/pkg/utils/root.go b/pkg/utils/root.go deleted file mode 100644 index 7bf5ce7..0000000 --- a/pkg/utils/root.go +++ /dev/null @@ -1,95 +0,0 @@ -package utils - -import ( - "bytes" - formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1" - "github.com/go-logr/logr" - "github.com/go-logr/zapr" - "go.uber.org/zap" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "regexp" - "strconv" -) - -var logger logr.Logger - -func init() { - zapLog, _ := zap.NewDevelopment() - logger = zapr.NewLogger(zapLog) -} - -func Run(runCmd string, args []string) error { - log := logger.WithValues("Run", runCmd, "Args", args) - cmd := exec.Command(runCmd, args...) - output, err := cmd.CombinedOutput() - log.V(1).Info("result", "output", string(output)) - if err != nil { - log.Error(err, "something went wrong") - return err - } - return nil -} - -func RunChroot(lookForTag bool, runCmd string, args ...string) error { - log := logger.WithValues("RunChroot", runCmd, "Args", args) - root := regexp.MustCompile(`/proc/[0-9]+/root`) - env := regexp.MustCompile(`/proc/[0-9]+/environ`) - pid := strconv.Itoa(os.Getpid()) - skip := false - if err := filepath.Walk("/proc", func(path string, info os.FileInfo, err error) error { - if skip { - return filepath.SkipDir - } - if err != nil { - return nil - } - if info.IsDir() && (info.Name() == "1" || info.Name() == pid) { - return filepath.SkipDir - } - if lookForTag && env.MatchString(path) { - log.V(0).Info("Looking for tag", "file", path) - content, err := ioutil.ReadFile(path) - if err != nil { - return filepath.SkipDir - } - - var matched bool - for _, envVar := range bytes.Split(content, []byte{'\000'}) { - matched, err = regexp.Match(formolv1alpha1.TARGETCONTAINER_TAG, envVar) - if err != nil { - log.Error(err, "cannot regexp") - return err - } - if matched { - log.V(0).Info("Found the target tag", "file", path) - break - } - } - if matched == false { - return filepath.SkipDir - } - } - if root.MatchString(path) { - if _, err := filepath.EvalSymlinks(path); err != nil { - return filepath.SkipDir - } - log.V(0).Info("running chroot in", "path", path) - cmd := exec.Command("chroot", append([]string{path, runCmd}, args...)...) - output, err := cmd.CombinedOutput() - log.V(0).Info("result", "output", string(output)) - if err != nil { - log.Error(err, "something went wrong") - return err - } - skip = true - return filepath.SkipDir - } - return nil - }); err != nil { - return err - } - return nil -}