diff --git a/.goreleaser.yml b/.goreleaser.yml index 8fc5b814..275981b8 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -3,7 +3,7 @@ project_name: kubekey builds: - env: - CGO_ENABLED=0 - main: ./cmd/kk/main.go + main: ./cmd/main.go binary: kk goarch: - amd64 diff --git a/Dockerfile b/Dockerfile index c6b564b1..95e031a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ RUN git clone https://github.com/kubesphere/helm-charts.git ADD ./ /workspace # Build RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o kk cmd/kk/main.go +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o kk cmd/main.go # Build the manager image FROM debian:stable diff --git a/Makefile b/Makefile index cae69d3e..33cca024 100644 --- a/Makefile +++ b/Makefile @@ -232,7 +232,7 @@ binary: -e CGO_ENABLED=0 \ -e GO111MODULE=on \ -w /usr/src/myapp golang:1.16 \ - go build -ldflags '$(LDFLAGS)' -v -o output/linux/amd64/kk ./cmd/kk/main.go # linux + go build -ldflags '$(LDFLAGS)' -v -o output/linux/amd64/kk ./cmd/main.go # linux sha256sum output/linux/amd64/kk || shasum -a 256 output/linux/amd64/kk docker run --rm \ @@ -242,13 +242,13 @@ binary: -e CGO_ENABLED=0 \ -e GO111MODULE=on \ -w /usr/src/myapp golang:1.16 \ - go build -ldflags '$(LDFLAGS)' -v -o output/linux/arm64/kk ./cmd/kk/main.go # linux + go build -ldflags '$(LDFLAGS)' -v -o output/linux/arm64/kk ./cmd/main.go # linux sha256sum output/linux/arm64/kk || shasum -a 256 output/linux/arm64/kk # build the binary file of kk kk-linux: - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GO111MODULE=on go build -ldflags '$(LDFLAGS)' -o bin/linux/amd64/kk ./cmd/kk/main.go + GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GO111MODULE=on go build -ldflags '$(LDFLAGS)' -o bin/linux/amd64/kk ./cmd/main.go kk-darwin: - GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 GO111MODULE=on go build -ldflags '$(LDFLAGS)' -o bin/darwin/amd64/kk ./cmd/kk/main.go + GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 GO111MODULE=on go build -ldflags '$(LDFLAGS)' -o bin/darwin/amd64/kk ./cmd/main.go go-releaser-test: goreleaser release --rm-dist --skip-publish --snapshot \ No newline at end of file diff --git a/build.sh b/build.sh index 1b3d18f1..e4e86876 100755 --- a/build.sh +++ b/build.sh @@ -24,10 +24,10 @@ LDFLAGS="-X github.com/kubesphere/kubekey/version.version=${VERSION} if [ -n "$1" ]; then if [ "$1" == "-p" ] || [ "$1" == "--proxy" ]; then # Using the most trusted Go module proxy in China - docker run --rm -e GO111MODULE=on -e GOPROXY=https://goproxy.cn -v "$PWD":/usr/src/myapp -w /usr/src/myapp golang:1.16 go build -ldflags "$LDFLAGS" -v -o output/kk ./cmd/kk/main.go + docker run --rm -e GO111MODULE=on -e GOPROXY=https://goproxy.cn -v "$PWD":/usr/src/myapp -w /usr/src/myapp golang:1.16 go build -ldflags "$LDFLAGS" -v -o output/kk ./cmd/main.go else echo "The option should be '-p' or '--proxy'" fi else - docker run --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp golang:1.16 go build -ldflags "$LDFLAGS" -v -o output/kk ./cmd/kk/main.go + docker run --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp golang:1.16 go build -ldflags "$LDFLAGS" -v -o output/kk ./cmd/main.go fi diff --git a/cmd/add.go b/cmd/add.go deleted file mode 100644 index a726366d..00000000 --- a/cmd/add.go +++ /dev/null @@ -1,13 +0,0 @@ -package cmd - -import "github.com/spf13/cobra" - -// addCmd represents the add command -var addCmd = &cobra.Command{ - Use: "add", - Short: "Add nodes to kubernetes cluster", -} - -func init() { - rootCmd.AddCommand(addCmd) -} diff --git a/cmd/add_nodes.go b/cmd/add_nodes.go deleted file mode 100644 index dd49fa87..00000000 --- a/cmd/add_nodes.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/spf13/cobra" -) - -// addNodesCmd represents the nodes command -var addNodesCmd = &cobra.Command{ - Use: "nodes", - Short: "Add nodes to the cluster according to the new nodes information from the specified configuration file", - RunE: func(cmd *cobra.Command, args []string) error { - arg := common.Argument{ - FilePath: opt.ClusterCfgFile, - KsEnable: false, - Debug: opt.Verbose, - IgnoreErr: opt.IgnoreErr, - SkipConfirmCheck: opt.SkipConfirmCheck, - SkipPullImages: opt.SkipPullImages, - InCluster: opt.InCluster, - ContainerManager: opt.ContainerManager, - } - return pipelines.AddNodes(arg, opt.DownloadCmd) - }, -} - -func init() { - addCmd.AddCommand(addNodesCmd) - addNodesCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") - addNodesCmd.Flags().BoolVarP(&opt.SkipPullImages, "skip-pull-images", "", false, "Skip pre pull images") - addNodesCmd.Flags().StringVarP(&opt.ContainerManager, "container-manager", "", "docker", "Container manager: docker, crio, containerd and isula.") - addNodesCmd.Flags().StringVarP(&opt.DownloadCmd, "download-cmd", "", "curl -L -o %s %s", - `The user defined command to download the necessary binary files. The first param '%s' is output path, the second param '%s', is the URL`) -} diff --git a/cmd/cert.go b/cmd/cert.go deleted file mode 100644 index 43d83d9f..00000000 --- a/cmd/cert.go +++ /dev/null @@ -1,12 +0,0 @@ -package cmd - -import "github.com/spf13/cobra" - -var certsCmd = &cobra.Command{ - Use: "certs", - Short: "cluster certs", -} - -func init() { - rootCmd.AddCommand(certsCmd) -} diff --git a/cmd/cluster.go b/cmd/cluster.go deleted file mode 100644 index d7056d78..00000000 --- a/cmd/cluster.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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 ( - "fmt" - "github.com/kubesphere/kubekey/apis/kubekey/v1alpha2" - "github.com/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/kubesphere/kubekey/version" - "github.com/spf13/cobra" - "time" -) - -// clusterCmd represents the cluster command -var clusterCmd = &cobra.Command{ - Use: "cluster", - Short: "Create a Kubernetes or KubeSphere cluster", - RunE: func(cmd *cobra.Command, args []string) error { - var ksVersion string - if opt.Kubesphere && len(args) > 0 { - ksVersion = args[0] - } else { - ksVersion = "" - } - - arg := common.Argument{ - FilePath: opt.ClusterCfgFile, - KubernetesVersion: opt.Kubernetes, - KsEnable: opt.Kubesphere, - KsVersion: ksVersion, - SkipPullImages: opt.SkipPullImages, - InCluster: opt.InCluster, - DeployLocalStorage: opt.LocalStorage, - Debug: opt.Verbose, - IgnoreErr: opt.IgnoreErr, - SkipConfirmCheck: opt.SkipConfirmCheck, - ContainerManager: opt.ContainerManager, - } - - return pipelines.CreateCluster(arg, opt.DownloadCmd) - }, -} - -func init() { - createCmd.AddCommand(clusterCmd) - - clusterCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") - clusterCmd.Flags().StringVarP(&opt.Kubernetes, "with-kubernetes", "", v1alpha2.DefaultKubeVersion, "Specify a supported version of kubernetes") - clusterCmd.Flags().BoolVarP(&opt.LocalStorage, "with-local-storage", "", false, "Deploy a local PV provisioner") - clusterCmd.Flags().BoolVarP(&opt.Kubesphere, "with-kubesphere", "", false, "Deploy a specific version of kubesphere (default v3.2.0)") - clusterCmd.Flags().BoolVarP(&opt.SkipPullImages, "skip-pull-images", "", false, "Skip pre pull images") - clusterCmd.Flags().StringVarP(&opt.ContainerManager, "container-manager", "", "docker", "Container runtime: docker, crio, containerd and isula.") - clusterCmd.Flags().StringVarP(&opt.DownloadCmd, "download-cmd", "", "curl -L -o %s %s", - `The user defined command to download the necessary binary files. The first param '%s' is output path, the second param '%s', is the URL`) - - if err := setValidArgs(clusterCmd); err != nil { - panic(fmt.Sprintf("Got error with the completion setting")) - } -} - -func setValidArgs(cmd *cobra.Command) (err error) { - cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ( - strings []string, directive cobra.ShellCompDirective) { - versionArray := []string{"v2.1.1", "v3.0.0", "v3.1.0", "v3.1.1", time.Now().Add(-time.Hour * 24).Format("nightly-20060102")} - return versionArray, cobra.ShellCompDirectiveNoFileComp - } - - err = cmd.RegisterFlagCompletionFunc("with-kubernetes", func(cmd *cobra.Command, args []string, toComplete string) ( - strings []string, directive cobra.ShellCompDirective) { - return version.SupportedK8sVersionList(), cobra.ShellCompDirectiveNoFileComp - }) - return -} diff --git a/cmd/config.go b/cmd/config.go deleted file mode 100644 index 352d3eb0..00000000 --- a/cmd/config.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/config" - "github.com/spf13/cobra" -) - -// configCmd represents the config command -var configCmd = &cobra.Command{ - Use: "config", - Short: "Create cluster configuration file", - RunE: func(cmd *cobra.Command, args []string) error { - var ksVersion string - if opt.Kubesphere && len(args) > 0 { - ksVersion = args[0] - } else { - ksVersion = "" - } - - arg := common.Argument{ - FilePath: opt.ClusterCfgFile, - KubernetesVersion: opt.Kubernetes, - KsEnable: opt.Kubesphere, - KsVersion: ksVersion, - FromCluster: opt.FromCluster, - KubeConfig: opt.Kubeconfig, - } - - err := config.GenerateKubeKeyConfig(arg, opt.Name) - if err != nil { - return err - } - return err - }, -} - -func init() { - createCmd.AddCommand(configCmd) - - configCmd.Flags().StringVarP(&opt.Name, "name", "", "sample", "Specify a name of cluster object") - configCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Specify a configuration file path") - configCmd.Flags().StringVarP(&opt.Kubernetes, "with-kubernetes", "", "", "Specify a supported version of kubernetes") - configCmd.Flags().BoolVarP(&opt.Kubesphere, "with-kubesphere", "", false, "Deploy a specific version of kubesphere (default v3.1.0)") - configCmd.Flags().BoolVarP(&opt.FromCluster, "from-cluster", "", false, "Create a configuration based on existing cluster") - configCmd.Flags().StringVarP(&opt.Kubeconfig, "kubeconfig", "", "", "Specify a kubeconfig file") -} diff --git a/cmd/ctl/add/add.go b/cmd/ctl/add/add.go new file mode 100644 index 00000000..5d3dff37 --- /dev/null +++ b/cmd/ctl/add/add.go @@ -0,0 +1,30 @@ +package add + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/spf13/cobra" +) + +type AddOptions struct { + CommonOptions *options.CommonOptions +} + +func NewAddOptions() *AddOptions { + return &AddOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdAdd creates a new add command +func NewCmdAdd() *cobra.Command { + o := NewAddOptions() + cmd := &cobra.Command{ + Use: "add", + Short: "Add nodes to kubernetes cluster", + } + + o.CommonOptions.AddCommonFlag(cmd) + + cmd.AddCommand(NewCmdAddNodes()) + return cmd +} diff --git a/cmd/ctl/add/add_nodes.go b/cmd/ctl/add/add_nodes.go new file mode 100644 index 00000000..575c55a4 --- /dev/null +++ b/cmd/ctl/add/add_nodes.go @@ -0,0 +1,76 @@ +/* +Copyright 2020 The KubeSphere 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 add + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/spf13/cobra" +) + +type AddNodesOptions struct { + CommonOptions *options.CommonOptions + ClusterCfgFile string + SkipPullImages bool + ContainerManager string + DownloadCmd string +} + +func NewAddNodesOptions() *AddNodesOptions { + return &AddNodesOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdAddNodes creates a new add nodes command +func NewCmdAddNodes() *cobra.Command { + o := NewAddNodesOptions() + cmd := &cobra.Command{ + Use: "nodes", + Short: "Add nodes to the cluster according to the new nodes information from the specified configuration file", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + return cmd +} + +func (o *AddNodesOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + KsEnable: false, + Debug: o.CommonOptions.Verbose, + IgnoreErr: o.CommonOptions.IgnoreErr, + SkipConfirmCheck: o.CommonOptions.SkipConfirmCheck, + SkipPullImages: o.SkipPullImages, + InCluster: o.CommonOptions.InCluster, + ContainerManager: o.ContainerManager, + } + return pipelines.AddNodes(arg, o.DownloadCmd) +} + +func (o *AddNodesOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") + cmd.Flags().BoolVarP(&o.SkipPullImages, "skip-pull-images", "", false, "Skip pre pull images") + cmd.Flags().StringVarP(&o.ContainerManager, "container-manager", "", "docker", "Container manager: docker, crio, containerd and isula.") + cmd.Flags().StringVarP(&o.DownloadCmd, "download-cmd", "", "curl -L -o %s %s", + `The user defined command to download the necessary binary files. The first param '%s' is output path, the second param '%s', is the URL`) +} diff --git a/cmd/ctl/cert/cert.go b/cmd/ctl/cert/cert.go new file mode 100644 index 00000000..abb650b2 --- /dev/null +++ b/cmd/ctl/cert/cert.go @@ -0,0 +1,31 @@ +package cert + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/spf13/cobra" +) + +type CertOptions struct { + CommonOptions *options.CommonOptions +} + +func NewCertsOptions() *CertOptions { + return &CertOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdCerts creates a new cert command +func NewCmdCerts() *cobra.Command { + o := NewCertsOptions() + cmd := &cobra.Command{ + Use: "certs", + Short: "cluster certs", + } + + o.CommonOptions.AddCommonFlag(cmd) + + cmd.AddCommand(NewCmdCertList()) + cmd.AddCommand(NewCmdCertRenew()) + return cmd +} diff --git a/cmd/ctl/cert/list_cert.go b/cmd/ctl/cert/list_cert.go new file mode 100644 index 00000000..8fb24a97 --- /dev/null +++ b/cmd/ctl/cert/list_cert.go @@ -0,0 +1,48 @@ +package cert + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/spf13/cobra" +) + +type CertListOptions struct { + CommonOptions *options.CommonOptions + ClusterCfgFile string +} + +func NewCertListOptions() *CertListOptions { + return &CertListOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdCertList creates a new cert list command +func NewCmdCertList() *cobra.Command { + o := NewCertListOptions() + cmd := &cobra.Command{ + Use: "check-expiration", + Short: "Check certificates expiration for a Kubernetes cluster", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + return cmd +} + +func (o *CertListOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + Debug: o.CommonOptions.Verbose, + } + return pipelines.CheckCerts(arg) +} + +func (o *CertListOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") +} diff --git a/cmd/ctl/cert/renew_cert.go b/cmd/ctl/cert/renew_cert.go new file mode 100644 index 00000000..2cdc26dd --- /dev/null +++ b/cmd/ctl/cert/renew_cert.go @@ -0,0 +1,48 @@ +package cert + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/spf13/cobra" +) + +type CertRenewOptions struct { + CommonOptions *options.CommonOptions + ClusterCfgFile string +} + +func NewCertRenewOptions() *CertRenewOptions { + return &CertRenewOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdCertRenew creates a new cert renew command +func NewCmdCertRenew() *cobra.Command { + o := NewCertRenewOptions() + cmd := &cobra.Command{ + Use: "renew", + Short: "renew a cluster certs", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + return cmd +} + +func (o *CertRenewOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + Debug: o.CommonOptions.Verbose, + } + return pipelines.RenewCerts(arg) +} + +func (o *CertRenewOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") +} diff --git a/cmd/completion.go b/cmd/ctl/completion/completion.go similarity index 61% rename from cmd/completion.go rename to cmd/ctl/completion/completion.go index b1cc37e1..9f493bef 100644 --- a/cmd/completion.go +++ b/cmd/ctl/completion/completion.go @@ -14,10 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cmd +package completion import ( "fmt" + "github.com/kubesphere/kubekey/cmd/ctl/util" "github.com/spf13/cobra" ) @@ -26,6 +27,10 @@ type CompletionOptions struct { Type string } +func NewCompletionOptions() *CompletionOptions { + return &CompletionOptions{} +} + // ShellTypes contains all types of shell var ShellTypes = []string{ "zsh", "bash", "powerShell", @@ -33,28 +38,14 @@ var ShellTypes = []string{ var completionOptions CompletionOptions -func init() { - rootCmd.AddCommand(completionCmd) - - flags := completionCmd.Flags() - flags.StringVarP(&completionOptions.Type, "type", "t", "", - fmt.Sprintf("Generate different types of shell which are %v", ShellTypes)) - - err := completionCmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ( - i []string, directive cobra.ShellCompDirective) { - return ShellTypes, cobra.ShellCompDirectiveDefault - }) - if err != nil { - completionCmd.PrintErrf("register flag type for sub-command doc failed %#v\n", err) - } -} - -var completionCmd = &cobra.Command{ - Use: "completion", - Short: "Generate shell completion scripts", - Long: `Generate shell completion scripts +func NewCmdCompletion() *cobra.Command { + o := NewCompletionOptions() + cmd := &cobra.Command{ + Use: "completion", + Short: "Generate shell completion scripts", + Long: `Generate shell completion scripts Normally you don't need to do more extra work to have this feature if you've installed kk by brew`, - Example: `# Installing bash completion on Linux + Example: `# Installing bash completion on Linux ## If bash-completion is not installed on Linux, please install the 'bash-completion' package ## via your distribution's package manager. ## Load the ks completion code for bash into the current shell @@ -76,20 +67,45 @@ Load the kk completion code for zsh[1] into the current shell source <(kk completion --type zsh) Set the kk completion code for zsh[1] to autoload on startup kk completion --type zsh > "${fpath[1]}/_kk"`, - RunE: func(cmd *cobra.Command, _ []string) (err error) { - shellType := completionOptions.Type - switch shellType { - case "zsh": - err = rootCmd.GenZshCompletion(cmd.OutOrStdout()) - case "powerShell": - err = rootCmd.GenPowerShellCompletion(cmd.OutOrStdout()) - case "bash": - err = rootCmd.GenBashCompletion(cmd.OutOrStdout()) - case "": - err = cmd.Help() - default: - err = fmt.Errorf("unknown shell type %s", shellType) - } - return - }, + Run: func(cmd *cobra.Command, _ []string) { + util.CheckErr(o.Run(cmd)) + }, + } + + o.AddFlags(cmd) + if err := completionSetting(cmd); err != nil { + panic(fmt.Sprintf("register flag type for sub-command doc failed %#v\n", err)) + } + return cmd +} + +func (o *CompletionOptions) Run(cmd *cobra.Command) error { + var err error + shellType := completionOptions.Type + switch shellType { + case "zsh": + err = cmd.GenZshCompletion(cmd.OutOrStdout()) + case "powerShell": + err = cmd.GenPowerShellCompletion(cmd.OutOrStdout()) + case "bash": + err = cmd.GenBashCompletion(cmd.OutOrStdout()) + case "": + err = cmd.Help() + default: + err = fmt.Errorf("unknown shell type %s", shellType) + } + return err +} + +func (o *CompletionOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&completionOptions.Type, "type", "t", "", + fmt.Sprintf("Generate different types of shell which are %v", ShellTypes)) +} + +func completionSetting(cmd *cobra.Command) error { + err := cmd.RegisterFlagCompletionFunc("type", func(cmd *cobra.Command, args []string, toComplete string) ( + i []string, directive cobra.ShellCompDirective) { + return ShellTypes, cobra.ShellCompDirectiveDefault + }) + return err } diff --git a/cmd/ctl/create/cluster.go b/cmd/ctl/create/cluster.go new file mode 100644 index 00000000..51854e30 --- /dev/null +++ b/cmd/ctl/create/cluster.go @@ -0,0 +1,122 @@ +/* +Copyright 2020 The KubeSphere 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 create + +import ( + "fmt" + "github.com/kubesphere/kubekey/apis/kubekey/v1alpha2" + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/kubesphere/kubekey/pkg/version/kubesphere" + "github.com/kubesphere/kubekey/version" + "github.com/spf13/cobra" + "time" +) + +type CreateClusterOptions struct { + CommonOptions *options.CommonOptions + + ClusterCfgFile string + Kubernetes string + EnableKubeSphere bool + KubeSphere string + LocalStorage bool + SkipPullImages bool + ContainerManager string + DownloadCmd string +} + +func NewCreateClusterOptions() *CreateClusterOptions { + return &CreateClusterOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdCreateCluster creates a new create cluster command +func NewCmdCreateCluster() *cobra.Command { + o := NewCreateClusterOptions() + cmd := &cobra.Command{ + Use: "cluster", + Short: "Create a Kubernetes or KubeSphere cluster", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Complete(cmd, args)) + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + if err := completionSetting(cmd); err != nil { + panic(fmt.Sprintf("Got error with the completion setting")) + } + return cmd +} + +func (o *CreateClusterOptions) Complete(cmd *cobra.Command, args []string) error { + var ksVersion string + if o.EnableKubeSphere && len(args) > 0 { + ksVersion = args[0] + } else { + ksVersion = kubesphere.Latest().Version + } + o.KubeSphere = ksVersion + return nil +} + +func (o *CreateClusterOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + KubernetesVersion: o.Kubernetes, + KsEnable: o.EnableKubeSphere, + KsVersion: o.KubeSphere, + SkipPullImages: o.SkipPullImages, + InCluster: o.CommonOptions.InCluster, + DeployLocalStorage: o.LocalStorage, + Debug: o.CommonOptions.Verbose, + IgnoreErr: o.CommonOptions.IgnoreErr, + SkipConfirmCheck: o.CommonOptions.SkipConfirmCheck, + ContainerManager: o.ContainerManager, + } + + return pipelines.CreateCluster(arg, o.DownloadCmd) +} + +func (o *CreateClusterOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") + cmd.Flags().StringVarP(&o.Kubernetes, "with-kubernetes", "", v1alpha2.DefaultKubeVersion, "Specify a supported version of kubernetes") + cmd.Flags().BoolVarP(&o.LocalStorage, "with-local-storage", "", false, "Deploy a local PV provisioner") + cmd.Flags().BoolVarP(&o.EnableKubeSphere, "with-kubesphere", "", false, "Deploy a specific version of kubesphere (default v3.2.0)") + cmd.Flags().BoolVarP(&o.SkipPullImages, "skip-pull-images", "", false, "Skip pre pull images") + cmd.Flags().StringVarP(&o.ContainerManager, "container-manager", "", "docker", "Container runtime: docker, crio, containerd and isula.") + cmd.Flags().StringVarP(&o.DownloadCmd, "download-cmd", "", "curl -L -o %s %s", + `The user defined command to download the necessary binary files. The first param '%s' is output path, the second param '%s', is the URL`) +} + +func completionSetting(cmd *cobra.Command) (err error) { + cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ( + strings []string, directive cobra.ShellCompDirective) { + versionArray := []string{"v2.1.1", "v3.0.0", "v3.1.0", "v3.1.1", "v3.2.0", time.Now().Add(-time.Hour * 24).Format("nightly-20060102")} + return versionArray, cobra.ShellCompDirectiveNoFileComp + } + + err = cmd.RegisterFlagCompletionFunc("with-kubernetes", func(cmd *cobra.Command, args []string, toComplete string) ( + strings []string, directive cobra.ShellCompDirective) { + return version.SupportedK8sVersionList(), cobra.ShellCompDirectiveNoFileComp + }) + return +} diff --git a/cmd/ctl/create/config.go b/cmd/ctl/create/config.go new file mode 100644 index 00000000..c9c59d2e --- /dev/null +++ b/cmd/ctl/create/config.go @@ -0,0 +1,93 @@ +/* +Copyright 2020 The KubeSphere 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 create + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/config" + "github.com/kubesphere/kubekey/pkg/version/kubesphere" + "github.com/spf13/cobra" +) + +type CreateConfigOptions struct { + CommonOptions *options.CommonOptions + Name string + ClusterCfgFile string + Kubernetes string + EnableKubeSphere bool + KubeSphere string + FromCluster bool + KubeConfig string +} + +func NewCreateConfigOptions() *CreateConfigOptions { + return &CreateConfigOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdCreateConfig creates a create config command +func NewCmdCreateConfig() *cobra.Command { + o := NewCreateConfigOptions() + cmd := &cobra.Command{ + Use: "config", + Short: "Create cluster configuration file", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Complete(cmd, args)) + util.CheckErr(o.Run()) + + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + return cmd +} + +func (o *CreateConfigOptions) Complete(cmd *cobra.Command, args []string) error { + var ksVersion string + if o.EnableKubeSphere && len(args) > 0 { + ksVersion = args[0] + } else { + ksVersion = kubesphere.Latest().Version + } + o.KubeSphere = ksVersion + return nil +} + +func (o *CreateConfigOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + KubernetesVersion: o.Kubernetes, + KsEnable: o.EnableKubeSphere, + KsVersion: o.KubeSphere, + FromCluster: o.FromCluster, + KubeConfig: o.KubeConfig, + } + + return config.GenerateKubeKeyConfig(arg, o.Name) +} + +func (o *CreateConfigOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.Name, "name", "", "sample", "Specify a name of cluster object") + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Specify a configuration file path") + cmd.Flags().StringVarP(&o.Kubernetes, "with-kubernetes", "", "", "Specify a supported version of kubernetes") + cmd.Flags().BoolVarP(&o.EnableKubeSphere, "with-kubesphere", "", false, "Deploy a specific version of kubesphere (default v3.1.0)") + cmd.Flags().BoolVarP(&o.FromCluster, "from-cluster", "", false, "Create a configuration based on existing cluster") + cmd.Flags().StringVarP(&o.KubeConfig, "kubeconfig", "", "", "Specify a kubeconfig file") +} diff --git a/cmd/create.go b/cmd/ctl/create/create.go similarity index 51% rename from cmd/create.go rename to cmd/ctl/create/create.go index 3f7e3ebb..5b91c863 100644 --- a/cmd/create.go +++ b/cmd/ctl/create/create.go @@ -13,18 +13,34 @@ 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 +package create import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" "github.com/spf13/cobra" ) -// createCmd represents the create command -var createCmd = &cobra.Command{ - Use: "create", - Short: "Create a cluster or a cluster configuration file", +type CreateOptions struct { + CommonOptions *options.CommonOptions } -func init() { - rootCmd.AddCommand(createCmd) +func NewCreateOptions() *CreateOptions { + return &CreateOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdCreate creates a new create command +func NewCmdCreate() *cobra.Command { + o := NewCreateOptions() + cmd := &cobra.Command{ + Use: "create", + Short: "Create a cluster or a cluster configuration file", + } + + o.CommonOptions.AddCommonFlag(cmd) + + cmd.AddCommand(NewCmdCreateCluster()) + cmd.AddCommand(NewCmdCreateConfig()) + return cmd } diff --git a/cmd/delete.go b/cmd/ctl/delete/delete.go similarity index 52% rename from cmd/delete.go rename to cmd/ctl/delete/delete.go index 19c1ffb2..9c18c4a7 100644 --- a/cmd/delete.go +++ b/cmd/ctl/delete/delete.go @@ -13,18 +13,34 @@ 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 +package delete import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" "github.com/spf13/cobra" ) -// deleteCmd represents the delete command -var deleteCmd = &cobra.Command{ - Use: "delete", - Short: "Delete nodes or cluster", +type DeleteOptions struct { + CommonOptions *options.CommonOptions } -func init() { - rootCmd.AddCommand(deleteCmd) +func NewDeleteOptions() *DeleteOptions { + return &DeleteOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdDelete creates a new delete command +func NewCmdDelete() *cobra.Command { + o := NewDeleteOptions() + cmd := &cobra.Command{ + Use: "delete", + Short: "Delete nodes or cluster", + } + + o.CommonOptions.AddCommonFlag(cmd) + + cmd.AddCommand(NewCmdDeleteCluster()) + cmd.AddCommand(NewCmdDeleteNode()) + return cmd } diff --git a/cmd/ctl/delete/delete_cluster.go b/cmd/ctl/delete/delete_cluster.go new file mode 100644 index 00000000..b01a70e0 --- /dev/null +++ b/cmd/ctl/delete/delete_cluster.go @@ -0,0 +1,48 @@ +package delete + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/spf13/cobra" +) + +type DeleteClusterOptions struct { + CommonOptions *options.CommonOptions + ClusterCfgFile string +} + +func NewDeleteClusterOptions() *DeleteClusterOptions { + return &DeleteClusterOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdDeleteCluster creates a new delete cluster command +func NewCmdDeleteCluster() *cobra.Command { + o := NewDeleteClusterOptions() + cmd := &cobra.Command{ + Use: "cluster", + Short: "Delete a cluster", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + return cmd +} + +func (o *DeleteClusterOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + Debug: o.CommonOptions.Verbose, + } + return pipelines.DeleteCluster(arg) +} + +func (o *DeleteClusterOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") +} diff --git a/cmd/ctl/delete/delete_node.go b/cmd/ctl/delete/delete_node.go new file mode 100644 index 00000000..eb6c9a17 --- /dev/null +++ b/cmd/ctl/delete/delete_node.go @@ -0,0 +1,67 @@ +package delete + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "strings" +) + +type DeleteNodeOptions struct { + CommonOptions *options.CommonOptions + ClusterCfgFile string + nodes string +} + +func NewDeleteNodeOptions() *DeleteNodeOptions { + return &DeleteNodeOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdDeleteNode creates a new delete node command +func NewCmdDeleteNode() *cobra.Command { + o := NewDeleteNodeOptions() + cmd := &cobra.Command{ + Use: "node", + Short: "delete a node", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Complete(cmd, args)) + util.CheckErr(o.Validate()) + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + return cmd +} + +func (o *DeleteNodeOptions) Complete(cmd *cobra.Command, args []string) error { + o.nodes = strings.Join(args, "") + return nil +} + +func (o *DeleteNodeOptions) Validate() error { + if o.nodes == "" { + return errors.New("node can not be empty") + } + return nil +} + +func (o *DeleteNodeOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + Debug: o.CommonOptions.Verbose, + NodeName: o.nodes, + } + return pipelines.DeleteNode(arg) +} + +func (o *DeleteNodeOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") + +} diff --git a/cmd/init.go b/cmd/ctl/init/init.go similarity index 50% rename from cmd/init.go rename to cmd/ctl/init/init.go index 3f8db07c..25e586b0 100644 --- a/cmd/init.go +++ b/cmd/ctl/init/init.go @@ -5,7 +5,7 @@ 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 + 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, @@ -13,18 +13,31 @@ 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 +package init import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" "github.com/spf13/cobra" ) -// initCmd represents the create command -var initCmd = &cobra.Command{ - Use: "init", - Short: "Initializes the installation environment", +type InitOptions struct { + CommonOptions *options.CommonOptions } -func init() { - rootCmd.AddCommand(initCmd) +func NewInitOptions() *InitOptions { + return &InitOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdInit create a new init command +func NewCmdInit() *cobra.Command { + o := NewInitOptions() + cmd := &cobra.Command{ + Use: "init", + Short: "Initializes the installation environment", + } + o.CommonOptions.AddCommonFlag(cmd) + cmd.AddCommand(NewCmdInitOs()) + return cmd } diff --git a/cmd/ctl/init/init_os.go b/cmd/ctl/init/init_os.go new file mode 100644 index 00000000..e9ba6bf7 --- /dev/null +++ b/cmd/ctl/init/init_os.go @@ -0,0 +1,69 @@ +/* +Copyright 2020 The KubeSphere 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 init + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/spf13/cobra" +) + +type InitOsOptions struct { + CommonOptions *options.CommonOptions + ClusterCfgFile string + SourcesDir string + AddImagesRepo bool +} + +func NewInitOsOptions() *InitOsOptions { + return &InitOsOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdInitOs creates a new init os command +func NewCmdInitOs() *cobra.Command { + o := NewInitOsOptions() + cmd := &cobra.Command{ + Use: "os", + Short: "Init operating system", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + return cmd +} + +func (o *InitOsOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + SourcesDir: o.SourcesDir, + AddImagesRepo: o.AddImagesRepo, + Debug: o.CommonOptions.Verbose, + } + return pipelines.InitDependencies(arg) +} + +func (o *InitOsOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") + cmd.Flags().StringVarP(&o.SourcesDir, "sources", "s", "", "Path to the dependencies' dir") + cmd.Flags().BoolVarP(&o.AddImagesRepo, "add-images-repo", "", false, "Create a local images registry") +} diff --git a/cmd/ctl/options/persistent_options.go b/cmd/ctl/options/persistent_options.go new file mode 100644 index 00000000..baa28a43 --- /dev/null +++ b/cmd/ctl/options/persistent_options.go @@ -0,0 +1,23 @@ +package options + +import ( + "github.com/spf13/cobra" +) + +type CommonOptions struct { + InCluster bool + Verbose bool + SkipConfirmCheck bool + IgnoreErr bool +} + +func NewCommonOptions() *CommonOptions { + return &CommonOptions{} +} + +func (o *CommonOptions) AddCommonFlag(cmd *cobra.Command) { + cmd.Flags().BoolVar(&o.InCluster, "in-cluster", false, "Running inside the cluster") + cmd.Flags().BoolVar(&o.Verbose, "debug", true, "Print detailed information") + cmd.Flags().BoolVarP(&o.SkipConfirmCheck, "yes", "y", false, "Skip confirm check") + cmd.Flags().BoolVar(&o.IgnoreErr, "ignore-err", false, "Ignore the error message, remove the host which reported error and force to continue") +} diff --git a/cmd/ctl/root.go b/cmd/ctl/root.go new file mode 100644 index 00000000..edcba69b --- /dev/null +++ b/cmd/ctl/root.go @@ -0,0 +1,62 @@ +/* +Copyright 2020 The KubeSphere 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 ctl + +import ( + "github.com/kubesphere/kubekey/cmd/ctl/add" + "github.com/kubesphere/kubekey/cmd/ctl/cert" + "github.com/kubesphere/kubekey/cmd/ctl/completion" + "github.com/kubesphere/kubekey/cmd/ctl/create" + "github.com/kubesphere/kubekey/cmd/ctl/delete" + initOs "github.com/kubesphere/kubekey/cmd/ctl/init" + "github.com/kubesphere/kubekey/cmd/ctl/upgrade" + "github.com/kubesphere/kubekey/cmd/ctl/version" + "github.com/spf13/cobra" +) + +func NewDefaultKubeKeyCommand() *cobra.Command { + return NewDefaultKubeKeyCommandWithArgs() +} + +func NewDefaultKubeKeyCommandWithArgs() *cobra.Command { + cmd := NewKubeKeyCommand() + + return cmd +} + +// NewKubeKeyCommand creates a new kubekey root command +func NewKubeKeyCommand() *cobra.Command { + cmds := &cobra.Command{ + Use: "kk", + Short: "Kubernetes/KubeSphere Deploy Tool", + Long: `Deploy a Kubernetes or KubeSphere cluster efficiently, flexibly and easily. There are three scenarios to use KubeKey. +1. Install Kubernetes only +2. Install Kubernetes and KubeSphere together in one command +3. Install Kubernetes first, then deploy KubeSphere on it using https://github.com/kubesphere/ks-installer`, + } + + cmds.AddCommand(initOs.NewCmdInit()) + + cmds.AddCommand(create.NewCmdCreate()) + cmds.AddCommand(delete.NewCmdDelete()) + cmds.AddCommand(add.NewCmdAdd()) + cmds.AddCommand(upgrade.NewCmdUpgrade()) + cmds.AddCommand(cert.NewCmdCerts()) + + cmds.AddCommand(completion.NewCmdCompletion()) + cmds.AddCommand(version.NewCmdVersion()) + return cmds +} diff --git a/cmd/ctl/upgrade/upgrade.go b/cmd/ctl/upgrade/upgrade.go new file mode 100644 index 00000000..1d751fac --- /dev/null +++ b/cmd/ctl/upgrade/upgrade.go @@ -0,0 +1,110 @@ +/* +Copyright 2020 The KubeSphere 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 upgrade + +import ( + "fmt" + "github.com/kubesphere/kubekey/cmd/ctl/options" + "github.com/kubesphere/kubekey/cmd/ctl/util" + "github.com/kubesphere/kubekey/pkg/common" + "github.com/kubesphere/kubekey/pkg/pipelines" + "github.com/kubesphere/kubekey/pkg/version/kubesphere" + "github.com/kubesphere/kubekey/version" + "github.com/spf13/cobra" + "time" +) + +type UpgradeOptions struct { + CommonOptions *options.CommonOptions + ClusterCfgFile string + Kubernetes string + EnableKubeSphere bool + KubeSphere string + SkipPullImages bool + DownloadCmd string +} + +func NewUpgradeOptions() *UpgradeOptions { + return &UpgradeOptions{ + CommonOptions: options.NewCommonOptions(), + } +} + +// NewCmdUpgrade creates a new upgrade command +func NewCmdUpgrade() *cobra.Command { + o := NewUpgradeOptions() + cmd := &cobra.Command{ + Use: "upgrade", + Short: "Upgrade your cluster smoothly to a newer version with this command", + Run: func(cmd *cobra.Command, args []string) { + util.CheckErr(o.Complete(cmd, args)) + util.CheckErr(o.Run()) + }, + } + + o.CommonOptions.AddCommonFlag(cmd) + o.AddFlags(cmd) + if err := completionSetting(cmd); err != nil { + panic(fmt.Sprintf("Got error with the completion setting")) + } + return cmd +} + +func (o *UpgradeOptions) Complete(cmd *cobra.Command, args []string) error { + var ksVersion string + if o.EnableKubeSphere && len(args) > 0 { + ksVersion = args[0] + } else { + ksVersion = kubesphere.Latest().Version + } + o.KubeSphere = ksVersion + return nil +} + +func (o *UpgradeOptions) Run() error { + arg := common.Argument{ + FilePath: o.ClusterCfgFile, + KubernetesVersion: o.Kubernetes, + KsEnable: o.EnableKubeSphere, + KsVersion: o.KubeSphere, + SkipPullImages: o.SkipPullImages, + Debug: o.CommonOptions.Verbose, + } + return pipelines.UpgradeCluster(arg, o.DownloadCmd) +} + +func (o *UpgradeOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringVarP(&o.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") + cmd.Flags().StringVarP(&o.Kubernetes, "with-kubernetes", "", "", "Specify a supported version of kubernetes") + cmd.Flags().BoolVarP(&o.EnableKubeSphere, "with-kubesphere", "", false, "Deploy a specific version of kubesphere (default v3.2.0)") + cmd.Flags().BoolVarP(&o.SkipPullImages, "skip-pull-images", "", false, "Skip pre pull images") + cmd.Flags().StringVarP(&o.DownloadCmd, "download-cmd", "", "curl -L -o %s %s", + `The user defined command to download the necessary binary files. The first param '%s' is output path, the second param '%s', is the URL`) +} + +func completionSetting(cmd *cobra.Command) (err error) { + cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ( + strings []string, directive cobra.ShellCompDirective) { + versionArray := []string{"v2.1.1", "v3.0.0", "v3.1.0", "v3.1.1", "v3.2.0", time.Now().Add(-time.Hour * 24).Format("nightly-20060102")} + return versionArray, cobra.ShellCompDirectiveNoFileComp + } + + err = cmd.RegisterFlagCompletionFunc("with-kubernetes", func(cmd *cobra.Command, args []string, toComplete string) ( + strings []string, directive cobra.ShellCompDirective) { + return version.SupportedK8sVersionList(), cobra.ShellCompDirectiveNoFileComp + }) + return +} diff --git a/cmd/ctl/util/helpers.go b/cmd/ctl/util/helpers.go new file mode 100644 index 00000000..1683578f --- /dev/null +++ b/cmd/ctl/util/helpers.go @@ -0,0 +1,45 @@ +package util + +import ( + "fmt" + "os" + "strings" +) + +const DefaultErrorExitCode = 1 + +var ErrExit = fmt.Errorf("exit") + +func fatal(msg string, code int) { + if len(msg) > 0 { + // add newline if needed + if !strings.HasSuffix(msg, "\n") { + msg += "\n" + } + fmt.Fprint(os.Stderr, msg) + } + os.Exit(code) +} + +var fatalErrHandler = fatal + +func CheckErr(err error) { + checkErr(err, fatalErrHandler) +} + +func checkErr(err error, handleErr func(string, int)) { + if err == nil { + return + } + + switch { + case err == ErrExit: + handleErr("", DefaultErrorExitCode) + default: + msg := err.Error() + if !strings.HasPrefix(msg, "error: ") { + msg = fmt.Sprintf("error: %s", msg) + } + handleErr(msg, DefaultErrorExitCode) + } +} diff --git a/cmd/version.go b/cmd/ctl/version/version.go similarity index 57% rename from cmd/version.go rename to cmd/ctl/version/version.go index 76f6e6d5..943faa0b 100644 --- a/cmd/version.go +++ b/cmd/ctl/version/version.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cmd +package version import ( "fmt" @@ -24,25 +24,36 @@ import ( "strings" ) -var shortVersion bool -var showSupportedK8sVersionList bool - -// versionCmd represents the version command -var versionCmd = &cobra.Command{ - Use: "version", - Short: "print the client version information", - RunE: func(cmd *cobra.Command, _ []string) error { - if showSupportedK8sVersionList { - return printSupportedK8sVersionList(cmd.OutOrStdout()) - } - return printVersion(shortVersion) - }, +type VersionOptions struct { + ShortVersion bool + ShowSupportedK8sVersionList bool } -func init() { - rootCmd.AddCommand(versionCmd) - versionCmd.Flags().BoolVarP(&shortVersion, "short", "", false, "print the version number") - versionCmd.Flags().BoolVarP(&showSupportedK8sVersionList, "show-supported-k8s", "", false, +func NewVersionOptions() *VersionOptions { + return &VersionOptions{} +} + +// NewCmdVersion creates a new version command +func NewCmdVersion() *cobra.Command { + o := NewVersionOptions() + + cmd := &cobra.Command{ + Use: "version", + Short: "print the client version information", + RunE: func(cmd *cobra.Command, _ []string) error { + if o.ShowSupportedK8sVersionList { + return printSupportedK8sVersionList(cmd.OutOrStdout()) + } + return printVersion(o.ShortVersion) + }, + } + o.AddFlags(cmd) + return cmd +} + +func (o *VersionOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().BoolVarP(&o.ShortVersion, "short", "", false, "print the version number") + cmd.Flags().BoolVarP(&o.ShowSupportedK8sVersionList, "show-supported-k8s", "", false, `print the version of supported k8s`) } diff --git a/cmd/delete_cluster.go b/cmd/delete_cluster.go deleted file mode 100644 index 18d51e40..00000000 --- a/cmd/delete_cluster.go +++ /dev/null @@ -1,25 +0,0 @@ -package cmd - -import ( - "github.com/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/spf13/cobra" -) - -var deleteClusterCmd = &cobra.Command{ - Use: "cluster", - Short: "Delete a cluster", - RunE: func(cmd *cobra.Command, args []string) error { - arg := common.Argument{ - FilePath: opt.ClusterCfgFile, - Debug: opt.Verbose, - } - return pipelines.DeleteCluster(arg) - }, -} - -func init() { - deleteCmd.AddCommand(deleteClusterCmd) - - deleteClusterCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") -} diff --git a/cmd/delete_node.go b/cmd/delete_node.go deleted file mode 100644 index 66a3745d..00000000 --- a/cmd/delete_node.go +++ /dev/null @@ -1,33 +0,0 @@ -package cmd - -import ( - "github.com/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "strings" -) - -var deleteNodeCmd = &cobra.Command{ - Use: "node", - Short: "delete a node", - PreRunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return errors.New("node can not be empty") - } - return nil - }, - RunE: func(cmd *cobra.Command, args []string) error { - arg := common.Argument{ - FilePath: opt.ClusterCfgFile, - Debug: opt.Verbose, - NodeName: strings.Join(args, ""), - } - return pipelines.DeleteNode(arg) - }, -} - -func init() { - deleteCmd.AddCommand(deleteNodeCmd) - deleteNodeCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") -} diff --git a/cmd/init_os.go b/cmd/init_os.go deleted file mode 100644 index de7c9912..00000000 --- a/cmd/init_os.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/spf13/cobra" -) - -// osCmd represents the os command -var osCmd = &cobra.Command{ - Use: "os", - Short: "Init operating system", - RunE: func(cmd *cobra.Command, args []string) error { - arg := common.Argument{ - FilePath: opt.ClusterCfgFile, - SourcesDir: opt.SourcesDir, - AddImagesRepo: opt.AddImagesRepo, - Debug: opt.Verbose, - } - return pipelines.InitDependencies(arg) - }, -} - -func init() { - initCmd.AddCommand(osCmd) - osCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") - osCmd.Flags().StringVarP(&opt.SourcesDir, "sources", "s", "", "Path to the dependencies' dir") - osCmd.Flags().BoolVarP(&opt.AddImagesRepo, "add-images-repo", "", false, "Create a local images registry") -} diff --git a/cmd/init_registry.go b/cmd/init_registry.go deleted file mode 100644 index af8ed271..00000000 --- a/cmd/init_registry.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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" -) - -// osCmd represents the os command -var registryCmd = &cobra.Command{ - Use: "registry", - Short: "Init a local image registry", - RunE: func(cmd *cobra.Command, args []string) error { - return nil - }, -} - -func init() { - initCmd.AddCommand(registryCmd) - registryCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") -} diff --git a/cmd/list_cert.go b/cmd/list_cert.go deleted file mode 100644 index 7a35d2ff..00000000 --- a/cmd/list_cert.go +++ /dev/null @@ -1,25 +0,0 @@ -package cmd - -import ( - common2 "github.com/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/spf13/cobra" -) - -var listClusterCertsCmd = &cobra.Command{ - Use: "check-expiration", - Short: "Check certificates expiration for a Kubernetes cluster", - RunE: func(cmd *cobra.Command, args []string) error { - arg := common2.Argument{ - FilePath: opt.ClusterCfgFile, - Debug: opt.Verbose, - } - return pipelines.CheckCerts(arg) - }, -} - -func init() { - certsCmd.AddCommand(listClusterCertsCmd) - - listClusterCertsCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") -} diff --git a/cmd/kk/main.go b/cmd/main.go similarity index 59% rename from cmd/kk/main.go rename to cmd/main.go index e425357b..fd17a3d4 100644 --- a/cmd/kk/main.go +++ b/cmd/main.go @@ -17,10 +17,21 @@ limitations under the License. package main import ( - "github.com/kubesphere/kubekey/cmd" + "github.com/kubesphere/kubekey/cmd/ctl" + "os" + "os/exec" ) // Using a separate entry-point can reduce the size of the binary file func main() { - cmd.Execute() + cmd := ctl.NewDefaultKubeKeyCommand() + _ = exec.Command("/bin/bash", "-c", "ulimit -u 65535").Run() + _ = exec.Command("/bin/bash", "-c", "ulimit -n 65535").Run() + + // Execute adds all child commands to the root command and sets flags appropriately. + // This is called by main.main(). It only needs to happen once to the rootCmd. + if err := cmd.Execute(); err != nil { + //fmt.Println(err) + os.Exit(1) + } } diff --git a/cmd/renew_cert.go b/cmd/renew_cert.go deleted file mode 100644 index 905e054e..00000000 --- a/cmd/renew_cert.go +++ /dev/null @@ -1,25 +0,0 @@ -package cmd - -import ( - common2 "github.com/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/spf13/cobra" -) - -var renewClusterCertsCmd = &cobra.Command{ - Use: "renew", - Short: "renew a cluster certs", - RunE: func(cmd *cobra.Command, args []string) error { - arg := common2.Argument{ - FilePath: opt.ClusterCfgFile, - Debug: opt.Verbose, - } - return pipelines.RenewCerts(arg) - }, -} - -func init() { - certsCmd.AddCommand(renewClusterCertsCmd) - - renewClusterCertsCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") -} diff --git a/cmd/root.go b/cmd/root.go deleted file mode 100644 index a94cc53d..00000000 --- a/cmd/root.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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" - "os" - "os/exec" -) - -type Options struct { - Verbose bool - IgnoreErr bool - Addons string - Name string - ClusterCfgPath string - Kubeconfig string - FromCluster bool - ClusterCfgFile string - Kubernetes string - Kubesphere bool - LocalStorage bool - SkipPullImages bool - KsVersion string - Registry string - SourcesDir string - AddImagesRepo bool - ContainerManager string - InCluster bool - DownloadCmd string - SkipConfirmCheck bool -} - -var ( - opt Options -) - -// rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ - Use: "kk", - Short: "Kubernetes/KubeSphere Deploy Tool", - Long: `Deploy a Kubernetes or KubeSphere cluster efficiently, flexibly and easily. There are three scenarios to use KubeKey. -1. Install Kubernetes only -2. Install Kubernetes and KubeSphere together in one command -3. Install Kubernetes first, then deploy KubeSphere on it using https://github.com/kubesphere/ks-installer`, -} - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - _ = exec.Command("/bin/bash", "-c", "ulimit -u 65535").Run() - _ = exec.Command("/bin/bash", "-c", "ulimit -n 65535").Run() - if err := rootCmd.Execute(); err != nil { - //fmt.Println(err) - os.Exit(1) - } -} - -func init() { - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - rootCmd.PersistentFlags().BoolVar(&opt.InCluster, "in-cluster", false, "Running inside the cluster") - rootCmd.PersistentFlags().BoolVar(&opt.Verbose, "debug", true, "Print detailed information") - rootCmd.PersistentFlags().BoolVarP(&opt.SkipConfirmCheck, "yes", "y", false, "Skip confirm check") - rootCmd.PersistentFlags().BoolVar(&opt.IgnoreErr, "ignore-err", false, "Ignore the error message, remove the host which reported error and force to continue") - // Cobra also supports local flags, which will only run - // when this action is called directly. -} diff --git a/cmd/upgrade.go b/cmd/upgrade.go deleted file mode 100644 index b53d6da3..00000000 --- a/cmd/upgrade.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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 ( - "fmt" - common2 "github.com/kubesphere/kubekey/pkg/common" - "github.com/kubesphere/kubekey/pkg/pipelines" - "github.com/spf13/cobra" -) - -// upgradeCmd represents the upgrade command -var upgradeCmd = &cobra.Command{ - Use: "upgrade", - Short: "Upgrade your cluster smoothly to a newer version with this command", - RunE: func(cmd *cobra.Command, args []string) error { - var ksVersion string - if opt.Kubesphere && len(args) > 0 { - ksVersion = args[0] - } else { - ksVersion = "" - } - - arg := common2.Argument{ - FilePath: opt.ClusterCfgFile, - KubernetesVersion: opt.Kubernetes, - KsEnable: opt.Kubesphere, - KsVersion: ksVersion, - SkipConfirmCheck: opt.SkipConfirmCheck, - SkipPullImages: opt.SkipPullImages, - InCluster: opt.InCluster, - DeployLocalStorage: opt.LocalStorage, - Debug: opt.Verbose, - } - return pipelines.UpgradeCluster(arg, opt.DownloadCmd) - }, -} - -func init() { - rootCmd.AddCommand(upgradeCmd) - upgradeCmd.Flags().StringVarP(&opt.ClusterCfgFile, "filename", "f", "", "Path to a configuration file") - upgradeCmd.Flags().StringVarP(&opt.Kubernetes, "with-kubernetes", "", "", "Specify a supported version of kubernetes") - upgradeCmd.Flags().BoolVarP(&opt.Kubesphere, "with-kubesphere", "", false, "Deploy a specific version of kubesphere (default v3.1.0)") - upgradeCmd.Flags().BoolVarP(&opt.SkipPullImages, "skip-pull-images", "", false, "Skip pre pull images") - upgradeCmd.Flags().StringVarP(&opt.DownloadCmd, "download-cmd", "", "curl -L -o %s %s", - `The user defined command to download the necessary binary files. The first param '%s' is output path, the second param '%s', is the URL`) - - if err := setValidArgs(upgradeCmd); err != nil { - panic(fmt.Sprintf("Got error with the completion setting")) - } -} diff --git a/go.sum b/go.sum index b6c23493..1c48fb72 100644 --- a/go.sum +++ b/go.sum @@ -920,7 +920,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=