From 9cdbeb943b5c08fa84a77ff68216797564bdb347 Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Mon, 13 Aug 2018 19:22:34 +0800 Subject: [PATCH] climc: k8s resource cli --- cmd/climc/shell/k8s/configmap.go | 27 +++++ cmd/climc/shell/k8s/deployment.go | 145 +++++++++++++++++++++++++ cmd/climc/shell/k8s/k8s.go | 67 +++++++++++- cmd/climc/shell/k8s/pods.go | 20 +++- cmd/climc/shell/k8s/raw.go | 35 ++++++ cmd/climc/shell/k8s/repos.go | 106 ++++++++++++++++++ cmd/climc/shell/k8s/service.go | 27 +++++ pkg/mcclient/modules/k8s/base.go | 47 +++++++- pkg/mcclient/modules/k8s/cluster.go | 4 +- pkg/mcclient/modules/k8s/configmap.go | 20 ++++ pkg/mcclient/modules/k8s/deployment.go | 20 ++++ pkg/mcclient/modules/k8s/event.go | 4 +- pkg/mcclient/modules/k8s/helm.go | 17 +++ pkg/mcclient/modules/k8s/node.go | 2 +- pkg/mcclient/modules/k8s/pod.go | 4 +- pkg/mcclient/modules/k8s/raw.go | 95 ++++++++++++++++ pkg/mcclient/modules/k8s/service.go | 20 ++++ 17 files changed, 646 insertions(+), 14 deletions(-) create mode 100644 cmd/climc/shell/k8s/configmap.go create mode 100644 cmd/climc/shell/k8s/deployment.go create mode 100644 cmd/climc/shell/k8s/raw.go create mode 100644 cmd/climc/shell/k8s/repos.go create mode 100644 cmd/climc/shell/k8s/service.go create mode 100644 pkg/mcclient/modules/k8s/configmap.go create mode 100644 pkg/mcclient/modules/k8s/deployment.go create mode 100644 pkg/mcclient/modules/k8s/helm.go create mode 100644 pkg/mcclient/modules/k8s/raw.go create mode 100644 pkg/mcclient/modules/k8s/service.go diff --git a/cmd/climc/shell/k8s/configmap.go b/cmd/climc/shell/k8s/configmap.go new file mode 100644 index 0000000000..30d8fd6d9e --- /dev/null +++ b/cmd/climc/shell/k8s/configmap.go @@ -0,0 +1,27 @@ +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)) + ret, err := k8s.ConfigMaps.ListInContexts(s, params, args.ClusterContext()) + if err != nil { + return err + } + printList(ret, k8s.ConfigMaps.GetColumns(s)) + return nil + }) +} diff --git a/cmd/climc/shell/k8s/deployment.go b/cmd/climc/shell/k8s/deployment.go new file mode 100644 index 0000000000..dfdc392bba --- /dev/null +++ b/cmd/climc/shell/k8s/deployment.go @@ -0,0 +1,145 @@ +package k8s + +import ( + "fmt" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/sets" + + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initDeployment() { + cmdN := func(suffix string) string { + return resourceCmdN("deployment", suffix) + } + + type listOpt struct { + namespaceListOptions + baseListOptions + } + R(&listOpt{}, cmdN("list"), "List k8s deployment", func(s *mcclient.ClientSession, args *listOpt) error { + params := fetchNamespaceParams(args.namespaceListOptions) + params.Update(fetchPagingParams(args.baseListOptions)) + ret, err := k8s.Deployments.ListInContexts(s, params, args.ClusterContext()) + if err != nil { + return err + } + printList(ret, k8s.Deployments.GetColumns(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"` + } + R(&createOpt{}, cmdN("create"), "Create deployment resource", func(s *mcclient.ClientSession, args *createOpt) error { + params := jsonutils.NewDict() + 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) + if err != nil { + return err + } + params.Add(portMappings, "portMappings") + } + ret, err := k8s.Deployments.CreateInContexts(s, params, args.ClusterContext()) + if err != nil { + return err + } + 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 := jsonutils.NewDict() + if args.Namespace != "" { + params.Add(jsonutils.NewString(args.Namespace), "namespace") + } + ret, err := k8s.Deployments.GetInContexts(s, id, params, args.ClusterContext()) + 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) + } + } + } + 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 +} diff --git a/cmd/climc/shell/k8s/k8s.go b/cmd/climc/shell/k8s/k8s.go index 2e63757294..af4892e71a 100644 --- a/cmd/climc/shell/k8s/k8s.go +++ b/cmd/climc/shell/k8s/k8s.go @@ -12,24 +12,81 @@ import ( ) func init() { + // cluster resources initCluster() initNode() + + // helm resources + initRepo() + + // kubernetes original resources + initRaw() + initConfigMap() + initDeployment() initPod() + initService() } type BaseListOptions shell.BaseListOptions type clusterBaseOptions struct { - Cluster string `default:"$K8S_CLUSTER" help:"Kubernetes cluster name"` + Cluster string `default:"$K8S_CLUSTER|default" help:"Kubernetes cluster name"` } func (o clusterBaseOptions) ClusterContext() []modules.ManagerContext { return []modules.ManagerContext{clusterContext(o.Cluster)} } -type k8sBaseListOptions struct { +type baseListOptions struct { + Limit int `default:"20" help:"Page limit"` + Offset int `default:"0" help:"page offset"` +} + +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 - Limit int `default:"20" help:"Page limit"` + 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 := jsonutils.NewDict() + 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 } var ( @@ -53,3 +110,7 @@ func clusterContext(clusterId string) modules.ManagerContext { InstanceId: clusterId, } } + +func printObjectYAML(obj jsonutils.JSONObject) { + fmt.Println(obj.YAMLString()) +} diff --git a/cmd/climc/shell/k8s/pods.go b/cmd/climc/shell/k8s/pods.go index 8d2fdd0d3b..ee8803c414 100644 --- a/cmd/climc/shell/k8s/pods.go +++ b/cmd/climc/shell/k8s/pods.go @@ -13,10 +13,26 @@ func initPod() { } type listOpt struct { - k8sBaseListOptions + namespaceListOptions + baseListOptions } R(&listOpt{}, cmdN("list"), "List k8s pod", func(s *mcclient.ClientSession, args *listOpt) error { - ret, err := k8s.Pods.ListInContexts(s, nil, args.ClusterContext()) + params := fetchNamespaceParams(args.namespaceListOptions) + params.Update(fetchPagingParams(args.baseListOptions)) + ret, err := k8s.Pods.ListInContexts(s, params, args.ClusterContext()) + if err != nil { + return err + } + printList(ret, k8s.Pods.GetColumns(s)) + 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.DeleteInContexts(s, id, args.ToJSON(), args.ClusterContext()) if err != nil { return err } diff --git a/cmd/climc/shell/k8s/raw.go b/cmd/climc/shell/k8s/raw.go new file mode 100644 index 0000000000..6aeb500f91 --- /dev/null +++ b/cmd/climc/shell/k8s/raw.go @@ -0,0 +1,35 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +type rawGetOpt struct { + namespaceOptions + KIND string `help:"resource kind"` + NAME string `help:"instance name"` +} + +type rawDeleteOpt struct { + rawGetOpt +} + +func initRaw() { + R(&rawGetOpt{}, "k8s-get", "Get k8s resource instance raw info", func(s *mcclient.ClientSession, args *rawGetOpt) error { + obj, err := k8s.RawResource.Get(s, args.KIND, args.Namespace, args.NAME, nil, args.ClusterContext()) + if err != nil { + return err + } + printObjectYAML(obj) + return nil + }) + + R(&rawDeleteOpt{}, "k8s-delete", "Delete k8s resource instance", func(s *mcclient.ClientSession, args *rawDeleteOpt) error { + err := k8s.RawResource.Delete(s, args.KIND, args.Namespace, args.NAME, nil, args.ClusterContext()) + if err != nil { + return err + } + return nil + }) +} diff --git a/cmd/climc/shell/k8s/repos.go b/cmd/climc/shell/k8s/repos.go new file mode 100644 index 0000000000..ee34d8a2f9 --- /dev/null +++ b/cmd/climc/shell/k8s/repos.go @@ -0,0 +1,106 @@ +package k8s + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initRepo() { + cmdN := func(suffix string) string { + return resourceCmdN("repo", suffix) + } + type listOpt struct { + BaseListOptions + } + R(&listOpt{}, cmdN("list"), "List k8s global helm repos", func(s *mcclient.ClientSession, args *listOpt) error { + params := FetchPagingParams(args.BaseListOptions) + result, err := k8s.Repos.List(s, params) + if err != nil { + return err + } + printList(result, k8s.Repos.GetColumns(s)) + return nil + }) + + type getOpt struct { + NAME string `help:"ID or name of the repo"` + } + R(&getOpt{}, cmdN("show"), "Show details fo a repo", func(s *mcclient.ClientSession, args *getOpt) error { + repo, err := k8s.Repos.Get(s, args.NAME, nil) + if err != nil { + return err + } + printObject(repo) + 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) + if err != nil { + return err + } + printObject(repo) + 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) + if err != nil { + return err + } + printObject(repo) + 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 { + repo, err := k8s.Repos.Delete(s, args.NAME, nil) + if err != nil { + return err + } + printObject(repo) + return nil + }) +} diff --git a/cmd/climc/shell/k8s/service.go b/cmd/climc/shell/k8s/service.go new file mode 100644 index 0000000000..3260b28b88 --- /dev/null +++ b/cmd/climc/shell/k8s/service.go @@ -0,0 +1,27 @@ +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)) + ret, err := k8s.Services.ListInContexts(s, params, args.ClusterContext()) + if err != nil { + return err + } + printList(ret, k8s.Services.GetColumns(s)) + return nil + }) +} diff --git a/pkg/mcclient/modules/k8s/base.go b/pkg/mcclient/modules/k8s/base.go index 6c5eef1847..3b5fc20b61 100644 --- a/pkg/mcclient/modules/k8s/base.go +++ b/pkg/mcclient/modules/k8s/base.go @@ -1,13 +1,56 @@ package k8s import ( + "yunion.io/x/pkg/util/sets" + "yunion.io/x/onecloud/pkg/mcclient/modules" ) -func NewManager(keyword, keywordPlural string, columns, adminColumns []string) *modules.ResourceManager { +func NewManager(keyword, keywordPlural string, columns, adminColumns *Columns) *modules.ResourceManager { return &modules.ResourceManager{ - BaseManager: *modules.NewBaseManager("k8s", "", "", columns, adminColumns), + BaseManager: *modules.NewBaseManager("k8s", "", "", columns.Array(), adminColumns.Array()), Keyword: keyword, KeywordPlural: keywordPlural, } } + +type Columns struct { + cols []string +} + +func NewColumns(cols ...string) *Columns { + c := &Columns{cols: make([]string, 0)} + return c.Add(cols...) +} + +func (c *Columns) Add(cols ...string) *Columns { + for _, col := range cols { + c.add(col) + } + return c +} + +func (c *Columns) add(col string) *Columns { + src := sets.NewString(c.Array()...) + if src.Has(col) { + return c + } + c.cols = append(c.cols, col) + return c +} + +func (c Columns) Array() []string { + return c.cols +} + +func NewNamespaceCols(col ...string) *Columns { + return NewColumns("name", "namespace").Add(col...) +} + +func NewClusterCols(col ...string) *Columns { + return NewColumns("cluster").Add(col...) +} + +func NewResourceCols(col ...string) *Columns { + return NewColumns("name", "id").Add(col...) +} diff --git a/pkg/mcclient/modules/k8s/cluster.go b/pkg/mcclient/modules/k8s/cluster.go index df2df5ca39..42ee41d6b1 100644 --- a/pkg/mcclient/modules/k8s/cluster.go +++ b/pkg/mcclient/modules/k8s/cluster.go @@ -10,7 +10,7 @@ var ( func init() { Clusters = NewManager("cluster", "clusters", - []string{"id", "name", "mode", "k8s_version", "status", "api_endpoint"}, - []string{}) + NewResourceCols("mode", "k8s_version", "status", "api_endpoint"), + NewColumns()) modules.Register(Clusters) } diff --git a/pkg/mcclient/modules/k8s/configmap.go b/pkg/mcclient/modules/k8s/configmap.go new file mode 100644 index 0000000000..4bfcbbafdf --- /dev/null +++ b/pkg/mcclient/modules/k8s/configmap.go @@ -0,0 +1,20 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var ConfigMaps *ConfigMapManager + +type ConfigMapManager struct { + modules.ResourceManager +} + +func init() { + ConfigMaps = &ConfigMapManager{ + ResourceManager: *NewManager( + "configmap", "configmaps", + NewNamespaceCols(), + NewClusterCols())} + modules.Register(ConfigMaps) +} diff --git a/pkg/mcclient/modules/k8s/deployment.go b/pkg/mcclient/modules/k8s/deployment.go new file mode 100644 index 0000000000..f56a2947ef --- /dev/null +++ b/pkg/mcclient/modules/k8s/deployment.go @@ -0,0 +1,20 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var Deployments *DeploymentManager + +type DeploymentManager struct { + modules.ResourceManager +} + +func init() { + Deployments = &DeploymentManager{ + ResourceManager: *NewManager( + "deployment", "deployments", + NewNamespaceCols("labels"), + NewClusterCols())} + modules.Register(Deployments) +} diff --git a/pkg/mcclient/modules/k8s/event.go b/pkg/mcclient/modules/k8s/event.go index f71c5541ef..584ddbc376 100644 --- a/pkg/mcclient/modules/k8s/event.go +++ b/pkg/mcclient/modules/k8s/event.go @@ -10,7 +10,7 @@ var ( func init() { Logs = NewManager("kube_event", "kube_events", - []string{"id", "ops_time", "obj_id", "obj_type", "obj_name", "user", "user_id", "tenant", "tenant_id", "owner_tenant_id", "action", "notes"}, - []string{}) + NewColumns("id", "ops_time", "obj_id", "obj_type", "obj_name", "user", "user_id", "tenant", "tenant_id", "owner_tenant_id", "action", "notes"), + NewColumns()) modules.Register(Logs) } diff --git a/pkg/mcclient/modules/k8s/helm.go b/pkg/mcclient/modules/k8s/helm.go new file mode 100644 index 0000000000..b3e04f21ea --- /dev/null +++ b/pkg/mcclient/modules/k8s/helm.go @@ -0,0 +1,17 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var ( + Repos *modules.ResourceManager +) + +func init() { + Repos = NewManager("repo", "repos", + NewResourceCols("url", "is_public", "source"), + NewColumns(), + ) + modules.Register(Repos) +} diff --git a/pkg/mcclient/modules/k8s/node.go b/pkg/mcclient/modules/k8s/node.go index 5b8cb0798b..60f5bd6ade 100644 --- a/pkg/mcclient/modules/k8s/node.go +++ b/pkg/mcclient/modules/k8s/node.go @@ -9,6 +9,6 @@ var ( ) func init() { - Nodes = NewManager("node", "nodes", []string{"id", "name", "cluster", "roles", "address", "status"}, []string{}) + Nodes = NewManager("node", "nodes", NewResourceCols("cluster", "roles", "address", "status"), NewColumns()) modules.Register(Nodes) } diff --git a/pkg/mcclient/modules/k8s/pod.go b/pkg/mcclient/modules/k8s/pod.go index 46417df838..218ef6a243 100644 --- a/pkg/mcclient/modules/k8s/pod.go +++ b/pkg/mcclient/modules/k8s/pod.go @@ -14,7 +14,7 @@ func init() { Pods = &PodManager{ ResourceManager: *NewManager( "pod", "pods", - []string{"id", "name", "cluster", "roles", "address", "status"}, - []string{})} + NewNamespaceCols("podIP", "status", "restartCount", "labels"), + NewClusterCols("nodeName"))} modules.Register(Pods) } diff --git a/pkg/mcclient/modules/k8s/raw.go b/pkg/mcclient/modules/k8s/raw.go new file mode 100644 index 0000000000..8853a18742 --- /dev/null +++ b/pkg/mcclient/modules/k8s/raw.go @@ -0,0 +1,95 @@ +package k8s + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var RawResource *RawResourceManager + +func init() { + RawResource = &RawResourceManager{ + serviceType: "k8s", + } +} + +type rawResourceContext struct { + kind string + name string + query jsonutils.JSONObject + ctxs []modules.ManagerContext +} + +func newRawResourceContext(kind, namespace, name string, query jsonutils.JSONObject, ctxs []modules.ManagerContext) *rawResourceContext { + nsQuery := getNamespaceQuery(namespace) + if query != nil { + nsQuery.Update(query) + } + ctx := &rawResourceContext{kind: kind, name: name, query: nsQuery, ctxs: ctxs} + return ctx +} + +func (ctx rawResourceContext) contextPath() string { + segs := make([]string, 0) + ctxs := ctx.ctxs + if ctxs != nil && len(ctxs) > 0 { + for _, c := range ctxs { + segs = append(segs, c.InstanceManager.KeyString()) + if len(c.InstanceId) > 0 { + segs = append(segs, url.PathEscape(c.InstanceId)) + } + } + } + segs = append(segs, "_raw", ctx.kind, ctx.name) + path := fmt.Sprintf("/%s", strings.Join(segs, "/")) + if ctx.query != nil { + qs := ctx.query.QueryString() + if len(qs) > 0 { + path = fmt.Sprintf("%s?%s", path, qs) + } + } + return path +} + +type RawResourceManager struct { + serviceType string +} + +func (m *RawResourceManager) request(s *mcclient.ClientSession, method string, path string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { + _, ret, err := s.JSONRequest(m.serviceType, "", method, path, nil, body) + return ret, err +} + +func getNamespaceQuery(namespace string) *jsonutils.JSONDict { + query := jsonutils.NewDict() + if namespace != "" { + query.Set("namespace", jsonutils.NewString(namespace)) + } + return query +} + +func (m *RawResourceManager) Get(s *mcclient.ClientSession, kind string, namespace string, name string, query jsonutils.JSONObject, ctxs []modules.ManagerContext) (jsonutils.JSONObject, error) { + ctx := newRawResourceContext(kind, namespace, name, query, ctxs) + return m.request(s, "GET", ctx.contextPath(), nil) +} + +func (m *RawResourceManager) Put(s *mcclient.ClientSession, kind string, namespace string, name string, body jsonutils.JSONObject, ctxs []modules.ManagerContext) error { + rawBytes := body.String() + newBody := jsonutils.NewDict() + newBody.Add(jsonutils.NewString(rawBytes), "raw") + ctx := newRawResourceContext(kind, namespace, name, nil, ctxs) + _, err := m.request(s, "PUT", ctx.contextPath(), newBody) + return err +} + +func (m *RawResourceManager) Delete(s *mcclient.ClientSession, kind string, namespace string, name string, query jsonutils.JSONObject, ctxs []modules.ManagerContext) error { + ctx := newRawResourceContext(kind, namespace, name, query, ctxs) + _, err := m.request(s, "DELETE", ctx.contextPath(), nil) + return err +} diff --git a/pkg/mcclient/modules/k8s/service.go b/pkg/mcclient/modules/k8s/service.go new file mode 100644 index 0000000000..e66f38dda3 --- /dev/null +++ b/pkg/mcclient/modules/k8s/service.go @@ -0,0 +1,20 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var Services *ServiceManager + +type ServiceManager struct { + modules.ResourceManager +} + +func init() { + Services = &ServiceManager{ + ResourceManager: *NewManager( + "service", "services", + NewNamespaceCols("clusterIP", "selector", "internalEndpoint", "externalEndpoints"), + NewClusterCols())} + modules.Register(Services) +}