From cfe4b9a72a98e655527f4f08b4b9e1a14b81091c Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Fri, 16 Jun 2023 00:33:24 +0800 Subject: [PATCH 01/11] fix bug with upload etcd file fail in the case of `OS:linux` and `Arch:amd64` --- pkg/deployer/baremetal/artifacts.go | 62 ++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/pkg/deployer/baremetal/artifacts.go b/pkg/deployer/baremetal/artifacts.go index 6ed74852..c383117d 100644 --- a/pkg/deployer/baremetal/artifacts.go +++ b/pkg/deployer/baremetal/artifacts.go @@ -27,6 +27,7 @@ import ( "path" "path/filepath" "runtime" + "strings" "github.com/GreptimeTeam/gtctl/pkg/logger" "github.com/GreptimeTeam/gtctl/pkg/utils" @@ -38,6 +39,9 @@ const ( EtcdGitHubOrg = "etcd-io" EtcdGithubRepo = "etcd" + + ZipExtension = ".zip" + TarGzExtension = ".tar.gz" ) // ArtifactManager is responsible for managing the artifacts of a GreptimeDB cluster. @@ -147,6 +151,9 @@ func (am *ArtifactManager) installEtcd(artifactFile, pkgDir, binDir string) erro artifactFile = path.Base(artifactFile) // If the artifactFile is '${pkgDir}/etcd-v3.5.7-darwin-arm64.zip', it will get '${pkgDir}/etcd-v3.5.7-darwin-arm64'. uncompressedDir := path.Join(pkgDir, artifactFile[:len(artifactFile)-len(filepath.Ext(artifactFile))]) + if strings.HasSuffix(uncompressedDir, ".tar") { + uncompressedDir = uncompressedDir[:len(uncompressedDir)-len(".tar")] + } binaries := []string{"etcd", "etcdctl", "etcdutl"} for _, binary := range binaries { if err := am.copyFile(path.Join(uncompressedDir, binary), path.Join(binDir, binary)); err != nil { @@ -176,7 +183,7 @@ func (am *ArtifactManager) installGreptime(artifactFile, binDir string) error { } func (am *ArtifactManager) download(typ ArtifactType, version, pkgDir string) (string, error) { - downloadURL, err := am.artifactURL(typ, version) + downloadURL, err := am.artifactURL(typ, version, ZipExtension) if err != nil { return "", err } @@ -200,16 +207,33 @@ func (am *ArtifactManager) download(typ ArtifactType, version, pkgDir string) (s } httpClient := &http.Client{} - req, err := http.NewRequest(http.MethodGet, downloadURL, nil) - if err != nil { - return "", err - } am.logger.V(3).Infof("Downloading artifact from '%s' to '%s'", downloadURL, artifactFile) - resp, err := httpClient.Do(req) + resp, err := am.startDownload(downloadURL, httpClient) if err != nil { - return "", err + downloadURL, err = am.artifactURL(typ, version, TarGzExtension) + if err != nil { + return "", err + } + artifactFile = path.Join(pkgDir, path.Base(downloadURL)) + if !am.alwaysDownload { + // The artifact file already exists, skip downloading. + if _, err := os.Stat(artifactFile); err == nil { + am.logger.V(3).Infof("The artifact file '%s' already exists, skip downloading.", artifactFile) + return artifactFile, nil + } + + // Other error happened, return it. + if err != nil && !os.IsNotExist(err) { + return "", err + } + } + resp, err = am.startDownload(downloadURL, httpClient) + if err != nil { + return "", err + } + } defer resp.Body.Close() @@ -231,7 +255,23 @@ func (am *ArtifactManager) download(typ ArtifactType, version, pkgDir string) (s return artifactFile, nil } -func (am *ArtifactManager) artifactURL(typ ArtifactType, version string) (string, error) { +func (am *ArtifactManager) startDownload(downloadURL string, client *http.Client) (*http.Response, error) { + resp := &http.Response{} + request, err := http.NewRequest(http.MethodGet, downloadURL, nil) + if err != nil { + return resp, err + } + resp, err = client.Do(request) + if resp.StatusCode != http.StatusOK { + return resp, fmt.Errorf("download failed, status code: %d", resp.StatusCode) + } + if err != nil { + return resp, err + } + return resp, nil +} + +func (am *ArtifactManager) artifactURL(typ ArtifactType, version, ext string) (string, error) { switch typ { case GreptimeArtifactType: var downloadURL string @@ -245,8 +285,8 @@ func (am *ArtifactManager) artifactURL(typ ArtifactType, version string) (string return downloadURL, nil case EtcdArtifactType: // For the function stability, we use the specific version of etcd. - downloadURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s-%s-%s-%s.zip", - EtcdGitHubOrg, EtcdGithubRepo, version, string(typ), version, runtime.GOOS, runtime.GOARCH) + downloadURL := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s-%s-%s-%s%s", + EtcdGitHubOrg, EtcdGithubRepo, version, string(typ), version, runtime.GOOS, runtime.GOARCH, ext) return downloadURL, nil default: return "", fmt.Errorf("unsupported artifact type: %v", typ) @@ -260,6 +300,8 @@ func (am *ArtifactManager) uncompress(file, dst string) error { return am.unzip(file, dst) case ".tgz": return am.untar(file, dst) + case ".gz": + return am.untar(file, dst) default: return fmt.Errorf("unsupported file type: %s", fileType) } From 5a418a360388f7f5f1feb5eee9a5bd4f1c1470d0 Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Fri, 16 Jun 2023 00:37:09 +0800 Subject: [PATCH 02/11] fix bug with upload etcd file fail in the case of `OS:linux` and `Arch:amd64` --- pkg/deployer/baremetal/artifacts.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/deployer/baremetal/artifacts.go b/pkg/deployer/baremetal/artifacts.go index c383117d..10f22daa 100644 --- a/pkg/deployer/baremetal/artifacts.go +++ b/pkg/deployer/baremetal/artifacts.go @@ -42,6 +42,7 @@ const ( ZipExtension = ".zip" TarGzExtension = ".tar.gz" + TarExtension = ".tar" ) // ArtifactManager is responsible for managing the artifacts of a GreptimeDB cluster. @@ -151,8 +152,8 @@ func (am *ArtifactManager) installEtcd(artifactFile, pkgDir, binDir string) erro artifactFile = path.Base(artifactFile) // If the artifactFile is '${pkgDir}/etcd-v3.5.7-darwin-arm64.zip', it will get '${pkgDir}/etcd-v3.5.7-darwin-arm64'. uncompressedDir := path.Join(pkgDir, artifactFile[:len(artifactFile)-len(filepath.Ext(artifactFile))]) - if strings.HasSuffix(uncompressedDir, ".tar") { - uncompressedDir = uncompressedDir[:len(uncompressedDir)-len(".tar")] + if strings.HasSuffix(uncompressedDir, TarExtension) { + uncompressedDir = uncompressedDir[:len(uncompressedDir)-len(TarExtension)] } binaries := []string{"etcd", "etcdctl", "etcdutl"} for _, binary := range binaries { From 5f0dce9c7c4b67825dd218391c65be29e7e4fff7 Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Sat, 17 Jun 2023 21:07:36 +0800 Subject: [PATCH 03/11] run `golanglint` has make error: `TrimSuffix doesn't have side effects and its return value is ignored` --- pkg/deployer/baremetal/artifacts.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/deployer/baremetal/artifacts.go b/pkg/deployer/baremetal/artifacts.go index 10f22daa..569a4a79 100644 --- a/pkg/deployer/baremetal/artifacts.go +++ b/pkg/deployer/baremetal/artifacts.go @@ -152,9 +152,7 @@ func (am *ArtifactManager) installEtcd(artifactFile, pkgDir, binDir string) erro artifactFile = path.Base(artifactFile) // If the artifactFile is '${pkgDir}/etcd-v3.5.7-darwin-arm64.zip', it will get '${pkgDir}/etcd-v3.5.7-darwin-arm64'. uncompressedDir := path.Join(pkgDir, artifactFile[:len(artifactFile)-len(filepath.Ext(artifactFile))]) - if strings.HasSuffix(uncompressedDir, TarExtension) { - uncompressedDir = uncompressedDir[:len(uncompressedDir)-len(TarExtension)] - } + uncompressedDir = strings.TrimSuffix(uncompressedDir, TarExtension) binaries := []string{"etcd", "etcdctl", "etcdutl"} for _, binary := range binaries { if err := am.copyFile(path.Join(uncompressedDir, binary), path.Join(binDir, binary)); err != nil { From b50c5e1d6cf1d7cdd039456d4eedaacbce7095c6 Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Mon, 19 Jun 2023 15:45:15 +0800 Subject: [PATCH 04/11] determine ext by `GOOS` --- pkg/deployer/baremetal/artifacts.go | 61 ++++++++++------------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/pkg/deployer/baremetal/artifacts.go b/pkg/deployer/baremetal/artifacts.go index 569a4a79..852d0e44 100644 --- a/pkg/deployer/baremetal/artifacts.go +++ b/pkg/deployer/baremetal/artifacts.go @@ -43,6 +43,9 @@ const ( ZipExtension = ".zip" TarGzExtension = ".tar.gz" TarExtension = ".tar" + + GOOSDarwin = "darwin" + GOOSLinux = "linux" ) // ArtifactManager is responsible for managing the artifacts of a GreptimeDB cluster. @@ -182,7 +185,15 @@ func (am *ArtifactManager) installGreptime(artifactFile, binDir string) error { } func (am *ArtifactManager) download(typ ArtifactType, version, pkgDir string) (string, error) { - downloadURL, err := am.artifactURL(typ, version, ZipExtension) + var extension string + if runtime.GOOS == GOOSDarwin { + extension = ZipExtension + } else if runtime.GOOS == GOOSLinux { + extension = TarGzExtension + } else { + return "", fmt.Errorf("unsupported OS: %s", runtime.GOOS) + } + downloadURL, err := am.artifactURL(typ, version, extension) if err != nil { return "", err } @@ -209,30 +220,16 @@ func (am *ArtifactManager) download(typ ArtifactType, version, pkgDir string) (s am.logger.V(3).Infof("Downloading artifact from '%s' to '%s'", downloadURL, artifactFile) - resp, err := am.startDownload(downloadURL, httpClient) + req, err := http.NewRequest(http.MethodGet, downloadURL, nil) if err != nil { - downloadURL, err = am.artifactURL(typ, version, TarGzExtension) - if err != nil { - return "", err - } - artifactFile = path.Join(pkgDir, path.Base(downloadURL)) - if !am.alwaysDownload { - // The artifact file already exists, skip downloading. - if _, err := os.Stat(artifactFile); err == nil { - am.logger.V(3).Infof("The artifact file '%s' already exists, skip downloading.", artifactFile) - return artifactFile, nil - } - - // Other error happened, return it. - if err != nil && !os.IsNotExist(err) { - return "", err - } - } - resp, err = am.startDownload(downloadURL, httpClient) - if err != nil { - return "", err - } - + return "", err + } + resp, err := httpClient.Do(req) + if err != nil { + return "", err + } + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("download failed, status code: %d", resp.StatusCode) } defer resp.Body.Close() @@ -254,22 +251,6 @@ func (am *ArtifactManager) download(typ ArtifactType, version, pkgDir string) (s return artifactFile, nil } -func (am *ArtifactManager) startDownload(downloadURL string, client *http.Client) (*http.Response, error) { - resp := &http.Response{} - request, err := http.NewRequest(http.MethodGet, downloadURL, nil) - if err != nil { - return resp, err - } - resp, err = client.Do(request) - if resp.StatusCode != http.StatusOK { - return resp, fmt.Errorf("download failed, status code: %d", resp.StatusCode) - } - if err != nil { - return resp, err - } - return resp, nil -} - func (am *ArtifactManager) artifactURL(typ ArtifactType, version, ext string) (string, error) { switch typ { case GreptimeArtifactType: From d9994289e925c655f4ba8368957ebce11b2f1b04 Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Wed, 28 Jun 2023 13:07:44 +0800 Subject: [PATCH 05/11] modify const and code style --- pkg/deployer/baremetal/artifacts.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pkg/deployer/baremetal/artifacts.go b/pkg/deployer/baremetal/artifacts.go index 852d0e44..5ae1735a 100644 --- a/pkg/deployer/baremetal/artifacts.go +++ b/pkg/deployer/baremetal/artifacts.go @@ -43,6 +43,8 @@ const ( ZipExtension = ".zip" TarGzExtension = ".tar.gz" TarExtension = ".tar" + TgzExtension = ".tgz" + GzExtension = ".gz" GOOSDarwin = "darwin" GOOSLinux = "linux" @@ -186,11 +188,12 @@ func (am *ArtifactManager) installGreptime(artifactFile, binDir string) error { func (am *ArtifactManager) download(typ ArtifactType, version, pkgDir string) (string, error) { var extension string - if runtime.GOOS == GOOSDarwin { + switch runtime.GOOS { + case GOOSDarwin: extension = ZipExtension - } else if runtime.GOOS == GOOSLinux { + case GOOSLinux: extension = TarGzExtension - } else { + default: return "", fmt.Errorf("unsupported OS: %s", runtime.GOOS) } downloadURL, err := am.artifactURL(typ, version, extension) @@ -276,11 +279,11 @@ func (am *ArtifactManager) artifactURL(typ ArtifactType, version, ext string) (s func (am *ArtifactManager) uncompress(file, dst string) error { fileType := path.Ext(file) switch fileType { - case ".zip": + case ZipExtension: return am.unzip(file, dst) - case ".tgz": + case TgzExtension: return am.untar(file, dst) - case ".gz": + case GzExtension: return am.untar(file, dst) default: return fmt.Errorf("unsupported file type: %s", fileType) From 1dfc06fd8f6cc77e7fe2f2dfa49455754c5d9e7b Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Wed, 28 Jun 2023 15:31:58 +0800 Subject: [PATCH 06/11] add `gtctl connect mysql://user:password@host:port` command --- pkg/cmd/gtctl/connect/connect.go | 48 ++++++++++++++++++++++ pkg/cmd/gtctl/connect/mysql/mysql.go | 59 ++++++++++++++++++++++++++++ pkg/cmd/gtctl/root.go | 2 + 3 files changed, 109 insertions(+) create mode 100644 pkg/cmd/gtctl/connect/connect.go create mode 100644 pkg/cmd/gtctl/connect/mysql/mysql.go diff --git a/pkg/cmd/gtctl/connect/connect.go b/pkg/cmd/gtctl/connect/connect.go new file mode 100644 index 00000000..4018952b --- /dev/null +++ b/pkg/cmd/gtctl/connect/connect.go @@ -0,0 +1,48 @@ +// 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 connect + +import ( + "errors" + "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/connect/mysql" + "github.com/GreptimeTeam/gtctl/pkg/logger" + "github.com/spf13/cobra" + "strings" +) + +func NewConnectCommand(l logger.Logger) *cobra.Command { + cmd := &cobra.Command{ + Use: "connect", + Short: "Connect to a GreptimeDB cluster", + Long: `Connect to a GreptimeDB cluster`, + RunE: connectCommand, + } + return cmd +} + +func connectCommand(cmd *cobra.Command, args []string) error { + s := args[0] + split := strings.Split(s, "://") + if len(split) != 2 { + return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") + } + prefix := split[0] + switch prefix { + case "mysql": + return mysql.ConnectCommand(cmd, args) + default: + return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") + } +} diff --git a/pkg/cmd/gtctl/connect/mysql/mysql.go b/pkg/cmd/gtctl/connect/mysql/mysql.go new file mode 100644 index 00000000..fc20ba3a --- /dev/null +++ b/pkg/cmd/gtctl/connect/mysql/mysql.go @@ -0,0 +1,59 @@ +// 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 mysql + +import ( + "errors" + "github.com/spf13/cobra" + "log" + "os" + "os/exec" + "strings" +) + +func ConnectCommand(cmd *cobra.Command, args []string) error { + s := args[0] + suffix := strings.Split(s, "://")[1] + split := strings.Split(suffix, "@") + if len(split) != 2 { + return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") + } + up := strings.Split(split[0], ":") + if len(up) != 2 { + return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") + } + hp := strings.Split(split[1], ":") + if len(hp) != 2 { + return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") + } + user := up[0] + password := up[1] + host := hp[0] + port := hp[1] + return Connect(user, password, host, port) +} + +func Connect(user, password, host, port string) error { + cmd := exec.Command("mysql", "-h", host, "-P", port, "-u", user, "-p", password) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + err := cmd.Start() + if err != nil { + log.Fatal(err) + } + err = cmd.Wait() + return err +} diff --git a/pkg/cmd/gtctl/root.go b/pkg/cmd/gtctl/root.go index 9df8cf2d..6ab76b21 100644 --- a/pkg/cmd/gtctl/root.go +++ b/pkg/cmd/gtctl/root.go @@ -16,6 +16,7 @@ package gtctl import ( "fmt" + "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/connect" "os" "github.com/spf13/cobra" @@ -62,6 +63,7 @@ func NewRootCommand() *cobra.Command { // Add all top level subcommands. cmd.AddCommand(version.NewVersionCommand(l)) cmd.AddCommand(cluster.NewClusterCommand(l)) + cmd.AddCommand(connect.NewConnectCommand(l)) return cmd } From 155a9cb9bdd2e32f3b8362691443230396959ef2 Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Wed, 28 Jun 2023 15:42:10 +0800 Subject: [PATCH 07/11] add `gtctl connect mysql://user:password@host:port` command --- pkg/cmd/gtctl/connect/connect.go | 9 +++++++-- pkg/cmd/gtctl/connect/mysql/mysql.go | 21 ++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/pkg/cmd/gtctl/connect/connect.go b/pkg/cmd/gtctl/connect/connect.go index 4018952b..13a900bd 100644 --- a/pkg/cmd/gtctl/connect/connect.go +++ b/pkg/cmd/gtctl/connect/connect.go @@ -22,6 +22,11 @@ import ( "strings" ) +const ( + SplitSeparator = "://" + MySQL = "mysql" +) + func NewConnectCommand(l logger.Logger) *cobra.Command { cmd := &cobra.Command{ Use: "connect", @@ -34,13 +39,13 @@ func NewConnectCommand(l logger.Logger) *cobra.Command { func connectCommand(cmd *cobra.Command, args []string) error { s := args[0] - split := strings.Split(s, "://") + split := strings.Split(s, SplitSeparator) if len(split) != 2 { return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") } prefix := split[0] switch prefix { - case "mysql": + case MySQL: return mysql.ConnectCommand(cmd, args) default: return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") diff --git a/pkg/cmd/gtctl/connect/mysql/mysql.go b/pkg/cmd/gtctl/connect/mysql/mysql.go index fc20ba3a..3b588658 100644 --- a/pkg/cmd/gtctl/connect/mysql/mysql.go +++ b/pkg/cmd/gtctl/connect/mysql/mysql.go @@ -23,18 +23,29 @@ import ( "strings" ) +const ( + UpSeparator = ":" + AtSeparator = "@" + ArgHost = "-h" + ArgPort = "-P" + ArgUser = "-u" + ArgPassword = "-p" + MySQL = "mysql" + SplitSeparator = "://" +) + func ConnectCommand(cmd *cobra.Command, args []string) error { s := args[0] - suffix := strings.Split(s, "://")[1] - split := strings.Split(suffix, "@") + suffix := strings.Split(s, SplitSeparator)[1] + split := strings.Split(suffix, AtSeparator) if len(split) != 2 { return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") } - up := strings.Split(split[0], ":") + up := strings.Split(split[0], UpSeparator) if len(up) != 2 { return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") } - hp := strings.Split(split[1], ":") + hp := strings.Split(split[1], UpSeparator) if len(hp) != 2 { return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") } @@ -46,7 +57,7 @@ func ConnectCommand(cmd *cobra.Command, args []string) error { } func Connect(user, password, host, port string) error { - cmd := exec.Command("mysql", "-h", host, "-P", port, "-u", user, "-p", password) + cmd := exec.Command(MySQL, ArgHost, host, ArgPort, port, ArgUser, user, ArgPassword, password) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin From 3c3468634e51f22c2a151e21050a31cb0451aecf Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Mon, 24 Jul 2023 20:24:05 +0800 Subject: [PATCH 08/11] Implement gtctl cluster connect mysql subcommand #3 --- pkg/cmd/gtctl/cluster/cluster.go | 2 + pkg/cmd/gtctl/cluster/connect/connect.go | 93 ++++++++++++++++ pkg/cmd/gtctl/cluster/connect/mysql/mysql.go | 108 +++++++++++++++++++ pkg/cmd/gtctl/cluster/connect/pg/pg.go | 24 +++++ pkg/cmd/gtctl/connect/connect.go | 53 --------- pkg/cmd/gtctl/connect/mysql/mysql.go | 70 ------------ pkg/cmd/gtctl/root.go | 2 - 7 files changed, 227 insertions(+), 125 deletions(-) create mode 100644 pkg/cmd/gtctl/cluster/connect/connect.go create mode 100644 pkg/cmd/gtctl/cluster/connect/mysql/mysql.go create mode 100644 pkg/cmd/gtctl/cluster/connect/pg/pg.go delete mode 100644 pkg/cmd/gtctl/connect/connect.go delete mode 100644 pkg/cmd/gtctl/connect/mysql/mysql.go diff --git a/pkg/cmd/gtctl/cluster/cluster.go b/pkg/cmd/gtctl/cluster/cluster.go index 4e3c3c4d..e0961c6a 100644 --- a/pkg/cmd/gtctl/cluster/cluster.go +++ b/pkg/cmd/gtctl/cluster/cluster.go @@ -19,6 +19,7 @@ import ( "github.com/spf13/cobra" + "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/connect" "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/create" "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/delete" "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/get" @@ -47,6 +48,7 @@ func NewClusterCommand(l logger.Logger) *cobra.Command { cmd.AddCommand(scale.NewScaleClusterCommand(l)) cmd.AddCommand(get.NewGetClusterCommand(l)) cmd.AddCommand(list.NewListClustersCommand(l)) + cmd.AddCommand(connect.NewConnectCommand(l)) return cmd } diff --git a/pkg/cmd/gtctl/cluster/connect/connect.go b/pkg/cmd/gtctl/cluster/connect/connect.go new file mode 100644 index 00000000..49bc824f --- /dev/null +++ b/pkg/cmd/gtctl/cluster/connect/connect.go @@ -0,0 +1,93 @@ +// 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 connect + +import ( + "context" + "fmt" + "strings" + + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + + greptimedbclusterv1alpha1 "github.com/GreptimeTeam/greptimedb-operator/apis/v1alpha1" + "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/connect/mysql" + "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/cluster/connect/pg" + "github.com/GreptimeTeam/gtctl/pkg/deployer/k8s" + "github.com/GreptimeTeam/gtctl/pkg/logger" +) + +type getClusterCliOptions struct { + Namespace string +} + +func NewConnectCommand(l logger.Logger) *cobra.Command { + var options getClusterCliOptions + cmd := &cobra.Command{ + Use: "connect", + Short: "Connect to a GreptimeDB cluster", + Long: `Connect to a GreptimeDB cluster`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return fmt.Errorf("cluster name should be set") + } + + k8sDeployer, err := k8s.NewDeployer(l) + if err != nil { + return err + } + + var ( + ctx = context.TODO() + clusterName = args[0] + namespace = options.Namespace + ) + + name := types.NamespacedName{ + Namespace: options.Namespace, + Name: clusterName, + }.String() + cluster, err := k8sDeployer.GetGreptimeDBCluster(ctx, name, nil) + if err != nil && errors.IsNotFound(err) { + l.Errorf("cluster %s in %s not found\n", clusterName, namespace) + return nil + } + rawCluster, ok := cluster.Raw.(*greptimedbclusterv1alpha1.GreptimeDBCluster) + if !ok { + return fmt.Errorf("invalid cluster type") + } + dbType := cmd.Flag("p") + switch strings.ToLower(dbType.Value.String()) { + case "mysql": + err := mysql.ConnectCommand(rawCluster, l) + if err != nil { + _ = fmt.Errorf("error connecting to mysql: %v", err) + } + case "pg": + err := pg.ConnectCommand(rawCluster, l) + if err != nil { + _ = fmt.Errorf("error connecting to postgres: %v", err) + } + default: + return fmt.Errorf("database type not supported") + } + return nil + }, + } + cmd.Flags().String("p", "mysql", "Specify a database") + cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "default", "Namespace of GreptimeDB cluster.") + return cmd +} diff --git a/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go new file mode 100644 index 00000000..ba4188bc --- /dev/null +++ b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go @@ -0,0 +1,108 @@ +// 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 mysql + +import ( + "context" + "database/sql" + "os" + "os/exec" + "strconv" + "sync" + + "github.com/go-sql-driver/mysql" + + greptimedbclusterv1alpha1 "github.com/GreptimeTeam/greptimedb-operator/apis/v1alpha1" + "github.com/GreptimeTeam/gtctl/pkg/logger" +) + +const ( + ArgHost = "-h" + ArgPort = "-P" + MySQL = "mysql" +) + +// ConnectCommand connects to a GreptimeDB cluster +func ConnectCommand(rawCluster *greptimedbclusterv1alpha1.GreptimeDBCluster, l logger.Logger) error { + return connect("127.0.0.1", strconv.Itoa(int(rawCluster.Spec.MySQLServicePort)), rawCluster.Name, l) +} + +// connect connects to a GreptimeDB cluster +func connect(host, port, clusterName string, l logger.Logger) error { + waitGroup := sync.WaitGroup{} + cmd := exec.CommandContext(context.Background(), "kubectl", "port-forward", "-n", "default", "svc/"+clusterName+"-frontend", port+":"+port) + err := cmd.Start() + if err != nil { + l.Errorf("Error starting port-forwarding: %v", err) + return err + } + go func() { + waitGroup.Add(1) + defer waitGroup.Done() + if err = cmd.Wait(); err != nil { + } + }() + for { + cfg := mysql.Config{ + Net: "tcp", + Addr: "127.0.0.1:4002", + User: "", + Passwd: "", + DBName: "", + AllowNativePasswords: true, + } + + db, err := sql.Open("mysql", cfg.FormatDSN()) + if err != nil { + continue + } + + _, err = db.Conn(context.Background()) + if err != nil { + continue + } + + err = db.Close() + if err != nil { + l.V(1).Infof("Error closing connection: %v", err) + return err + } + break + } + + cmd = exec.Command(MySQL, ArgHost, host, ArgPort, port) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + err = cmd.Start() + if err != nil { + l.Errorf("Error starting mysql client: %v", err) + return err + } + if err = cmd.Wait(); err != nil { + l.Errorf("Error waiting for mysql client to finish: %v", err) + return err + } + // gracefully stop port-forwarding + err = cmd.Process.Kill() + if err != nil { + if err.Error() != "os: process already finished" { + l.V(1).Info("Shutting down port-forwarding successfully") + } + return err + } + waitGroup.Wait() + return nil +} diff --git a/pkg/cmd/gtctl/cluster/connect/pg/pg.go b/pkg/cmd/gtctl/cluster/connect/pg/pg.go new file mode 100644 index 00000000..27293a0e --- /dev/null +++ b/pkg/cmd/gtctl/cluster/connect/pg/pg.go @@ -0,0 +1,24 @@ +// 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 pg + +import ( + greptimedbclusterv1alpha1 "github.com/GreptimeTeam/greptimedb-operator/apis/v1alpha1" + "github.com/GreptimeTeam/gtctl/pkg/logger" +) + +func ConnectCommand(rawCluster *greptimedbclusterv1alpha1.GreptimeDBCluster, l logger.Logger) error { + return nil +} diff --git a/pkg/cmd/gtctl/connect/connect.go b/pkg/cmd/gtctl/connect/connect.go deleted file mode 100644 index 13a900bd..00000000 --- a/pkg/cmd/gtctl/connect/connect.go +++ /dev/null @@ -1,53 +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 connect - -import ( - "errors" - "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/connect/mysql" - "github.com/GreptimeTeam/gtctl/pkg/logger" - "github.com/spf13/cobra" - "strings" -) - -const ( - SplitSeparator = "://" - MySQL = "mysql" -) - -func NewConnectCommand(l logger.Logger) *cobra.Command { - cmd := &cobra.Command{ - Use: "connect", - Short: "Connect to a GreptimeDB cluster", - Long: `Connect to a GreptimeDB cluster`, - RunE: connectCommand, - } - return cmd -} - -func connectCommand(cmd *cobra.Command, args []string) error { - s := args[0] - split := strings.Split(s, SplitSeparator) - if len(split) != 2 { - return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") - } - prefix := split[0] - switch prefix { - case MySQL: - return mysql.ConnectCommand(cmd, args) - default: - return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") - } -} diff --git a/pkg/cmd/gtctl/connect/mysql/mysql.go b/pkg/cmd/gtctl/connect/mysql/mysql.go deleted file mode 100644 index 3b588658..00000000 --- a/pkg/cmd/gtctl/connect/mysql/mysql.go +++ /dev/null @@ -1,70 +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 mysql - -import ( - "errors" - "github.com/spf13/cobra" - "log" - "os" - "os/exec" - "strings" -) - -const ( - UpSeparator = ":" - AtSeparator = "@" - ArgHost = "-h" - ArgPort = "-P" - ArgUser = "-u" - ArgPassword = "-p" - MySQL = "mysql" - SplitSeparator = "://" -) - -func ConnectCommand(cmd *cobra.Command, args []string) error { - s := args[0] - suffix := strings.Split(s, SplitSeparator)[1] - split := strings.Split(suffix, AtSeparator) - if len(split) != 2 { - return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") - } - up := strings.Split(split[0], UpSeparator) - if len(up) != 2 { - return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") - } - hp := strings.Split(split[1], UpSeparator) - if len(hp) != 2 { - return errors.New("invalid argument, you can try gtctl connect mysql://user:password@host:port") - } - user := up[0] - password := up[1] - host := hp[0] - port := hp[1] - return Connect(user, password, host, port) -} - -func Connect(user, password, host, port string) error { - cmd := exec.Command(MySQL, ArgHost, host, ArgPort, port, ArgUser, user, ArgPassword, password) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Stdin = os.Stdin - err := cmd.Start() - if err != nil { - log.Fatal(err) - } - err = cmd.Wait() - return err -} diff --git a/pkg/cmd/gtctl/root.go b/pkg/cmd/gtctl/root.go index 6ab76b21..9df8cf2d 100644 --- a/pkg/cmd/gtctl/root.go +++ b/pkg/cmd/gtctl/root.go @@ -16,7 +16,6 @@ package gtctl import ( "fmt" - "github.com/GreptimeTeam/gtctl/pkg/cmd/gtctl/connect" "os" "github.com/spf13/cobra" @@ -63,7 +62,6 @@ func NewRootCommand() *cobra.Command { // Add all top level subcommands. cmd.AddCommand(version.NewVersionCommand(l)) cmd.AddCommand(cluster.NewClusterCommand(l)) - cmd.AddCommand(connect.NewConnectCommand(l)) return cmd } From 85da549e4adc7f7ee6b4891372d367b6f89757db Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Mon, 24 Jul 2023 20:31:39 +0800 Subject: [PATCH 09/11] fix bug with golangci-lint #3 --- pkg/cmd/gtctl/cluster/connect/mysql/mysql.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go index ba4188bc..aadf5187 100644 --- a/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go +++ b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go @@ -48,10 +48,13 @@ func connect(host, port, clusterName string, l logger.Logger) error { l.Errorf("Error starting port-forwarding: %v", err) return err } + waitGroup.Add(1) go func() { - waitGroup.Add(1) defer waitGroup.Done() if err = cmd.Wait(); err != nil { + if err != nil && err.Error() != "signal: killed" { + l.V(1).Info("Shutting down port-forwarding successfully") + } } }() for { From b8fe51f5c01e277cdb4c606d0fd8f086d3f46ae3 Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Tue, 25 Jul 2023 21:05:47 +0800 Subject: [PATCH 10/11] improve code style #3 --- pkg/cmd/gtctl/cluster/connect/connect.go | 19 +++++---- pkg/cmd/gtctl/cluster/connect/mysql/mysql.go | 43 ++++++++++++++------ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/pkg/cmd/gtctl/cluster/connect/connect.go b/pkg/cmd/gtctl/cluster/connect/connect.go index 49bc824f..ae8c4bf0 100644 --- a/pkg/cmd/gtctl/cluster/connect/connect.go +++ b/pkg/cmd/gtctl/cluster/connect/connect.go @@ -17,7 +17,6 @@ package connect import ( "context" "fmt" - "strings" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/api/errors" @@ -30,8 +29,14 @@ import ( "github.com/GreptimeTeam/gtctl/pkg/logger" ) +const ( + connectionProtocolMySQL = "mysql" + connectionProtocolPostgres = "pg" +) + type getClusterCliOptions struct { Namespace string + Protocol string } func NewConnectCommand(l logger.Logger) *cobra.Command { @@ -69,17 +74,16 @@ func NewConnectCommand(l logger.Logger) *cobra.Command { if !ok { return fmt.Errorf("invalid cluster type") } - dbType := cmd.Flag("p") - switch strings.ToLower(dbType.Value.String()) { - case "mysql": + switch options.Protocol { + case connectionProtocolMySQL: err := mysql.ConnectCommand(rawCluster, l) if err != nil { - _ = fmt.Errorf("error connecting to mysql: %v", err) + return fmt.Errorf("error connecting to mysql: %v", err) } - case "pg": + case connectionProtocolPostgres: err := pg.ConnectCommand(rawCluster, l) if err != nil { - _ = fmt.Errorf("error connecting to postgres: %v", err) + return fmt.Errorf("error connecting to postgres: %v", err) } default: return fmt.Errorf("database type not supported") @@ -89,5 +93,6 @@ func NewConnectCommand(l logger.Logger) *cobra.Command { } cmd.Flags().String("p", "mysql", "Specify a database") cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "default", "Namespace of GreptimeDB cluster.") + cmd.Flags().StringVarP(&options.Protocol, "protocol", "p", "mysql", "Specify a database") return cmd } diff --git a/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go index aadf5187..4f43e02e 100644 --- a/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go +++ b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go @@ -21,6 +21,7 @@ import ( "os/exec" "strconv" "sync" + "syscall" "github.com/go-sql-driver/mysql" @@ -29,9 +30,14 @@ import ( ) const ( - ArgHost = "-h" - ArgPort = "-P" - MySQL = "mysql" + ArgHost = "-h" + ArgPort = "-P" + MySQL = "mysql" + DefaultAddr = "127.0.0.1" + DefaultNet = "tcp" + PrePort = ":" + Kubectl = "kubectl" + PortForward = "port-forward" ) // ConnectCommand connects to a GreptimeDB cluster @@ -42,7 +48,7 @@ func ConnectCommand(rawCluster *greptimedbclusterv1alpha1.GreptimeDBCluster, l l // connect connects to a GreptimeDB cluster func connect(host, port, clusterName string, l logger.Logger) error { waitGroup := sync.WaitGroup{} - cmd := exec.CommandContext(context.Background(), "kubectl", "port-forward", "-n", "default", "svc/"+clusterName+"-frontend", port+":"+port) + cmd := exec.CommandContext(context.Background(), Kubectl, PortForward, "-n", "default", "svc/"+clusterName+"-frontend", port+PrePort+port) err := cmd.Start() if err != nil { l.Errorf("Error starting port-forwarding: %v", err) @@ -52,22 +58,28 @@ func connect(host, port, clusterName string, l logger.Logger) error { go func() { defer waitGroup.Done() if err = cmd.Wait(); err != nil { - if err != nil && err.Error() != "signal: killed" { - l.V(1).Info("Shutting down port-forwarding successfully") + //exit status 1 + exitError, ok := err.(*exec.ExitError) + if !ok { + l.Errorf("Error waiting for port-forwarding to finish: %v", err) + return + } + if exitError.Sys().(syscall.WaitStatus).ExitStatus() == 1 { + return } } }() for { cfg := mysql.Config{ - Net: "tcp", - Addr: "127.0.0.1:4002", + Net: DefaultNet, + Addr: DefaultAddr + PrePort + port, User: "", Passwd: "", DBName: "", AllowNativePasswords: true, } - db, err := sql.Open("mysql", cfg.FormatDSN()) + db, err := sql.Open(MySQL, cfg.FormatDSN()) if err != nil { continue } @@ -79,13 +91,15 @@ func connect(host, port, clusterName string, l logger.Logger) error { err = db.Close() if err != nil { - l.V(1).Infof("Error closing connection: %v", err) + if err == os.ErrProcessDone { + return nil + } return err } break } - cmd = exec.Command(MySQL, ArgHost, host, ArgPort, port) + cmd = mysqlCommand(port) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin @@ -101,11 +115,16 @@ func connect(host, port, clusterName string, l logger.Logger) error { // gracefully stop port-forwarding err = cmd.Process.Kill() if err != nil { - if err.Error() != "os: process already finished" { + if err == os.ErrProcessDone { l.V(1).Info("Shutting down port-forwarding successfully") + return nil } return err } waitGroup.Wait() return nil } + +func mysqlCommand(port string) *exec.Cmd { + return exec.Command(MySQL, ArgHost, DefaultAddr, ArgPort, port) +} From ce0dd3f327f182ed03a59e6dfe02f7400c16ee91 Mon Sep 17 00:00:00 2001 From: sjcsjc123 <1401189096@qq.com> Date: Tue, 8 Aug 2023 21:44:50 +0800 Subject: [PATCH 11/11] feat: add new command gtctl connect pg --- go.mod | 17 +++- go.sum | 50 +++++++++++ pkg/cmd/gtctl/cluster/connect/mysql/mysql.go | 4 +- pkg/cmd/gtctl/cluster/connect/pg/pg.go | 95 ++++++++++++++++++++ 4 files changed, 160 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a93cd112..90e159e4 100644 --- a/go.mod +++ b/go.mod @@ -61,6 +61,8 @@ require ( github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-pg/pg/v10 v10.11.1 // indirect + github.com/go-pg/zerochecker v0.2.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/gobwas/glob v0.2.3 // indirect @@ -78,6 +80,7 @@ require ( github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -118,18 +121,23 @@ require ( github.com/sirupsen/logrus v1.9.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect + github.com/vmihailenco/bufpool v0.1.11 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/tagparser v0.1.2 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/crypto v0.7.0 // indirect + golang.org/x/crypto v0.12.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect @@ -142,6 +150,7 @@ require ( k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect k8s.io/kubectl v0.26.0 // indirect k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + mellium.im/sasl v0.3.1 // indirect oras.land/oras-go v1.2.2 // indirect sigs.k8s.io/controller-runtime v0.12.3 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect diff --git a/go.sum b/go.sum index 4f03ae92..4304f29e 100644 --- a/go.sum +++ b/go.sum @@ -168,6 +168,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= @@ -200,6 +201,10 @@ github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXym github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-pg/pg/v10 v10.11.1 h1:vYwbFpqoMpTDphnzIPshPPepdy3VpzD8qo29OFKp4vo= +github.com/go-pg/pg/v10 v10.11.1/go.mod h1:ExJWndhDNNftBdw1Ow83xqpSf4WMSJK8urmXD5VXS1I= +github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU= +github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -340,6 +345,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= @@ -353,6 +359,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -473,11 +481,18 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -582,6 +597,17 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= +github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94= +github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ= +github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -621,6 +647,7 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -630,9 +657,12 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -671,6 +701,7 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -695,10 +726,12 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -712,6 +745,7 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= @@ -748,6 +782,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -761,10 +796,12 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -780,6 +817,7 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -811,14 +849,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -831,6 +875,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1015,10 +1061,12 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1066,6 +1114,8 @@ k8s.io/kubectl v0.26.0 h1:xmrzoKR9CyNdzxBmXV7jW9Ln8WMrwRK6hGbbf69o4T0= k8s.io/kubectl v0.26.0/go.mod h1:eInP0b+U9XUJWSYeU9XZnTA+cVYuWyl3iYPGtru0qhQ= k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= +mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= oras.land/oras-go v1.2.2 h1:0E9tOHUfrNH7TCDk5KU0jVBEzCqbfdyuVfGmJ7ZeRPE= oras.land/oras-go v1.2.2/go.mod h1:Apa81sKoZPpP7CDciE006tSZ0x3Q3+dOoBcMZ/aNxvw= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go index 4f43e02e..9e4d58f5 100644 --- a/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go +++ b/pkg/cmd/gtctl/cluster/connect/mysql/mysql.go @@ -42,11 +42,11 @@ const ( // ConnectCommand connects to a GreptimeDB cluster func ConnectCommand(rawCluster *greptimedbclusterv1alpha1.GreptimeDBCluster, l logger.Logger) error { - return connect("127.0.0.1", strconv.Itoa(int(rawCluster.Spec.MySQLServicePort)), rawCluster.Name, l) + return connect(strconv.Itoa(int(rawCluster.Spec.MySQLServicePort)), rawCluster.Name, l) } // connect connects to a GreptimeDB cluster -func connect(host, port, clusterName string, l logger.Logger) error { +func connect(port, clusterName string, l logger.Logger) error { waitGroup := sync.WaitGroup{} cmd := exec.CommandContext(context.Background(), Kubectl, PortForward, "-n", "default", "svc/"+clusterName+"-frontend", port+PrePort+port) err := cmd.Start() diff --git a/pkg/cmd/gtctl/cluster/connect/pg/pg.go b/pkg/cmd/gtctl/cluster/connect/pg/pg.go index 27293a0e..eea23cdd 100644 --- a/pkg/cmd/gtctl/cluster/connect/pg/pg.go +++ b/pkg/cmd/gtctl/cluster/connect/pg/pg.go @@ -15,10 +15,105 @@ package pg import ( + "context" + "os" + "os/exec" + "strconv" + "sync" + "syscall" + + "github.com/go-pg/pg/v10" + greptimedbclusterv1alpha1 "github.com/GreptimeTeam/greptimedb-operator/apis/v1alpha1" "github.com/GreptimeTeam/gtctl/pkg/logger" ) +const ( + PostgresSQL = "psql" + DbName = "public" + DefaultAddr = "127.0.0.1" + DefaultNet = "tcp" + ArgsHost = "-h" + ArgsPort = "-p" + ArgDb = "-d" + PrePort = ":" + Kubectl = "kubectl" + PortForward = "port-forward" +) + func ConnectCommand(rawCluster *greptimedbclusterv1alpha1.GreptimeDBCluster, l logger.Logger) error { + return connect(strconv.Itoa(int(rawCluster.Spec.PostgresServicePort)), rawCluster.Name, l) +} + +func connect(port, clusterName string, l logger.Logger) error { + waitGroup := sync.WaitGroup{} + cmd := exec.CommandContext(context.Background(), Kubectl, PortForward, "-n", "default", "svc/"+clusterName+"-frontend", port+PrePort+port) + err := cmd.Start() + if err != nil { + l.Errorf("Error starting port-forwarding: %v", err) + return err + } + defer func() { + if recover() != nil { + err := cmd.Process.Kill() + if err != nil { + l.Errorf("Error killing port-forwarding process: %v", err) + } + } + }() + waitGroup.Add(1) + go func() { + defer waitGroup.Done() + if err = cmd.Wait(); err != nil { + //exit status 1 + exitError, ok := err.(*exec.ExitError) + if !ok { + l.Errorf("Error waiting for port-forwarding to finish: %v", err) + return + } + if exitError.Sys().(syscall.WaitStatus).ExitStatus() == 1 { + return + } + } + }() + for { + opt := &pg.Options{ + Addr: DefaultAddr + PrePort + port, + Network: DefaultNet, + Database: DbName, + } + db := pg.Connect(opt) + _, err = db.Exec("SELECT 1") + if err == nil { + break + } + } + cmd = pgCommand(port) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + err = cmd.Start() + if err != nil { + l.Errorf("Error starting pg: %v", err) + return err + } + if err = cmd.Wait(); err != nil { + l.Errorf("Error waiting for pg client to finish: %v", err) + return err + } + // gracefully stop port-forwarding + err = cmd.Process.Kill() + if err != nil { + if err == os.ErrProcessDone { + l.V(1).Info("Shutting down port-forwarding successfully") + return nil + } + return err + } + waitGroup.Wait() return nil } + +func pgCommand(port string) *exec.Cmd { + return exec.Command(PostgresSQL, ArgsHost, DefaultAddr, ArgsPort, port, ArgDb, DbName) +}