backup works
This commit is contained in:
parent
4c300253c4
commit
aa640afff2
@ -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
BIN
bin/restic
Executable file
Binary file not shown.
@ -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
61
src/backup/root.go
Normal 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
51
src/cmd/backup.go
Normal 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
53
src/cmd/server.go
Normal 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
56
src/cmd/volume.go
Normal 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")
|
||||
}
|
||||
113
src/controllers/backupsession_controller.go
Normal file
113
src/controllers/backupsession_controller.go
Normal 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)
|
||||
}
|
||||
|
||||
@ -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
62
src/create/server.go
Normal 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)
|
||||
}
|
||||
}
|
||||
16
src/go.mod
16
src/go.mod
@ -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
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user