From 352a76d9489111b08c42c3c0d00919be90ba7b8b Mon Sep 17 00:00:00 2001 From: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> Date: Mon, 10 Feb 2025 08:55:15 +0530 Subject: [PATCH 1/2] changed the cli go module name Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> --- cmd/cli.go | 4 ++-- cmd/configure.go | 4 ++-- cmd/connect.go | 2 +- cmd/create.go | 2 +- cmd/delete.go | 2 +- cmd/get.go | 2 +- cmd/handle_meta.go | 2 +- cmd/handler.go | 2 +- cmd/root.go | 4 ++-- cmd/scale.go | 2 +- cmd/userinput.go | 2 +- cmd/version.go | 2 +- gen/docs.go | 2 +- go.mod | 2 +- main.go | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmd/cli.go b/cmd/cli.go index 2dc910d..6830e5b 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -18,8 +18,8 @@ import ( "context" "os" - "github.com/ksctl/cli/pkg/config" - cLogger "github.com/ksctl/cli/pkg/logger" + "github.com/ksctl/cli/v2/pkg/config" + cLogger "github.com/ksctl/cli/v2/pkg/logger" "github.com/ksctl/ksctl/v2/pkg/consts" "github.com/ksctl/ksctl/v2/pkg/logger" "github.com/ksctl/ksctl/v2/pkg/provider" diff --git a/cmd/configure.go b/cmd/configure.go index 5ef7101..a65b235 100644 --- a/cmd/configure.go +++ b/cmd/configure.go @@ -20,8 +20,8 @@ import ( "os" "strconv" - "github.com/ksctl/cli/pkg/cli" - "github.com/ksctl/cli/pkg/config" + "github.com/ksctl/cli/v2/pkg/cli" + "github.com/ksctl/cli/v2/pkg/config" "github.com/ksctl/ksctl/v2/pkg/consts" "github.com/ksctl/ksctl/v2/pkg/statefile" "github.com/ksctl/ksctl/v2/pkg/utilities" diff --git a/cmd/connect.go b/cmd/connect.go index 9917868..577e871 100644 --- a/cmd/connect.go +++ b/cmd/connect.go @@ -27,7 +27,7 @@ import ( "github.com/creack/pty" "github.com/fatih/color" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/common" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller" "github.com/ksctl/ksctl/v2/pkg/logger" diff --git a/cmd/create.go b/cmd/create.go index 283751f..88ca035 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -20,7 +20,7 @@ import ( "github.com/ksctl/ksctl/v2/pkg/addons" "github.com/ksctl/ksctl/v2/pkg/consts" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller" controllerManaged "github.com/ksctl/ksctl/v2/pkg/handler/cluster/managed" diff --git a/cmd/delete.go b/cmd/delete.go index dd6cc3c..33c7bd4 100644 --- a/cmd/delete.go +++ b/cmd/delete.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/consts" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/managed" diff --git a/cmd/get.go b/cmd/get.go index ee5945f..f2b9daf 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/consts" "github.com/ksctl/ksctl/v2/pkg/logger" "github.com/ksctl/ksctl/v2/pkg/provider" diff --git a/cmd/handle_meta.go b/cmd/handle_meta.go index 0cda0c2..1d169a4 100644 --- a/cmd/handle_meta.go +++ b/cmd/handle_meta.go @@ -19,7 +19,7 @@ import ( "os" "strconv" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/consts" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller" controllerMeta "github.com/ksctl/ksctl/v2/pkg/handler/cluster/metadata" diff --git a/cmd/handler.go b/cmd/handler.go index e48e88d..8128a95 100644 --- a/cmd/handler.go +++ b/cmd/handler.go @@ -14,7 +14,7 @@ package cmd -import "github.com/ksctl/cli/pkg/cli" +import "github.com/ksctl/cli/v2/pkg/cli" func (k *KsctlCommand) CommandMapping() error { c := k.Cluster() diff --git a/cmd/root.go b/cmd/root.go index 369a204..1a4d107 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,10 +18,10 @@ import ( "context" "os" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/consts" - cLogger "github.com/ksctl/cli/pkg/logger" + cLogger "github.com/ksctl/cli/v2/pkg/logger" "github.com/spf13/cobra" ) diff --git a/cmd/scale.go b/cmd/scale.go index 246cfe8..7da9d1f 100644 --- a/cmd/scale.go +++ b/cmd/scale.go @@ -18,7 +18,7 @@ import ( "os" "strconv" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/consts" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller" "github.com/ksctl/ksctl/v2/pkg/handler/cluster/selfmanaged" diff --git a/cmd/userinput.go b/cmd/userinput.go index de035d4..3997ee2 100644 --- a/cmd/userinput.go +++ b/cmd/userinput.go @@ -18,7 +18,7 @@ import ( "fmt" "strconv" - "github.com/ksctl/cli/pkg/cli" + "github.com/ksctl/cli/v2/pkg/cli" "github.com/ksctl/ksctl/v2/pkg/consts" "github.com/ksctl/ksctl/v2/pkg/provider" ) diff --git a/cmd/version.go b/cmd/version.go index 7308dcd..293c8b0 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -18,7 +18,7 @@ import ( "fmt" "github.com/fatih/color" - "github.com/ksctl/cli/pkg/config" + "github.com/ksctl/cli/v2/pkg/config" "github.com/spf13/cobra" ) diff --git a/gen/docs.go b/gen/docs.go index 63a2737..2426db9 100644 --- a/gen/docs.go +++ b/gen/docs.go @@ -20,7 +20,7 @@ import ( "os" "path/filepath" - "github.com/ksctl/cli/cmd" + "github.com/ksctl/cli/v2/cmd" "github.com/spf13/cobra/doc" ) diff --git a/go.mod b/go.mod index b9e9791..f8a5c56 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/ksctl/cli +module github.com/ksctl/cli/v2 go 1.23.3 diff --git a/main.go b/main.go index 5e06c9d..a4ad14b 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ import ( "os" "time" - "github.com/ksctl/cli/cmd" + "github.com/ksctl/cli/v2/cmd" ) func main() { From c06337f18ada87630a7fb0090084235a9688b11a Mon Sep 17 00:00:00 2001 From: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> Date: Mon, 10 Feb 2025 10:28:21 +0530 Subject: [PATCH 2/2] added self update command Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> --- cmd/addons.go | 71 +++++++++++++ cmd/handler.go | 10 ++ cmd/update.go | 277 +++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 +- 4 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 cmd/addons.go create mode 100644 cmd/update.go diff --git a/cmd/addons.go b/cmd/addons.go new file mode 100644 index 0000000..1dcca97 --- /dev/null +++ b/cmd/addons.go @@ -0,0 +1,71 @@ +// Copyright 2025 Ksctl Authors +// +// 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 cmd + +import "github.com/spf13/cobra" + +func (k *KsctlCommand) Addons() *cobra.Command { + + cmd := &cobra.Command{ + Use: "addons", + Example: ` +ksctl addons --help +`, + Short: "Use to work with addons", + Long: "It is used to work with addons", + } + + return cmd +} + +func (k *KsctlCommand) ListAddon() *cobra.Command { + + cmd := &cobra.Command{ + Use: "list", + Example: ` +ksctl addons list --help +`, + Short: "Use to list the addons", + Long: "It is used to list the addons", + } + + return cmd +} + +func (k *KsctlCommand) EnableAddon() *cobra.Command { + + cmd := &cobra.Command{ + Use: "enable", + Example: ` +ksctl addons enable --help +`, + Short: "Use to enable an addon", + Long: "It is used to enable an addon", + } + return cmd +} + +func (k *KsctlCommand) DisableAddon() *cobra.Command { + + cmd := &cobra.Command{ + Use: "disable", + Example: ` +ksctl addons disable --help +`, + Short: "Use to disable an addon", + Long: "It is used to disable an addon", + } + return cmd +} diff --git a/cmd/handler.go b/cmd/handler.go index 8128a95..60dd9c8 100644 --- a/cmd/handler.go +++ b/cmd/handler.go @@ -20,12 +20,15 @@ func (k *KsctlCommand) CommandMapping() error { c := k.Cluster() cr := k.Configure() cl := k.List() + a := k.Addons() cli.RegisterCommand( k.root, c, k.Version(), + k.SelfUpdate(), cr, + a, ) cli.RegisterCommand( c, @@ -49,5 +52,12 @@ func (k *KsctlCommand) CommandMapping() error { k.ConfigureCloud(), ) + cli.RegisterCommand( + a, + k.EnableAddon(), + k.DisableAddon(), + k.ListAddon(), + ) + return nil } diff --git a/cmd/update.go b/cmd/update.go new file mode 100644 index 0000000..870a81f --- /dev/null +++ b/cmd/update.go @@ -0,0 +1,277 @@ +// Copyright 2025 Ksctl Authors +// +// 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 cmd + +import ( + "archive/tar" + "compress/gzip" + "crypto/sha256" + "encoding/hex" + "fmt" + "github.com/ksctl/cli/v2/pkg/cli" + "github.com/ksctl/cli/v2/pkg/config" + "github.com/ksctl/ksctl/v2/pkg/poller" + "github.com/spf13/cobra" + "golang.org/x/mod/semver" + "io" + "net/http" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" +) + +func (k *KsctlCommand) SelfUpdate() *cobra.Command { + + cmd := &cobra.Command{ + Use: "self-update", + Example: ` +ksctl self-update --help +`, + Short: "Use to update the ksctl cli", + Long: "It is used to update the ksctl cli", + Run: func(cmd *cobra.Command, args []string) { + + if config.Version == "v0.0.1-dev" { + k.l.Error("Cannot update dev version", "msg", "Please use a stable version to update") + os.Exit(1) + } + + k.l.Warn(k.Ctx, "Currently no migrations are supported", "msg", "Please help us by creating a PR to support migrations. Thank you!") + + vers, err := k.fetchLatestVersion() + if err != nil { + k.l.Error("Failed to fetch latest version", "error", err) + os.Exit(1) + } + vers = k.filterToUpgradeableVersions(vers) + + if len(vers) == 0 { + k.l.Note(k.Ctx, "You are already on the latest version", "version", config.Version) + os.Exit(0) + } + + selectedOption, err := cli.DropDownList("Select a version to update", vers, vers[0]) + if err != nil { + return + } + + newVer := selectedOption + + if err := k.update(newVer); err != nil { + k.l.Error("Failed to update ksctl cli", "error", err) + os.Exit(1) + } + + k.l.Box(k.Ctx, "Updated Successful 🎉", "ksctl has been updated to version "+newVer) + }, + } + + return cmd +} + +func (k *KsctlCommand) fetchLatestVersion() ([]string, error) { + + k.l.Print(k.Ctx, "Fetching available versions") + + poller.InitSharedGithubReleasePoller() + return poller.GetSharedPoller().Get("ksctl", "cli") +} + +func (k *KsctlCommand) filterToUpgradeableVersions(versions []string) []string { + var upgradeableVersions []string + for _, version := range versions { + if semver.Compare(version, config.Version) > 0 { + upgradeableVersions = append(upgradeableVersions, version) + } + } + return upgradeableVersions +} + +func (k *KsctlCommand) downloadFile(url, localFilename string) error { + k.l.Print(k.Ctx, "Downloading file", "url", url, "localFilename", localFilename) + + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + out, err := os.Create(localFilename) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, resp.Body) + return err +} +func (k *KsctlCommand) verifyChecksum(filePath, checksumfileLoc string) (bool, error) { + k.l.Print(k.Ctx, "Verifying checksum", "file", filePath, "checksumfile", checksumfileLoc) + + rawChecksum, err := os.ReadFile(checksumfileLoc) + if err != nil { + return false, err + } + checksums := strings.Split(string(rawChecksum), "\n") + + var expectedChecksum string = "LOL" + for _, line := range checksums { + if strings.Contains(line, filePath) { + expectedChecksum = strings.Fields(line)[0] + break + } + } + if expectedChecksum == "LOL" { + return false, k.l.NewError(k.Ctx, "Checksum not found in checksum file") + } + + file, err := os.Open(filePath) + if err != nil { + return false, err + } + defer file.Close() + + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + return false, err + } + + calculatedChecksum := hex.EncodeToString(hash.Sum(nil)) + return calculatedChecksum == expectedChecksum, nil +} + +func (k *KsctlCommand) getOsArch() (string, error) { + arch := runtime.GOARCH + + if arch != "amd64" && arch != "arm64" { + return "", k.l.NewError(k.Ctx, "Unsupported architecture") + } + return arch, nil +} + +func (k *KsctlCommand) getOs() (string, error) { + goos := runtime.GOOS + + if goos != "linux" && goos != "darwin" { + return "", k.l.NewError(k.Ctx, "Unsupported OS", "message", "will provide support for windows based OS soon") + } + return goos, nil +} + +func (k *KsctlCommand) update(version string) error { + osName, err := k.getOs() + if err != nil { + return err + } + archName, err := k.getOsArch() + if err != nil { + return err + } + + k.l.Print(k.Ctx, "Delected System", "OS", osName, "Arch", archName) + downloadURLBase := fmt.Sprintf("https://github.com/ksctl/cli/releases/download/%s", version) + tarFile := fmt.Sprintf("ksctl-cli_%s_%s_%s.tar.gz", version[1:], osName, archName) + checksumFile := fmt.Sprintf("ksctl-cli_%s_checksums.txt", version[1:]) + + tarUri := fmt.Sprintf("%s/%s", downloadURLBase, tarFile) + checksumUri := fmt.Sprintf("%s/%s", downloadURLBase, checksumFile) + + defer func() { + k.l.Print(k.Ctx, "Cleaning up") + if err := os.Remove(checksumFile); err != nil { + k.l.Error("Failed to remove checksum file", "error", err) + } + + if err := os.Remove(tarFile); err != nil { + k.l.Error("Failed to remove checksum file", "error", err) + } + }() + + if err := k.downloadFile(tarUri, tarFile); err != nil { + return err + } + + if err := k.downloadFile(checksumUri, checksumFile); err != nil { + return err + } + + match, err := k.verifyChecksum(tarFile, checksumFile) + if err != nil { + return k.l.NewError(k.Ctx, "Failed to verify checksum", "error", err) + } + if !match { + return k.l.NewError(k.Ctx, "Checksum verification failed") + } + k.l.Success(k.Ctx, "Checksum verification successful") + + tempDir, err := os.MkdirTemp("", "ksctl-update") + if err != nil { + return k.l.NewError(k.Ctx, "Failed to create temp dir", "error", err) + } + file, err := os.Open(tarFile) + if err != nil { + return k.l.NewError(k.Ctx, "Failed to open tar file", "error", err) + } + defer file.Close() + + gzr, err := gzip.NewReader(file) + if err != nil { + return k.l.NewError(k.Ctx, "Failed to read gzip file", "error", err) + } + defer gzr.Close() + tr := tar.NewReader(gzr) + for { + header, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return k.l.NewError(k.Ctx, "Failed to read tar file", "error", err) + } + if header.Name == "ksctl" { + outFile, err := os.Create(filepath.Join(tempDir, "ksctl")) + if err != nil { + return k.l.NewError(k.Ctx, "Failed to create ksctl binary", "error", err) + } + defer outFile.Close() + + if _, err := io.Copy(outFile, tr); err != nil { + return k.l.NewError(k.Ctx, "Failed to copy ksctl binary", "error", err) + } + break + } + } + + k.l.Print(k.Ctx, "Making ksctl executable...") + if err := os.Chmod(filepath.Join(tempDir, "ksctl"), 0550); err != nil { + return k.l.NewError(k.Ctx, "Failed to make ksctl executable", "error", err) + } + + k.l.Print(k.Ctx, "Moving ksctl to /usr/local/bin (requires sudo)...") + cmd := exec.Command("sudo", "mv", "-v", filepath.Join(tempDir, "ksctl"), "/usr/local/bin/ksctl") + err = cmd.Run() + if err != nil { + return k.l.NewError(k.Ctx, "Failed to move ksctl to /usr/local/bin", "error", err) + } + + _, err = exec.LookPath("ksctl") + if err != nil { + return k.l.NewError(k.Ctx, "Failed to find ksctl in PATH", "error", err) + } + + return nil +} diff --git a/go.mod b/go.mod index f8a5c56..8117c6f 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/pterm/pterm v0.12.80 github.com/rodaine/table v1.2.0 github.com/spf13/cobra v1.8.1 + golang.org/x/mod v0.22.0 golang.org/x/term v0.28.0 k8s.io/client-go v0.32.0 ) @@ -172,7 +173,6 @@ require ( go.opentelemetry.io/otel/trace v1.28.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect golang.org/x/crypto v0.32.0 // indirect - golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.10.0 // indirect