Skip to content

Commit 412ad43

Browse files
authored
refactor: reimplement delete cmd for cluster delete (GreptimeTeam#179)
* 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]>
1 parent 72efdf2 commit 412ad43

File tree

18 files changed

+354
-289
lines changed

18 files changed

+354
-289
lines changed

cmd/gtctl/cluster.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919

2020
"github.com/spf13/cobra"
2121

22-
"github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/delete"
2322
"github.com/GreptimeTeam/gtctl/pkg/logger"
2423
)
2524

@@ -38,9 +37,8 @@ func NewClusterCommand(l logger.Logger) *cobra.Command {
3837
},
3938
}
4039

41-
// TODO(sh2): will refactor them in the following PR.
4240
cmd.AddCommand(NewCreateClusterCommand(l))
43-
cmd.AddCommand(delete.NewDeleteClusterCommand(l))
41+
cmd.AddCommand(NewDeleteClusterCommand(l))
4442
cmd.AddCommand(NewScaleClusterCommand(l))
4543
cmd.AddCommand(NewGetClusterCommand(l))
4644
cmd.AddCommand(NewListClustersCommand(l))

cmd/gtctl/cluster_create.go

Lines changed: 6 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"fmt"
2020
"os"
2121
"os/signal"
22-
"strings"
2322
"syscall"
2423
"time"
2524

@@ -34,13 +33,6 @@ import (
3433
"github.com/GreptimeTeam/gtctl/pkg/status"
3534
)
3635

37-
const (
38-
// Various of support config type
39-
configOperator = "operator"
40-
configCluster = "cluster"
41-
configEtcd = "etcd"
42-
)
43-
4436
type clusterCreateCliOptions struct {
4537
// The options for deploying GreptimeDBCluster in K8s.
4638
Namespace string
@@ -72,74 +64,13 @@ type clusterCreateCliOptions struct {
7264
// Common options.
7365
Timeout int
7466
DryRun bool
75-
Set configValues
67+
Set config.SetValues
7668

7769
// If UseGreptimeCNArtifacts is true, the creation will download the artifacts(charts and binaries) from 'downloads.greptime.cn'.
7870
// Also, it will use ACR registry for charts images.
7971
UseGreptimeCNArtifacts bool
8072
}
8173

82-
type configValues struct {
83-
rawConfig []string
84-
85-
operatorConfig string
86-
clusterConfig string
87-
etcdConfig string
88-
}
89-
90-
// parseConfig parse raw config values and classify it to different
91-
// categories of config type by its prefix.
92-
func (c *configValues) parseConfig() error {
93-
var (
94-
operatorConfig []string
95-
clusterConfig []string
96-
etcdConfig []string
97-
)
98-
99-
for _, raw := range c.rawConfig {
100-
if len(raw) == 0 {
101-
return fmt.Errorf("cannot parse empty config values")
102-
}
103-
104-
var configPrefix, configValue string
105-
values := strings.Split(raw, ",")
106-
107-
for _, value := range values {
108-
value = strings.Trim(value, " ")
109-
cfg := strings.SplitN(value, ".", 2)
110-
configPrefix = cfg[0]
111-
if len(cfg) == 2 {
112-
configValue = cfg[1]
113-
} else {
114-
configValue = configPrefix
115-
}
116-
117-
switch configPrefix {
118-
case configOperator:
119-
operatorConfig = append(operatorConfig, configValue)
120-
case configCluster:
121-
clusterConfig = append(clusterConfig, configValue)
122-
case configEtcd:
123-
etcdConfig = append(etcdConfig, configValue)
124-
default:
125-
clusterConfig = append(clusterConfig, value)
126-
}
127-
}
128-
}
129-
130-
if len(operatorConfig) > 0 {
131-
c.operatorConfig = strings.Join(operatorConfig, ",")
132-
}
133-
if len(clusterConfig) > 0 {
134-
c.clusterConfig = strings.Join(clusterConfig, ",")
135-
}
136-
if len(etcdConfig) > 0 {
137-
c.etcdConfig = strings.Join(etcdConfig, ",")
138-
}
139-
140-
return nil
141-
}
142-
14374
func NewCreateClusterCommand(l logger.Logger) *cobra.Command {
14475
var options clusterCreateCliOptions
14576

@@ -159,7 +90,7 @@ func NewCreateClusterCommand(l logger.Logger) *cobra.Command {
15990
cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "default", "Namespace of GreptimeDB cluster.")
16091
cmd.Flags().BoolVar(&options.DryRun, "dry-run", false, "Output the manifests without applying them.")
16192
cmd.Flags().IntVar(&options.Timeout, "timeout", 600, "Timeout in seconds for the command to complete, -1 means no timeout, default is 10 min.")
162-
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).")
93+
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).")
16394
cmd.Flags().StringVar(&options.GreptimeDBChartVersion, "greptimedb-chart-version", "", "The greptimedb helm chart version, use latest version if not specified.")
16495
cmd.Flags().StringVar(&options.GreptimeDBOperatorChartVersion, "greptimedb-operator-chart-version", "", "The greptimedb-operator helm chart version, use latest version if not specified.")
16596
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
205136
}
206137

207138
// Parse config values that set in command line.
208-
if err = options.Set.parseConfig(); err != nil {
139+
if err = options.Set.Parse(); err != nil {
209140
return err
210141
}
211142

@@ -218,14 +149,14 @@ func NewCluster(args []string, options *clusterCreateCliOptions, l logger.Logger
218149
EtcdStorageClassName: options.EtcdStorageClassName,
219150
EtcdStorageSize: options.EtcdStorageSize,
220151
EtcdClusterSize: options.EtcdClusterSize,
221-
ConfigValues: options.Set.etcdConfig,
152+
ConfigValues: options.Set.EtcdConfig,
222153
UseGreptimeCNArtifacts: options.UseGreptimeCNArtifacts,
223154
ValuesFile: options.EtcdClusterValuesFile,
224155
},
225156
Operator: &opt.CreateOperatorOptions{
226157
GreptimeDBOperatorChartVersion: options.GreptimeDBOperatorChartVersion,
227158
ImageRegistry: options.ImageRegistry,
228-
ConfigValues: options.Set.operatorConfig,
159+
ConfigValues: options.Set.OperatorConfig,
229160
UseGreptimeCNArtifacts: options.UseGreptimeCNArtifacts,
230161
ValuesFile: options.GreptimeDBOperatorValuesFile,
231162
},
@@ -237,7 +168,7 @@ func NewCluster(args []string, options *clusterCreateCliOptions, l logger.Logger
237168
DatanodeStorageSize: options.StorageSize,
238169
DatanodeStorageRetainPolicy: options.StorageRetainPolicy,
239170
EtcdEndPoints: fmt.Sprintf("%s.%s:2379", kubernetes.EtcdClusterName(clusterName), options.EtcdNamespace),
240-
ConfigValues: options.Set.clusterConfig,
171+
ConfigValues: options.Set.ClusterConfig,
241172
UseGreptimeCNArtifacts: options.UseGreptimeCNArtifacts,
242173
ValuesFile: options.GreptimeDBClusterValuesFile,
243174
},

cmd/gtctl/cluster_delete.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2023 Greptime Team
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"context"
19+
"fmt"
20+
21+
"github.com/spf13/cobra"
22+
23+
opt "github.com/GreptimeTeam/gtctl/pkg/cluster"
24+
"github.com/GreptimeTeam/gtctl/pkg/cluster/baremetal"
25+
"github.com/GreptimeTeam/gtctl/pkg/cluster/kubernetes"
26+
"github.com/GreptimeTeam/gtctl/pkg/logger"
27+
)
28+
29+
type clusterDeleteOptions struct {
30+
Namespace string
31+
TearDownEtcd bool
32+
33+
// The options for deleting GreptimeDB cluster in bare-metal.
34+
BareMetal bool
35+
}
36+
37+
func NewDeleteClusterCommand(l logger.Logger) *cobra.Command {
38+
var options clusterDeleteOptions
39+
40+
cmd := &cobra.Command{
41+
Use: "delete",
42+
Short: "Delete a GreptimeDB cluster",
43+
Long: `Delete a GreptimeDB cluster`,
44+
RunE: func(cmd *cobra.Command, args []string) error {
45+
if len(args) == 0 {
46+
return fmt.Errorf("cluster name should be set")
47+
}
48+
49+
clusterName := args[0]
50+
var (
51+
cluster opt.Operations
52+
err error
53+
ctx = context.TODO()
54+
)
55+
56+
if options.BareMetal {
57+
cluster, err = baremetal.NewCluster(l, clusterName, baremetal.WithCreateNoDirs())
58+
} else {
59+
cluster, err = kubernetes.NewCluster(l)
60+
}
61+
if err != nil {
62+
return err
63+
}
64+
65+
deleteOptions := &opt.DeleteOptions{
66+
Namespace: options.Namespace,
67+
Name: clusterName,
68+
}
69+
return cluster.Delete(ctx, deleteOptions)
70+
},
71+
}
72+
73+
cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "default", "Namespace of GreptimeDB cluster.")
74+
cmd.Flags().BoolVar(&options.TearDownEtcd, "tear-down-etcd", false, "Tear down etcd cluster.")
75+
cmd.Flags().BoolVar(&options.BareMetal, "bare-metal", false, "Get the greptimedb cluster on bare-metal environment.")
76+
77+
return cmd
78+
}

cmd/gtctl/cluster_get.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
type clusterGetCliOptions struct {
3232
Namespace string
3333

34-
// The options for getting GreptimeDBCluster in bare-metal.
34+
// The options for getting GreptimeDB cluster in bare-metal.
3535
BareMetal bool
3636
}
3737

@@ -57,7 +57,7 @@ func NewGetClusterCommand(l logger.Logger) *cobra.Command {
5757
)
5858

5959
if options.BareMetal {
60-
cluster, err = baremetal.NewCluster(l, clusterName) // TODO(sh2): call baremetal.WithCreateNoDirs()
60+
cluster, err = baremetal.NewCluster(l, clusterName, baremetal.WithCreateNoDirs())
6161
} else {
6262
cluster, err = kubernetes.NewCluster(l)
6363
}

pkg/cluster/baremetal/cluster.go

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,26 @@ type Option func(cluster *Cluster)
6565

6666
// WithReplaceConfig replaces current cluster config with given config.
6767
func WithReplaceConfig(cfg *config.BareMetalClusterConfig) Option {
68-
return func(d *Cluster) {
69-
d.config = cfg
68+
return func(c *Cluster) {
69+
c.config = cfg
7070
}
7171
}
7272

7373
func WithGreptimeVersion(version string) Option {
74-
return func(d *Cluster) {
75-
d.config.Cluster.Artifact.Version = version
74+
return func(c *Cluster) {
75+
c.config.Cluster.Artifact.Version = version
7676
}
7777
}
7878

7979
func WithEnableCache(enableCache bool) Option {
80-
return func(d *Cluster) {
81-
d.enableCache = enableCache
80+
return func(c *Cluster) {
81+
c.enableCache = enableCache
82+
}
83+
}
84+
85+
func WithCreateNoDirs() Option {
86+
return func(c *Cluster) {
87+
c.createNoDirs = true
8288
}
8389
}
8490

@@ -117,19 +123,18 @@ func NewCluster(l logger.Logger, clusterName string, opts ...Option) (cluster.Op
117123
c.am = am
118124

119125
// Configure Cluster Components.
126+
mm.AllocateClusterScopeDirs(clusterName)
120127
if !c.createNoDirs {
121-
mm.AllocateClusterScopeDirs(clusterName)
122128
if err = mm.CreateClusterScopeDirs(c.config); err != nil {
123129
return nil, err
124130
}
125-
126-
csd := mm.GetClusterScopeDirs()
127-
c.cc = NewClusterComponents(c.config.Cluster, components.WorkingDirs{
128-
DataDir: csd.DataDir,
129-
LogsDir: csd.LogsDir,
130-
PidsDir: csd.PidsDir,
131-
}, &c.wg, c.logger)
132131
}
132+
csd := mm.GetClusterScopeDirs()
133+
c.cc = NewClusterComponents(c.config.Cluster, components.WorkingDirs{
134+
DataDir: csd.DataDir,
135+
LogsDir: csd.LogsDir,
136+
PidsDir: csd.PidsDir,
137+
}, &c.wg, c.logger)
133138

134139
return c, nil
135140
}

pkg/cluster/baremetal/delete.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2023 Greptime Team
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package baremetal
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"os"
21+
"syscall"
22+
23+
opt "github.com/GreptimeTeam/gtctl/pkg/cluster"
24+
fileutils "github.com/GreptimeTeam/gtctl/pkg/utils/file"
25+
)
26+
27+
func (c *Cluster) Delete(ctx context.Context, options *opt.DeleteOptions) error {
28+
cluster, err := c.get(ctx, &opt.GetOptions{Name: options.Name})
29+
if err != nil {
30+
return err
31+
}
32+
33+
running, ferr, serr := c.isClusterRunning(cluster.ForegroundPid)
34+
if ferr != nil {
35+
return fmt.Errorf("error checking whether cluster '%s' is running: %v", options.Name, ferr)
36+
}
37+
if running || serr == nil {
38+
return fmt.Errorf("cluster '%s' is running, please stop it before deleting", options.Name)
39+
}
40+
41+
csd := c.mm.GetClusterScopeDirs()
42+
c.logger.V(0).Infof("Deleting cluster configurations and runtime directories in %s", csd.BaseDir)
43+
if err = c.delete(ctx, csd.BaseDir); err != nil {
44+
return err
45+
}
46+
c.logger.V(0).Info("Deleted!")
47+
48+
return nil
49+
}
50+
51+
func (c *Cluster) delete(_ context.Context, baseDir string) error {
52+
return fileutils.DeleteDirIfExists(baseDir)
53+
}
54+
55+
// isClusterRunning checks the current status of cluster by sending signal to process.
56+
func (c *Cluster) isClusterRunning(pid int) (runs bool, f error, s error) {
57+
p, f := os.FindProcess(pid)
58+
if f != nil {
59+
return false, f, nil
60+
}
61+
62+
s = p.Signal(syscall.Signal(0))
63+
if s != nil {
64+
return false, nil, s
65+
}
66+
67+
return true, nil, nil
68+
}

pkg/cluster/baremetal/get.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ func collectClusterInfoFromBareMetal(data *cfg.BareMetalClusterMetadata) (
116116
rows(string(greptimedbclusterv1alpha1.DatanodeComponentKind), data.Config.Cluster.Datanode.Replicas)
117117
rows(string(greptimedbclusterv1alpha1.MetaComponentKind), data.Config.Cluster.MetaSrv.Replicas)
118118

119-
// TODO(sh2): make "etcd" a const?
120119
bulk = append(bulk, []string{"etcd", pidsMap["etcd"]})
121120

122121
config, err := yaml.Marshal(data.Config)

0 commit comments

Comments
 (0)