diff --git a/cmd/climc/shell/k8s/charts.go b/cmd/climc/shell/k8s/charts.go index 1eaf2c7b04..487cbbbd73 100644 --- a/cmd/climc/shell/k8s/charts.go +++ b/cmd/climc/shell/k8s/charts.go @@ -1,10 +1,9 @@ package k8s import ( - json "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initChart() { @@ -12,32 +11,8 @@ func initChart() { return resourceCmdN("chart", suffix) } - type listOpt struct { - baseListOptions - Name string `help:"Chart name"` - Repo string `help:"Repository name"` - RepoUrl string `help:"Repository url"` - AllVersion bool `json:"Get Chart all history versions"` - Keyword string `json:"Chart keyword"` - } - R(&listOpt{}, cmdN("list"), "List k8s helm global charts", func(s *mcclient.ClientSession, args *listOpt) error { - params := fetchPagingParams(args.baseListOptions) - if len(args.Name) != 0 { - params.Add(json.NewString(args.Name), "name") - } - if len(args.Repo) != 0 { - params.Add(json.NewString(args.Repo), "repo") - } - if len(args.RepoUrl) != 0 { - params.Add(json.NewString(args.RepoUrl), "repo_url") - } - if args.AllVersion { - params.Add(json.JSONTrue, "all_version") - } - if len(args.Keyword) != 0 { - params.Add(json.NewString(args.Keyword), "keyword") - } - charts, err := k8s.Charts.List(s, params) + R(&o.ChartListOptions{}, cmdN("list"), "List k8s helm global charts", func(s *mcclient.ClientSession, args *o.ChartListOptions) error { + charts, err := k8s.Charts.List(s, args.Params()) if err != nil { return err } @@ -46,18 +21,8 @@ func initChart() { return nil }) - type getOpt struct { - REPO string `help:"Repo of the chart"` - NAME string `help:"Chart name"` - Version string `help:"Chart version"` - } - R(&getOpt{}, cmdN("show"), "Show details of a chart", func(s *mcclient.ClientSession, args *getOpt) error { - params := json.NewDict() - params.Add(json.NewString(args.REPO), "repo") - if args.Version != "" { - params.Add(json.NewString(args.Version), "version") - } - chart, err := k8s.Charts.Get(s, args.NAME, params) + R(&o.ChartGetOptions{}, cmdN("show"), "Show details of a chart", func(s *mcclient.ClientSession, args *o.ChartGetOptions) error { + chart, err := k8s.Charts.Get(s, args.NAME, args.Params()) if err != nil { return err } diff --git a/cmd/climc/shell/k8s/clusters.go b/cmd/climc/shell/k8s/clusters.go index aa95a2d594..05a09d7fef 100644 --- a/cmd/climc/shell/k8s/clusters.go +++ b/cmd/climc/shell/k8s/clusters.go @@ -2,35 +2,19 @@ package k8s import ( "fmt" - "io/ioutil" - "strings" - "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" - "yunion.io/x/onecloud/pkg/mcclient/options" - "yunion.io/x/pkg/util/sets" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initCluster() { cmdN := func(suffix string) string { return kubeResourceCmdN("cluster", suffix) } - type listOpt struct { - options.BaseListOptions - } - R(&listOpt{}, cmdN("list"), "List k8s infra clusters", func(s *mcclient.ClientSession, args *listOpt) error { - args.Details = options.Bool(true) - var params *jsonutils.JSONDict - { - var err error - params, err = args.BaseListOptions.Params() - if err != nil { - return err - } - } - result, err := k8s.Clusters.List(s, params) + R(&o.ClusterListOptions{}, cmdN("list"), "List k8s infra clusters", func(s *mcclient.ClientSession, args *o.ClusterListOptions) error { + result, err := k8s.Clusters.List(s, args.Params()) if err != nil { return err } @@ -38,33 +22,8 @@ func initCluster() { return nil }) - type createOpt struct { - NAME string `help:"Name of cluster"` - Mode string `help:"Cluster mode" choices:"internal"` - K8sVersion string `help:"Cluster kubernetes components version" choices:"v1.8.10|v1.9.5|v1.10.0"` - InfraImage string `help:"Cluster kubelet infra container image"` - Cidr string `help:"Cluster service CIDR, e.g. 10.43.0.0/16"` - Domain string `help:"Cluster pod domain, e.g. cluster.local"` - } - R(&createOpt{}, cmdN("create"), "Create k8s cluster", func(s *mcclient.ClientSession, args *createOpt) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.NAME), "name") - if args.Mode != "" { - params.Add(jsonutils.NewString(args.Mode), "mode") - } - if args.K8sVersion != "" { - params.Add(jsonutils.NewString(args.K8sVersion), "k8s_version") - } - if args.InfraImage != "" { - params.Add(jsonutils.NewString(args.InfraImage), "infra_container_image") - } - if args.Cidr != "" { - params.Add(jsonutils.NewString(args.Cidr), "cluster_cidr") - } - if args.Domain != "" { - params.Add(jsonutils.NewString(args.Domain), "cluster_domain") - } - cluster, err := k8s.Clusters.Create(s, params) + R(&o.ClusterCreateOptions{}, cmdN("create"), "Create k8s cluster", func(s *mcclient.ClientSession, args *o.ClusterCreateOptions) error { + cluster, err := k8s.Clusters.Create(s, args.Params()) if err != nil { return err } @@ -72,21 +31,12 @@ func initCluster() { return nil }) - type importOpt struct { - NAME string `help:"Name of cluster to import"` - Kubeconfig string `help:"Kubernetes auth config"` - } - R(&importOpt{}, cmdN("import"), "Import exists YKE deployed kubernetes cluster", func(s *mcclient.ClientSession, args *importOpt) error { - if args.Kubeconfig == "" { - return fmt.Errorf("Kubeconfig file must provide") - } - kubeconfig, err := ioutil.ReadFile(args.Kubeconfig) + R(&o.ClusterImportOptions{}, cmdN("import"), "Import exists YKE deployed kubernetes cluster", func(s *mcclient.ClientSession, args *o.ClusterImportOptions) error { + params, err := args.Params() if err != nil { - return fmt.Errorf("Read kube config %q error: %v", args.Kubeconfig, err) + return err } - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(string(kubeconfig)), "kube_config") cluster, err := k8s.Clusters.PerformAction(s, args.NAME, "import", params) if err != nil { return err @@ -95,16 +45,8 @@ func initCluster() { return nil }) - type updateOpt struct { - NAME string `help:"Name of cluster"` - K8sVersion string `help:"Cluster kubernetes components version" choices:"v1.8.10|v1.9.5|v1.10.0" default:"v1.9.5"` - } - R(&updateOpt{}, cmdN("update"), "Update k8s cluster", func(s *mcclient.ClientSession, args *updateOpt) error { - params := jsonutils.NewDict() - if args.K8sVersion != "" { - params.Add(jsonutils.NewString(args.K8sVersion), "k8s_version") - } - cluster, err := k8s.Clusters.Update(s, args.NAME, params) + R(&o.ClusterUpdateOptions{}, cmdN("update"), "Update k8s cluster", func(s *mcclient.ClientSession, args *o.ClusterUpdateOptions) error { + cluster, err := k8s.Clusters.Update(s, args.NAME, args.Params()) if err != nil { return err } @@ -112,19 +54,8 @@ func initCluster() { return nil }) - type identOpt struct { - ID string `help:"ID or name of the cluster"` - } - type deployOpt struct { - identOpt - Force bool `help:"Force deploy"` - } - R(&deployOpt{}, cmdN("deploy"), "Start deploy a cluster", func(s *mcclient.ClientSession, args *deployOpt) error { - params := jsonutils.NewDict() - if args.Force { - params.Add(jsonutils.JSONTrue, "force") - } - ret, err := k8s.Clusters.PerformAction(s, args.ID, "deploy", params) + R(&o.ClusterDeployOptions{}, cmdN("deploy"), "Start deploy a cluster", func(s *mcclient.ClientSession, args *o.ClusterDeployOptions) error { + ret, err := k8s.Clusters.PerformAction(s, args.ID, "deploy", args.Params()) if err != nil { return err } @@ -132,14 +63,7 @@ func initCluster() { return nil }) - type identsOpt struct { - ID []string `help:"ID of clusters to operate"` - } - - type getOpt struct { - identOpt - } - R(&getOpt{}, cmdN("show"), "Show details of a cluster", func(s *mcclient.ClientSession, args *getOpt) error { + R(&o.IdentOptions{}, cmdN("show"), "Show details of a cluster", func(s *mcclient.ClientSession, args *o.IdentOptions) error { result, err := k8s.Clusters.Get(s, args.ID, nil) if err != nil { return err @@ -148,25 +72,14 @@ func initCluster() { return nil }) - type deleteOpt struct { - identsOpt - } - R(&deleteOpt{}, cmdN("delete"), "Delete cluster", func(s *mcclient.ClientSession, args *deleteOpt) error { + R(&o.ClusterDeleteOptions{}, cmdN("delete"), "Delete cluster", func(s *mcclient.ClientSession, args *o.ClusterDeleteOptions) error { ret := k8s.Clusters.BatchDeleteWithParam(s, args.ID, nil, nil) printBatchResults(ret, k8s.Clusters.GetColumns(s)) return nil }) - type kubeConfigOpt struct { - getOpt - Directly bool `help:"Get directly connect kubeconfig"` - } - R(&kubeConfigOpt{}, cmdN("kubeconfig"), "Generate kubeconfig of a cluster", func(s *mcclient.ClientSession, args *kubeConfigOpt) error { - params := jsonutils.NewDict() - if args.Directly { - params.Add(jsonutils.JSONTrue, "directly") - } - ret, err := k8s.Clusters.PerformAction(s, args.ID, "generate-kubeconfig", params) + R(&o.ClusterKubeconfigOptions{}, cmdN("kubeconfig"), "Generate kubeconfig of a cluster", func(s *mcclient.ClientSession, args *o.ClusterKubeconfigOptions) error { + ret, err := k8s.Clusters.PerformAction(s, args.ID, "generate-kubeconfig", args.Params()) if err != nil { return err } @@ -178,7 +91,7 @@ func initCluster() { return nil }) - R(&getOpt{}, cmdN("engineconfig"), "Get kubernetes engine config of a cluster", func(s *mcclient.ClientSession, args *getOpt) error { + R(&o.IdentOptions{}, cmdN("engineconfig"), "Get kubernetes engine config of a cluster", func(s *mcclient.ClientSession, args *o.IdentOptions) error { ret, err := k8s.Clusters.GetSpecific(s, args.ID, "engine-config", nil) if err != nil { return err @@ -191,7 +104,7 @@ func initCluster() { return nil }) - R(&getOpt{}, cmdN("webhookauthurl"), "Get cluster kubernetes api server webhook auth url", func(s *mcclient.ClientSession, args *getOpt) error { + R(&o.IdentOptions{}, cmdN("webhookauthurl"), "Get cluster kubernetes api server webhook auth url", func(s *mcclient.ClientSession, args *o.IdentOptions) error { ret, err := k8s.Clusters.GetSpecific(s, args.ID, "webhook-auth-url", nil) if err != nil { return err @@ -204,25 +117,11 @@ func initCluster() { return nil }) - type addNodesOpt struct { - identOpt - NodeConfig []string `help:"Node spec, 'host:[roles]' e.g: --node-config host01:controlplane,etcd,worker --node-config host02:worker"` - AutoDeploy bool `help:"Auto deploy"` - } - R(&addNodesOpt{}, cmdN("addnodes"), "Add nodes to cluster", func(s *mcclient.ClientSession, args *addNodesOpt) error { - params := jsonutils.NewDict() - if args.AutoDeploy { - params.Add(jsonutils.JSONTrue, "auto_deploy") + R(&o.ClusterAddNodesOptions{}, cmdN("addnodes"), "Add nodes to cluster", func(s *mcclient.ClientSession, args *o.ClusterAddNodesOptions) error { + params, err := args.Params() + if err != nil { + return err } - nodesArray := jsonutils.NewArray() - for _, config := range args.NodeConfig { - opt, err := parseNodeAddConfigStr(config) - if err != nil { - return err - } - nodesArray.Add(jsonutils.Marshal(opt)) - } - params.Add(nodesArray, "nodes") ret, err := k8s.Clusters.PerformAction(s, args.ID, "add-nodes", params) if err != nil { return err @@ -231,36 +130,3 @@ func initCluster() { return nil }) } - -type dockerConfig struct { - RegistryMirrors []string `json:"registry-mirrors"` - InsecureRegistries []string `json:"insecure-registries"` -} - -type nodeAddConfig struct { - Host string `json:"host"` - Roles []string `json:"roles"` - Name string `json:"name"` - HostnameOverride string `json:"hostname_override"` - DockerdConfig dockerConfig `json:"dockerd_config"` -} - -func parseNodeAddConfigStr(config string) (nodeAddConfig, error) { - ret := nodeAddConfig{} - parts := strings.Split(config, ":") - if len(parts) != 2 { - return ret, fmt.Errorf("Invalid config: %q", config) - } - host := parts[0] - roleStr := parts[1] - ret.Host = host - roles := []string{} - for _, role := range strings.Split(roleStr, ",") { - if !sets.NewString("etcd", "controlplane", "worker").Has(role) { - return ret, fmt.Errorf("Invalid role: %q", role) - } - roles = append(roles, role) - } - ret.Roles = roles - return ret, nil -} diff --git a/cmd/climc/shell/k8s/configmap.go b/cmd/climc/shell/k8s/configmap.go index 6162aa1dc4..a4931fd9b5 100644 --- a/cmd/climc/shell/k8s/configmap.go +++ b/cmd/climc/shell/k8s/configmap.go @@ -1,28 +1,9 @@ package k8s import ( - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) func initConfigMap() { - cmdN := func(suffix string) string { - return resourceCmdN("configmap", suffix) - } - - type listOpt struct { - namespaceListOptions - baseListOptions - } - R(&listOpt{}, cmdN("list"), "List k8s configmap", func(s *mcclient.ClientSession, args *listOpt) error { - params := fetchNamespaceParams(args.namespaceListOptions) - params.Update(fetchPagingParams(args.baseListOptions)) - params.Update(args.ClusterParams()) - ret, err := k8s.ConfigMaps.List(s, params) - if err != nil { - return err - } - printList(ret, k8s.ConfigMaps.GetColumns(s)) - return nil - }) + initK8sNamespaceResource("configmap", k8s.ConfigMaps) } diff --git a/cmd/climc/shell/k8s/cronjob.go b/cmd/climc/shell/k8s/cronjob.go new file mode 100644 index 0000000000..44c912aeb8 --- /dev/null +++ b/cmd/climc/shell/k8s/cronjob.go @@ -0,0 +1,9 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initCronJob() { + initK8sNamespaceResource("cronjob", k8s.CronJobs) +} diff --git a/cmd/climc/shell/k8s/deployment.go b/cmd/climc/shell/k8s/deployment.go index 21e8338e7d..bd1934cedd 100644 --- a/cmd/climc/shell/k8s/deployment.go +++ b/cmd/climc/shell/k8s/deployment.go @@ -1,199 +1,48 @@ package k8s import ( - "fmt" - "io/ioutil" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/regutils" - "yunion.io/x/pkg/util/sets" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initDeployment() { - cmdN := func(suffix string) string { - return resourceCmdN("deployment", suffix) - } + cmd := initK8sNamespaceResource("deployment", k8s.Deployments) + cmdN := cmd.CommandNameFactory - R(&NamespaceResourceListOptions{}, cmdN("list"), "List k8s deployment", func(s *mcclient.ClientSession, args *NamespaceResourceListOptions) error { - ret, err := k8s.Deployments.List(s, args.Params()) - if err != nil { - return err - } - PrintListResultTable(ret, k8s.Deployments, s) - return nil - }) - - type createOpt struct { - namespaceOptions - NAME string `help:"Name of deployment"` - Image string `help:"The image for the container to run"` - Replicas int64 `help:"Number of replicas for pods in this deployment"` - RunAsPrivileged bool `help:"Whether to run the container as privileged user"` - Labels string `help:"Comma separated labels to apply to the pod(s)"` - Env []string `help:"Environment variables to set in container"` - Port []string `help:"Port for the service that is created, format is :: e.g. tcp:80:3000"` - Net string `help:"Network config, e.g. net1, net1:10.168.222.171"` - } - R(&createOpt{}, cmdN("create"), "Create deployment resource", func(s *mcclient.ClientSession, args *createOpt) error { - params := args.ClusterParams() - if len(args.Image) == 0 { - return fmt.Errorf("Image must provided") - } - params.Add(jsonutils.NewString(args.NAME), "name") - params.Add(jsonutils.NewString(args.Image), "containerImage") - if args.Namespace != "" { - params.Add(jsonutils.NewString(args.Namespace), "namespace") - } - if args.Replicas > 1 { - params.Add(jsonutils.NewInt(args.Replicas), "replicas") - } - if args.RunAsPrivileged { - params.Add(jsonutils.JSONTrue, "runAsPrivileged") - } - if len(args.Port) != 0 { - portMappings, err := parsePortMappings(args.Port) + createCmd := NewCommand( + &o.DeploymentCreateOptions{}, + cmdN("create"), + "Create deployment resource", + func(s *mcclient.ClientSession, args *o.DeploymentCreateOptions) error { + params, err := args.Params() if err != nil { return err } - params.Add(portMappings, "portMappings") - } - - envList := jsonutils.NewArray() - for _, env := range args.Env { - parts := strings.Split(env, "=") - if len(parts) != 2 { - return fmt.Errorf("Bad env value: %v", env) - } - envObj := jsonutils.NewDict() - envObj.Add(jsonutils.NewString(parts[0]), "name") - envObj.Add(jsonutils.NewString(parts[1]), "value") - envList.Add(envObj) - } - params.Add(envList, "variables") - if args.Net != "" { - net, err := parseNetConfig(args.Net) + ret, err := k8s.Deployments.Create(s, params) if err != nil { return err } - params.Add(net, "networkConfig") - } - ret, err := k8s.Deployments.Create(s, params) - if err != nil { - return err - } - printObject(ret) - return nil - }) + printObject(ret) + return nil + }) - type getOpt struct { - resourceGetOptions - } - R(&getOpt{}, cmdN("show"), "Get deployment details", func(s *mcclient.ClientSession, args *getOpt) error { - id := args.NAME - params := args.ClusterParams() - if args.Namespace != "" { - params.Add(jsonutils.NewString(args.Namespace), "namespace") - } - ret, err := k8s.Deployments.Get(s, id, params) - if err != nil { - return err - } - printObjectYAML(ret) - return nil - }) - - type createFromFileOpt struct { - resourceGetOptions - FILE string `help:"K8s resource YAML or JSON file"` - } - R(&createFromFileOpt{}, "k8s-create", "Create resource by file", func(s *mcclient.ClientSession, args *createFromFileOpt) error { - params := args.ClusterParams() - params.Add(jsonutils.NewString(args.NAME), "name") - - content, err := ioutil.ReadFile(args.FILE) - if err != nil { - return err - } - namespace := args.Namespace - if namespace != "" { - params.Add(jsonutils.NewString(namespace), "namespace") - } - params.Add(jsonutils.NewString(string(content)), "content") - ret, err := k8s.DeployFromFile.Create(s, params) - if err != nil { - return err - } - printObjectYAML(ret) - return nil - }) -} - -type portMapping struct { - Port int32 `json:"port"` - TargetPort int32 `json:"targetPort"` - Protocol string `json:"protocol"` -} - -func parsePortMapping(port string) (*portMapping, error) { - if len(port) == 0 { - return nil, fmt.Errorf("empty port mapping desc string") - } - parts := strings.Split(port, ":") - mapping := &portMapping{} - for _, part := range parts { - if sets.NewString("tcp", "udp").Has(strings.ToLower(part)) { - mapping.Protocol = strings.ToUpper(part) - } - if port, err := strconv.Atoi(part); err != nil { - continue - } else { - if mapping.Port == 0 { - mapping.Port = int32(port) - } else { - mapping.TargetPort = int32(port) + createFromFileCmd := NewCommand( + &o.DeploymentCreateFromFileOptions{}, + "k8s-create", + "Create resource by file", + func(s *mcclient.ClientSession, args *o.DeploymentCreateFromFileOptions) error { + params, err := args.Params() + if err != nil { + return err } - } - } - if mapping.Protocol == "" { - mapping.Protocol = "TCP" - } - if mapping.Port <= 0 { - return nil, fmt.Errorf("Service port not provided") - } - if mapping.TargetPort < 0 { - return nil, fmt.Errorf("Container invalid targetPort %d", mapping.TargetPort) - } - if mapping.TargetPort == 0 { - mapping.TargetPort = mapping.Port - } - return mapping, nil -} + ret, err := k8s.DeployFromFile.Create(s, params) + if err != nil { + return err + } + printObjectYAML(ret) + return nil + }) -func parsePortMappings(ports []string) (*jsonutils.JSONArray, error) { - ret := jsonutils.NewArray() - for _, port := range ports { - mapping, err := parsePortMapping(port) - if err != nil { - return nil, fmt.Errorf("Port %q error: %v", port, err) - } - ret.Add(jsonutils.Marshal(mapping)) - } - return ret, nil -} - -func parseNetConfig(net string) (*jsonutils.JSONDict, error) { - ret := jsonutils.NewDict() - for _, p := range strings.Split(net, ":") { - if regutils.MatchIP4Addr(p) { - ret.Add(jsonutils.NewString(p), "address") - } else { - ret.Add(jsonutils.NewString(p), "network") - } - } - return ret, nil + cmd.AddR(createCmd, createFromFileCmd) } diff --git a/cmd/climc/shell/k8s/ingress.go b/cmd/climc/shell/k8s/ingress.go index b93ab1464c..4ef4ce26a4 100644 --- a/cmd/climc/shell/k8s/ingress.go +++ b/cmd/climc/shell/k8s/ingress.go @@ -1,40 +1,9 @@ package k8s import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) func initIngress() { - cmdN := func(suffix string) string { - return resourceCmdN("statefulset", suffix) - } - - R(&NamespaceResourceListOptions{}, cmdN("list"), "List k8s ingress", func(s *mcclient.ClientSession, args *NamespaceResourceListOptions) error { - ret, err := k8s.Ingresses.List(s, args.Params()) - if err != nil { - return err - } - PrintListResultTable(ret, k8s.Ingresses, s) - return nil - }) - - type getOpt struct { - resourceGetOptions - } - R(&getOpt{}, cmdN("show"), "Get ingress details", func(s *mcclient.ClientSession, args *getOpt) error { - id := args.NAME - params := args.ClusterParams() - if args.Namespace != "" { - params.Add(jsonutils.NewString(args.Namespace), "namespace") - } - ret, err := k8s.Ingresses.Get(s, id, params) - if err != nil { - return err - } - printObjectYAML(ret) - return nil - }) + initK8sNamespaceResource("ingress", k8s.Ingresses) } diff --git a/cmd/climc/shell/k8s/job.go b/cmd/climc/shell/k8s/job.go new file mode 100644 index 0000000000..f468ea0871 --- /dev/null +++ b/cmd/climc/shell/k8s/job.go @@ -0,0 +1,9 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initJob() { + initK8sNamespaceResource("job", k8s.Jobs) +} diff --git a/cmd/climc/shell/k8s/k8s.go b/cmd/climc/shell/k8s/k8s.go index dfa86745fc..963d72f668 100644 --- a/cmd/climc/shell/k8s/k8s.go +++ b/cmd/climc/shell/k8s/k8s.go @@ -5,8 +5,10 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/cmd/climc/shell" + "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" "yunion.io/x/onecloud/pkg/util/printutils" ) @@ -31,80 +33,12 @@ func init() { initIngress() initNamespace() initK8sNode() -} - -type clusterBaseOptions struct { - Cluster string `default:"$K8S_CLUSTER|default" help:"Kubernetes cluster name"` -} - -func (o clusterBaseOptions) ClusterParams() *jsonutils.JSONDict { - ret := jsonutils.NewDict() - ret.Add(jsonutils.NewString(o.Cluster), "cluster") - return ret -} - -type baseListOptions struct { - Limit int `default:"20" help:"Page limit"` - Offset int `default:"0" help:"page offset"` -} - -type NamespaceResourceListOptions struct { - namespaceListOptions - baseListOptions -} - -func (o NamespaceResourceListOptions) Params() *jsonutils.JSONDict { - params := fetchNamespaceParams(o.namespaceListOptions) - params.Update(fetchPagingParams(o.baseListOptions)) - params.Update(o.ClusterParams()) - return params -} - -func fetchPagingParams(opt baseListOptions) *jsonutils.JSONDict { - params := jsonutils.NewDict() - if opt.Limit > 0 { - params.Add(jsonutils.NewInt(int64(opt.Limit)), "limit") - } - if opt.Offset > 0 { - params.Add(jsonutils.NewInt(int64(opt.Offset)), "offset") - } - return params -} - -type namespaceListOptions struct { - namespaceOptions - AllNamespace bool `help:"Show resource in all namespace"` -} - -type namespaceOptions struct { - clusterBaseOptions - Namespace string `help:"Namespace of this resource"` -} - -type resourceGetOptions struct { - clusterBaseOptions - Namespace string `help:"Namespace of this resource"` - NAME string `help:"Name ident of the resource"` -} - -func (o resourceGetOptions) ToJSON() *jsonutils.JSONDict { - params := o.ClusterParams() - if o.Namespace != "" { - params.Add(jsonutils.NewString(o.Namespace), "namespace") - } - return params -} - -func fetchNamespaceParams(opt namespaceListOptions) *jsonutils.JSONDict { - params := jsonutils.NewDict() - if opt.AllNamespace { - params.Add(jsonutils.JSONTrue, "all_namespace") - return params - } - if opt.Namespace != "" { - params.Add(jsonutils.NewString(opt.Namespace), "namespace") - } - return params + initSecret() + initStorageClass() + initPV() + initPVC() + initJob() + initCronJob() } var ( @@ -132,3 +66,118 @@ func clusterContext(clusterId string) modules.ManagerContext { func printObjectYAML(obj jsonutils.JSONObject) { fmt.Println(obj.YAMLString()) } + +type Cmd struct { + Options interface{} + Command string + Desc string + Callback interface{} +} + +func NewCommand(options interface{}, command string, desc string, callback interface{}) *Cmd { + return &Cmd{ + Options: options, + Command: command, + Desc: desc, + Callback: callback, + } +} + +func (c Cmd) R() { + R(c.Options, c.Command, c.Desc, c.Callback) +} + +type ShellCommands struct { + Commands []*Cmd + CommandNameFactory func(suffix string) string +} + +func NewShellCommands(cmdN func(suffix string) string) *ShellCommands { + c := &ShellCommands{ + CommandNameFactory: cmdN, + } + c.Commands = make([]*Cmd, 0) + return c +} + +func (c *ShellCommands) AddR(rs ...*Cmd) *ShellCommands { + for _, r := range rs { + r.R() + c.Commands = append(c.Commands, r) + } + return c +} + +func initK8sClusterResource(kind string, manager modules.Manager) *ShellCommands { + cmdN := func(suffix string) string { + return resourceCmdN(kind, suffix) + } + + // List resource + listCmd := NewCommand( + &o.ResourceListOptions{}, + cmdN("list"), + fmt.Sprintf("List k8s %s", kind), + func(s *mcclient.ClientSession, args *o.ResourceListOptions) error { + ret, err := manager.List(s, args.Params()) + if err != nil { + return err + } + PrintListResultTable(ret, manager.(k8s.ListPrinter), s) + return nil + }, + ) + + // Get resource details + getCmd := NewCommand( + &o.ResourceGetOptions{}, + cmdN("show"), + fmt.Sprintf("Show k8s %s", kind), + func(s *mcclient.ClientSession, args *o.ResourceGetOptions) error { + ret, err := manager.Get(s, args.NAME, args.Params()) + if err != nil { + return err + } + printObjectYAML(ret) + return nil + }, + ) + return NewShellCommands(cmdN).AddR(listCmd, getCmd) +} + +func initK8sNamespaceResource(kind string, manager modules.Manager) *ShellCommands { + cmdN := func(suffix string) string { + return resourceCmdN(kind, suffix) + } + + // List resource + listCmd := NewCommand( + &o.NamespaceResourceListOptions{}, + cmdN("list"), + fmt.Sprintf("List k8s %s", kind), + func(s *mcclient.ClientSession, args *o.NamespaceResourceListOptions) error { + ret, err := manager.List(s, args.Params()) + if err != nil { + return err + } + PrintListResultTable(ret, manager.(k8s.ListPrinter), s) + return nil + }, + ) + + // Get resource details + getCmd := NewCommand( + &o.NamespaceResourceGetOptions{}, + cmdN("show"), + fmt.Sprintf("Show k8s %s", kind), + func(s *mcclient.ClientSession, args *o.NamespaceResourceGetOptions) error { + ret, err := manager.Get(s, args.NAME, args.Params()) + if err != nil { + return err + } + printObjectYAML(ret) + return nil + }, + ) + return NewShellCommands(cmdN).AddR(listCmd, getCmd) +} diff --git a/cmd/climc/shell/k8s/k8s_node.go b/cmd/climc/shell/k8s/k8s_node.go index 03750bd464..eb0206df03 100644 --- a/cmd/climc/shell/k8s/k8s_node.go +++ b/cmd/climc/shell/k8s/k8s_node.go @@ -1,41 +1,9 @@ package k8s import ( - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) func initK8sNode() { - cmdN := func(suffix string) string { - return resourceCmdN("node", suffix) - } - - type listOpt struct { - clusterBaseOptions - baseListOptions - } - R(&listOpt{}, cmdN("list"), "List k8s nodes resource", func(s *mcclient.ClientSession, args *listOpt) error { - params := fetchPagingParams(args.baseListOptions) - params.Update(args.ClusterParams()) - ret, err := k8s.K8sNodes.List(s, params) - if err != nil { - return err - } - PrintListResultTable(ret, k8s.K8sNodes, s) - return nil - }) - - type getOpt struct { - clusterBaseOptions - NAME string `help:"Node name"` - } - R(&getOpt{}, cmdN("show"), "Show k8s node", func(s *mcclient.ClientSession, args *getOpt) error { - params := args.ClusterParams() - ret, err := k8s.K8sNodes.Get(s, args.NAME, params) - if err != nil { - return err - } - printObjectYAML(ret) - return nil - }) + initK8sClusterResource("node", k8s.K8sNodes) } diff --git a/cmd/climc/shell/k8s/namespace.go b/cmd/climc/shell/k8s/namespace.go index 65dcc77ab3..a83c154bf5 100644 --- a/cmd/climc/shell/k8s/namespace.go +++ b/cmd/climc/shell/k8s/namespace.go @@ -1,41 +1,9 @@ package k8s import ( - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) func initNamespace() { - cmdN := func(suffix string) string { - return resourceCmdN("namespace", suffix) - } - - type listOpt struct { - clusterBaseOptions - baseListOptions - } - R(&listOpt{}, cmdN("list"), "List k8s namespace", func(s *mcclient.ClientSession, args *listOpt) error { - params := fetchPagingParams(args.baseListOptions) - params.Update(args.ClusterParams()) - ret, err := k8s.Namespaces.List(s, params) - if err != nil { - return err - } - PrintListResultTable(ret, k8s.Namespaces, s) - return nil - }) - - type getOpt struct { - clusterBaseOptions - NAME string `help:"Namespace name"` - } - R(&getOpt{}, cmdN("show"), "Show k8s namespace", func(s *mcclient.ClientSession, args *getOpt) error { - params := args.ClusterParams() - ret, err := k8s.Namespaces.Get(s, args.NAME, params) - if err != nil { - return err - } - printObjectYAML(ret) - return nil - }) + initK8sClusterResource("namespace", k8s.Namespaces) } diff --git a/cmd/climc/shell/k8s/nodes.go b/cmd/climc/shell/k8s/nodes.go index 7c6c9f2a0c..ac59cb05fa 100644 --- a/cmd/climc/shell/k8s/nodes.go +++ b/cmd/climc/shell/k8s/nodes.go @@ -3,31 +3,19 @@ package k8s import ( "fmt" - "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" - "yunion.io/x/onecloud/pkg/mcclient/options" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initNode() { cmdN := func(suffix string) string { return kubeResourceCmdN("node", suffix) } - type listOpt struct { - options.BaseListOptions - Cluster string `help:"Filter by cluster"` - } - R(&listOpt{}, cmdN("list"), "List k8s infra nodes", func(s *mcclient.ClientSession, args *listOpt) error { - args.Details = options.Bool(true) - var params *jsonutils.JSONDict - { - var err error - params, err = options.ListStructToParams(args) - if err != nil { - return err - - } + R(&o.NodeListOptions{}, cmdN("list"), "List k8s infra nodes", func(s *mcclient.ClientSession, args *o.NodeListOptions) error { + params, err := args.Params() + if err != nil { + return err } result, err := k8s.Nodes.List(s, params) if err != nil { @@ -37,56 +25,8 @@ func initNode() { return nil }) - type createOpt struct { - CLUSTER string `help:"Cluster id"` - Etcd bool `help:"Etcd role"` - Controlplane bool `help:"Controlplane role"` - Worker bool `help:"Worker role"` - AllRole bool `help:"All roles"` - HostnameOverride string `help:"Worker node overrided hostname"` - Host string `help:"Yunion host server name or id"` - Name string `help:"Name of node"` - RegistryMirror []string `help:"Docker registry mirrors, e.g. 'https://registry.docker-cn.com'"` - InsecureRegistry []string `help:"Docker insecure registry"` - } - R(&createOpt{}, cmdN("create"), "Create k8s cluster node", func(s *mcclient.ClientSession, args *createOpt) error { - params := jsonutils.NewDict() - if args.Name != "" { - params.Add(jsonutils.NewString(args.Name), "name") - } - params.Add(jsonutils.NewString(args.CLUSTER), "cluster") - - dockerConf := dockerConfig{} - for _, rm := range args.RegistryMirror { - dockerConf.RegistryMirrors = append(dockerConf.RegistryMirrors, rm) - } - for _, im := range args.InsecureRegistry { - dockerConf.InsecureRegistries = append(dockerConf.InsecureRegistries, im) - } - confObj := jsonutils.Marshal(dockerConf) - params.Add(confObj, "dockerd_config") - - roles := jsonutils.NewArray() - if args.AllRole { - roles.Add(jsonutils.NewString("etcd"), jsonutils.NewString("controlplane"), jsonutils.NewString("worker")) - } else { - if args.Etcd { - roles.Add(jsonutils.NewString("etcd")) - } - if args.Controlplane { - roles.Add(jsonutils.NewString("controlplane")) - } - if args.Worker { - roles.Add(jsonutils.NewString("worker")) - } - } - params.Add(roles, "roles") - if args.HostnameOverride != "" { - params.Add(jsonutils.NewString(args.HostnameOverride), "hostname_override") - } - if args.Host != "" { - params.Add(jsonutils.NewString(args.Host), "host") - } + R(&o.NodeCreateOptions{}, cmdN("create"), "Create k8s cluster node", func(s *mcclient.ClientSession, args *o.NodeCreateOptions) error { + params := args.Params() node, err := k8s.Nodes.Create(s, params) if err != nil { return err @@ -95,23 +35,13 @@ func initNode() { return nil }) - type identOpt struct { - ID string `help:"ID or name of the node"` - } - - type identsOpt struct { - ID []string `help:"ID or name of the nodes"` - } - type deleteOpt struct { - identsOpt - } - R(&deleteOpt{}, cmdN("delete"), "Delete node", func(s *mcclient.ClientSession, args *deleteOpt) error { + R(&o.IdentsOptions{}, cmdN("delete"), "Delete node", func(s *mcclient.ClientSession, args *o.IdentsOptions) error { ret := k8s.Nodes.BatchDeleteWithParam(s, args.ID, nil, nil) printBatchResults(ret, k8s.Nodes.GetColumns(s)) return nil }) - R(&identOpt{}, cmdN("show"), "Show node details", func(s *mcclient.ClientSession, args *identOpt) error { + R(&o.IdentOptions{}, cmdN("show"), "Show node details", func(s *mcclient.ClientSession, args *o.IdentOptions) error { obj, err := k8s.Nodes.Get(s, args.ID, nil) if err != nil { return err @@ -120,13 +50,13 @@ func initNode() { return nil }) - R(&identsOpt{}, cmdN("purge"), "Purge a node record in database, not actually do deletion", func(s *mcclient.ClientSession, args *identsOpt) error { + R(&o.IdentsOptions{}, cmdN("purge"), "Purge a node record in database, not actually do deletion", func(s *mcclient.ClientSession, args *o.IdentsOptions) error { ret := k8s.Nodes.BatchPerformAction(s, args.ID, "purge", nil) printBatchResults(ret, k8s.Nodes.GetColumns(s)) return nil }) - R(&identOpt{}, cmdN("dockerconfig"), "Get docker daemon config", func(s *mcclient.ClientSession, args *identOpt) error { + R(&o.IdentOptions{}, cmdN("dockerconfig"), "Get docker daemon config", func(s *mcclient.ClientSession, args *o.IdentOptions) error { ret, err := k8s.Nodes.GetSpecific(s, args.ID, "docker-config", nil) if err != nil { return err diff --git a/cmd/climc/shell/k8s/pods.go b/cmd/climc/shell/k8s/pods.go index 72b7ba1d0a..8de0c7ed5d 100644 --- a/cmd/climc/shell/k8s/pods.go +++ b/cmd/climc/shell/k8s/pods.go @@ -1,55 +1,9 @@ package k8s import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) func initPod() { - cmdN := func(suffix string) string { - return resourceCmdN("pod", suffix) - } - - R(&NamespaceResourceListOptions{}, cmdN("list"), "List k8s pod", func(s *mcclient.ClientSession, args *NamespaceResourceListOptions) error { - ret, err := k8s.Pods.List(s, args.Params()) - if err != nil { - return err - } - PrintListResultTable(ret, k8s.Pods, s) - return nil - }) - - type getOpt struct { - resourceGetOptions - } - R(&getOpt{}, cmdN("show"), "Get pod details", func(s *mcclient.ClientSession, args *getOpt) error { - id := args.NAME - params := args.ClusterParams() - if args.Namespace != "" { - params.Add(jsonutils.NewString(args.Namespace), "namespace") - } - ret, err := k8s.Pods.Get(s, id, params) - if err != nil { - return err - } - printObjectYAML(ret) - return nil - }) - - type deleteOpt struct { - resourceGetOptions - } - R(&deleteOpt{}, cmdN("delete"), "Delete pod", func(s *mcclient.ClientSession, args *deleteOpt) error { - id := args.NAME - ret, err := k8s.Pods.Delete(s, id, args.ToJSON()) - if err != nil { - return err - } - fmt.Println(ret) - return nil - }) + initK8sNamespaceResource("pod", k8s.Pods) } diff --git a/cmd/climc/shell/k8s/pv.go b/cmd/climc/shell/k8s/pv.go new file mode 100644 index 0000000000..a1d4b14da6 --- /dev/null +++ b/cmd/climc/shell/k8s/pv.go @@ -0,0 +1,9 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initPV() { + initK8sClusterResource("persistentvolume", k8s.PersistentVolumes) +} diff --git a/cmd/climc/shell/k8s/pvc.go b/cmd/climc/shell/k8s/pvc.go new file mode 100644 index 0000000000..14a66d0693 --- /dev/null +++ b/cmd/climc/shell/k8s/pvc.go @@ -0,0 +1,9 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initPVC() { + initK8sNamespaceResource("persistentvolumeclaim", k8s.PersistentVolumeClaims) +} diff --git a/cmd/climc/shell/k8s/raw.go b/cmd/climc/shell/k8s/raw.go index cebcd968a8..e2643c9166 100644 --- a/cmd/climc/shell/k8s/raw.go +++ b/cmd/climc/shell/k8s/raw.go @@ -8,10 +8,11 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) type rawOpt struct { - namespaceOptions + o.NamespaceWithClusterOptions KIND string `help:"resource kind"` NAME string `help:"instance name"` } diff --git a/cmd/climc/shell/k8s/releases.go b/cmd/climc/shell/k8s/releases.go index 534b08e925..eaa4e41652 100644 --- a/cmd/climc/shell/k8s/releases.go +++ b/cmd/climc/shell/k8s/releases.go @@ -2,66 +2,18 @@ package k8s import ( "fmt" - "io/ioutil" - - json "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initRelease() { cmdN := func(suffix string) string { return resourceCmdN("release", suffix) } - type listOpt struct { - namespaceListOptions - baseListOptions - Name string `help:"Search by name"` - Filter string `help:"Filter, split by space"` - Admin bool `help:"Admin to show all namespace releases"` - Deployed bool `help:"Show deployed status releases"` - Deleted bool `help:"Show deleted status releases"` - Deleting bool `help:"Show deleting status releases"` - Failed bool `help:"Show failed status releases"` - Superseded bool `help:"Show superseded status releases"` - Pending bool `help:"Show pending status releases"` - } - R(&listOpt{}, cmdN("list"), "List k8s cluster helm releases", func(s *mcclient.ClientSession, args *listOpt) error { - params := fetchNamespaceParams(args.namespaceListOptions) - params.Update(fetchPagingParams(args.baseListOptions)) - params.Update(args.ClusterParams()) - if args.Filter != "" { - params.Add(json.NewString(args.Filter), "filter") - } - if args.Namespace != "" { - params.Add(json.NewString(args.Namespace), "namespace") - } - if args.Name != "" { - params.Add(json.NewString(args.Name), "name") - } - params.Add(json.JSONTrue, "all") - if args.Admin { - params.Add(json.JSONTrue, "admin") - } - if args.Deployed { - params.Add(json.JSONTrue, "deployed") - } - if args.Deleted { - params.Add(json.JSONTrue, "deleted") - } - if args.Deleting { - params.Add(json.JSONTrue, "deleting") - } - if args.Failed { - params.Add(json.JSONTrue, "failed") - } - if args.Superseded { - params.Add(json.JSONTrue, "superseded") - } - if args.Pending { - params.Add(json.JSONTrue, "pending") - } + R(&o.ReleaseListOptions{}, cmdN("list"), "List k8s cluster helm releases", func(s *mcclient.ClientSession, args *o.ReleaseListOptions) error { + params := args.Params() ret, err := k8s.Releases.List(s, params) if err != nil { return err @@ -70,12 +22,8 @@ func initRelease() { return nil }) - type showOpt struct { - clusterBaseOptions - NAME string `help:"Release instance name"` - } - R(&showOpt{}, cmdN("show"), "Get helm release details", func(s *mcclient.ClientSession, args *showOpt) error { - ret, err := k8s.Releases.Get(s, args.NAME, args.ClusterParams()) + R(&o.ResourceGetOptions{}, cmdN("show"), "Get helm release details", func(s *mcclient.ClientSession, args *o.ResourceGetOptions) error { + ret, err := k8s.Releases.Get(s, args.NAME, args.Params()) if err != nil { return err } @@ -87,53 +35,11 @@ func initRelease() { return nil }) - type releaseCUOpts struct { - Values string `help:"Specify values in a YAML file (can specify multiple)" short-token:"f"` - Version string `help:"Specify the exact chart version to install. If not specified, latest version installed"` - //Set []string `help:"set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)"` - DryRun bool `help:"Simulate an install"` - Details bool `help:"Show release deploy details, include kubernetes created resources"` - Timeout int64 `help:"Time in seconds to wait for any individual kubernetes operation (like Jobs for hooks)" default:"600"` - } - releaseCUDict := func(args releaseCUOpts) (*json.JSONDict, error) { - params := json.NewDict() - if args.Version != "" { - params.Add(json.NewString(args.Version), "version") - } - if args.DryRun { - params.Add(json.JSONTrue, "dry_run") - } - params.Add(json.NewInt(args.Timeout), "timeout") - if args.Values != "" { - //vals, err := helm.MergeValuesF(args.Values, args.Set, []string{}) - vals, err := ioutil.ReadFile(args.Values) - if err != nil { - return nil, err - } - params.Add(json.NewString(string(vals)), "values") - } - return params, nil - } - - type releaseCreateOpts struct { - namespaceOptions - releaseCUOpts - Name string `help:"Release name, If unspecified, it will autogenerate one for you"` - CHARTNAME string `help:"Helm chart name, e.g stable/etcd"` - } - R(&releaseCreateOpts{}, cmdN("create"), "Create release with specified helm chart", func(s *mcclient.ClientSession, args *releaseCreateOpts) error { - params, err := releaseCUDict(args.releaseCUOpts) + R(&o.ReleaseCreateOptions{}, cmdN("create"), "Create release with specified helm chart", func(s *mcclient.ClientSession, args *o.ReleaseCreateOptions) error { + params, err := args.Params() if err != nil { return err } - params.Update(args.ClusterParams()) - params.Add(json.NewString(args.CHARTNAME), "chart_name") - if args.Namespace != "" { - params.Add(json.NewString(args.Namespace), "namespace") - } - if args.Name != "" { - params.Add(json.NewString(args.Name), "release_name") - } ret, err := k8s.Releases.Create(s, params) if err != nil { return err @@ -142,28 +48,11 @@ func initRelease() { return nil }) - type releaseUpgradeOpts struct { - clusterBaseOptions - releaseCUOpts - NAME string `help:"Release instance name"` - CHARTNAME string `help:"Helm chart name, e.g stable/etcd"` - ReuseValues bool `help:"When upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored"` - ResetValues bool `help:"When upgrading, reset the values to the ones built into the chart"` - } - R(&releaseUpgradeOpts{}, cmdN("upgrade"), "Upgrade release", func(s *mcclient.ClientSession, args *releaseUpgradeOpts) error { - params, err := releaseCUDict(args.releaseCUOpts) + R(&o.ReleaseUpgradeOptions{}, cmdN("upgrade"), "Upgrade release", func(s *mcclient.ClientSession, args *o.ReleaseUpgradeOptions) error { + params, err := args.Params() if err != nil { return err } - params.Update(args.ClusterParams()) - params.Add(json.NewString(args.CHARTNAME), "chart_name") - params.Add(json.NewString(args.NAME), "release_name") - if args.ReuseValues { - params.Add(json.JSONTrue, "reuse_values") - } - if args.ResetValues { - params.Add(json.JSONTrue, "reset_values") - } res, err := k8s.Releases.Put(s, args.NAME, params) if err != nil { @@ -173,12 +62,8 @@ func initRelease() { return nil }) - type deleteOpt struct { - clusterBaseOptions - NAME string `help:"Release instance name"` - } - R(&deleteOpt{}, cmdN("delete"), "Delete release", func(s *mcclient.ClientSession, args *deleteOpt) error { - _, err := k8s.Releases.Delete(s, args.NAME, args.ClusterParams()) + R(&o.ReleaseDeleteOptions{}, cmdN("delete"), "Delete release", func(s *mcclient.ClientSession, args *o.ReleaseDeleteOptions) error { + _, err := k8s.Releases.Delete(s, args.NAME, args.Params()) return err }) } diff --git a/cmd/climc/shell/k8s/repos.go b/cmd/climc/shell/k8s/repos.go index a8633570c7..c423e69712 100644 --- a/cmd/climc/shell/k8s/repos.go +++ b/cmd/climc/shell/k8s/repos.go @@ -1,29 +1,19 @@ package k8s import ( - "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" - "yunion.io/x/onecloud/pkg/mcclient/options" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initRepo() { cmdN := func(suffix string) string { return resourceCmdN("repo", suffix) } - type listOpt struct { - options.BaseListOptions - } - R(&listOpt{}, cmdN("list"), "List k8s global helm repos", func(s *mcclient.ClientSession, args *listOpt) error { - var params *jsonutils.JSONDict - { - var err error - params, err = args.BaseListOptions.Params() - if err != nil { - return err - - } + R(&o.RepoListOptions{}, cmdN("list"), "List k8s global helm repos", func(s *mcclient.ClientSession, args *o.RepoListOptions) error { + params, err := args.Params() + if err != nil { + return err } result, err := k8s.Repos.List(s, params) if err != nil { @@ -33,10 +23,7 @@ func initRepo() { return nil }) - type getOpt struct { - NAME string `help:"ID or name of the repo"` - } - R(&getOpt{}, cmdN("show"), "Show details of a repo", func(s *mcclient.ClientSession, args *getOpt) error { + R(&o.RepoGetOptions{}, cmdN("show"), "Show details of a repo", func(s *mcclient.ClientSession, args *o.RepoGetOptions) error { repo, err := k8s.Repos.Get(s, args.NAME, nil) if err != nil { return err @@ -45,19 +32,8 @@ func initRepo() { return nil }) - type createOpt struct { - getOpt - URL string `help:"Repository url"` - Public bool `help:"Make repository public"` - } - R(&createOpt{}, cmdN("create"), "Add repository", func(s *mcclient.ClientSession, args *createOpt) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.NAME), "name") - params.Add(jsonutils.NewString(args.URL), "url") - if args.Public { - params.Add(jsonutils.JSONTrue, "is_public") - } - repo, err := k8s.Repos.Create(s, params) + R(&o.RepoCreateOptions{}, cmdN("create"), "Add repository", func(s *mcclient.ClientSession, args *o.RepoCreateOptions) error { + repo, err := k8s.Repos.Create(s, args.Params()) if err != nil { return err } @@ -65,20 +41,8 @@ func initRepo() { return nil }) - type updateOpt struct { - getOpt - Name string `help:"Repository name to change"` - Url string `help:"Repository url to change"` - } - R(&updateOpt{}, cmdN("update"), "Update helm repository", func(s *mcclient.ClientSession, args *updateOpt) error { - params := jsonutils.NewDict() - if args.Name != "" { - params.Add(jsonutils.NewString(args.Name), "name") - } - if args.Url != "" { - params.Add(jsonutils.NewString(args.Url), "url") - } - repo, err := k8s.Repos.Update(s, args.NAME, params) + R(&o.RepoUpdateOptions{}, cmdN("update"), "Update helm repository", func(s *mcclient.ClientSession, args *o.RepoUpdateOptions) error { + repo, err := k8s.Repos.Update(s, args.NAME, args.Params()) if err != nil { return err } @@ -86,25 +50,7 @@ func initRepo() { return nil }) - R(&getOpt{}, cmdN("private"), "Make repository private", func(s *mcclient.ClientSession, args *getOpt) error { - repo, err := k8s.Repos.PerformAction(s, args.NAME, "private", nil) - if err != nil { - return err - } - printObject(repo) - return nil - }) - - R(&getOpt{}, cmdN("public"), "Make repository public", func(s *mcclient.ClientSession, args *getOpt) error { - repo, err := k8s.Repos.PerformAction(s, args.NAME, "public", nil) - if err != nil { - return err - } - printObject(repo) - return nil - }) - - R(&getOpt{}, cmdN("delete"), "Delete a repository", func(s *mcclient.ClientSession, args *getOpt) error { + R(&o.RepoGetOptions{}, cmdN("delete"), "Delete a repository", func(s *mcclient.ClientSession, args *o.RepoGetOptions) error { repo, err := k8s.Repos.Delete(s, args.NAME, nil) if err != nil { return err diff --git a/cmd/climc/shell/k8s/secret.go b/cmd/climc/shell/k8s/secret.go new file mode 100644 index 0000000000..f8ae6cc412 --- /dev/null +++ b/cmd/climc/shell/k8s/secret.go @@ -0,0 +1,9 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initSecret() { + initK8sNamespaceResource("secret", k8s.Secrets) +} diff --git a/cmd/climc/shell/k8s/service.go b/cmd/climc/shell/k8s/service.go index 8803d17607..6fc63eb83b 100644 --- a/cmd/climc/shell/k8s/service.go +++ b/cmd/climc/shell/k8s/service.go @@ -1,28 +1,9 @@ package k8s import ( - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) func initService() { - cmdN := func(suffix string) string { - return resourceCmdN("service", suffix) - } - - type listOpt struct { - namespaceListOptions - baseListOptions - } - R(&listOpt{}, cmdN("list"), "List k8s service", func(s *mcclient.ClientSession, args *listOpt) error { - params := fetchNamespaceParams(args.namespaceListOptions) - params.Update(fetchPagingParams(args.baseListOptions)) - params.Update(args.ClusterParams()) - ret, err := k8s.Services.List(s, params) - if err != nil { - return err - } - PrintListResultTable(ret, k8s.Services, s) - return nil - }) + initK8sNamespaceResource("service", k8s.Services) } diff --git a/cmd/climc/shell/k8s/statefulset.go b/cmd/climc/shell/k8s/statefulset.go index 3c20e5d6a6..371fe03052 100644 --- a/cmd/climc/shell/k8s/statefulset.go +++ b/cmd/climc/shell/k8s/statefulset.go @@ -1,40 +1,9 @@ package k8s import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) func initStatefulset() { - cmdN := func(suffix string) string { - return resourceCmdN("statefulset", suffix) - } - - R(&NamespaceResourceListOptions{}, cmdN("list"), "List k8s statefulset", func(s *mcclient.ClientSession, args *NamespaceResourceListOptions) error { - ret, err := k8s.StatefulSets.List(s, args.Params()) - if err != nil { - return err - } - PrintListResultTable(ret, k8s.StatefulSets, s) - return nil - }) - - type getOpt struct { - resourceGetOptions - } - R(&getOpt{}, cmdN("show"), "Get statefulset details", func(s *mcclient.ClientSession, args *getOpt) error { - id := args.NAME - params := args.ClusterParams() - if args.Namespace != "" { - params.Add(jsonutils.NewString(args.Namespace), "namespace") - } - ret, err := k8s.StatefulSets.Get(s, id, params) - if err != nil { - return err - } - printObjectYAML(ret) - return nil - }) + initK8sNamespaceResource("statefulset", k8s.StatefulSets) } diff --git a/cmd/climc/shell/k8s/storageclass.go b/cmd/climc/shell/k8s/storageclass.go new file mode 100644 index 0000000000..507e5a36aa --- /dev/null +++ b/cmd/climc/shell/k8s/storageclass.go @@ -0,0 +1,9 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initStorageClass() { + initK8sClusterResource("storageclass", k8s.Storageclass) +} diff --git a/cmd/climc/shell/k8s/tiller.go b/cmd/climc/shell/k8s/tiller.go index 610dcb0e5e..38f4dfc7f9 100644 --- a/cmd/climc/shell/k8s/tiller.go +++ b/cmd/climc/shell/k8s/tiller.go @@ -1,51 +1,17 @@ package k8s import ( - json "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initTiller() { cmdN := func(suffix string) string { return resourceCmdN("tiller", suffix) } - type createOpt struct { - clusterBaseOptions - KubeContext string `json:"kube_context"` - Namespace string `json:"namespace" default:"kube-system"` - // Upgrade if Tiller is already installed - Upgrade bool `json:"upgrade"` - // Name of service account - ServiceAccount string `json:"service_account" default:"tiller"` - // Use the canary Tiller image - Canary bool `json:"canary_image"` - - // Override Tiller image - Image string `json:"tiller_image" default:"yunion/tiller:v2.9.0"` - // Limit the maximum number of revisions saved per release. Use 0 for no limit. - MaxHistory int `json:"history_max"` - } - R(&createOpt{}, cmdN("create"), "Install helm tiller server to Kubernetes cluster", func(s *mcclient.ClientSession, args *createOpt) error { - params := args.ClusterParams() - if len(args.KubeContext) > 0 { - params.Add(json.NewString(args.KubeContext), "kube_context") - } - params.Add(json.NewString(args.Namespace), "namespace") - params.Add(json.NewString(args.ServiceAccount), "service_account") - if args.Canary { - params.Add(json.JSONTrue, "canary_image") - } - if args.Upgrade { - params.Add(json.JSONTrue, "upgrade") - } - if len(args.Image) > 0 { - params.Add(json.NewString(args.Image), "tiller_image") - } - if args.MaxHistory > 0 { - params.Add(json.NewInt(int64(args.MaxHistory)), "history_max") - } + R(&o.TillerCreateOptions{}, cmdN("create"), "Install helm tiller server to Kubernetes cluster", func(s *mcclient.ClientSession, args *o.TillerCreateOptions) error { + params := args.Params() ret, err := k8s.Tiller.Create(s, params) if err != nil { return err diff --git a/pkg/mcclient/modules/k8s/cronjob.go b/pkg/mcclient/modules/k8s/cronjob.go new file mode 100644 index 0000000000..c890948982 --- /dev/null +++ b/pkg/mcclient/modules/k8s/cronjob.go @@ -0,0 +1,19 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var CronJobs *CronJobManager + +type CronJobManager struct { + *NamespaceResourceManager +} + +func init() { + CronJobs = &CronJobManager{ + NamespaceResourceManager: NewNamespaceResourceManager("cronjob", "cronjobs", NewNamespaceCols(), NewColumns()), + } + + modules.Register(CronJobs) +} diff --git a/pkg/mcclient/modules/k8s/job.go b/pkg/mcclient/modules/k8s/job.go new file mode 100644 index 0000000000..8b0fcef3cb --- /dev/null +++ b/pkg/mcclient/modules/k8s/job.go @@ -0,0 +1,19 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var Jobs *JobManager + +type JobManager struct { + *NamespaceResourceManager +} + +func init() { + Jobs = &JobManager{ + NamespaceResourceManager: NewNamespaceResourceManager("job", "jobs", NewNamespaceCols(), NewColumns()), + } + + modules.Register(Jobs) +} diff --git a/pkg/mcclient/modules/k8s/pv.go b/pkg/mcclient/modules/k8s/pv.go new file mode 100644 index 0000000000..152e880827 --- /dev/null +++ b/pkg/mcclient/modules/k8s/pv.go @@ -0,0 +1,38 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var PersistentVolumes *PersistentVolumeManager + +type PersistentVolumeManager struct { + *MetaResourceManager +} + +func init() { + PersistentVolumes = &PersistentVolumeManager{ + MetaResourceManager: NewMetaResourceManager("persistentvolume", "persistentvolumes", + NewColumns("StorageClass", "Claim", "AccessModes"), + NewColumns()), + } + + modules.Register(PersistentVolumes) +} + +func (m PersistentVolumeManager) GetStorageClass(obj jsonutils.JSONObject) interface{} { + sc, _ := obj.GetString("storageClass") + return sc +} + +func (m PersistentVolumeManager) GetClaim(obj jsonutils.JSONObject) interface{} { + claim, _ := obj.GetString("claim") + return claim +} + +func (m PersistentVolumeManager) GetAccessModes(obj jsonutils.JSONObject) interface{} { + modes, _ := obj.(*jsonutils.JSONDict).GetArray("accessModes") + return modes +} diff --git a/pkg/mcclient/modules/k8s/pvc.go b/pkg/mcclient/modules/k8s/pvc.go new file mode 100644 index 0000000000..f248e26514 --- /dev/null +++ b/pkg/mcclient/modules/k8s/pvc.go @@ -0,0 +1,34 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var PersistentVolumeClaims *PersistentVolumeClaimManager + +type PersistentVolumeClaimManager struct { + *NamespaceResourceManager + statusGetter +} + +func init() { + PersistentVolumeClaims = &PersistentVolumeClaimManager{ + NamespaceResourceManager: NewNamespaceResourceManager( + "persistentvolumeclaim", "persistentvolumeclaims", + NewColumns("Status", "Volume", "StorageClass"), NewColumns()), + statusGetter: getStatus, + } + modules.Register(PersistentVolumeClaims) +} + +func (m PersistentVolumeClaimManager) GetVolume(obj jsonutils.JSONObject) interface{} { + volume, _ := obj.GetString("volume") + return volume +} + +func (m PersistentVolumeClaimManager) GetStorageClass(obj jsonutils.JSONObject) interface{} { + sc, _ := obj.GetString("storageClass") + return sc +} diff --git a/pkg/mcclient/modules/k8s/secret.go b/pkg/mcclient/modules/k8s/secret.go new file mode 100644 index 0000000000..b66a27a9e5 --- /dev/null +++ b/pkg/mcclient/modules/k8s/secret.go @@ -0,0 +1,25 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var Secrets *SecretManager + +type SecretManager struct { + *NamespaceResourceManager +} + +func init() { + Secrets = &SecretManager{ + NewNamespaceResourceManager("secret", "secrets", + NewNamespaceCols("Type"), NewColumns())} + modules.Register(Secrets) +} + +func (m SecretManager) GetType(obj jsonutils.JSONObject) interface{} { + typ, _ := obj.GetString("type") + return typ +} diff --git a/pkg/mcclient/modules/k8s/storageclass.go b/pkg/mcclient/modules/k8s/storageclass.go new file mode 100644 index 0000000000..1db927ff6f --- /dev/null +++ b/pkg/mcclient/modules/k8s/storageclass.go @@ -0,0 +1,26 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var Storageclass *StorageclassManager + +type StorageclassManager struct { + *MetaResourceManager +} + +func init() { + Storageclass = &StorageclassManager{ + MetaResourceManager: NewMetaResourceManager("storageclass", "storageclasses", NewColumns("Provisioner"), NewColumns()), + } + + modules.Register(Storageclass) +} + +func (m StorageclassManager) GetProvisioner(obj jsonutils.JSONObject) interface{} { + provisioner, _ := obj.GetString("provisioner") + return provisioner +} diff --git a/pkg/mcclient/options/k8s/base.go b/pkg/mcclient/options/k8s/base.go new file mode 100644 index 0000000000..384c027251 --- /dev/null +++ b/pkg/mcclient/options/k8s/base.go @@ -0,0 +1,104 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" +) + +type ClusterBaseOptions struct { + Cluster string `default:"$K8S_CLUSTER|default" help:"Kubernetes cluster name"` +} + +func (o ClusterBaseOptions) Params() *jsonutils.JSONDict { + ret := jsonutils.NewDict() + ret.Add(jsonutils.NewString(o.Cluster), "cluster") + return ret +} + +type BaseListOptions struct { + Limit int `default:"20" help:"Page limit"` + Offset int `default:"0" help:"page offset"` +} + +func (o BaseListOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + if o.Limit > 0 { + params.Add(jsonutils.NewInt(int64(o.Limit)), "limit") + } + if o.Offset > 0 { + params.Add(jsonutils.NewInt(int64(o.Offset)), "offset") + } + return params +} + +type ResourceListOptions struct { + ClusterBaseOptions + BaseListOptions +} + +func (o ResourceListOptions) Params() *jsonutils.JSONDict { + params := o.BaseListOptions.Params() + params.Update(o.ClusterBaseOptions.Params()) + return params +} + +type ResourceGetOptions struct { + ClusterBaseOptions + NAME string `help:"Name ident of the resource"` +} + +func (o ResourceGetOptions) Params() *jsonutils.JSONDict { + params := o.ClusterBaseOptions.Params() + return params +} + +type NamespaceResourceListOptions struct { + ResourceListOptions + Namespace string `help:"Namespace of this resource"` + AllNamespace bool `help:"Show resource in all namespace"` +} + +func (o NamespaceResourceListOptions) Params() *jsonutils.JSONDict { + params := o.ResourceListOptions.Params() + if o.AllNamespace { + params.Add(jsonutils.JSONTrue, "all_namespace") + return params + } + if o.Namespace != "" { + params.Add(jsonutils.NewString(o.Namespace), "namespace") + } + return params +} + +type NamespaceOptions struct { + Namespace string `help:"Namespace of this resource"` +} + +func (o NamespaceOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + if o.Namespace != "" { + params.Add(jsonutils.NewString(o.Namespace), "namespace") + } + return params +} + +type NamespaceResourceGetOptions struct { + ResourceGetOptions + NamespaceOptions +} + +func (o NamespaceResourceGetOptions) Params() *jsonutils.JSONDict { + params := o.ResourceGetOptions.Params() + params.Update(o.NamespaceOptions.Params()) + return params +} + +type NamespaceWithClusterOptions struct { + NamespaceOptions + ClusterBaseOptions +} + +func (o NamespaceWithClusterOptions) Params() *jsonutils.JSONDict { + params := o.ClusterBaseOptions.Params() + params.Update(o.NamespaceOptions.Params()) + return params +} diff --git a/pkg/mcclient/options/k8s/charts.go b/pkg/mcclient/options/k8s/charts.go new file mode 100644 index 0000000000..427e63622d --- /dev/null +++ b/pkg/mcclient/options/k8s/charts.go @@ -0,0 +1,49 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" +) + +type ChartListOptions struct { + BaseListOptions + Name string `help:"Chart name"` + Repo string `help:"Repository name"` + RepoUrl string `help:"Repository url"` + AllVersion bool `json:"Get Chart all history versions"` + Keyword string `json:"Chart keyword"` +} + +func (o ChartListOptions) Params() *jsonutils.JSONDict { + params := o.BaseListOptions.Params() + if len(o.Name) != 0 { + params.Add(jsonutils.NewString(o.Name), "name") + } + if len(o.Repo) != 0 { + params.Add(jsonutils.NewString(o.Repo), "repo") + } + if len(o.RepoUrl) != 0 { + params.Add(jsonutils.NewString(o.RepoUrl), "repo_url") + } + if o.AllVersion { + params.Add(jsonutils.JSONTrue, "all_version") + } + if len(o.Keyword) != 0 { + params.Add(jsonutils.NewString(o.Keyword), "keyword") + } + return params +} + +type ChartGetOptions struct { + REPO string `help:"Repo of the chart"` + NAME string `help:"Chart name"` + Version string `help:"Chart version"` +} + +func (o ChartGetOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(o.REPO), "repo") + if o.Version != "" { + params.Add(jsonutils.NewString(o.Version), "version") + } + return params +} diff --git a/pkg/mcclient/options/k8s/cluster.go b/pkg/mcclient/options/k8s/cluster.go new file mode 100644 index 0000000000..99d8722819 --- /dev/null +++ b/pkg/mcclient/options/k8s/cluster.go @@ -0,0 +1,177 @@ +package k8s + +import ( + "fmt" + "io/ioutil" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/sets" + + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +type ClusterListOptions struct { + options.BaseListOptions +} + +func (o ClusterListOptions) Params() *jsonutils.JSONDict { + o.Details = options.Bool(true) + params, err := o.BaseListOptions.Params() + if err != nil { + panic(err) + } + return params +} + +type ClusterCreateOptions struct { + NAME string `help:"Name of cluster"` + Mode string `help:"Cluster mode" choices:"internal"` + K8sVersion string `help:"Cluster kubernetes components version" choices:"v1.8.10|v1.9.5|v1.10.0"` + InfraImage string `help:"Cluster kubelet infra container image"` + Cidr string `help:"Cluster service CIDR, e.g. 10.43.0.0/16"` + Domain string `help:"Cluster pod domain, e.g. cluster.local"` +} + +func (o ClusterCreateOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(o.NAME), "name") + if o.Mode != "" { + params.Add(jsonutils.NewString(o.Mode), "mode") + } + if o.K8sVersion != "" { + params.Add(jsonutils.NewString(o.K8sVersion), "k8s_version") + } + if o.InfraImage != "" { + params.Add(jsonutils.NewString(o.InfraImage), "infra_container_image") + } + if o.Cidr != "" { + params.Add(jsonutils.NewString(o.Cidr), "cluster_cidr") + } + if o.Domain != "" { + params.Add(jsonutils.NewString(o.Domain), "cluster_domain") + } + return params +} + +type ClusterImportOptions struct { + NAME string `help:"Name of cluster to import"` + KUBECONFIG string `help:"Kubernetes auth config"` +} + +func (o ClusterImportOptions) Params() (*jsonutils.JSONDict, error) { + kubeconfig, err := ioutil.ReadFile(o.KUBECONFIG) + if err != nil { + return nil, fmt.Errorf("Read kube config %q error: %v", o.KUBECONFIG, err) + } + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(string(kubeconfig)), "kube_config") + return params, nil +} + +type ClusterUpdateOptions struct { + NAME string `help:"Name of cluster"` + K8sVersion string `help:"Cluster kubernetes components version" choices:"v1.8.10|v1.9.5|v1.10.0"` +} + +func (o ClusterUpdateOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + if o.K8sVersion != "" { + params.Add(jsonutils.NewString(o.K8sVersion), "k8s_version") + } + return params +} + +type IdentOptions struct { + ID string `help:"ID or name of the model"` +} + +type IdentsOptions struct { + ID []string `help:"ID of models to operate"` +} + +type ClusterDeployOptions struct { + IdentOptions + Force bool `help:"Force deploy"` +} + +func (o ClusterDeployOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + if o.Force { + params.Add(jsonutils.JSONTrue, "force") + } + return params +} + +type ClusterDeleteOptions struct { + IdentsOptions +} + +type ClusterKubeconfigOptions struct { + IdentOptions + Directly bool `help:"Get directly connect kubeconfig"` +} + +func (o ClusterKubeconfigOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + if o.Directly { + params.Add(jsonutils.JSONTrue, "directly") + } + return params +} + +type ClusterAddNodesOptions struct { + IdentOptions + NodeConfig []string `help:"Node spec, 'host:[roles]' e.g: --node-config host01:controlplane,etcd,worker --node-config host02:worker"` + AutoDeploy bool `help:"Auto deploy"` +} + +func (o ClusterAddNodesOptions) Params() (*jsonutils.JSONDict, error) { + params := jsonutils.NewDict() + if o.AutoDeploy { + params.Add(jsonutils.JSONTrue, "auto_deploy") + } + nodesArray := jsonutils.NewArray() + for _, config := range o.NodeConfig { + opt, err := parseNodeAddConfigStr(config) + if err != nil { + return nil, err + } + nodesArray.Add(jsonutils.Marshal(opt)) + } + params.Add(nodesArray, "nodes") + return params, nil +} + +type dockerConfig struct { + RegistryMirrors []string `json:"registry-mirrors"` + InsecureRegistries []string `json:"insecure-registries"` +} + +type nodeAddConfig struct { + Host string `json:"host"` + Roles []string `json:"roles"` + Name string `json:"name"` + HostnameOverride string `json:"hostname_override"` + DockerdConfig dockerConfig `json:"dockerd_config"` +} + +func parseNodeAddConfigStr(config string) (nodeAddConfig, error) { + ret := nodeAddConfig{} + parts := strings.Split(config, ":") + if len(parts) != 2 { + return ret, fmt.Errorf("Invalid config: %q", config) + } + host := parts[0] + roleStr := parts[1] + ret.Host = host + roles := []string{} + for _, role := range strings.Split(roleStr, ",") { + if !sets.NewString("etcd", "controlplane", "worker").Has(role) { + return ret, fmt.Errorf("Invalid role: %q", role) + } + roles = append(roles, role) + } + ret.Roles = roles + return ret, nil +} diff --git a/pkg/mcclient/options/k8s/deployment.go b/pkg/mcclient/options/k8s/deployment.go new file mode 100644 index 0000000000..7d69632601 --- /dev/null +++ b/pkg/mcclient/options/k8s/deployment.go @@ -0,0 +1,147 @@ +package k8s + +import ( + "fmt" + "io/ioutil" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/util/sets" +) + +type DeploymentCreateOptions struct { + NamespaceWithClusterOptions + NAME string `help:"Name of deployment"` + Image string `help:"The image for the container to run"` + Replicas int64 `help:"Number of replicas for pods in this deployment"` + RunAsPrivileged bool `help:"Whether to run the container as privileged user"` + Labels string `help:"Comma separated labels to apply to the pod(s)"` + Env []string `help:"Environment variables to set in container"` + Port []string `help:"Port for the service that is created, format is :: e.g. tcp:80:3000"` + Net string `help:"Network config, e.g. net1, net1:10.168.222.171"` +} + +func (o DeploymentCreateOptions) Params() (*jsonutils.JSONDict, error) { + params := o.NamespaceWithClusterOptions.Params() + params.Add(jsonutils.NewString(o.NAME), "name") + if len(o.Image) == 0 { + return nil, fmt.Errorf("Image must provided") + } + params.Add(jsonutils.NewString(o.Image), "containerImage") + if o.Replicas > 1 { + params.Add(jsonutils.NewInt(o.Replicas), "replicas") + } + if o.RunAsPrivileged { + params.Add(jsonutils.JSONTrue, "runAsPrivileged") + } + if len(o.Port) != 0 { + portMappings, err := parsePortMappings(o.Port) + if err != nil { + return nil, err + } + params.Add(portMappings, "portMappings") + } + envList := jsonutils.NewArray() + for _, env := range o.Env { + parts := strings.Split(env, "=") + if len(parts) != 2 { + return nil, fmt.Errorf("Bad env value: %v", env) + } + envObj := jsonutils.NewDict() + envObj.Add(jsonutils.NewString(parts[0]), "name") + envObj.Add(jsonutils.NewString(parts[1]), "value") + envList.Add(envObj) + } + params.Add(envList, "variables") + if o.Net != "" { + net, err := parseNetConfig(o.Net) + if err != nil { + return nil, err + } + params.Add(net, "networkConfig") + } + return params, nil +} + +type portMapping struct { + Port int32 `json:"port"` + TargetPort int32 `json:"targetPort"` + Protocol string `json:"protocol"` +} + +func parsePortMapping(port string) (*portMapping, error) { + if len(port) == 0 { + return nil, fmt.Errorf("empty port mapping desc string") + } + parts := strings.Split(port, ":") + mapping := &portMapping{} + for _, part := range parts { + if sets.NewString("tcp", "udp").Has(strings.ToLower(part)) { + mapping.Protocol = strings.ToUpper(part) + } + if port, err := strconv.Atoi(part); err != nil { + continue + } else { + if mapping.Port == 0 { + mapping.Port = int32(port) + } else { + mapping.TargetPort = int32(port) + } + } + } + if mapping.Protocol == "" { + mapping.Protocol = "TCP" + } + if mapping.Port <= 0 { + return nil, fmt.Errorf("Service port not provided") + } + if mapping.TargetPort < 0 { + return nil, fmt.Errorf("Container invalid targetPort %d", mapping.TargetPort) + } + if mapping.TargetPort == 0 { + mapping.TargetPort = mapping.Port + } + return mapping, nil +} + +func parsePortMappings(ports []string) (*jsonutils.JSONArray, error) { + ret := jsonutils.NewArray() + for _, port := range ports { + mapping, err := parsePortMapping(port) + if err != nil { + return nil, fmt.Errorf("Port %q error: %v", port, err) + } + ret.Add(jsonutils.Marshal(mapping)) + } + return ret, nil +} + +func parseNetConfig(net string) (*jsonutils.JSONDict, error) { + ret := jsonutils.NewDict() + for _, p := range strings.Split(net, ":") { + if regutils.MatchIP4Addr(p) { + ret.Add(jsonutils.NewString(p), "address") + } else { + ret.Add(jsonutils.NewString(p), "network") + } + } + return ret, nil +} + +type DeploymentCreateFromFileOptions struct { + NamespaceResourceGetOptions + FILE string `help:"K8s resource YAML or JSON file"` +} + +func (o DeploymentCreateFromFileOptions) Params() (*jsonutils.JSONDict, error) { + params := o.NamespaceResourceGetOptions.Params() + params.Add(jsonutils.NewString(o.NAME), "name") + content, err := ioutil.ReadFile(o.FILE) + if err != nil { + return nil, err + } + params.Add(jsonutils.NewString(string(content)), "content") + return params, nil +} diff --git a/pkg/mcclient/options/k8s/node.go b/pkg/mcclient/options/k8s/node.go new file mode 100644 index 0000000000..2a516b1635 --- /dev/null +++ b/pkg/mcclient/options/k8s/node.go @@ -0,0 +1,69 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +type NodeListOptions struct { + options.BaseListOptions + Cluster string `help:"Filter by cluster"` +} + +func (o NodeListOptions) Params() (*jsonutils.JSONDict, error) { + return options.ListStructToParams(&o) +} + +type NodeCreateOptions struct { + CLUSTER string `help:"Cluster id"` + Etcd bool `help:"Etcd role"` + Controlplane bool `help:"Controlplane role"` + Worker bool `help:"Worker role"` + AllRole bool `help:"All roles"` + HostnameOverride string `help:"Worker node overrided hostname"` + Host string `help:"Yunion host server name or id"` + Name string `help:"Name of node"` + RegistryMirror []string `help:"Docker registry mirrors, e.g. 'https://registry.docker-cn.com'"` + InsecureRegistry []string `help:"Docker insecure registry"` +} + +func (o NodeCreateOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + if o.Name != "" { + params.Add(jsonutils.NewString(o.Name), "name") + } + params.Add(jsonutils.NewString(o.CLUSTER), "cluster") + dockerConf := dockerConfig{} + for _, rm := range o.RegistryMirror { + dockerConf.RegistryMirrors = append(dockerConf.RegistryMirrors, rm) + } + for _, im := range o.InsecureRegistry { + dockerConf.InsecureRegistries = append(dockerConf.InsecureRegistries, im) + } + confObj := jsonutils.Marshal(dockerConf) + params.Add(confObj, "dockerd_config") + + roles := jsonutils.NewArray() + if o.AllRole { + roles.Add(jsonutils.NewString("etcd"), jsonutils.NewString("controlplane"), jsonutils.NewString("worker")) + } else { + if o.Etcd { + roles.Add(jsonutils.NewString("etcd")) + } + if o.Controlplane { + roles.Add(jsonutils.NewString("controlplane")) + } + if o.Worker { + roles.Add(jsonutils.NewString("worker")) + } + } + params.Add(roles, "roles") + if o.HostnameOverride != "" { + params.Add(jsonutils.NewString(o.HostnameOverride), "hostname_override") + } + if o.Host != "" { + params.Add(jsonutils.NewString(o.Host), "host") + } + return params +} diff --git a/pkg/mcclient/options/k8s/release.go b/pkg/mcclient/options/k8s/release.go new file mode 100644 index 0000000000..a63bc601cc --- /dev/null +++ b/pkg/mcclient/options/k8s/release.go @@ -0,0 +1,136 @@ +package k8s + +import ( + "io/ioutil" + + "yunion.io/x/jsonutils" +) + +type ReleaseListOptions struct { + NamespaceResourceListOptions + Name string `help:"Search by name"` + Filter string `help:"Filter, split by space"` + Admin bool `help:"Admin to show all namespace releases"` + Deployed bool `help:"Show deployed status releases"` + Deleted bool `help:"Show deleted status releases"` + Deleting bool `help:"Show deleting status releases"` + Failed bool `help:"Show failed status releases"` + Superseded bool `help:"Show superseded status releases"` + Pending bool `help:"Show pending status releases"` +} + +func (o ReleaseListOptions) Params() *jsonutils.JSONDict { + params := o.NamespaceResourceListOptions.Params() + if o.Filter != "" { + params.Add(jsonutils.NewString(o.Filter), "filter") + } + if o.Namespace != "" { + params.Add(jsonutils.NewString(o.Namespace), "namespace") + } + if o.Name != "" { + params.Add(jsonutils.NewString(o.Name), "name") + } + params.Add(jsonutils.JSONTrue, "all") + if o.Admin { + params.Add(jsonutils.JSONTrue, "admin") + } + if o.Deployed { + params.Add(jsonutils.JSONTrue, "deployed") + } + if o.Deleted { + params.Add(jsonutils.JSONTrue, "deleted") + } + if o.Deleting { + params.Add(jsonutils.JSONTrue, "deleting") + } + if o.Failed { + params.Add(jsonutils.JSONTrue, "failed") + } + if o.Superseded { + params.Add(jsonutils.JSONTrue, "superseded") + } + if o.Pending { + params.Add(jsonutils.JSONTrue, "pending") + } + return params +} + +type ReleaseCreateUpdateOptions struct { + Values string `help:"Specify values in a YAML file (can specify multiple)" short-token:"f"` + Version string `help:"Specify the exact chart version to install. If not specified, latest version installed"` + //Set []string `help:"set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)"` + DryRun bool `help:"Simulate an install"` + Details bool `help:"Show release deploy details, include kubernetes created resources"` + Timeout int64 `help:"Time in seconds to wait for any individual kubernetes operation (like Jobs for hooks)" default:"600"` +} + +func (o ReleaseCreateUpdateOptions) Params() (*jsonutils.JSONDict, error) { + params := jsonutils.NewDict() + if o.Version != "" { + params.Add(jsonutils.NewString(o.Version), "version") + } + if o.DryRun { + params.Add(jsonutils.JSONTrue, "dry_run") + } + params.Add(jsonutils.NewInt(o.Timeout), "timeout") + if o.Values != "" { + //vals, err := helm.MergeValuesF(args.Values, args.Set, []string{}) + vals, err := ioutil.ReadFile(o.Values) + if err != nil { + return nil, err + } + params.Add(jsonutils.NewString(string(vals)), "values") + } + return params, nil +} + +type ReleaseCreateOptions struct { + NamespaceWithClusterOptions + ReleaseCreateUpdateOptions + Name string `help:"Release name, If unspecified, it will autogenerate one for you"` + CHARTNAME string `help:"Helm chart name, e.g stable/etcd"` +} + +func (o ReleaseCreateOptions) Params() (*jsonutils.JSONDict, error) { + params, err := o.ReleaseCreateUpdateOptions.Params() + if err != nil { + return nil, err + } + params.Update(o.NamespaceWithClusterOptions.Params()) + params.Add(jsonutils.NewString(o.CHARTNAME), "chart_name") + if o.Name != "" { + params.Add(jsonutils.NewString(o.Name), "release_name") + } + return params, nil +} + +type ReleaseUpgradeOptions struct { + ClusterBaseOptions + ReleaseCreateUpdateOptions + NAME string `help:"Release instance name"` + CHARTNAME string `help:"Helm chart name, e.g stable/etcd"` + ReuseValues bool `help:"When upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored"` + ResetValues bool `help:"When upgrading, reset the values to the ones built into the chart"` +} + +func (o ReleaseUpgradeOptions) Params() (*jsonutils.JSONDict, error) { + params, err := o.ReleaseCreateUpdateOptions.Params() + if err != nil { + return nil, err + } + params.Update(o.ClusterBaseOptions.Params()) + params.Add(jsonutils.NewString(o.CHARTNAME), "chart_name") + params.Add(jsonutils.NewString(o.NAME), "release_name") + if o.ReuseValues { + params.Add(jsonutils.JSONTrue, "reuse_values") + } + if o.ResetValues { + params.Add(jsonutils.JSONTrue, "reset_values") + } + return params, nil +} + +type ReleaseDeleteOptions struct { + ClusterBaseOptions + NAME string `help:"Release instance name"` +} diff --git a/pkg/mcclient/options/k8s/repo.go b/pkg/mcclient/options/k8s/repo.go new file mode 100644 index 0000000000..5c42277134 --- /dev/null +++ b/pkg/mcclient/options/k8s/repo.go @@ -0,0 +1,44 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +type RepoListOptions struct { + options.BaseListOptions +} + +type RepoGetOptions struct { + NAME string `help:"ID or name of the repo"` +} + +type RepoCreateOptions struct { + RepoGetOptions + URL string `help:"Repository url"` +} + +func (o RepoCreateOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(o.NAME), "name") + params.Add(jsonutils.NewString(o.URL), "url") + return params +} + +type RepoUpdateOptions struct { + RepoGetOptions + Name string `help:"Repository name to change"` + Url string `help:"Repository url to change"` +} + +func (o RepoUpdateOptions) Params() *jsonutils.JSONDict { + params := jsonutils.NewDict() + if o.Name != "" { + params.Add(jsonutils.NewString(o.Name), "name") + } + if o.Url != "" { + params.Add(jsonutils.NewString(o.Url), "url") + } + return params +} diff --git a/pkg/mcclient/options/k8s/tiller.go b/pkg/mcclient/options/k8s/tiller.go new file mode 100644 index 0000000000..a1a6a64552 --- /dev/null +++ b/pkg/mcclient/options/k8s/tiller.go @@ -0,0 +1,44 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" +) + +type TillerCreateOptions struct { + ClusterBaseOptions + KubeContext string `json:"kube_context"` + Namespace string `json:"namespace" default:"kube-system"` + // Upgrade if Tiller is already installed + Upgrade bool `json:"upgrade"` + // Name of service account + ServiceAccount string `json:"service_account" default:"tiller"` + // Use the canary Tiller image + Canary bool `json:"canary_image"` + + // Override Tiller image + Image string `json:"tiller_image" default:"yunion/tiller:v2.9.0"` + // Limit the maximum number of revisions saved per release. Use 0 for no limit. + MaxHistory int `json:"history_max"` +} + +func (o TillerCreateOptions) Params() *jsonutils.JSONDict { + params := o.ClusterBaseOptions.Params() + if len(o.KubeContext) > 0 { + params.Add(jsonutils.NewString(o.KubeContext), "kube_context") + } + params.Add(jsonutils.NewString(o.Namespace), "namespace") + params.Add(jsonutils.NewString(o.ServiceAccount), "service_account") + if o.Canary { + params.Add(jsonutils.JSONTrue, "canary_image") + } + if o.Upgrade { + params.Add(jsonutils.JSONTrue, "upgrade") + } + if len(o.Image) > 0 { + params.Add(jsonutils.NewString(o.Image), "tiller_image") + } + if o.MaxHistory > 0 { + params.Add(jsonutils.NewInt(int64(o.MaxHistory)), "history_max") + } + return params +}