diff --git a/cmd/gtctl/cluster.go b/cmd/gtctl/cluster.go index 1c88f02c..73ce8578 100644 --- a/cmd/gtctl/cluster.go +++ b/cmd/gtctl/cluster.go @@ -19,7 +19,6 @@ import ( "github.com/spf13/cobra" - "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/delete" "github.com/GreptimeTeam/gtctl/pkg/logger" ) @@ -38,9 +37,8 @@ func NewClusterCommand(l logger.Logger) *cobra.Command { }, } - // TODO(sh2): will refactor them in the following PR. cmd.AddCommand(NewCreateClusterCommand(l)) - cmd.AddCommand(delete.NewDeleteClusterCommand(l)) + cmd.AddCommand(NewDeleteClusterCommand(l)) cmd.AddCommand(NewScaleClusterCommand(l)) cmd.AddCommand(NewGetClusterCommand(l)) cmd.AddCommand(NewListClustersCommand(l)) diff --git a/cmd/gtctl/cluster_create.go b/cmd/gtctl/cluster_create.go index 5dfb57b4..6e26c9cd 100644 --- a/cmd/gtctl/cluster_create.go +++ b/cmd/gtctl/cluster_create.go @@ -19,7 +19,6 @@ import ( "fmt" "os" "os/signal" - "strings" "syscall" "time" @@ -34,13 +33,6 @@ import ( "github.com/GreptimeTeam/gtctl/pkg/status" ) -const ( - // Various of support config type - configOperator = "operator" - configCluster = "cluster" - configEtcd = "etcd" -) - type clusterCreateCliOptions struct { // The options for deploying GreptimeDBCluster in K8s. Namespace string @@ -72,74 +64,13 @@ type clusterCreateCliOptions struct { // Common options. Timeout int DryRun bool - Set configValues + Set config.SetValues // If UseGreptimeCNArtifacts is true, the creation will download the artifacts(charts and binaries) from 'downloads.greptime.cn'. // Also, it will use ACR registry for charts images. UseGreptimeCNArtifacts bool } -type configValues struct { - rawConfig []string - - operatorConfig string - clusterConfig string - etcdConfig string -} - -// parseConfig parse raw config values and classify it to different -// categories of config type by its prefix. -func (c *configValues) parseConfig() error { - var ( - operatorConfig []string - clusterConfig []string - etcdConfig []string - ) - - for _, raw := range c.rawConfig { - if len(raw) == 0 { - return fmt.Errorf("cannot parse empty config values") - } - - var configPrefix, configValue string - values := strings.Split(raw, ",") - - for _, value := range values { - value = strings.Trim(value, " ") - cfg := strings.SplitN(value, ".", 2) - configPrefix = cfg[0] - if len(cfg) == 2 { - configValue = cfg[1] - } else { - configValue = configPrefix - } - - switch configPrefix { - case configOperator: - operatorConfig = append(operatorConfig, configValue) - case configCluster: - clusterConfig = append(clusterConfig, configValue) - case configEtcd: - etcdConfig = append(etcdConfig, configValue) - default: - clusterConfig = append(clusterConfig, value) - } - } - } - - if len(operatorConfig) > 0 { - c.operatorConfig = strings.Join(operatorConfig, ",") - } - if len(clusterConfig) > 0 { - c.clusterConfig = strings.Join(clusterConfig, ",") - } - if len(etcdConfig) > 0 { - c.etcdConfig = strings.Join(etcdConfig, ",") - } - - return nil -} - func NewCreateClusterCommand(l logger.Logger) *cobra.Command { var options clusterCreateCliOptions @@ -159,7 +90,7 @@ func NewCreateClusterCommand(l logger.Logger) *cobra.Command { cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "default", "Namespace of GreptimeDB cluster.") cmd.Flags().BoolVar(&options.DryRun, "dry-run", false, "Output the manifests without applying them.") cmd.Flags().IntVar(&options.Timeout, "timeout", 600, "Timeout in seconds for the command to complete, -1 means no timeout, default is 10 min.") - cmd.Flags().StringArrayVar(&options.Set.rawConfig, "set", []string{}, "set values on the command line for greptimedb cluster, etcd and operator (can specify multiple or separate values with commas: eg. cluster.key1=val1,etcd.key2=val2).") + cmd.Flags().StringArrayVar(&options.Set.RawConfig, "set", []string{}, "set values on the command line for greptimedb cluster, etcd and operator (can specify multiple or separate values with commas: eg. cluster.key1=val1,etcd.key2=val2).") cmd.Flags().StringVar(&options.GreptimeDBChartVersion, "greptimedb-chart-version", "", "The greptimedb helm chart version, use latest version if not specified.") cmd.Flags().StringVar(&options.GreptimeDBOperatorChartVersion, "greptimedb-operator-chart-version", "", "The greptimedb-operator helm chart version, use latest version if not specified.") cmd.Flags().StringVar(&options.EtcdChartVersion, "etcd-chart-version", "", "The greptimedb-etcd helm chart version, use latest version if not specified.") @@ -205,7 +136,7 @@ func NewCluster(args []string, options *clusterCreateCliOptions, l logger.Logger } // Parse config values that set in command line. - if err = options.Set.parseConfig(); err != nil { + if err = options.Set.Parse(); err != nil { return err } @@ -218,14 +149,14 @@ func NewCluster(args []string, options *clusterCreateCliOptions, l logger.Logger EtcdStorageClassName: options.EtcdStorageClassName, EtcdStorageSize: options.EtcdStorageSize, EtcdClusterSize: options.EtcdClusterSize, - ConfigValues: options.Set.etcdConfig, + ConfigValues: options.Set.EtcdConfig, UseGreptimeCNArtifacts: options.UseGreptimeCNArtifacts, ValuesFile: options.EtcdClusterValuesFile, }, Operator: &opt.CreateOperatorOptions{ GreptimeDBOperatorChartVersion: options.GreptimeDBOperatorChartVersion, ImageRegistry: options.ImageRegistry, - ConfigValues: options.Set.operatorConfig, + ConfigValues: options.Set.OperatorConfig, UseGreptimeCNArtifacts: options.UseGreptimeCNArtifacts, ValuesFile: options.GreptimeDBOperatorValuesFile, }, @@ -237,7 +168,7 @@ func NewCluster(args []string, options *clusterCreateCliOptions, l logger.Logger DatanodeStorageSize: options.StorageSize, DatanodeStorageRetainPolicy: options.StorageRetainPolicy, EtcdEndPoints: fmt.Sprintf("%s.%s:2379", kubernetes.EtcdClusterName(clusterName), options.EtcdNamespace), - ConfigValues: options.Set.clusterConfig, + ConfigValues: options.Set.ClusterConfig, UseGreptimeCNArtifacts: options.UseGreptimeCNArtifacts, ValuesFile: options.GreptimeDBClusterValuesFile, }, diff --git a/cmd/gtctl/cluster_delete.go b/cmd/gtctl/cluster_delete.go new file mode 100644 index 00000000..66f460db --- /dev/null +++ b/cmd/gtctl/cluster_delete.go @@ -0,0 +1,78 @@ +// Copyright 2023 Greptime Team +// +// 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 main + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + opt "github.com/GreptimeTeam/gtctl/pkg/cluster" + "github.com/GreptimeTeam/gtctl/pkg/cluster/baremetal" + "github.com/GreptimeTeam/gtctl/pkg/cluster/kubernetes" + "github.com/GreptimeTeam/gtctl/pkg/logger" +) + +type clusterDeleteOptions struct { + Namespace string + TearDownEtcd bool + + // The options for deleting GreptimeDB cluster in bare-metal. + BareMetal bool +} + +func NewDeleteClusterCommand(l logger.Logger) *cobra.Command { + var options clusterDeleteOptions + + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete a GreptimeDB cluster", + Long: `Delete a GreptimeDB cluster`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return fmt.Errorf("cluster name should be set") + } + + clusterName := args[0] + var ( + cluster opt.Operations + err error + ctx = context.TODO() + ) + + if options.BareMetal { + cluster, err = baremetal.NewCluster(l, clusterName, baremetal.WithCreateNoDirs()) + } else { + cluster, err = kubernetes.NewCluster(l) + } + if err != nil { + return err + } + + deleteOptions := &opt.DeleteOptions{ + Namespace: options.Namespace, + Name: clusterName, + } + return cluster.Delete(ctx, deleteOptions) + }, + } + + cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "default", "Namespace of GreptimeDB cluster.") + cmd.Flags().BoolVar(&options.TearDownEtcd, "tear-down-etcd", false, "Tear down etcd cluster.") + cmd.Flags().BoolVar(&options.BareMetal, "bare-metal", false, "Get the greptimedb cluster on bare-metal environment.") + + return cmd +} diff --git a/cmd/gtctl/cluster_get.go b/cmd/gtctl/cluster_get.go index 819f054a..f498ad4c 100644 --- a/cmd/gtctl/cluster_get.go +++ b/cmd/gtctl/cluster_get.go @@ -31,7 +31,7 @@ import ( type clusterGetCliOptions struct { Namespace string - // The options for getting GreptimeDBCluster in bare-metal. + // The options for getting GreptimeDB cluster in bare-metal. BareMetal bool } @@ -57,7 +57,7 @@ func NewGetClusterCommand(l logger.Logger) *cobra.Command { ) if options.BareMetal { - cluster, err = baremetal.NewCluster(l, clusterName) // TODO(sh2): call baremetal.WithCreateNoDirs() + cluster, err = baremetal.NewCluster(l, clusterName, baremetal.WithCreateNoDirs()) } else { cluster, err = kubernetes.NewCluster(l) } diff --git a/pkg/cluster/baremetal/cluster.go b/pkg/cluster/baremetal/cluster.go index 990c7ebb..2306931b 100644 --- a/pkg/cluster/baremetal/cluster.go +++ b/pkg/cluster/baremetal/cluster.go @@ -65,20 +65,26 @@ type Option func(cluster *Cluster) // WithReplaceConfig replaces current cluster config with given config. func WithReplaceConfig(cfg *config.BareMetalClusterConfig) Option { - return func(d *Cluster) { - d.config = cfg + return func(c *Cluster) { + c.config = cfg } } func WithGreptimeVersion(version string) Option { - return func(d *Cluster) { - d.config.Cluster.Artifact.Version = version + return func(c *Cluster) { + c.config.Cluster.Artifact.Version = version } } func WithEnableCache(enableCache bool) Option { - return func(d *Cluster) { - d.enableCache = enableCache + return func(c *Cluster) { + c.enableCache = enableCache + } +} + +func WithCreateNoDirs() Option { + return func(c *Cluster) { + c.createNoDirs = true } } @@ -117,19 +123,18 @@ func NewCluster(l logger.Logger, clusterName string, opts ...Option) (cluster.Op c.am = am // Configure Cluster Components. + mm.AllocateClusterScopeDirs(clusterName) if !c.createNoDirs { - mm.AllocateClusterScopeDirs(clusterName) if err = mm.CreateClusterScopeDirs(c.config); err != nil { return nil, err } - - csd := mm.GetClusterScopeDirs() - c.cc = NewClusterComponents(c.config.Cluster, components.WorkingDirs{ - DataDir: csd.DataDir, - LogsDir: csd.LogsDir, - PidsDir: csd.PidsDir, - }, &c.wg, c.logger) } + csd := mm.GetClusterScopeDirs() + c.cc = NewClusterComponents(c.config.Cluster, components.WorkingDirs{ + DataDir: csd.DataDir, + LogsDir: csd.LogsDir, + PidsDir: csd.PidsDir, + }, &c.wg, c.logger) return c, nil } diff --git a/pkg/cluster/baremetal/delete.go b/pkg/cluster/baremetal/delete.go new file mode 100644 index 00000000..4efc8e7a --- /dev/null +++ b/pkg/cluster/baremetal/delete.go @@ -0,0 +1,68 @@ +// Copyright 2023 Greptime Team +// +// 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 baremetal + +import ( + "context" + "fmt" + "os" + "syscall" + + opt "github.com/GreptimeTeam/gtctl/pkg/cluster" + fileutils "github.com/GreptimeTeam/gtctl/pkg/utils/file" +) + +func (c *Cluster) Delete(ctx context.Context, options *opt.DeleteOptions) error { + cluster, err := c.get(ctx, &opt.GetOptions{Name: options.Name}) + if err != nil { + return err + } + + running, ferr, serr := c.isClusterRunning(cluster.ForegroundPid) + if ferr != nil { + return fmt.Errorf("error checking whether cluster '%s' is running: %v", options.Name, ferr) + } + if running || serr == nil { + return fmt.Errorf("cluster '%s' is running, please stop it before deleting", options.Name) + } + + csd := c.mm.GetClusterScopeDirs() + c.logger.V(0).Infof("Deleting cluster configurations and runtime directories in %s", csd.BaseDir) + if err = c.delete(ctx, csd.BaseDir); err != nil { + return err + } + c.logger.V(0).Info("Deleted!") + + return nil +} + +func (c *Cluster) delete(_ context.Context, baseDir string) error { + return fileutils.DeleteDirIfExists(baseDir) +} + +// isClusterRunning checks the current status of cluster by sending signal to process. +func (c *Cluster) isClusterRunning(pid int) (runs bool, f error, s error) { + p, f := os.FindProcess(pid) + if f != nil { + return false, f, nil + } + + s = p.Signal(syscall.Signal(0)) + if s != nil { + return false, nil, s + } + + return true, nil, nil +} diff --git a/pkg/cluster/baremetal/get.go b/pkg/cluster/baremetal/get.go index f45fee86..994d8531 100644 --- a/pkg/cluster/baremetal/get.go +++ b/pkg/cluster/baremetal/get.go @@ -116,7 +116,6 @@ func collectClusterInfoFromBareMetal(data *cfg.BareMetalClusterMetadata) ( rows(string(greptimedbclusterv1alpha1.DatanodeComponentKind), data.Config.Cluster.Datanode.Replicas) rows(string(greptimedbclusterv1alpha1.MetaComponentKind), data.Config.Cluster.MetaSrv.Replicas) - // TODO(sh2): make "etcd" a const? bulk = append(bulk, []string{"etcd", pidsMap["etcd"]}) config, err := yaml.Marshal(data.Config) diff --git a/pkg/cluster/kubernetes/cluster.go b/pkg/cluster/kubernetes/cluster.go index 8e11f390..fe03af88 100644 --- a/pkg/cluster/kubernetes/cluster.go +++ b/pkg/cluster/kubernetes/cluster.go @@ -36,15 +36,15 @@ type Option func(cluster *Cluster) // WithDryRun enables Cluster to dry run. func WithDryRun(dryRun bool) Option { - return func(d *Cluster) { - d.dryRun = dryRun + return func(c *Cluster) { + c.dryRun = dryRun } } // WithTimeout enables Cluster to have a timeout. func WithTimeout(timeout time.Duration) Option { - return func(d *Cluster) { - d.timeout = timeout + return func(c *Cluster) { + c.timeout = timeout } } diff --git a/pkg/cluster/kubernetes/delete.go b/pkg/cluster/kubernetes/delete.go new file mode 100644 index 00000000..852ec8b1 --- /dev/null +++ b/pkg/cluster/kubernetes/delete.go @@ -0,0 +1,64 @@ +// Copyright 2023 Greptime Team +// +// 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 kubernetes + +import ( + "context" + + "k8s.io/apimachinery/pkg/api/errors" + + opt "github.com/GreptimeTeam/gtctl/pkg/cluster" +) + +func (c *Cluster) Delete(ctx context.Context, options *opt.DeleteOptions) error { + cluster, err := c.get(ctx, &opt.GetOptions{ + Namespace: options.Namespace, + Name: options.Name, + }) + if errors.IsNotFound(err) || cluster == nil { + c.logger.V(0).Infof("Cluster '%s' in '%s' not found", options.Name, options.Namespace) + return nil + } + if err != nil { + return err + } + + // TODO: should wait cluster to be terminated? + c.logger.V(0).Infof("Deleting cluster '%s' in namespace '%s'...", options.Name, options.Namespace) + if err = c.deleteCluster(ctx, options); err != nil { + return err + } + c.logger.V(0).Infof("Cluster '%s' in namespace '%s' is deleted!", options.Name, options.Namespace) + + if options.TearDownEtcd { + c.logger.V(0).Infof("Deleting etcd cluster in namespace '%s'...", options.Namespace) + if err = c.deleteEtcdCluster(ctx, &opt.DeleteOptions{ + Namespace: options.Namespace, + Name: EtcdClusterName(options.Name), + }); err != nil { + return err + } + c.logger.V(0).Infof("Etcd cluster in namespace '%s' is deleted!", options.Namespace) + } + return nil +} + +func (c *Cluster) deleteCluster(ctx context.Context, options *opt.DeleteOptions) error { + return c.client.DeleteCluster(ctx, options.Name, options.Namespace) +} + +func (c *Cluster) deleteEtcdCluster(ctx context.Context, options *opt.DeleteOptions) error { + return c.client.DeleteEtcdCluster(ctx, options.Name, options.Namespace) +} diff --git a/pkg/cluster/types.go b/pkg/cluster/types.go index 9e80957d..1694a36e 100644 --- a/pkg/cluster/types.go +++ b/pkg/cluster/types.go @@ -37,7 +37,8 @@ type Operations interface { // Create creates a new cluster. Create(ctx context.Context, options *CreateOptions, spinner *status.Spinner) error - // TODO(sh2): Delete API + // Delete deletes a specific cluster. + Delete(ctx context.Context, options *DeleteOptions) error } type GetOptions struct { @@ -60,7 +61,11 @@ type ScaleOptions struct { ComponentType greptimedbclusterv1alpha1.ComponentKind } -type DeleteOptions struct{} +type DeleteOptions struct { + Namespace string + Name string + TearDownEtcd bool +} type CreateOptions struct { Namespace string diff --git a/pkg/cmd/gtctl/cluster/delete/delete.go b/pkg/cmd/gtctl/cluster/delete/delete.go deleted file mode 100644 index a8a8fd79..00000000 --- a/pkg/cmd/gtctl/cluster/delete/delete.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2023 Greptime Team -// -// 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 delete - -import ( - "context" - "fmt" - "strings" - - greptimedbclusterv1alpha1 "github.com/GreptimeTeam/greptimedb-operator/apis/v1alpha1" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - - "github.com/GreptimeTeam/gtctl/pkg/deployer/k8s" - "github.com/GreptimeTeam/gtctl/pkg/logger" -) - -// TODO(sh2): remove this file later - -type deleteClusterOptions struct { - Namespace string - TearDownEtcd bool -} - -func NewDeleteClusterCommand(l logger.Logger) *cobra.Command { - var options deleteClusterOptions - - cmd := &cobra.Command{ - Use: "delete", - Short: "Delete a GreptimeDB cluster", - Long: `Delete a GreptimeDB cluster`, - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return fmt.Errorf("cluster name should be set") - } - - clusterName, namespace := args[0], options.Namespace - l.V(0).Infof("Deleting cluster '%s' in namespace '%s'...\n", logger.Bold(clusterName), logger.Bold(namespace)) - - k8sDeployer, err := k8s.NewDeployer(l) - if err != nil { - return err - } - - ctx := context.TODO() - name := types.NamespacedName{Namespace: options.Namespace, Name: clusterName}.String() - cluster, err := k8sDeployer.GetGreptimeDBCluster(ctx, name, nil) - if errors.IsNotFound(err) { - l.V(0).Infof("Cluster '%s' in '%s' not found\n", clusterName, namespace) - return nil - } - if err != nil { - return err - } - - rawCluster, ok := cluster.Raw.(*greptimedbclusterv1alpha1.GreptimeDBCluster) - if !ok { - return fmt.Errorf("invalid cluster type") - } - - name = types.NamespacedName{Namespace: options.Namespace, Name: clusterName}.String() - if err := k8sDeployer.DeleteGreptimeDBCluster(ctx, name, nil); err != nil { - return err - } - - // TODO(zyy17): Should we wait until the cluster is actually deleted? - l.V(0).Infof("Cluster '%s' in namespace '%s' is deleted!\n", clusterName, namespace) - - if options.TearDownEtcd { - etcdNamespace := strings.Split(strings.Split(rawCluster.Spec.Meta.EtcdEndpoints[0], ".")[1], ":")[0] - l.V(0).Infof("Deleting etcd cluster in namespace '%s'...\n", logger.Bold(etcdNamespace)) - name = types.NamespacedName{Namespace: etcdNamespace, Name: EtcdClusterName(clusterName)}.String() - if err := k8sDeployer.DeleteEtcdCluster(ctx, name, nil); err != nil { - return err - } - l.V(0).Infof("Etcd cluster in namespace '%s' is deleted!\n", etcdNamespace) - } - - return nil - }, - } - - cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "default", "Namespace of GreptimeDB cluster.") - cmd.Flags().BoolVar(&options.TearDownEtcd, "tear-down-etcd", false, "Tear down etcd cluster.") - - return cmd -} - -func EtcdClusterName(clusterName string) string { - return fmt.Sprintf("%s-etcd", clusterName) -} diff --git a/pkg/components/datanode.go b/pkg/components/datanode.go index 83af3535..ee0f237b 100644 --- a/pkg/components/datanode.go +++ b/pkg/components/datanode.go @@ -26,7 +26,6 @@ import ( greptimev1alpha1 "github.com/GreptimeTeam/greptimedb-operator/apis/v1alpha1" - opt "github.com/GreptimeTeam/gtctl/pkg/cluster" "github.com/GreptimeTeam/gtctl/pkg/config" "github.com/GreptimeTeam/gtctl/pkg/logger" fileutils "github.com/GreptimeTeam/gtctl/pkg/utils/file" @@ -176,20 +175,6 @@ func (d *datanode) IsRunning(_ context.Context) bool { return true } -func (d *datanode) Delete(ctx context.Context, options *opt.DeleteOptions) error { - for _, dir := range d.dataHomeDirs { - if err := fileutils.DeleteDirIfExists(dir); err != nil { - return err - } - } - - if err := d.delete(ctx, options); err != nil { - return err - } - - return nil -} - func generateDatanodeAddr(addr string, nodeID int) string { // Already checked in validation. host, port, _ := net.SplitHostPort(addr) diff --git a/pkg/components/etcd.go b/pkg/components/etcd.go index 65554c4c..9477a471 100644 --- a/pkg/components/etcd.go +++ b/pkg/components/etcd.go @@ -19,7 +19,6 @@ import ( "path" "sync" - opt "github.com/GreptimeTeam/gtctl/pkg/cluster" "github.com/GreptimeTeam/gtctl/pkg/logger" fileutils "github.com/GreptimeTeam/gtctl/pkg/utils/file" ) @@ -82,10 +81,3 @@ func (e *etcd) IsRunning(_ context.Context) bool { // Have not implemented the healthy checker now. return false } - -func (e *etcd) Delete(ctx context.Context, options *opt.DeleteOptions) error { - if err := e.delete(ctx, options); err != nil { - return err - } - return nil -} diff --git a/pkg/components/frontend.go b/pkg/components/frontend.go index 3bb0d202..0c16a8e8 100644 --- a/pkg/components/frontend.go +++ b/pkg/components/frontend.go @@ -22,7 +22,6 @@ import ( greptimedbclusterv1alpha1 "github.com/GreptimeTeam/greptimedb-operator/apis/v1alpha1" - opt "github.com/GreptimeTeam/gtctl/pkg/cluster" "github.com/GreptimeTeam/gtctl/pkg/config" "github.com/GreptimeTeam/gtctl/pkg/logger" fileutils "github.com/GreptimeTeam/gtctl/pkg/utils/file" @@ -108,11 +107,3 @@ func (f *frontend) IsRunning(_ context.Context) bool { // Have not implemented the healthy checker now. return false } - -func (f *frontend) Delete(ctx context.Context, options *opt.DeleteOptions) error { - if err := f.delete(ctx, options); err != nil { - return err - } - - return nil -} diff --git a/pkg/components/metasrv.go b/pkg/components/metasrv.go index ad8dc09a..f549de03 100644 --- a/pkg/components/metasrv.go +++ b/pkg/components/metasrv.go @@ -24,7 +24,6 @@ import ( "sync" "time" - opt "github.com/GreptimeTeam/gtctl/pkg/cluster" "github.com/GreptimeTeam/gtctl/pkg/config" "github.com/GreptimeTeam/gtctl/pkg/logger" fileutils "github.com/GreptimeTeam/gtctl/pkg/utils/file" @@ -160,13 +159,6 @@ func (m *metaSrv) IsRunning(_ context.Context) bool { return true } -func (m *metaSrv) Delete(ctx context.Context, options *opt.DeleteOptions) error { - if err := m.delete(ctx, options); err != nil { - return err - } - return nil -} - func generateMetaSrvAddr(addr string, nodeID int) string { host, port, _ := net.SplitHostPort(addr) portInt, _ := strconv.Atoi(port) diff --git a/pkg/components/types.go b/pkg/components/types.go index 30529f68..d0b34b56 100644 --- a/pkg/components/types.go +++ b/pkg/components/types.go @@ -16,50 +16,26 @@ package components import ( "context" - - opt "github.com/GreptimeTeam/gtctl/pkg/cluster" - fileutils "github.com/GreptimeTeam/gtctl/pkg/utils/file" ) const ( DefaultLogLevel = "info" ) -// WorkingDirs include all the dirs used in bare-metal mode. +// WorkingDirs include all the directories used in bare-metal mode. type WorkingDirs struct { DataDir string `yaml:"dataDir"` LogsDir string `yaml:"logsDir"` PidsDir string `yaml:"pidsDir"` } +// allocatedDirs include all the directories that created during bare-metal mode. type allocatedDirs struct { dataDirs []string logsDirs []string pidsDirs []string } -func (ad *allocatedDirs) delete(_ context.Context, _ *opt.DeleteOptions) error { - for _, dir := range ad.logsDirs { - if err := fileutils.DeleteDirIfExists(dir); err != nil { - return err - } - } - - for _, dir := range ad.dataDirs { - if err := fileutils.DeleteDirIfExists(dir); err != nil { - return err - } - } - - for _, dir := range ad.pidsDirs { - if err := fileutils.DeleteDirIfExists(dir); err != nil { - return err - } - } - - return nil -} - // ClusterComponent is the basic component of running GreptimeDB Cluster in bare-metal mode. type ClusterComponent interface { // Start starts cluster component by executing binary. @@ -71,9 +47,6 @@ type ClusterComponent interface { // IsRunning returns the status of current cluster component. IsRunning(ctx context.Context) bool - // Delete deletes resources that allocated in the system for current component. - Delete(ctx context.Context, options *opt.DeleteOptions) error - // Name return the name of component. Name() string } diff --git a/pkg/config/kubernetes.go b/pkg/config/kubernetes.go new file mode 100644 index 00000000..e535fbba --- /dev/null +++ b/pkg/config/kubernetes.go @@ -0,0 +1,88 @@ +// Copyright 2023 Greptime Team +// +// 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 config + +import ( + "fmt" + "strings" +) + +const ( + // Various of support config type + configOperator = "operator" + configCluster = "cluster" + configEtcd = "etcd" +) + +type SetValues struct { + RawConfig []string + + OperatorConfig string + ClusterConfig string + EtcdConfig string +} + +// Parse parses raw config values and classify it to different +// categories of config type by its prefix. +func (c *SetValues) Parse() error { + var ( + operatorConfig []string + clusterConfig []string + etcdConfig []string + ) + + for _, raw := range c.RawConfig { + if len(raw) == 0 { + return fmt.Errorf("cannot parse empty config values") + } + + var configPrefix, configValue string + values := strings.Split(raw, ",") + + for _, value := range values { + value = strings.Trim(value, " ") + cfg := strings.SplitN(value, ".", 2) + configPrefix = cfg[0] + if len(cfg) == 2 { + configValue = cfg[1] + } else { + configValue = configPrefix + } + + switch configPrefix { + case configOperator: + operatorConfig = append(operatorConfig, configValue) + case configCluster: + clusterConfig = append(clusterConfig, configValue) + case configEtcd: + etcdConfig = append(etcdConfig, configValue) + default: + clusterConfig = append(clusterConfig, value) + } + } + } + + if len(operatorConfig) > 0 { + c.OperatorConfig = strings.Join(operatorConfig, ",") + } + if len(clusterConfig) > 0 { + c.ClusterConfig = strings.Join(clusterConfig, ",") + } + if len(etcdConfig) > 0 { + c.EtcdConfig = strings.Join(etcdConfig, ",") + } + + return nil +} diff --git a/cmd/gtctl/cluster_create_test.go b/pkg/config/kubernetes_test.go similarity index 74% rename from cmd/gtctl/cluster_create_test.go rename to pkg/config/kubernetes_test.go index 7a7031b1..42fc42bd 100644 --- a/cmd/gtctl/cluster_create_test.go +++ b/pkg/config/kubernetes_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package main +package config import ( "testing" @@ -24,31 +24,31 @@ func TestParseConfig(t *testing.T) { testCases := []struct { name string config []string - expect configValues + expect SetValues err bool }{ { name: "all-with-prefix", config: []string{"cluster.foo=bar", "etcd.foo=bar", "operator.foo=bar"}, - expect: configValues{ - clusterConfig: "foo=bar", - etcdConfig: "foo=bar", - operatorConfig: "foo=bar", + expect: SetValues{ + ClusterConfig: "foo=bar", + EtcdConfig: "foo=bar", + OperatorConfig: "foo=bar", }, }, { name: "all-without-prefix", config: []string{"foo=bar", "foo.boo=bar", "foo.boo.coo=bar"}, - expect: configValues{ - clusterConfig: "foo=bar,foo.boo=bar,foo.boo.coo=bar", + expect: SetValues{ + ClusterConfig: "foo=bar,foo.boo=bar,foo.boo.coo=bar", }, }, { name: "mix-with-prefix", config: []string{"etcd.foo=bar", "foo.boo=bar", "foo.boo.coo=bar"}, - expect: configValues{ - clusterConfig: "foo.boo=bar,foo.boo.coo=bar", - etcdConfig: "foo=bar", + expect: SetValues{ + ClusterConfig: "foo.boo=bar,foo.boo.coo=bar", + EtcdConfig: "foo=bar", }, }, { @@ -59,21 +59,21 @@ func TestParseConfig(t *testing.T) { { name: "empty-config", config: []string{}, - expect: configValues{}, + expect: SetValues{}, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := configValues{rawConfig: tc.config} - err := actual.parseConfig() + actual := SetValues{RawConfig: tc.config} + err := actual.Parse() if tc.err { assert.Error(t, err) return } - tc.expect.rawConfig = tc.config + tc.expect.RawConfig = tc.config assert.Equal(t, tc.expect, actual) }) }