From 4212b3add3fe10146eb39811a0c0d06a8e43d9b0 Mon Sep 17 00:00:00 2001 From: Josh De Winne Date: Mon, 11 Dec 2023 10:20:51 -0800 Subject: [PATCH 1/2] refactor --- cli/cmd/cluster_rm.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/cli/cmd/cluster_rm.go b/cli/cmd/cluster_rm.go index b12e6c37..3a074d73 100644 --- a/cli/cmd/cluster_rm.go +++ b/cli/cmd/cluster_rm.go @@ -38,25 +38,31 @@ func (r *runners) removeCluster(_ *cobra.Command, args []string) error { } for _, cluster := range clusters { - err := r.kotsAPI.RemoveCluster(cluster.ID) - if errors.Cause(err) == platformclient.ErrForbidden { - return ErrCompatibilityMatrixTermsNotAccepted - } else if err != nil { + err := remove(r, cluster.ID) + if err != nil { return errors.Wrap(err, "remove cluster") - } else { - fmt.Printf("removed cluster %s\n", cluster.ID) } } } for _, arg := range args { - err := r.kotsAPI.RemoveCluster(arg) - if errors.Cause(err) == platformclient.ErrForbidden { - return ErrCompatibilityMatrixTermsNotAccepted - } else if err != nil { + err := remove(r, arg) + if err != nil { return errors.Wrap(err, "remove cluster") } } return nil } + +func remove(r *runners, clusterID string) error { + err := r.kotsAPI.RemoveCluster(clusterID) + if errors.Cause(err) == platformclient.ErrForbidden { + return ErrCompatibilityMatrixTermsNotAccepted + } else if err != nil { + return errors.Wrap(err, "remove cluster") + } else { + fmt.Printf("removed cluster %s\n", clusterID) + } + return nil +} From a46976782675343b830d25787f4b3ea89a8c51f2 Mon Sep 17 00:00:00 2001 From: Josh De Winne Date: Mon, 11 Dec 2023 12:48:21 -0800 Subject: [PATCH 2/2] Adding cluster rm by name or tag and dry-run --- cli/cmd/cluster.go | 25 +++++++++++++-- cli/cmd/cluster_create.go | 15 ++------- cli/cmd/cluster_rm.go | 65 ++++++++++++++++++++++++++++++++++++--- cli/cmd/runner.go | 5 ++- 4 files changed, 89 insertions(+), 21 deletions(-) diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index 2ff0fa35..1cba3265 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -1,7 +1,10 @@ package cmd import ( + "strings" + "github.com/pkg/errors" + "github.com/replicatedhq/replicated/pkg/kotsclient" "github.com/spf13/cobra" ) @@ -11,11 +14,27 @@ var ( func (r *runners) InitClusterCommand(parent *cobra.Command) *cobra.Command { cmd := &cobra.Command{ - Use: "cluster", - Short: "Manage test clusters", - Long: ``, + Use: "cluster", + Short: "Manage test clusters", + Long: ``, } parent.AddCommand(cmd) return cmd } + +func parseTags(tags []string) ([]kotsclient.ClusterTag, error) { + clusterTags := []kotsclient.ClusterTag{} + for _, tag := range tags { + tagParts := strings.SplitN(tag, "=", 2) + if len(tagParts) != 2 { + return nil, errors.Errorf("invalid tag format: %s", tag) + } + + clusterTags = append(clusterTags, kotsclient.ClusterTag{ + Key: tagParts[0], + Value: tagParts[1], + }) + } + return clusterTags, nil +} diff --git a/cli/cmd/cluster_create.go b/cli/cmd/cluster_create.go index eac582d8..f0169ec5 100644 --- a/cli/cmd/cluster_create.go +++ b/cli/cmd/cluster_create.go @@ -2,7 +2,6 @@ package cmd import ( "fmt" - "strings" "time" "github.com/moby/moby/pkg/namesgenerator" @@ -51,17 +50,9 @@ func (r *runners) createCluster(_ *cobra.Command, args []string) error { r.args.createClusterName = generateClusterName() } - tags := []kotsclient.ClusterTag{} - for _, tag := range r.args.createClusterTags { - tagParts := strings.SplitN(tag, "=", 2) - if len(tagParts) != 2 { - return errors.Errorf("invalid tag format: %s", tag) - } - - tags = append(tags, kotsclient.ClusterTag{ - Key: tagParts[0], - Value: tagParts[1], - }) + tags, err := parseTags(r.args.createClusterTags) + if err != nil { + return errors.Wrap(err, "parse tags") } opts := kotsclient.CreateClusterOpts{ diff --git a/cli/cmd/cluster_rm.go b/cli/cmd/cluster_rm.go index 3a074d73..afcec956 100644 --- a/cli/cmd/cluster_rm.go +++ b/cli/cmd/cluster_rm.go @@ -19,24 +19,75 @@ You can specify the --all flag to terminate all clusters.`, } parent.AddCommand(cmd) + cmd.Flags().StringArrayVar(&r.args.removeClusterNames, "name", []string{}, "Name of the cluster to remove (can be specified multiple times)") + cmd.Flags().StringArrayVar(&r.args.removeClusterTags, "tag", []string{}, "Tag of the cluster to remove (key=value format, can be specified multiple times)") + cmd.Flags().BoolVar(&r.args.removeClusterAll, "all", false, "remove all clusters") + cmd.Flags().BoolVar(&r.args.removeClusterDryRun, "dry-run", false, "Dry run") + return cmd } func (r *runners) removeCluster(_ *cobra.Command, args []string) error { - if len(args) == 0 && !r.args.removeClusterAll { - return errors.New("ID or --all flag required") - } else if len(args) > 0 && r.args.removeClusterAll { - return errors.New("cannot specify ID and --all flag") + if len(args) == 0 && !r.args.removeClusterAll && len(r.args.removeClusterNames) == 0 && len(r.args.removeClusterTags) == 0 { + return errors.New("One of ID, --all, --name or --tag flag required") + } else if len(args) > 0 && (r.args.removeClusterAll || len(r.args.removeClusterNames) > 0 || len(r.args.removeClusterTags) > 0) { + return errors.New("cannot specify ID and --all, --name or --tag flag") + } else if len(args) == 0 && r.args.removeClusterAll && (len(r.args.removeClusterNames) > 0 || len(r.args.removeClusterTags) > 0) { + return errors.New("cannot specify --all and --name or --tag flag") + } else if len(args) == 0 && !r.args.removeClusterAll && len(r.args.removeClusterNames) > 0 && len(r.args.removeClusterTags) > 0 { + return errors.New("cannot specify --name and --tag flag") } - if r.args.removeClusterAll { + if len(r.args.removeClusterNames) > 0 { clusters, err := r.kotsAPI.ListClusters(false, nil, nil) if err != nil { return errors.Wrap(err, "list clusters") } + for _, cluster := range clusters { + for _, name := range r.args.removeClusterNames { + if cluster.Name == name { + err := remove(r, cluster.ID) + if err != nil { + return errors.Wrap(err, "remove cluster") + } + } + } + } + } + if len(r.args.removeClusterTags) > 0 { + clusters, err := r.kotsAPI.ListClusters(false, nil, nil) + if err != nil { + return errors.Wrap(err, "list clusters") + } + tags, err := parseTags(r.args.removeClusterTags) + if err != nil { + return errors.Wrap(err, "parse tags") + } + + for _, cluster := range clusters { + if cluster.Tags != nil && len(cluster.Tags) > 0 { + for _, tag := range tags { + for _, clusterTag := range cluster.Tags { + if clusterTag.Key == tag.Key && clusterTag.Value == tag.Value { + err := remove(r, cluster.ID) + if err != nil { + return errors.Wrap(err, "remove cluster") + } + } + } + } + } + } + } + + if r.args.removeClusterAll { + clusters, err := r.kotsAPI.ListClusters(false, nil, nil) + if err != nil { + return errors.Wrap(err, "list clusters") + } for _, cluster := range clusters { err := remove(r, cluster.ID) if err != nil { @@ -56,6 +107,10 @@ func (r *runners) removeCluster(_ *cobra.Command, args []string) error { } func remove(r *runners, clusterID string) error { + if r.args.removeClusterDryRun { + fmt.Printf("would remove cluster %s\n", clusterID) + return nil + } err := r.kotsAPI.RemoveCluster(clusterID) if errors.Cause(err) == platformclient.ErrForbidden { return ErrCompatibilityMatrixTermsNotAccepted diff --git a/cli/cmd/runner.go b/cli/cmd/runner.go index de8a8f8a..1f4d0dc2 100644 --- a/cli/cmd/runner.go +++ b/cli/cmd/runner.go @@ -199,7 +199,10 @@ type runnerArgs struct { prepareClusterKotsSharedPassword string prepareClusterAppReadyTimeout time.Duration - removeClusterAll bool + removeClusterAll bool + removeClusterTags []string + removeClusterNames []string + removeClusterDryRun bool lsAppVersion string lsVersionsClusterKubernetesDistribution string