diff --git a/cmd/kubesphere.go b/cmd/deployKs.go similarity index 70% rename from cmd/kubesphere.go rename to cmd/deployKs.go index c207e49d..2bccc8cc 100644 --- a/cmd/kubesphere.go +++ b/cmd/deployKs.go @@ -21,7 +21,7 @@ import ( ) // clusterCmd represents the cluster command -var ksCmd = &cobra.Command{ +var deployKsCmd = &cobra.Command{ Use: "kubesphere", Short: "Deploy KubeSphere on the existing K8s", RunE: func(cmd *cobra.Command, args []string) error { @@ -30,9 +30,9 @@ var ksCmd = &cobra.Command{ } func init() { - deployCmd.AddCommand(ksCmd) + deployCmd.AddCommand(deployKsCmd) - ksCmd.Flags().StringVarP(&opt.Kubeconfig, "kubeconfig", "", "", "Specify a kubeconfig file") - ksCmd.Flags().StringVarP(&opt.KsVersion, "version", "v", "v3.0.0", "Specify a supported version of kubesphere") - ksCmd.Flags().StringVarP(&opt.Registry, "registry", "", "", "Specify a image registry address") + deployKsCmd.Flags().StringVarP(&opt.Kubeconfig, "kubeconfig", "", "", "Specify a kubeconfig file") + deployKsCmd.Flags().StringVarP(&opt.KsVersion, "version", "v", "v3.0.0", "Specify a supported version of kubesphere") + deployKsCmd.Flags().StringVarP(&opt.Registry, "registry", "", "", "Specify a image registry address") } diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 4ba357e5..514fbaae 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -208,4 +208,4 @@ func serveCRMetrics(cfg *rest.Config, operatorNs string) error { return err } return nil -} \ No newline at end of file +} diff --git a/cmd/upgradeKs.go b/cmd/upgradeKs.go new file mode 100644 index 00000000..7bc38803 --- /dev/null +++ b/cmd/upgradeKs.go @@ -0,0 +1,38 @@ +/* +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/upgrade" + "github.com/spf13/cobra" +) + +// clusterCmd represents the cluster command +var upgradeKsCmd = &cobra.Command{ + Use: "kubesphere", + Short: "Deploy KubeSphere on the existing K8s", + RunE: func(cmd *cobra.Command, args []string) error { + return upgrade.KsToV3(opt.KsVersion, opt.Registry, opt.Kubeconfig) + }, +} + +func init() { + upgradeCmd.AddCommand(upgradeKsCmd) + + upgradeKsCmd.Flags().StringVarP(&opt.Kubeconfig, "kubeconfig", "", "", "Specify a kubeconfig file") + upgradeKsCmd.Flags().StringVarP(&opt.KsVersion, "version", "v", "v3.0.0", "Specify a supported version of kubesphere") + upgradeKsCmd.Flags().StringVarP(&opt.Registry, "registry", "", "", "Specify a image registry address") +} diff --git a/pkg/apis/kubekey/v1alpha1/cluster_types.go b/pkg/apis/kubekey/v1alpha1/cluster_types.go index 2a225a38..6f70f26b 100644 --- a/pkg/apis/kubekey/v1alpha1/cluster_types.go +++ b/pkg/apis/kubekey/v1alpha1/cluster_types.go @@ -89,7 +89,6 @@ type HostCfg struct { IsEtcd bool `json:"-"` IsMaster bool `json:"-"` IsWorker bool `json:"-"` - IsClient bool `json:"-"` } type RoleGroups struct { diff --git a/pkg/apis/kubekey/v1alpha1/register.go b/pkg/apis/kubekey/v1alpha1/register.go index 86026b94..f3d43819 100644 --- a/pkg/apis/kubekey/v1alpha1/register.go +++ b/pkg/apis/kubekey/v1alpha1/register.go @@ -19,14 +19,13 @@ var ( // SchemeBuilder is used to add go types to the GroupVersionKind scheme // SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - AddToScheme = SchemeBuilder.AddToScheme + AddToScheme = SchemeBuilder.AddToScheme ) func init() { SchemeBuilder.Register(addKnownTypes) } - // Kind takes an unqualified kind and returns GroupKind func Kind(kind string) schema.GroupKind { return SchemeGroupVersion.WithKind(kind).GroupKind() @@ -41,7 +40,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &Cluster{}, &ClusterList{}, - ) + ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } diff --git a/pkg/config/from_cluster.go b/pkg/config/from_cluster.go index 753c741a..ab98025f 100644 --- a/pkg/config/from_cluster.go +++ b/pkg/config/from_cluster.go @@ -22,14 +22,11 @@ import ( "encoding/base64" "fmt" kubekeyapi "github.com/kubesphere/kubekey/pkg/apis/kubekey/v1alpha1" - "github.com/kubesphere/kubekey/pkg/kubesphere" "github.com/kubesphere/kubekey/pkg/util" "github.com/lithammer/dedent" "github.com/pkg/errors" "github.com/spf13/viper" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" "net" "os" "os/exec" @@ -78,9 +75,6 @@ spec: registry: privateRegistry: "" -{{ if .Options.KubeSphereEnabled }} -{{ .Options.KubeSphereConfigMap }} -{{ end }} `))) ) @@ -108,28 +102,10 @@ type OptionsCluster struct { ControlPlaneEndpointDomain string ControlPlaneEndpointAddress string ControlPlaneEndpointPort string - KubeSphereConfigMap string - KubeSphereEnabled bool } func GetInfoFromCluster(config, name string) (*OptionsCluster, error) { - var kubeconfig string - if config != "" { - config, err := filepath.Abs(config) - if err != nil { - return nil, errors.Wrap(err, "Failed to look up current directory") - } - kubeconfig = config - } else { - kubeconfig = filepath.Join(homeDir(), ".kube", "config") - } - // use the current context in kubeconfig - configCluster, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - return nil, err - } - // create the clientset - clientset, err := kubernetes.NewForConfig(configCluster) + clientset, err := util.NewClient(config) if err != nil { return nil, err } @@ -213,6 +189,9 @@ func GetInfoFromCluster(config, name string) (*OptionsCluster, error) { } pods, err := clientset.CoreV1().Pods("kube-system").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return nil, err + } for _, pod := range pods.Items { if strings.Contains(pod.Name, "calico") { opt.NetworkPlugin = "calico" @@ -242,27 +221,12 @@ func GetInfoFromCluster(config, name string) (*OptionsCluster, error) { return &opt, nil } -func GenerateConfigFromCluster(cfgPath, kubeconfig, name, ksVersion string, ksEnabled bool) error { +func GenerateConfigFromCluster(cfgPath, kubeconfig, name string) error { opt, err := GetInfoFromCluster(kubeconfig, name) if err != nil { return err } - if ksEnabled { - switch strings.TrimSpace(ksVersion) { - case "": - opt.KubeSphereConfigMap = kubesphere.V3_0_0 - case "v3.0.0": - opt.KubeSphereConfigMap = kubesphere.V3_0_0 - case "v2.1.1": - opt.KubeSphereConfigMap = kubesphere.V2_1_1 - default: - return errors.New(fmt.Sprintf("Unsupported version: %s", strings.TrimSpace(ksVersion))) - } - } - - opt.KubeSphereEnabled = ksEnabled - ClusterCfgStr, err := GenerateClusterCfgStr(opt) if err != nil { return errors.Wrap(err, "Faild to generate cluster config") @@ -291,10 +255,3 @@ func GenerateConfigFromCluster(cfgPath, kubeconfig, name, ksVersion string, ksEn return nil } - -func homeDir() string { - if h := os.Getenv("HOME"); h != "" { - return h - } - return os.Getenv("USERPROFILE") // windows -} diff --git a/pkg/config/generate.go b/pkg/config/generate.go index 3f1c28da..4f4ccdca 100644 --- a/pkg/config/generate.go +++ b/pkg/config/generate.go @@ -153,7 +153,7 @@ func GenerateClusterObjStr(opt *Options, storageNum int) (string, error) { func GenerateClusterObj(addons, k8sVersion, ksVersion, name, kubeconfig, clusterCfgPath string, ksEnabled, fromCluster bool) error { if fromCluster { - err := GenerateConfigFromCluster(clusterCfgPath, kubeconfig, name, ksVersion, ksEnabled) + err := GenerateConfigFromCluster(clusterCfgPath, kubeconfig, name) if err != nil { return err } diff --git a/pkg/config/parse.go b/pkg/config/parse.go index 40e20e5f..c8a93c47 100644 --- a/pkg/config/parse.go +++ b/pkg/config/parse.go @@ -43,7 +43,7 @@ func ParseClusterCfg(clusterCfgPath, k8sVersion, ksVersion string, ksEnabled boo } clusterCfg = AllinoneCfg(user, k8sVersion, ksVersion, ksEnabled, logger) } else { - cfg, err := ParseCfg(clusterCfgPath, k8sVersion) + cfg, err := ParseCfg(clusterCfgPath, k8sVersion, ksVersion, ksEnabled) if err != nil { return nil, err } @@ -53,7 +53,7 @@ func ParseClusterCfg(clusterCfgPath, k8sVersion, ksVersion string, ksEnabled boo return clusterCfg, nil } -func ParseCfg(clusterCfgPath, k8sVersion string) (*kubekeyapi.Cluster, error) { +func ParseCfg(clusterCfgPath, k8sVersion, ksVersion string, ksEnabled bool) (*kubekeyapi.Cluster, error) { clusterCfg := kubekeyapi.Cluster{} fp, err := filepath.Abs(clusterCfgPath) if err != nil { @@ -106,6 +106,24 @@ func ParseCfg(clusterCfgPath, k8sVersion string) (*kubekeyapi.Cluster, error) { } } } + + if ksEnabled { + clusterCfg.Spec.KubeSphere.Enabled = true + switch strings.TrimSpace(ksVersion) { + case "": + clusterCfg.Spec.KubeSphere.Version = "v3.0.0" + clusterCfg.Spec.KubeSphere.Configurations = kubesphere.V3_0_0 + case "v3.0.0": + clusterCfg.Spec.KubeSphere.Version = "v3.0.0" + clusterCfg.Spec.KubeSphere.Configurations = kubesphere.V3_0_0 + case "v2.1.1": + clusterCfg.Spec.KubeSphere.Version = "v2.1.1" + clusterCfg.Spec.KubeSphere.Configurations = kubesphere.V2_1_1 + default: + return nil, errors.New(fmt.Sprintf("Unsupported version: %s", strings.TrimSpace(ksVersion))) + } + } + return &clusterCfg, nil } diff --git a/pkg/deploy/kubesphere.go b/pkg/deploy/kubesphere.go index 7ecbeea1..65cea514 100644 --- a/pkg/deploy/kubesphere.go +++ b/pkg/deploy/kubesphere.go @@ -24,6 +24,7 @@ import ( jsonpatch "github.com/evanphx/json-patch" "github.com/ghodss/yaml" "github.com/kubesphere/kubekey/pkg/kubesphere" + "github.com/kubesphere/kubekey/pkg/util" "github.com/pkg/errors" kubeErr "k8s.io/apimachinery/pkg/api/errors" k8syaml "k8s.io/apimachinery/pkg/util/yaml" @@ -32,16 +33,21 @@ import ( ) const ( - customResourceDefinition = "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions" - namespaces = "/api/v1/namespaces" - serviceAccount = "/api/v1/namespaces/kubesphere-system/serviceaccounts" - clusterRole = "/apis/rbac.authorization.k8s.io/v1/clusterroles" - clusterRoleBinding = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings" - deployment = "/apis/apps/v1/namespaces/kubesphere-system/deployments" - clusterConfiguration = "/apis/installer.kubesphere.io/v1alpha1/namespaces/kubesphere-system/clusterconfigurations" + CustomResourceDefinition = "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions" + Namespaces = "/api/v1/namespaces" + ServiceAccount = "/api/v1/namespaces/kubesphere-system/serviceaccounts" + ClusterRole = "/apis/rbac.authorization.k8s.io/v1/clusterroles" + ClusterRoleBinding = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings" + Deployment = "/apis/apps/v1/namespaces/kubesphere-system/deployments" + ClusterConfiguration = "/apis/installer.kubesphere.io/v1alpha1/namespaces/kubesphere-system/clusterconfigurations" ) func DeployKubeSphere(version, repo, kubeconfig string) error { + clientset, err := util.NewClient(kubeconfig) + if err != nil { + return err + } + var kubesphereConfig, installerYaml string switch version { @@ -70,11 +76,6 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { return errors.New(fmt.Sprintf("Unsupported version: %s", strings.TrimSpace(version))) } - clientset, err := newClient(kubeconfig) - if err != nil { - return err - } - b1 := bufio.NewReader(bytes.NewReader([]byte(installerYaml))) for { result := make(map[string]interface{}) @@ -98,7 +99,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { switch result["kind"] { case "CustomResourceDefinition": - if err := createObject(clientset, j2, customResourceDefinition); err != nil { + if err := CreateObject(clientset, j2, CustomResourceDefinition); err != nil { if !kubeErr.IsAlreadyExists(err) { return err } @@ -108,7 +109,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) case "Namespace": - if err := createObject(clientset, j2, namespaces); err != nil { + if err := CreateObject(clientset, j2, Namespaces); err != nil { if !kubeErr.IsAlreadyExists(err) { return err } @@ -117,7 +118,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { metadata := result["metadata"].(map[string]interface{}) fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) case "ServiceAccount": - if err := createObject(clientset, j2, serviceAccount); err != nil { + if err := CreateObject(clientset, j2, ServiceAccount); err != nil { if !kubeErr.IsAlreadyExists(err) { return err } @@ -126,7 +127,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { metadata := result["metadata"].(map[string]interface{}) fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) case "ClusterRole": - if err := createObject(clientset, j2, clusterRole); err != nil { + if err := CreateObject(clientset, j2, ClusterRole); err != nil { if !kubeErr.IsAlreadyExists(err) { return err } @@ -135,7 +136,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { metadata := result["metadata"].(map[string]interface{}) fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) case "ClusterRoleBinding": - if err := createObject(clientset, j2, clusterRoleBinding); err != nil { + if err := CreateObject(clientset, j2, ClusterRoleBinding); err != nil { if !kubeErr.IsAlreadyExists(err) { return err } @@ -144,7 +145,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { metadata := result["metadata"].(map[string]interface{}) fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) case "Deployment": - if err := createObject(clientset, j2, deployment); err != nil { + if err := CreateObject(clientset, j2, Deployment); err != nil { if !kubeErr.IsAlreadyExists(err) { return err } @@ -173,7 +174,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { return err } - if err := createObject(clientset, modified, clusterConfiguration); err != nil { + if err := CreateObject(clientset, modified, ClusterConfiguration); err != nil { if !kubeErr.IsAlreadyExists(err) { return err } @@ -188,7 +189,7 @@ func DeployKubeSphere(version, repo, kubeconfig string) error { return nil } -func createObject(clientset *kubernetes.Clientset, body []byte, request string) error { +func CreateObject(clientset *kubernetes.Clientset, body []byte, request string) error { if err := clientset. RESTClient().Post(). AbsPath(request). diff --git a/pkg/kubesphere/kubesphere.go b/pkg/kubesphere/kubesphere.go index a4b81af2..d3861d15 100644 --- a/pkg/kubesphere/kubesphere.go +++ b/pkg/kubesphere/kubesphere.go @@ -165,7 +165,11 @@ EOF caFile := "/etc/ssl/etcd/ssl/ca.pem" certFile := fmt.Sprintf("/etc/ssl/etcd/ssl/node-%s.pem", mgr.EtcdNodes[0].Name) keyFile := fmt.Sprintf("/etc/ssl/etcd/ssl/node-%s-key.pem", mgr.EtcdNodes[0].Name) - _, _ = mgr.Runner.ExecuteCmd(fmt.Sprintf("sudo -E /bin/sh -c \"/usr/local/bin/kubectl -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs --from-file=etcd-client-ca.crt=%s --from-file=etcd-client.crt=%s --from-file=etcd-client.key=%s\"", caFile, certFile, keyFile), 5, true) + if output, err := mgr.Runner.ExecuteCmd(fmt.Sprintf("sudo -E /bin/sh -c \"/usr/local/bin/kubectl -n kubesphere-monitoring-system create secret generic kube-etcd-client-certs --from-file=etcd-client-ca.crt=%s --from-file=etcd-client.crt=%s --from-file=etcd-client.key=%s\"", caFile, certFile, keyFile), 1, true); err != nil { + if !strings.Contains(output, "AlreadyExists") { + return err + } + } deployKubesphereCmd := "sudo -E /bin/sh -c \"/usr/local/bin/kubectl apply -f /etc/kubernetes/addons/kubesphere.yaml\"" diff --git a/pkg/kubesphere/v2/types.go b/pkg/kubesphere/v2/types.go new file mode 100644 index 00000000..63b99aa0 --- /dev/null +++ b/pkg/kubesphere/v2/types.go @@ -0,0 +1,109 @@ +/* +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 v2 + +type V2 struct { + Persistence Persistence `yaml:"persistence"` + Common Common `yaml:"common"` + Etcd Etcd `yaml:"etcd"` + MetricsServerOld MetricsServerOld `yaml:"metrics-server"` + MetricsServerNew MetricsServerNew `yaml:"metrics_server"` + Console Console `yaml:"console"` + Monitoring Monitoring `yaml:"monitoring"` + Logging Logging `yaml:"logging"` + Openpitrix Openpitrix `yaml:"openpitrix"` + Devops Devops `yaml:"devops"` + Servicemesh Servicemesh `yaml:"servicemesh"` + Notification Notification `yaml:"notification"` + Alerting Alerting `yaml:"alerting"` + LocalRegistry string `yaml:"local_registry"` +} + +type Persistence struct { + StorageClass string `yaml:"storageClass"` +} +type Etcd struct { + Monitoring bool `yaml:"monitoring"` + EndpointIps string `yaml:"endpointIps"` + Port int `yaml:"port"` + TlsEnable bool `yaml:"tlsEnable"` +} + +type Common struct { + MysqlVolumeSize string `yaml:"mysqlVolumeSize"` + MinioVolumeSize string `yaml:"minioVolumeSize"` + EtcdVolumeSize string `yaml:"etcdVolumeSize"` + OpenldapVolumeSize string `yaml:"openldapVolumeSize"` + RedisVolumSize string `yaml:"redisVolumSize"` +} + +type MetricsServerOld struct { + Enabled string `yaml:"enabled"` +} + +type MetricsServerNew struct { + Enabled string `yaml:"enabled"` +} + +type Console struct { + EnableMultiLogin bool `yaml:"enableMultiLogin"` + Port int `yaml:"port"` +} + +type Monitoring struct { + PrometheusReplicas int `yaml:"prometheusReplicas"` + PrometheusMemoryRequest string `yaml:"prometheusMemoryRequest"` + PrometheusVolumeSize string `yaml:"prometheusVolumeSize"` +} + +type Logging struct { + Enabled bool `yaml:"enabled"` + ElasticsearchMasterReplicas int `yaml:"elasticsearchMasterReplicas"` + ElasticsearchDataReplicas int `yaml:"elasticsearchDataReplicas"` + LogsidecarReplicas int `yaml:"logsidecarReplicas"` + ElasticsearchVolumeSize string `yaml:"elasticsearchVolumeSize"` + ElasticsearchMasterVolumeSize string `yaml:"elasticsearchMasterVolumeSize"` + ElasticsearchDataVolumeSize string `yaml:"elasticsearchDataVolumeSize"` + LogMaxAge int `yaml:"logMaxAge"` + ElkPrefix string `yaml:"elkPrefix"` +} + +type Openpitrix struct { + Enabled bool `yaml:"enabled"` +} + +type Devops struct { + Enabled bool `yaml:"enabled"` + JenkinsMemoryLim string `yaml:"jenkinsMemoryLim"` + JenkinsMemoryReq string `yaml:"jenkinsMemoryReq"` + JenkinsVolumeSize string `yaml:"jenkinsVolumeSize"` + JenkinsjavaoptsXms string `yaml:"jenkinsJavaOpts_Xms"` + JenkinsjavaoptsXmx string `yaml:"jenkinsJavaOpts_Xmx"` + JenkinsjavaoptsMaxram string `yaml:"jenkinsJavaOpts_MaxRAM"` +} + +type Servicemesh struct { + Enabled bool `yaml:"enabled"` +} + +type Notification struct { + Enabled bool `yaml:"enabled"` +} + +type Alerting struct { + Enabled bool `yaml:"enabled"` +} diff --git a/pkg/kubesphere/v3/types.go b/pkg/kubesphere/v3/types.go new file mode 100644 index 00000000..23a32343 --- /dev/null +++ b/pkg/kubesphere/v3/types.go @@ -0,0 +1,160 @@ +/* +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 v3 + +type ClusterConfig struct { + ApiVersion string `yaml:"apiVersion"` + Kind string `yaml:"kind"` + Metadata Metadata `yaml:"metadata"` + Spec *V3 `yaml:"spec"` +} + +type Metadata struct { + Name string `yaml:"name"` + Namespace string `yaml:"namespace"` + Label Label `yaml:"labels"` +} + +type Label struct { + Version string `yaml:"version"` +} + +type V3 struct { + Persistence Persistence `yaml:"persistence"` + Authentication Authentication `yaml:"authentication"` + Common Common `yaml:"common"` + Etcd Etcd `yaml:"etcd"` + MetricsServer MetricsServer `yaml:"metrics_server"` + Console Console `yaml:"console"` + Monitoring Monitoring `yaml:"monitoring"` + Logging Logging `yaml:"logging"` + Openpitrix Openpitrix `yaml:"openpitrix"` + Devops Devops `yaml:"devops"` + Servicemesh Servicemesh `yaml:"servicemesh"` + Notification Notification `yaml:"notification"` + Alerting Alerting `yaml:"alerting"` + Auditing Auditing `yaml:"auditing"` + Events Events `yaml:"events"` + Multicluster Multicluster `yaml:"multicluster"` + Networkpolicy Networkpolicy `yaml:"networkpolicy"` + LocalRegistry string `yaml:"local_registry"` +} + +type Persistence struct { + StorageClass string `yaml:"storageClass"` +} + +type MetricsServer struct { + Enabled bool `yaml:"enabled"` +} + +type Authentication struct { + JwtSecret string `yaml:"jwtSecret"` +} +type Etcd struct { + Monitoring bool `yaml:"monitoring"` + EndpointIps string `yaml:"endpointIps"` + Port int `yaml:"port"` + TlsEnable bool `yaml:"tlsEnable"` +} + +type Common struct { + MysqlVolumeSize string `yaml:"mysqlVolumeSize"` + MinioVolumeSize string `yaml:"minioVolumeSize"` + EtcdVolumeSize string `yaml:"etcdVolumeSize"` + OpenldapVolumeSize string `yaml:"openldapVolumeSize"` + RedisVolumSize string `yaml:"redisVolumSize"` + ES ES `yaml:"es"` +} + +type ES struct { + ElasticsearchMasterReplicas int `yaml:"elasticsearchMasterReplicas"` + ElasticsearchDataReplicas int `yaml:"elasticsearchDataReplicas"` + ElasticsearchMasterVolumeSize string `yaml:"elasticsearchMasterVolumeSize"` + ElasticsearchDataVolumeSize string `yaml:"elasticsearchDataVolumeSize"` + LogMaxAge int `yaml:"logMaxAge"` + ElkPrefix string `yaml:"elkPrefix"` +} + +type Console struct { + EnableMultiLogin bool `yaml:"enableMultiLogin"` + Port int `yaml:"port"` +} + +type Alerting struct { + Enabled bool `yaml:"enabled"` +} + +type Auditing struct { + Enabled bool `yaml:"enabled"` +} + +type Devops struct { + Enabled bool `yaml:"enabled"` + JenkinsMemoryLim string `yaml:"jenkinsMemoryLim"` + JenkinsMemoryReq string `yaml:"jenkinsMemoryReq"` + JenkinsVolumeSize string `yaml:"jenkinsVolumeSize"` + JenkinsjavaoptsXms string `yaml:"jenkinsJavaOpts_Xms"` + JenkinsjavaoptsXmx string `yaml:"jenkinsJavaOpts_Xmx"` + JenkinsjavaoptsMaxram string `yaml:"jenkinsJavaOpts_MaxRAM"` +} + +type Events struct { + Enabled bool `yaml:"enabled"` + Ruler Ruler `yaml:"ruler"` +} + +type Ruler struct { + Enabled bool `yaml:"enabled"` + Replicas int `yaml:"replicas"` +} + +type Logging struct { + Enabled bool `yaml:"enabled"` + LogsidecarReplicas int `yaml:"logsidecarReplicas"` +} + +type Metrics struct { + Enabled bool `yaml:"enabled"` +} + +type Monitoring struct { + AlertmanagerReplicas int `yaml:"alertmanagerReplicas"` + PrometheusReplicas int `yaml:"prometheusReplicas"` + PrometheusMemoryRequest string `yaml:"prometheusMemoryRequest"` + PrometheusVolumeSize string `yaml:"prometheusVolumeSize"` +} + +type Multicluster struct { + ClusterRole string `yaml:"clusterRole"` +} + +type Networkpolicy struct { + Enabled bool `yaml:"enabled"` +} + +type Notification struct { + Enabled bool `yaml:"enabled"` +} + +type Openpitrix struct { + Enabled bool `yaml:"enabled"` +} + +type Servicemesh struct { + Enabled bool `yaml:"enabled"` +} diff --git a/pkg/upgrade/config.go b/pkg/upgrade/config.go deleted file mode 100644 index 32c2311a..00000000 --- a/pkg/upgrade/config.go +++ /dev/null @@ -1,16 +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 upgrade diff --git a/pkg/cluster/kubernetes/upgrade.go b/pkg/upgrade/kubernetes.go similarity index 95% rename from pkg/cluster/kubernetes/upgrade.go rename to pkg/upgrade/kubernetes.go index 593903bd..ec0064e3 100644 --- a/pkg/cluster/kubernetes/upgrade.go +++ b/pkg/upgrade/kubernetes.go @@ -1,9 +1,10 @@ -package kubernetes +package upgrade import ( "encoding/base64" "fmt" kubekeyapi "github.com/kubesphere/kubekey/pkg/apis/kubekey/v1alpha1" + "github.com/kubesphere/kubekey/pkg/cluster/kubernetes" "github.com/kubesphere/kubekey/pkg/cluster/kubernetes/tmpl" "github.com/kubesphere/kubekey/pkg/cluster/preinstall" "github.com/kubesphere/kubekey/pkg/files" @@ -98,7 +99,7 @@ func upgradeKubeMasters(mgr *manager.Manager, node *kubekeyapi.HostCfg) error { return errors.Wrap(err, "Failed to get current kubelet version") } if strings.Split(kubeletVersion, " ")[1] != mgr.Cluster.Kubernetes.Version { - if err := SyncKubeBinaries(mgr, node); err != nil { + if err := kubernetes.SyncKubeBinaries(mgr, node); err != nil { return err } @@ -132,7 +133,7 @@ func upgradeKubeMasters(mgr *manager.Manager, node *kubekeyapi.HostCfg) error { return errors.Wrap(errors.WithStack(err2), fmt.Sprintf("Failed to upgrade master: %s", node.Name)) } - if err := SetKubelet(mgr, node); err != nil { + if err := kubernetes.SetKubelet(mgr, node); err != nil { return err } @@ -151,11 +152,11 @@ func upgradeKubeWorkers(mgr *manager.Manager, node *kubekeyapi.HostCfg) error { } if strings.Split(kubeletVersion, " ")[1] != mgr.Cluster.Kubernetes.Version { - if err := SyncKubeBinaries(mgr, node); err != nil { + if err := kubernetes.SyncKubeBinaries(mgr, node); err != nil { return err } - if err := SetKubelet(mgr, node); err != nil { + if err := kubernetes.SetKubelet(mgr, node); err != nil { return err } diff --git a/pkg/upgrade/kubesphere.go b/pkg/upgrade/kubesphere.go new file mode 100644 index 00000000..3a6d1f10 --- /dev/null +++ b/pkg/upgrade/kubesphere.go @@ -0,0 +1,289 @@ +/* +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 ( + "bufio" + "bytes" + "context" + "fmt" + "github.com/ghodss/yaml" + kubekeyapi "github.com/kubesphere/kubekey/pkg/apis/kubekey/v1alpha1" + "github.com/kubesphere/kubekey/pkg/deploy" + "github.com/kubesphere/kubekey/pkg/kubesphere" + ksv2 "github.com/kubesphere/kubekey/pkg/kubesphere/v2" + ksv3 "github.com/kubesphere/kubekey/pkg/kubesphere/v3" + "github.com/kubesphere/kubekey/pkg/util" + "github.com/kubesphere/kubekey/pkg/util/manager" + "github.com/pkg/errors" + yamlV2 "gopkg.in/yaml.v2" + kubeErr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8syaml "k8s.io/apimachinery/pkg/util/yaml" + "strings" +) + +func KsToV3(version, repo, kubeconfig string) error { + clientset, err := util.NewClient(kubeconfig) + if err != nil { + return err + } + + clusterConfigMap, err1 := clientset.CoreV1().ConfigMaps("kubesphere-system").Get(context.TODO(), "ks-installer", metav1.GetOptions{}) + if err1 != nil { + return err1 + } + + clusterCfgV2 := ksv2.V2{} + clusterCfgV3 := ksv3.V3{} + if err := yamlV2.Unmarshal([]byte(clusterConfigMap.Data["ks-config.yaml"]), &clusterCfgV2); err != nil { + return err + } + + configV3, err := MigrateConfig2to3(&clusterCfgV2, &clusterCfgV3) + if err != nil { + return err + } + + fmt.Println(configV3) + + var kubesphereConfig, installerYaml string + + switch version { + case "": + kubesphereConfig = configV3 + str, err := kubesphere.GenerateKubeSphereYaml(repo, "latest") + if err != nil { + return err + } + installerYaml = str + case "v3.0.0": + kubesphereConfig = configV3 + str, err := kubesphere.GenerateKubeSphereYaml(repo, "latest") + if err != nil { + return err + } + installerYaml = str + default: + return errors.New(fmt.Sprintf("Unsupported version: %s", strings.TrimSpace(version))) + } + + b1 := bufio.NewReader(bytes.NewReader([]byte(installerYaml))) + for { + result := make(map[string]interface{}) + content, err := k8syaml.NewYAMLReader(b1).Read() + if len(content) == 0 { + break + } + if err != nil { + return errors.Wrap(err, "Unable to read the manifests") + } + + err = yaml.Unmarshal(content, &result) + if err != nil { + return errors.Wrap(err, "Unable to unmarshal the manifests") + } + + j2, err1 := yaml.YAMLToJSON(content) + if err1 != nil { + return err + } + + switch result["kind"] { + case "CustomResourceDefinition": + if err := deploy.CreateObject(clientset, j2, deploy.CustomResourceDefinition); err != nil { + if !kubeErr.IsAlreadyExists(err) { + return err + } + } + + metadata := result["metadata"].(map[string]interface{}) + + fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) + case "Namespace": + if err := deploy.CreateObject(clientset, j2, deploy.Namespaces); err != nil { + if !kubeErr.IsAlreadyExists(err) { + return err + } + } + + metadata := result["metadata"].(map[string]interface{}) + fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) + case "ServiceAccount": + if err := deploy.CreateObject(clientset, j2, deploy.ServiceAccount); err != nil { + if !kubeErr.IsAlreadyExists(err) { + return err + } + } + + metadata := result["metadata"].(map[string]interface{}) + fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) + case "ClusterRole": + if err := deploy.CreateObject(clientset, j2, deploy.ClusterRole); err != nil { + if !kubeErr.IsAlreadyExists(err) { + return err + } + } + + metadata := result["metadata"].(map[string]interface{}) + fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) + case "ClusterRoleBinding": + if err := deploy.CreateObject(clientset, j2, deploy.ClusterRoleBinding); err != nil { + if !kubeErr.IsAlreadyExists(err) { + return err + } + } + + metadata := result["metadata"].(map[string]interface{}) + fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) + case "Deployment": + if err := deploy.CreateObject(clientset, j2, deploy.Deployment); err != nil { + if !kubeErr.IsAlreadyExists(err) { + return err + } + } + + metadata := result["metadata"].(map[string]interface{}) + fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) + } + } + + j2, err1 := yaml.YAMLToJSON([]byte(kubesphereConfig)) + if err1 != nil { + return err + } + + if err := deploy.CreateObject(clientset, j2, deploy.ClusterConfiguration); err != nil { + if !kubeErr.IsAlreadyExists(err) { + return err + } + } + result := make(map[string]interface{}) + err = yaml.Unmarshal([]byte(kubesphereConfig), &result) + if err != nil { + return errors.Wrap(err, "Unable to unmarshal the manifests") + } + metadata := result["metadata"].(map[string]interface{}) + fmt.Printf("%s/%s created\n", result["kind"], metadata["name"]) + + return nil +} + +func MigrateConfig2to3(v2 *ksv2.V2, v3 *ksv3.V3) (string, error) { + v3.Etcd = ksv3.Etcd(v2.Etcd) + v3.Persistence = ksv3.Persistence(v2.Persistence) + v3.Alerting = ksv3.Alerting(v2.Alerting) + v3.Notification = ksv3.Notification(v2.Notification) + v3.LocalRegistry = v2.LocalRegistry + v3.Servicemesh = ksv3.Servicemesh(v2.Servicemesh) + v3.Devops = ksv3.Devops(v2.Devops) + v3.Openpitrix = ksv3.Openpitrix(v2.Openpitrix) + v3.Console = ksv3.Console(v2.Console) + + if v2.MetricsServerNew.Enabled == "" { + if v2.MetricsServerOld.Enabled == "true" || v2.MetricsServerOld.Enabled == "True" { + v3.MetricsServer.Enabled = true + } else { + v3.MetricsServer.Enabled = false + } + } else { + if v2.MetricsServerNew.Enabled == "true" || v2.MetricsServerNew.Enabled == "True" { + v3.MetricsServer.Enabled = true + } else { + v3.MetricsServer.Enabled = false + } + } + + v3.Monitoring.PrometheusMemoryRequest = v2.Monitoring.PrometheusMemoryRequest + v3.Monitoring.PrometheusReplicas = v2.Monitoring.PrometheusReplicas + v3.Monitoring.PrometheusVolumeSize = v2.Monitoring.PrometheusVolumeSize + v3.Monitoring.AlertmanagerReplicas = 1 + + v3.Common.EtcdVolumeSize = v2.Common.EtcdVolumeSize + v3.Common.MinioVolumeSize = v2.Common.MinioVolumeSize + v3.Common.MysqlVolumeSize = v2.Common.MysqlVolumeSize + v3.Common.OpenldapVolumeSize = v2.Common.OpenldapVolumeSize + v3.Common.RedisVolumSize = v2.Common.RedisVolumSize + v3.Common.ES.ElasticsearchDataReplicas = v2.Logging.ElasticsearchDataReplicas + v3.Common.ES.ElasticsearchMasterReplicas = v2.Logging.ElasticsearchMasterReplicas + v3.Common.ES.ElkPrefix = v2.Logging.ElkPrefix + v3.Common.ES.LogMaxAge = v2.Logging.LogMaxAge + if v2.Logging.ElasticsearchVolumeSize == "" { + v3.Common.ES.ElasticsearchDataVolumeSize = v2.Logging.ElasticsearchDataVolumeSize + v3.Common.ES.ElasticsearchMasterVolumeSize = v2.Logging.ElasticsearchMasterVolumeSize + } else { + v3.Common.ES.ElasticsearchMasterVolumeSize = "4Gi" + v3.Common.ES.ElasticsearchDataVolumeSize = v2.Logging.ElasticsearchVolumeSize + } + + v3.Logging.Enabled = v2.Logging.Enabled + v3.Logging.LogsidecarReplicas = v2.Logging.LogsidecarReplicas + + v3.Authentication.JwtSecret = "" + v3.Multicluster.ClusterRole = "none" + v3.Events.Ruler.Replicas = 2 + + var clusterConfiguration = ksv3.ClusterConfig{ + ApiVersion: "installer.kubesphere.io/v1alpha1", + Kind: "ClusterConfiguration", + Metadata: ksv3.Metadata{ + Name: "ks-installer", + Namespace: "kubesphere-system", + Label: ksv3.Label{Version: "v3.0.0"}, + }, + Spec: v3, + } + + configV3, err := yamlV2.Marshal(clusterConfiguration) + if err != nil { + return "", err + } + + return string(configV3), nil +} + +func SyncConfiguration(mgr *manager.Manager) error { + if err := mgr.RunTaskOnMasterNodes(syncConfiguration, true); err != nil { + return err + } + return nil +} + +func syncConfiguration(mgr *manager.Manager, _ *kubekeyapi.HostCfg) error { + if mgr.Runner.Index == 0 { + configV2Str, err := mgr.Runner.ExecuteCmd("sudo -E /bin/sh -c \"/usr/local/bin/kubectl get cm -n kubesphere-system ks-installer -o jsonpath='{.data.ks-config\\.yaml}'\"", 2, false) + if err != nil { + return err + } + + clusterCfgV2 := ksv2.V2{} + clusterCfgV3 := ksv3.V3{} + if err := yamlV2.Unmarshal([]byte(configV2Str), &clusterCfgV2); err != nil { + return err + } + + configV3, err := MigrateConfig2to3(&clusterCfgV2, &clusterCfgV3) + if err != nil { + return err + } + + mgr.Cluster.KubeSphere.Configurations = "---\n" + configV3 + + } + + return nil +} diff --git a/pkg/upgrade/policy.go b/pkg/upgrade/policy.go deleted file mode 100644 index bb8f3ea9..00000000 --- a/pkg/upgrade/policy.go +++ /dev/null @@ -1,68 +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 upgrade - -import ( - "bufio" - "fmt" - kubekeyapi "github.com/kubesphere/kubekey/pkg/apis/kubekey/v1alpha1" - "github.com/kubesphere/kubekey/pkg/util/manager" - "os" - "strings" -) - -func GetClusterInfo(mgr *manager.Manager) error { - return mgr.RunTaskOnMasterNodes(getClusterInfo, true) -} - -func getClusterInfo(mgr *manager.Manager, node *kubekeyapi.HostCfg) error { - if mgr.Runner.Index == 0 { - componentstatus, err := mgr.Runner.ExecuteCmd("sudo -E /bin/bash -c \"/usr/local/bin/kubectl get componentstatus\"", 2, false) - if err != nil { - return err - } - fmt.Println("Cluster components status:") - fmt.Println(componentstatus + "\n") - nodestatus, err := mgr.Runner.ExecuteCmd("sudo -E /bin/sh -c \"/usr/local/bin/kubectl get node -o wide\"", 2, false) - if err != nil { - return err - } - fmt.Println("Cluster nodes status:") - fmt.Println(nodestatus + "\n\n") - - reader := bufio.NewReader(os.Stdin) - Loop: - for { - fmt.Printf("Continue upgrading cluster? [yes/no]: ") - input, err := reader.ReadString('\n') - if err != nil { - mgr.Logger.Fatal(err) - } - input = strings.TrimSpace(input) - - switch input { - case "yes": - break Loop - case "no": - os.Exit(0) - default: - continue - } - } - } - return nil -} diff --git a/pkg/upgrade/precheck.go b/pkg/upgrade/precheck.go new file mode 100644 index 00000000..6a380335 --- /dev/null +++ b/pkg/upgrade/precheck.go @@ -0,0 +1,149 @@ +/* +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 ( + "bufio" + "fmt" + kubekeyapi "github.com/kubesphere/kubekey/pkg/apis/kubekey/v1alpha1" + "github.com/kubesphere/kubekey/pkg/util/manager" + "github.com/pkg/errors" + versionutil "k8s.io/apimachinery/pkg/util/version" + "os" + "strings" +) + +var versionCheck = map[string]map[string]map[string]bool{ + "v3.0.0": { + "k8s": { + "v1.18": true, + "v1.17": true, + "v1.16": true, + "v1.15": true, + }, + "ks": { + "v2.1.0": true, + "v2.1.1": true, + }, + }, + "v2.1.1": { + "k8s": { + "v1.18": true, + "v1.17": true, + "v1.16": true, + "v1.15": true, + }, + }, +} + +func GetClusterInfo(mgr *manager.Manager) error { + return mgr.RunTaskOnMasterNodes(getClusterInfo, true) +} + +func getClusterInfo(mgr *manager.Manager, _ *kubekeyapi.HostCfg) error { + if mgr.Runner.Index == 0 { + + k8sVersionStr, err := mgr.Runner.ExecuteCmd("sudo -E /bin/sh -c \"cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep 'image:' | cut -d ':' -f 3\"", 3, false) + if err != nil { + return errors.Wrap(err, "Failed to get current kube-apiserver version") + } + + ksVersion, err := mgr.Runner.ExecuteCmd("sudo -E /bin/sh -c \"/usr/local/bin/kubectl get deploy -n kubesphere-system ks-console -o jsonpath='{.metadata.labels.version}'\"", 2, false) + if err != nil { + if mgr.Cluster.KubeSphere.Enabled { + return err + } + } else { + if mgr.Cluster.KubeSphere.Enabled { + if _, ok := versionCheck[mgr.Cluster.KubeSphere.Version]; !ok { + return errors.New(fmt.Sprintf("Unsupported version: %s", mgr.Cluster.KubeSphere.Version)) + } + if _, ok := versionCheck[mgr.Cluster.KubeSphere.Version]["ks"][ksVersion]; !ok { + return errors.New(fmt.Sprintf("Unsupported upgrade plan: %s to %s", strings.TrimSpace(ksVersion), mgr.Cluster.KubeSphere.Version)) + } + K8sTargetVersion := versionutil.MustParseSemantic(mgr.Cluster.Kubernetes.Version) + if _, ok := versionCheck[mgr.Cluster.KubeSphere.Version]["k8s"][fmt.Sprintf("v%v.%v", K8sTargetVersion.Major(), K8sTargetVersion.Minor())]; !ok { + return errors.New(fmt.Sprintf("KubeSphere %s does not support running on Kubernetes %s", mgr.Cluster.KubeSphere.Version, fmt.Sprintf("v%v.%v", K8sTargetVersion.Major(), K8sTargetVersion.Minor()))) + } + } else { + if _, ok := versionCheck[ksVersion]; !ok { + return errors.New(fmt.Sprintf("Unsupported version: %s", ksVersion)) + } + K8sTargetVersion := versionutil.MustParseSemantic(mgr.Cluster.Kubernetes.Version) + if _, ok := versionCheck[ksVersion]["k8s"][fmt.Sprintf("v%v.%v", K8sTargetVersion.Major(), K8sTargetVersion.Minor())]; !ok { + return errors.New(fmt.Sprintf("KubeSphere %s does not support running on Kubernetes %s", ksVersion, fmt.Sprintf("v%v.%v", K8sTargetVersion.Major(), K8sTargetVersion.Minor()))) + } + } + } + + if err := getNodestatus(mgr); err != nil { + return err + } + if err := getComponentStatus(mgr); err != nil { + return err + } + + fmt.Println("Upgrade Confirmation:") + fmt.Printf("kubernetes version: %s to %s\n", k8sVersionStr, mgr.Cluster.Kubernetes.Version) + if mgr.Cluster.KubeSphere.Enabled { + fmt.Printf("kubesphere version: %s to %s\n\n", ksVersion, mgr.Cluster.KubeSphere.Version) + } else { + fmt.Println() + } + + reader := bufio.NewReader(os.Stdin) + Loop: + for { + fmt.Printf("Continue upgrading cluster? [yes/no]: ") + input, err := reader.ReadString('\n') + if err != nil { + mgr.Logger.Fatal(err) + } + input = strings.TrimSpace(input) + + switch input { + case "yes": + break Loop + case "no": + os.Exit(0) + default: + continue + } + } + } + return nil +} + +func getComponentStatus(mgr *manager.Manager) error { + componentStatusStr, err := mgr.Runner.ExecuteCmd("sudo -E /bin/bash -c \"/usr/local/bin/kubectl get componentstatus -o go-template='{{range .items}}{{ printf \\\"%s: \\\" .metadata.name}}{{range .conditions}}{{ printf \\\"%v\\n\\\" .message }}{{end}}{{end}}'\"", 1, false) + if err != nil { + return err + } + fmt.Println("Components Status:") + fmt.Println(componentStatusStr + "\n") + return nil +} + +func getNodestatus(mgr *manager.Manager) error { + nodestatus, err := mgr.Runner.ExecuteCmd("sudo -E /bin/sh -c \"/usr/local/bin/kubectl get node\"", 2, false) + if err != nil { + return err + } + fmt.Println("Cluster nodes status:") + fmt.Println(nodestatus + "\n") + return nil +} diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index fab83912..ea3c0317 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -18,7 +18,6 @@ package upgrade import ( "fmt" - "github.com/kubesphere/kubekey/pkg/cluster/kubernetes" "github.com/kubesphere/kubekey/pkg/config" "github.com/kubesphere/kubekey/pkg/kubesphere" "github.com/kubesphere/kubekey/pkg/util" @@ -52,8 +51,9 @@ func ExecTasks(mgr *manager.Manager) error { {Task: GetClusterInfo, ErrMsg: "Failed to get cluster info"}, //{Task: preinstall.InitOS, ErrMsg: "Failed to download kube binaries"}, //{Task: preinstall.PrePullImages, ErrMsg: "Failed to pre-pull images"}, - {Task: kubernetes.GetCurrentVersions, ErrMsg: "Failed to get current version"}, - {Task: kubernetes.UpgradeKubeCluster, ErrMsg: "Failed to upgrade kube cluster"}, + {Task: GetCurrentVersions, ErrMsg: "Failed to get current version"}, + {Task: UpgradeKubeCluster, ErrMsg: "Failed to upgrade kube cluster"}, + {Task: SyncConfiguration, ErrMsg: "Failed to sync configuration"}, {Task: kubesphere.DeployKubeSphere, ErrMsg: "Failed to upgrade kubesphere"}, } diff --git a/pkg/deploy/client.go b/pkg/util/client.go similarity index 94% rename from pkg/deploy/client.go rename to pkg/util/client.go index 0b68abfd..485f8307 100644 --- a/pkg/deploy/client.go +++ b/pkg/util/client.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package deploy +package util import ( "github.com/pkg/errors" @@ -24,7 +24,7 @@ import ( "path/filepath" ) -func newClient(config string) (*kubernetes.Clientset, error) { +func NewClient(config string) (*kubernetes.Clientset, error) { var kubeconfig string if config != "" { config, err := filepath.Abs(config)