backup works

This commit is contained in:
Jean-Marc ANDRE 2020-12-01 09:11:59 +01:00
parent 4c300253c4
commit aa640afff2
11 changed files with 438 additions and 10 deletions

View File

@ -27,10 +27,12 @@ WORKDIR /dist
RUN cp /build/formolcli .
# Build a small image
FROM scratch
FROM arm32v7/alpine:3.12
COPY --from=builder /dist/formolcli /
RUN apk add --no-cache restic
COPY bin/restic /usr/local/bin
COPY --from=builder /dist/formolcli /usr/local/bin
# Command to run
ENTRYPOINT ["/formolcli"]
ENTRYPOINT ["/usr/local/bin/formolcli"]
CMD ["--help"]

BIN
bin/restic Executable file

Binary file not shown.

View File

@ -13,6 +13,17 @@ metadata:
---
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"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: backupsession-creator
labels:
@ -37,3 +48,19 @@ subjects:
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

61
src/backup/root.go Normal file
View File

@ -0,0 +1,61 @@
package backup
import (
"strings"
"os"
"os/exec"
"log"
)
var (
repository string
passwordFile string
aws_access_key_id string
aws_secret_access_key string
resticExec = "/usr/local/bin/restic"
)
func init() {
if repository = os.Getenv("RESTIC_REPOSITORY"); repository == "" {
log.Fatal("RESTIC_REPOSITORY not set")
}
if passwordFile = os.Getenv("RESTIC_PASSWORD"); passwordFile == "" {
log.Fatal("RESTIC_PASSWORD not set")
}
if aws_access_key_id = os.Getenv("AWS_ACCESS_KEY_ID"); aws_access_key_id == "" {
log.Fatal("AWS_ACCESS_KEY_ID not set")
}
if aws_secret_access_key = os.Getenv("AWS_SECRET_ACCESS_KEY"); aws_secret_access_key == "" {
log.Fatal("AWS_SECRET_ACCESS_KEY not set")
}
}
func checkRepo(repo string) error {
cmd := exec.Command(resticExec, "check", "-r", repo)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
err := cmd.Run()
if err != nil {
cmd = exec.Command(resticExec, "init", "-r", repo)
err = cmd.Run()
}
return err
}
func BackupVolume(path string) error {
return nil
}
func BackupDeployment(prefix string, paths []string) error {
newrepo := repository
if prefix != "" {
newrepo = repository + "/" + prefix
}
if err := checkRepo(newrepo); err != nil {
log.Fatal("unable to setup newrepo", "newrepo", newrepo)
return err
}
cmd := exec.Command(resticExec, "backup", "-r", newrepo, strings.Join(paths, " "))
return cmd.Run()
}

51
src/cmd/backup.go Normal file
View File

@ -0,0 +1,51 @@
/*
Copyright © 2020 NAME HERE <EMAIL ADDRESS>
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"
)
// backupCmd represents the backup command
var backupCmd = &cobra.Command{
Use: "backup",
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) {
fmt.Println("backup called")
},
}
func init() {
rootCmd.AddCommand(backupCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// backupCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// backupCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

53
src/cmd/server.go Normal file
View File

@ -0,0 +1,53 @@
/*
Copyright © 2020 NAME HERE <EMAIL ADDRESS>
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"
"github.com/desmo999r/formolcli/create"
)
// serverCmd represents the server command
var serverCmd = &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) {
fmt.Println("server called")
create.Server()
},
}
func init() {
createCmd.AddCommand(serverCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// serverCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// serverCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

56
src/cmd/volume.go Normal file
View File

@ -0,0 +1,56 @@
/*
Copyright © 2020 NAME HERE <EMAIL ADDRESS>
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"
"github.com/desmo999r/formolcli/backup"
)
// pvcCmd represents the pvc command
var volumeCmd = &cobra.Command{
Use: "volume",
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) {
fmt.Println("volume called")
path, _ := cmd.Flags().GetString("path")
_ = backup.BackupVolume(path)
},
}
func init() {
backupCmd.AddCommand(volumeCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// pvcCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// pvcCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
volumeCmd.Flags().String("path", "", "Path to the data to backup")
volumeCmd.MarkFlagRequired("path")
}

View File

@ -0,0 +1,113 @@
package controllers
import (
"context"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"os"
"path/filepath"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"github.com/desmo999r/formolcli/backup"
)
var (
deploymentName = ""
)
func init() {
namespace := os.Getenv("POD_NAMESPACE")
if namespace == "" {
panic("No POD_NAMESPACE env var")
}
config, err := rest.InClusterConfig()
if err != nil {
config, err = clientcmd.BuildConfigFromFlags("", filepath.Join(os.Getenv("HOME"), ".kube", "config",))
if err != nil {
panic(err.Error())
}
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic("unable to get clientset")
}
hostname := os.Getenv("POD_NAME")
if hostname == "" {
panic("unable to get hostname")
}
pod, err := clientset.CoreV1().Pods(namespace).Get(hostname, metav1.GetOptions{})
if err != nil {
panic("unable to get pod")
}
podOwner := metav1.GetControllerOf(pod)
replicasetList, err := clientset.AppsV1().ReplicaSets(namespace).List(metav1.ListOptions{
FieldSelector: "metadata.name=" + string(podOwner.Name),
})
if err != nil {
panic("unable to get replicaset" + err.Error())
}
for _, replicaset := range replicasetList.Items {
replicasetOwner := metav1.GetControllerOf(&replicaset)
deploymentName = replicasetOwner.Name
}
}
// BackupSessionReconciler reconciles a BackupSession object
type BackupSessionReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
}
func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
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 ctrl.Result{}, client.IgnoreNotFound(err)
}
log.V(1).Info("backupSession.Namespace", "namespace", backupSession.Namespace)
log.V(1).Info("backupSession.Spec.Ref.Name", "name", backupSession.Spec.Ref.Name)
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 ctrl.Result{}, client.IgnoreNotFound(err)
}
log.V(1).Info("Found BackupConfiguration", "BackupConfiguration", backupConf)
// Found the BackupConfiguration.
switch backupConf.Spec.Target.Kind {
case "Deployment":
if err := backup.BackupDeployment("", backupConf.Spec.Paths); err != nil {
log.Error(err, "unable to backup deployment")
return ctrl.Result{}, nil
}
default:
return ctrl.Result{}, nil
}
return ctrl.Result{}, nil
}
func (r *BackupSessionReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&formolv1alpha1.BackupSession{}).
Complete(r)
}

View File

@ -39,7 +39,6 @@ func CreateBackupSession(name string, namespace string) {
Spec: formolv1alpha1.BackupSessionSpec{
Ref: formolv1alpha1.Ref{
Name: name,
Namespace: namespace,
},
},
Status: formolv1alpha1.BackupSessionStatus{},

62
src/create/server.go Normal file
View File

@ -0,0 +1,62 @@
package create
import (
"os"
"flag"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"github.com/desmo999r/formolcli/controllers"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
)
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",
})
if err != nil {
setupLog.Error(err, "unable to create manager")
os.Exit(1)
}
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)
}
setupLog.Info("starting manager")
if err = mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running the manager")
os.Exit(1)
}
}

View File

@ -3,11 +3,15 @@ module github.com/desmo999r/formolcli
go 1.14
require (
github.com/desmo999r/formol v0.0.0-20201125193419-7fbf7274cbde
github.com/desmo999r/formol v0.1.4
github.com/go-logr/logr v0.1.0
github.com/mitchellh/go-homedir v1.1.0
github.com/spf13/cobra v1.1.1
github.com/spf13/viper v1.7.1
k8s.io/apimachinery v0.18.6
k8s.io/client-go v0.18.6
sigs.k8s.io/controller-runtime v0.6.4
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/spf13/cobra v0.0.5
github.com/spf13/viper v1.3.2
k8s.io/api v0.17.2
k8s.io/apimachinery v0.17.2
k8s.io/client-go v0.17.2
sigs.k8s.io/controller-runtime v0.5.0
)