Skip to content

Commit

Permalink
refactor: reimplement delete cmd for cluster delete (GreptimeTeam#179)
Browse files Browse the repository at this point in the history
* implement k8s delete api and decouple the set values config logic

Signed-off-by: sh2 <[email protected]>

* implement bare-metal delete api

Signed-off-by: sh2 <[email protected]>

---------

Signed-off-by: sh2 <[email protected]>
  • Loading branch information
shawnh2 authored Nov 1, 2023
1 parent 72efdf2 commit 412ad43
Show file tree
Hide file tree
Showing 18 changed files with 354 additions and 289 deletions.
4 changes: 1 addition & 3 deletions cmd/gtctl/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (

"github.com/spf13/cobra"

"github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/delete"
"github.com/GreptimeTeam/gtctl/pkg/logger"
)

Expand All @@ -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))
Expand Down
81 changes: 6 additions & 75 deletions cmd/gtctl/cluster_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"time"

Expand All @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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.")
Expand Down Expand Up @@ -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
}

Expand All @@ -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,
},
Expand All @@ -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,
},
Expand Down
78 changes: 78 additions & 0 deletions cmd/gtctl/cluster_delete.go
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 2 additions & 2 deletions cmd/gtctl/cluster_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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)
}
Expand Down
33 changes: 19 additions & 14 deletions pkg/cluster/baremetal/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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
}
68 changes: 68 additions & 0 deletions pkg/cluster/baremetal/delete.go
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 0 additions & 1 deletion pkg/cluster/baremetal/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 412ad43

Please sign in to comment.