github.com/verrazzano/verrazzano-monitoring-operator@v0.0.30/verrazzano-backup-hook/main.go (about) 1 // Copyright (c) 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package main 5 6 import ( 7 "flag" 8 "fmt" 9 "github.com/verrazzano/verrazzano-monitoring-operator/verrazzano-backup-hook/constants" 10 "github.com/verrazzano/verrazzano-monitoring-operator/verrazzano-backup-hook/log" 11 "github.com/verrazzano/verrazzano-monitoring-operator/verrazzano-backup-hook/opensearch" 12 model "github.com/verrazzano/verrazzano-monitoring-operator/verrazzano-backup-hook/types" 13 futil "github.com/verrazzano/verrazzano-monitoring-operator/verrazzano-backup-hook/utilities" 14 kutil "github.com/verrazzano/verrazzano-monitoring-operator/verrazzano-backup-hook/utilities/k8s" 15 "go.uber.org/zap" 16 "k8s.io/client-go/dynamic" 17 "k8s.io/client-go/kubernetes" 18 "k8s.io/client-go/rest" 19 "net/http" 20 "os" 21 ctrl "sigs.k8s.io/controller-runtime" 22 "sigs.k8s.io/controller-runtime/pkg/client" 23 kzap "sigs.k8s.io/controller-runtime/pkg/log/zap" 24 "strings" 25 ) 26 27 var ( 28 VeleroBackupName string 29 Component string 30 Operation string 31 Profile string 32 VeleroNamespace string 33 ) 34 35 func main() { 36 flag.StringVar(&VeleroBackupName, "velero-backup-name", "", "The Velero-backup-name associated with this operation.") 37 flag.StringVar(&Component, "component", "opensearch", "The Verrazzano component to be backed up or restored (Default = opensearch).") 38 flag.StringVar(&Operation, "operation", "", "Operation must be one of 'backup' or 'restore'.") 39 flag.StringVar(&Profile, "profile", "default", "Object store credentials profile.") 40 flag.StringVar(&VeleroNamespace, "namespace", "verrazzano-backup", "Namespace where Velero component is deployed.") 41 42 // Add the zap logger flag set to the CLI. 43 opts := kzap.Options{} 44 opts.BindFlags(flag.CommandLine) 45 46 flag.Parse() 47 kzap.UseFlagOptions(&opts) 48 49 // Flag validations 50 if Operation == "" { 51 fmt.Printf("Operation cannot be empty . It has to be 'backup/restore\n") 52 os.Exit(1) 53 } 54 if Operation != constants.BackupOperation && Operation != constants.RestoreOperation { 55 fmt.Printf("Operation has to be 'backup/restore\n") 56 os.Exit(1) 57 } 58 if VeleroBackupName == "" { 59 fmt.Printf("VeleroBackupName must refer to an existing Velero backup.\n") 60 os.Exit(1) 61 } 62 63 // Initialize the zap log 64 file, err := os.CreateTemp(os.TempDir(), fmt.Sprintf("verrazzano-%s-hook-*.log", strings.ToLower(Operation))) 65 if err != nil { 66 fmt.Printf("Unable to create temp file") 67 os.Exit(1) 68 } 69 defer file.Close() 70 log, err := log.Logger(file.Name()) 71 if err != nil { 72 fmt.Printf("Unable to fetch logger") 73 os.Exit(1) 74 } 75 log.Info("Verrazzano backup and restore helper invoked.") 76 77 // Gathering k8s clients 78 done := false 79 retryCount := 0 80 k8sContextReady := true 81 var config *rest.Config 82 var kubeClientInterface *kubernetes.Clientset 83 var kubeClient client.Client 84 var dynamicKubeClientInterface dynamic.Interface 85 86 globalTimeout := futil.GetEnvWithDefault(constants.OpenSearchHealthCheckTimeoutKey, constants.OpenSearchHealthCheckTimeoutDefaultValue) 87 var checkConData model.ConnectionData 88 checkConData.VeleroTimeout = globalTimeout 89 // Initialize Opensearch object 90 search := opensearch.New(constants.OpenSearchURL, globalTimeout, http.DefaultClient, &checkConData, log) 91 // Check OpenSearch health before proceeding with backup or restore 92 err = search.EnsureOpenSearchIsHealthy() 93 if err != nil { 94 log.Errorf("Operation cannot be performed as OpenSearch is not healthy") 95 os.Exit(1) 96 } 97 98 // Feedback loop to gather k8s context 99 for !done { 100 config, err = ctrl.GetConfig() 101 if err != nil { 102 log.Errorf("Failed to get kubeconfig: %v", err) 103 k8sContextReady = false 104 } 105 kubeClientInterface, err = kubernetes.NewForConfig(config) 106 if err != nil { 107 log.Errorf("Failed to get clientset: %v", err) 108 k8sContextReady = false 109 } 110 kubeClient, err = client.New(config, client.Options{}) 111 if err != nil { 112 log.Errorf("Failed to get controller-runtime client: %v", err) 113 k8sContextReady = false 114 } 115 dynamicKubeClientInterface, err = dynamic.NewForConfig(config) 116 if err != nil { 117 log.Errorf("Failed to get dynamic client: %v", err) 118 k8sContextReady = false 119 } 120 121 if !k8sContextReady { 122 if retryCount <= constants.RetryCount { 123 message := "Unable to get context" 124 _, err := futil.WaitRandom(message, globalTimeout, log) 125 if err != nil { 126 log.Panic(err) 127 } 128 retryCount = retryCount + 1 129 // setting k8sContextReady flag to true os that subsequent checks dont re-use old value 130 // This flag will be changed to false if any k8s go-client retrieval fails. 131 log.Info("Resetting k8s context flag to true...") 132 k8sContextReady = true 133 } 134 } else { 135 done = true 136 log.Info("kubecontext retrieval successful") 137 } 138 } 139 140 // Initialize K8s object 141 k8s := kutil.New(dynamicKubeClientInterface, kubeClient, kubeClientInterface, config, Profile, log) 142 143 // Get S3 access details from Velero Backup Storage location associated with Backup given as input 144 // Ensure the Backup Storage Location is NOT default 145 openSearchConData, err := k8s.PopulateConnData(VeleroNamespace, VeleroBackupName) 146 if err != nil { 147 log.Errorf("Unable to fetch secret: %v", err) 148 os.Exit(1) 149 } 150 151 // Update OpenSearch keystore 152 _, err = k8s.UpdateKeystore(openSearchConData, globalTimeout) 153 if err != nil { 154 log.Errorf("Unable to update keystore") 155 os.Exit(1) 156 } 157 158 openSearch := opensearch.New(constants.OpenSearchURL, globalTimeout, http.DefaultClient, openSearchConData, log) 159 err = search.ReloadOpensearchSecureSettings() 160 if err != nil { 161 log.Errorf("Unable to reload security settings") 162 os.Exit(1) 163 } 164 165 switch strings.ToLower(Operation) { 166 // OpenSearch backup handling 167 case constants.BackupOperation: 168 log.Info("Commencing opensearch backup ..") 169 err = openSearch.Backup() 170 if err != nil { 171 log.Errorf("Operation '%s' unsuccessfull due to %v", Operation, zap.Error(err)) 172 os.Exit(1) 173 } 174 log.Infof("%s backup was successfull", strings.ToTitle(Component)) 175 176 case constants.RestoreOperation: 177 // OpenSearch restore handling 178 log.Infof("Commencing OpenSearch restore ..") 179 err = k8s.ScaleDeployment(constants.VMOLabelSelector, constants.VerrazzanoSystemNamespace, constants.VMODeploymentName, int32(0)) 180 if err != nil { 181 log.Errorf("Unable to scale deployment '%s' due to %v", constants.VMODeploymentName, zap.Error(err)) 182 os.Exit(1) 183 } 184 err = k8s.ScaleDeployment(constants.IngestLabelSelector, constants.VerrazzanoSystemNamespace, constants.IngestDeploymentName, int32(0)) 185 if err != nil { 186 log.Errorf("Unable to scale deployment '%s' due to %v", constants.IngestDeploymentName, zap.Error(err)) 187 os.Exit(1) 188 } 189 err = openSearch.Restore() 190 if err != nil { 191 log.Errorf("Operation '%s' unsuccessfull due to %v", Operation, zap.Error(err)) 192 os.Exit(1) 193 } 194 195 ok, err := k8s.CheckDeployment(constants.KibanaDeploymentLabelSelector, constants.VerrazzanoSystemNamespace) 196 if err != nil { 197 log.Errorf("Unable to detect Kibana deployment '%s' due to %v", constants.KibanaDeploymentLabelSelector, zap.Error(err)) 198 os.Exit(1) 199 } 200 // If kibana is deployed then scale it down 201 if ok { 202 err = k8s.ScaleDeployment(constants.KibanaLabelSelector, constants.VerrazzanoSystemNamespace, constants.KibanaDeploymentName, int32(0)) 203 if err != nil { 204 log.Errorf("Unable to scale deployment '%s' due to %v", constants.IngestDeploymentName, zap.Error(err)) 205 } 206 } 207 err = k8s.ScaleDeployment(constants.VMOLabelSelector, constants.VerrazzanoSystemNamespace, constants.VMODeploymentName, int32(1)) 208 if err != nil { 209 log.Errorf("Unable to scale deployment '%s' due to %v", constants.VMODeploymentName, zap.Error(err)) 210 } 211 212 err = k8s.CheckAllPodsAfterRestore() 213 if err != nil { 214 log.Errorf("Unable to check deployments after restoring Verrazzano Monitoring Operator %v", zap.Error(err)) 215 } 216 217 log.Infof("%s restore was successfull", strings.ToTitle(Component)) 218 219 } 220 221 }