diff --git a/cli/cmd/capture/capture.go b/cli/cmd/capture/capture.go index d8eb7d8fe7..8780ec42a4 100644 --- a/cli/cmd/capture/capture.go +++ b/cli/cmd/capture/capture.go @@ -9,7 +9,10 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" ) -var name string +var opts = struct { + genericclioptions.ConfigFlags + Name *string +}{} var capture = &cobra.Command{ Use: "capture", @@ -18,8 +21,8 @@ var capture = &cobra.Command{ func init() { cmd.Retina.AddCommand(capture) - configFlags = genericclioptions.NewConfigFlags(true) - configFlags.AddFlags(capture.PersistentFlags()) - capture.PersistentFlags().StringVar(&name, "name", "", "The name of the Retina Capture") + opts.ConfigFlags = *genericclioptions.NewConfigFlags(true) + opts.AddFlags(capture.PersistentFlags()) + capture.PersistentFlags().StringVar(opts.Name, "name", "", "The name of the Retina Capture") _ = capture.MarkPersistentFlagRequired("name") } diff --git a/cli/cmd/capture/create.go b/cli/cmd/capture/create.go index ee2ce4a344..358b80a9ae 100644 --- a/cli/cmd/capture/create.go +++ b/cli/cmd/capture/create.go @@ -23,15 +23,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" ) var ( - configFlags *genericclioptions.ConfigFlags - duration time.Duration maxSize int packetSize int @@ -52,7 +49,6 @@ var ( excludeFilter string includeFilter string includeMetadata bool - namespace string jobNumLimit int nowait bool @@ -101,7 +97,7 @@ var createCapture = &cobra.Command{ Short: "create a Retina Capture", Example: createExample, RunE: func(*cobra.Command, []string) error { - kubeConfig, err := configFlags.ToRESTConfig() + kubeConfig, err := opts.ToRESTConfig() if err != nil { return errors.Wrap(err, "failed to compose k8s rest config") } @@ -124,10 +120,10 @@ var createCapture = &cobra.Command{ if nowait { retinacmd.Logger.Info("Please manually delete all capture jobs") if capture.Spec.OutputConfiguration.BlobUpload != nil { - retinacmd.Logger.Info("Please manually delete capture secret", zap.String("namespace", namespace), zap.String("secret name", *capture.Spec.OutputConfiguration.BlobUpload)) + retinacmd.Logger.Info("Please manually delete capture secret", zap.String("namespace", *opts.Namespace), zap.String("secret name", *capture.Spec.OutputConfiguration.BlobUpload)) } if capture.Spec.OutputConfiguration.S3Upload != nil && capture.Spec.OutputConfiguration.S3Upload.SecretName != "" { - retinacmd.Logger.Info("Please manually delete capture secret", zap.String("namespace", namespace), zap.String("secret name", capture.Spec.OutputConfiguration.S3Upload.SecretName)) + retinacmd.Logger.Info("Please manually delete capture secret", zap.String("namespace", *opts.Namespace), zap.String("secret name", capture.Spec.OutputConfiguration.S3Upload.SecretName)) } printCaptureResult(jobsCreated) return nil @@ -144,19 +140,19 @@ var createCapture = &cobra.Command{ retinacmd.Logger.Info("Deleting jobs as all jobs are completed") jobsFailedToDelete := deleteJobs(kubeClient, jobsCreated) if len(jobsFailedToDelete) != 0 { - retinacmd.Logger.Info("Please manually delete capture jobs failed to delete", zap.String("namespace", namespace), zap.String("job list", strings.Join(jobsFailedToDelete, ","))) + retinacmd.Logger.Info("Please manually delete capture jobs failed to delete", zap.String("namespace", *opts.Namespace), zap.String("job list", strings.Join(jobsFailedToDelete, ","))) } err = deleteSecret(kubeClient, capture.Spec.OutputConfiguration.BlobUpload) if err != nil { retinacmd.Logger.Error("Failed to delete capture secret, please manually delete it", - zap.String("namespace", namespace), zap.String("secret name", *capture.Spec.OutputConfiguration.BlobUpload), zap.Error(err)) + zap.String("namespace", *opts.Namespace), zap.String("secret name", *capture.Spec.OutputConfiguration.BlobUpload), zap.Error(err)) } err = deleteSecret(kubeClient, &capture.Spec.OutputConfiguration.S3Upload.SecretName) if err != nil { retinacmd.Logger.Error("Failed to delete capture secret, please manually delete it", - zap.String("namespace", namespace), + zap.String("namespace", *opts.Namespace), zap.String("secret name", capture.Spec.OutputConfiguration.S3Upload.SecretName), zap.Error(err), ) @@ -170,7 +166,7 @@ var createCapture = &cobra.Command{ retinacmd.Logger.Info("Not all job are completed in the given time") retinacmd.Logger.Info("Please manually delete the Capture") - return getCaptureAndPrintCaptureResult(kubeClient, capture.Name, namespace) + return getCaptureAndPrintCaptureResult(kubeClient, capture.Name, *opts.Namespace) }, } @@ -189,7 +185,7 @@ func createSecretFromBlobUpload(kubeClient kubernetes.Interface, blobUpload, cap captureConstants.CaptureOutputLocationBlobUploadSecretKey: []byte(blobUpload), }, } - secret, err := kubeClient.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) + secret, err := kubeClient.CoreV1().Secrets(*opts.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) if err != nil { return "", err } @@ -208,7 +204,7 @@ func createSecretFromS3Upload(kubeClient kubernetes.Interface, s3AccessKeyID, s3 captureConstants.CaptureOutputLocationS3UploadSecretAccessKey: []byte(s3SecretAccessKey), }, } - secret, err := kubeClient.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) + secret, err := kubeClient.CoreV1().Secrets(*opts.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) if err != nil { return "", fmt.Errorf("failed to create s3 upload secret: %w", err) } @@ -220,14 +216,14 @@ func deleteSecret(kubeClient kubernetes.Interface, secretName *string) error { return nil } - return kubeClient.CoreV1().Secrets(namespace).Delete(context.TODO(), *secretName, metav1.DeleteOptions{}) + return kubeClient.CoreV1().Secrets(*opts.Namespace).Delete(context.TODO(), *secretName, metav1.DeleteOptions{}) //nolint:wrapcheck //internal return } func createCaptureF(kubeClient kubernetes.Interface) (*retinav1alpha1.Capture, error) { capture := &retinav1alpha1.Capture{ ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, + Name: *opts.Name, + Namespace: *opts.Namespace, }, Spec: retinav1alpha1.CaptureSpec{ CaptureConfiguration: retinav1alpha1.CaptureConfiguration{ @@ -304,7 +300,7 @@ func createCaptureF(kubeClient kubernetes.Interface) (*retinav1alpha1.Capture, e if len(blobUpload) != 0 { // Mount blob url as secret onto the capture pod for security concern if blob url is not empty. - secretName, err := createSecretFromBlobUpload(kubeClient, blobUpload, name) + secretName, err := createSecretFromBlobUpload(kubeClient, blobUpload, *opts.Name) if err != nil { return nil, err } @@ -312,7 +308,7 @@ func createCaptureF(kubeClient kubernetes.Interface) (*retinav1alpha1.Capture, e } if s3Bucket != "" { - secretName, err := createSecretFromS3Upload(kubeClient, s3AccessKeyID, s3SecretAccessKey, name) + secretName, err := createSecretFromS3Upload(kubeClient, s3AccessKeyID, s3SecretAccessKey, *opts.Name) if err != nil { return nil, fmt.Errorf("failed to create s3 upload secret: %w", err) } @@ -361,12 +357,12 @@ func createJobs(kubeClient kubernetes.Interface, capture *retinav1alpha1.Capture jobsCreated := []batchv1.Job{} for _, job := range jobs { - jobCreated, err := kubeClient.BatchV1().Jobs(namespace).Create(context.TODO(), job, metav1.CreateOptions{}) + jobCreated, err := kubeClient.BatchV1().Jobs(*opts.Namespace).Create(context.TODO(), job, metav1.CreateOptions{}) if err != nil { return nil, err } jobsCreated = append(jobsCreated, *jobCreated) - retinacmd.Logger.Info("Packet capture job is created", zap.String("namespace", namespace), zap.String("capture job", jobCreated.Name)) + retinacmd.Logger.Info("Packet capture job is created", zap.String("namespace", *opts.Namespace), zap.String("capture job", jobCreated.Name)) } return jobsCreated, nil } @@ -410,7 +406,7 @@ func waitUntilJobsComplete(kubeClient kubernetes.Interface, jobs []batchv1.Job) if len(jobsIncompleted) != 0 { retinacmd.Logger.Info("Not all jobs are completed", - zap.String("namespace", namespace), + zap.String("namespace", *opts.Namespace), zap.String("Completed jobs", strings.Join(jobsCompleted, ",")), zap.String("Uncompleted packet capture jobs", strings.Join(jobsIncompleted, ",")), ) diff --git a/cli/cmd/capture/delete.go b/cli/cmd/capture/delete.go index b672f7c04b..88c5e7020d 100644 --- a/cli/cmd/capture/delete.go +++ b/cli/cmd/capture/delete.go @@ -30,7 +30,7 @@ var deleteCapture = &cobra.Command{ Short: "Delete a Retina capture", Example: deleteExample, RunE: func(*cobra.Command, []string) error { - kubeConfig, err := configFlags.ToRESTConfig() + kubeConfig, err := opts.ToRESTConfig() if err != nil { return errors.Wrap(err, "") } @@ -42,7 +42,7 @@ var deleteCapture = &cobra.Command{ captureJobSelector := &metav1.LabelSelector{ MatchLabels: map[string]string{ - label.CaptureNameLabel: name, + label.CaptureNameLabel: *opts.Name, label.AppLabel: captureConstants.CaptureAppname, }, } @@ -51,12 +51,12 @@ var deleteCapture = &cobra.Command{ LabelSelector: labelSelector.String(), } - jobList, err := kubeClient.BatchV1().Jobs(namespace).List(context.TODO(), jobListOpt) + jobList, err := kubeClient.BatchV1().Jobs(*opts.Namespace).List(context.TODO(), jobListOpt) if err != nil { return errors.Wrap(err, "failed to list capture jobs") } if len(jobList.Items) == 0 { - return errors.Errorf("capture %s in namespace %s was not found", name, namespace) + return errors.Errorf("capture %s in namespace %s was not found", *opts.Name, *opts.Namespace) } for _, job := range jobList.Items { @@ -70,13 +70,13 @@ var deleteCapture = &cobra.Command{ for _, volume := range jobList.Items[0].Spec.Template.Spec.Volumes { if volume.Secret != nil { - if err := kubeClient.CoreV1().Secrets(namespace).Delete(context.TODO(), volume.Secret.SecretName, metav1.DeleteOptions{}); err != nil { + if err := kubeClient.CoreV1().Secrets(*opts.Namespace).Delete(context.TODO(), volume.Secret.SecretName, metav1.DeleteOptions{}); err != nil { return errors.Wrap(err, "failed to delete capture secret") } break } } - retinacmd.Logger.Info(fmt.Sprintf("Retina Capture %q delete", name)) + retinacmd.Logger.Info(fmt.Sprintf("Retina Capture %q delete", *opts.Name)) return nil }, diff --git a/cli/cmd/capture/download.go b/cli/cmd/capture/download.go index 227916f33b..00142b7f75 100644 --- a/cli/cmd/capture/download.go +++ b/cli/cmd/capture/download.go @@ -45,14 +45,14 @@ var downloadCapture = &cobra.Command{ splitPath := strings.SplitN(containerPath, "/", 2) //nolint:gomnd // TODO string splitting probably isn't the right way to parse this URL? containerName := splitPath[0] - params := storage.ListBlobsParameters{Prefix: name} + params := storage.ListBlobsParameters{Prefix: *opts.Name} blobList, err := blobService.GetContainerReference(containerName).ListBlobs(params) if err != nil { return errors.Wrap(err, "failed to list blobstore ") } if len(blobList.Blobs) == 0 { - return errors.Errorf("no blobs found with prefix: %s", name) + return errors.Errorf("no blobs found with prefix: %s", *opts.Name) } for _, v := range blobList.Blobs { diff --git a/cli/cmd/capture/list.go b/cli/cmd/capture/list.go index 04f02c67af..a95cefd2c4 100644 --- a/cli/cmd/capture/list.go +++ b/cli/cmd/capture/list.go @@ -26,7 +26,7 @@ var listCaptures = &cobra.Command{ Short: "List Retina Captures", Example: listExample, RunE: func(*cobra.Command, []string) error { - kubeConfig, err := configFlags.ToRESTConfig() + kubeConfig, err := opts.ToRESTConfig() if err != nil { return errors.Wrap(err, "failed to compose k8s rest config") } @@ -36,7 +36,7 @@ var listCaptures = &cobra.Command{ return errors.Wrap(err, "failed to initialize kubernetes client") } - captureNamespace := namespace + captureNamespace := *opts.Namespace if allNamespaces { captureNamespace = "" } @@ -46,7 +46,6 @@ var listCaptures = &cobra.Command{ func init() { capture.AddCommand(listCaptures) - listCaptures.Flags().StringVarP(&namespace, "namespace", "n", "default", "Namespace to host capture job") listCaptures.Flags().BoolVarP(&allNamespaces, "all-namespaces", "A", allNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.") }