diff --git a/cmd/climc/shell/k8s/pvc.go b/cmd/climc/shell/k8s/pvc.go index f53e1945a2..8056a7d965 100644 --- a/cmd/climc/shell/k8s/pvc.go +++ b/cmd/climc/shell/k8s/pvc.go @@ -7,7 +7,7 @@ import ( ) func initPVC() { - cmdN := NewCmdNameFactory("persistentvolumeclaim") + cmdN := NewCmdNameFactory("pvc") pvcCmd := NewShellCommands(cmdN.Do).AddR( NewK8sNsResourceGetCmd(cmdN, k8s.PersistentVolumeClaims), NewK8sNsResourceDeleteCmd(cmdN, k8s.PersistentVolumeClaims), diff --git a/cmd/climc/shell/k8s/service.go b/cmd/climc/shell/k8s/service.go index 6fc63eb83b..306fc07b02 100644 --- a/cmd/climc/shell/k8s/service.go +++ b/cmd/climc/shell/k8s/service.go @@ -1,9 +1,47 @@ package k8s import ( + "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" + o "yunion.io/x/onecloud/pkg/mcclient/options/k8s" ) func initService() { - initK8sNamespaceResource("service", k8s.Services) + cmdN := NewCmdNameFactory("service") + svcCmd := NewShellCommands(cmdN.Do).AddR( + NewK8sNsResourceGetCmd(cmdN, k8s.Services), + NewK8sNsResourceDeleteCmd(cmdN, k8s.Services), + ) + + listCmd := NewCommand( + &o.ServiceListOptions{}, + cmdN.Do("list"), + "List Services resource", + func(s *mcclient.ClientSession, args *o.ServiceListOptions) error { + ret, err := k8s.Services.List(s, args.Params()) + if err != nil { + return err + } + PrintListResultTable(ret, k8s.Services, s) + return nil + }, + ) + + createCmd := NewCommand( + &o.ServiceCreateOptions{}, + cmdN.Do("create"), + "Create service resource", + func(s *mcclient.ClientSession, args *o.ServiceCreateOptions) error { + params, err := args.Params() + if err != nil { + return err + } + ret, err := k8s.Services.Create(s, params) + if err != nil { + return err + } + printObject(ret) + return nil + }) + svcCmd.AddR(listCmd, createCmd) } diff --git a/pkg/mcclient/options/k8s/app.go b/pkg/mcclient/options/k8s/app.go index 56d3764d36..eb68456a84 100644 --- a/pkg/mcclient/options/k8s/app.go +++ b/pkg/mcclient/options/k8s/app.go @@ -13,6 +13,7 @@ import ( type K8sAppBaseCreateOptions struct { NamespaceWithClusterOptions + ServiceSpecOptions NAME string `help:"Name of deployment"` Image string `help:"The image for the container to run" required:"true"` Replicas int64 `help:"Number of replicas for pods in this deployment"` @@ -20,7 +21,6 @@ type K8sAppBaseCreateOptions struct { RegistrySecret string `help:"Docker registry secret"` Label []string `help:"Labels to apply to the pod(s), e.g. 'env=prod'"` 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"` Mem int `help:"Memory request MB size"` Cpu float64 `help:"Cpu request cores"` @@ -42,13 +42,13 @@ func (o K8sAppBaseCreateOptions) Params() (*jsonutils.JSONDict, error) { 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") + + svcSpec, err := o.ServiceSpecOptions.Params() + if err != nil { + return nil, err } + params.Update(svcSpec) + envList := jsonutils.NewArray() for _, env := range o.Env { parts := strings.Split(env, "=") diff --git a/pkg/mcclient/options/k8s/service.go b/pkg/mcclient/options/k8s/service.go new file mode 100644 index 0000000000..1f218dea8a --- /dev/null +++ b/pkg/mcclient/options/k8s/service.go @@ -0,0 +1,73 @@ +package k8s + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" +) + +type ServiceSpecOptions struct { + Port []string `help:"Port for the service that is created, format is :: e.g. tcp:80:3000"` + IsExternal bool `help:"Created service is external loadbalance"` + LbNetwork string `help:"LoadBalancer service network id"` +} + +func (o ServiceSpecOptions) Params() (*jsonutils.JSONDict, error) { + params := jsonutils.NewDict() + if len(o.Port) == 0 { + return params, nil + } + portMappings, err := parsePortMappings(o.Port) + if err != nil { + return nil, err + } + if o.IsExternal { + params.Add(jsonutils.JSONTrue, "isExternal") + if o.LbNetwork != "" { + params.Add(jsonutils.NewString(o.LbNetwork), "loadBalancerNetwork") + } + } + params.Add(portMappings, "portMappings") + return params, nil +} + +type ServiceCreateOptions struct { + NamespaceWithClusterOptions + ServiceSpecOptions + NAME string `help:"Name of deployment"` + Selector []string `help:"Selectors are backends pods labels, e.g. 'run=app'"` +} + +func (o ServiceCreateOptions) Params() (*jsonutils.JSONDict, error) { + params := o.NamespaceWithClusterOptions.Params() + svcSpec, err := o.ServiceSpecOptions.Params() + if err != nil { + return nil, err + } + selector := jsonutils.NewDict() + for _, s := range o.Selector { + parts := strings.Split(s, "=") + if len(parts) != 2 { + return nil, fmt.Errorf("Invalid selctor string: %s", s) + } + selector.Add(jsonutils.NewString(parts[1]), parts[0]) + } + params.Update(svcSpec) + params.Add(selector, "selector") + params.Add(jsonutils.NewString(o.NAME), "name") + return params, nil +} + +type ServiceListOptions struct { + NamespaceResourceListOptions + Type string `help:"Service type" choices:"ClusterIP|LoadBalancer|NodePort|ExternalName"` +} + +func (o ServiceListOptions) Params() *jsonutils.JSONDict { + params := o.NamespaceResourceListOptions.Params() + if o.Type != "" { + params.Add(jsonutils.NewString(o.Type), "type") + } + return params +}