diff --git a/cmd/climc/shell/k8s/event.go b/cmd/climc/shell/k8s/event.go new file mode 100644 index 0000000000..2471d98fce --- /dev/null +++ b/cmd/climc/shell/k8s/event.go @@ -0,0 +1,9 @@ +package k8s + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" +) + +func initEvent() { + initK8sNamespaceResource("event", k8s.Events) +} diff --git a/cmd/climc/shell/k8s/k8s.go b/cmd/climc/shell/k8s/k8s.go index 5dce79b790..90405f46a9 100644 --- a/cmd/climc/shell/k8s/k8s.go +++ b/cmd/climc/shell/k8s/k8s.go @@ -16,6 +16,11 @@ package k8s import ( "fmt" + "io/ioutil" + "os" + "os/exec" + + "github.com/ghodss/yaml" "yunion.io/x/jsonutils" @@ -57,7 +62,7 @@ func init() { initPVC() initJob() initCronJob() - + initEvent() initRbac() initApp() @@ -217,6 +222,71 @@ func NewK8sNsResourceGetCmd(cmdN CmdNameFactory, manager modulebase.Manager) *Cm ) } +func NewK8sNsResourceGetRawCmd(cmdN CmdNameFactory, manager k8s.IClusterResourceManager) *Cmd { + return NewCommand( + &o.NamespaceResourceGetOptions{}, + cmdN.Do("show-raw"), + fmt.Sprintf("Show k8s %s raw data", cmdN.Kind), + func(s *mcclient.ClientSession, args *o.NamespaceResourceGetOptions) error { + ret, err := manager.GetRaw(s, args.NAME, args.Params()) + if err != nil { + return err + } + printObjectYAML(ret) + return nil + }, + ) +} + +func NewK8sResourceEditRawCmd(cmdN CmdNameFactory, manager k8s.IClusterResourceManager) *Cmd { + return NewCommand( + &o.NamespaceResourceGetOptions{}, + cmdN.Do("edit-raw"), + fmt.Sprintf("Edit and update k8s %s raw data", cmdN.Kind), + func(s *mcclient.ClientSession, args *o.NamespaceResourceGetOptions) error { + rawData, err := manager.GetRaw(s, args.NAME, args.Params()) + if err != nil { + return err + } + yamlBytes := rawData.YAMLString() + tempfile, err := ioutil.TempFile("", fmt.Sprintf("k8s-%s-%s*.yaml", cmdN.Kind, args.NAME)) + if err != nil { + return err + } + defer os.Remove(tempfile.Name()) + if _, err := tempfile.Write([]byte(yamlBytes)); err != nil { + return err + } + if err := tempfile.Close(); err != nil { + return err + } + + cmd := exec.Command("vim", tempfile.Name()) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + if err := cmd.Run(); err != nil { + return err + } + content, err := ioutil.ReadFile(tempfile.Name()) + if err != nil { + return err + } + jsonBytes, err := yaml.YAMLToJSON(content) + if err != nil { + return err + } + body, err := jsonutils.Parse(jsonBytes) + if err != nil { + return err + } + if _, err := manager.UpdateRaw(s, args.NAME, args.Params(), body.(*jsonutils.JSONDict)); err != nil { + return err + } + return nil + }, + ) +} + func NewK8sResourceDeleteCmd(cmdN CmdNameFactory, manager modulebase.Manager) *Cmd { return NewCommand( &o.ResourceDeleteOptions{}, @@ -244,11 +314,13 @@ func NewK8sNsResourceDeleteCmd(cmdN CmdNameFactory, manager modulebase.Manager) return deleteCmd } -func initK8sNamespaceResource(kind string, manager modulebase.Manager) *ShellCommands { +func initK8sNamespaceResource(kind string, manager k8s.IClusterResourceManager) *ShellCommands { cmdN := NewCmdNameFactory(kind) return NewShellCommands(cmdN.Do).AddR( NewK8sNsResourceListCmd(cmdN, manager), NewK8sNsResourceGetCmd(cmdN, manager), NewK8sNsResourceDeleteCmd(cmdN, manager), + NewK8sNsResourceGetRawCmd(cmdN, manager), + NewK8sResourceEditRawCmd(cmdN, manager), ) } diff --git a/pkg/apigateway/handler/resource.go b/pkg/apigateway/handler/resource.go index bab13ae7a6..cc54fdc040 100644 --- a/pkg/apigateway/handler/resource.go +++ b/pkg/apigateway/handler/resource.go @@ -606,28 +606,45 @@ func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.Respons } } -// batch update Joint +// * batch update Joint +// * put specific +// /// +// /// func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { - req := newRequest(ctx, w, r).WithMod1().WithMod2() + req := newRequest(ctx, w, r).WithMod1() if err := req.Error(); err != nil { httperrors.GeneralServerError(w, err) return } session := req.Session() module := req.Mod1() - module2 := req.Mod2() body := req.Body() query := req.Query() - idlist := fetchIdList(query, w) - if idlist == nil { + if idlist, _ := query.GetArray("id"); len(idlist) == 0 { + // do put specific + spec := req.ResName2() + obj, e := module.PutSpecific(session, req.ResID(), spec, query, body) + if e != nil { + httperrors.GeneralServerError(w, e) + } else { + appsrv.SendJSON(w, obj) + } return } + + req = req.WithMod2() + if err := req.Error(); err != nil { + httperrors.GeneralServerError(w, err) + return + } + module2 := req.Mod2() jmod, e := modulebase.GetJointModule2(session, module, module2) if e != nil { // update joint httperrors.GeneralServerError(w, e) return } + idlist := fetchIdList(query, w) ret := jmod.BatchUpdate(session, req.ResID(), idlist, query, body) w.WriteHeader(207) appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret)) diff --git a/pkg/mcclient/modulebase/modules.go b/pkg/mcclient/modulebase/modules.go index 4a2619e29b..7e887ea4ce 100644 --- a/pkg/mcclient/modulebase/modules.go +++ b/pkg/mcclient/modulebase/modules.go @@ -109,6 +109,7 @@ type Manager interface { BatchCreateInContexts(session *mcclient.ClientSession, params jsonutils.JSONObject, count int, ctxs []ManagerContext) []SubmitResult Update(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) Put(session *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + PutSpecific(session *mcclient.ClientSession, id string, spec string, query jsonutils.JSONObject, params jsonutils.JSONObject) (jsonutils.JSONObject, error) PutInContext(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error) PutInContexts(session *mcclient.ClientSession, id string, params jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error) BatchUpdate(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []SubmitResult diff --git a/pkg/mcclient/modulebase/resource.go b/pkg/mcclient/modulebase/resource.go index 6f67a59a1f..d0c469d7a8 100644 --- a/pkg/mcclient/modulebase/resource.go +++ b/pkg/mcclient/modulebase/resource.go @@ -409,6 +409,32 @@ func (this *ResourceManager) PutInContexts(session *mcclient.ClientSession, id s return this.filterSingleResult(session, result, nil) } +func (this *ResourceManager) PutSpecific(session *mcclient.ClientSession, id string, spec string, query, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return this.PutSpecificInContexts(session, id, spec, query, body, nil) +} + +func (this *ResourceManager) PutSpecificInContext(session *mcclient.ClientSession, id string, spec string, query, body jsonutils.JSONObject, ctx Manager, ctxid string) (jsonutils.JSONObject, error) { + return this.PutSpecificInContexts(session, id, spec, query, body, []ManagerContext{{ctx, ctxid}}) +} + +func (this *ResourceManager) PutSpecificInContexts(session *mcclient.ClientSession, id string, spec string, query, body jsonutils.JSONObject, ctxs []ManagerContext) (jsonutils.JSONObject, error) { + path := fmt.Sprintf("/%s/%s/%s", this.ContextPath(ctxs), url.PathEscape(id), url.PathEscape(spec)) + if query != nil { + qs := query.QueryString() + if len(qs) > 0 { + path = fmt.Sprintf("%s?%s", path, qs) + } + } + if body != nil { + body = this.params2Body(session, body, this.Keyword) + } + result, err := this._put(session, path, body, this.Keyword) + if err != nil { + return nil, err + } + return this.filterSingleResult(session, result, nil) +} + func (this *ResourceManager) BatchUpdate(session *mcclient.ClientSession, idlist []string, params jsonutils.JSONObject) []SubmitResult { return this.BatchPutInContexts(session, idlist, params, nil) } diff --git a/pkg/mcclient/modules/k8s/base.go b/pkg/mcclient/modules/k8s/base.go index a3b9581a60..bf8f6434dd 100644 --- a/pkg/mcclient/modules/k8s/base.go +++ b/pkg/mcclient/modules/k8s/base.go @@ -35,6 +35,12 @@ func NewResourceManager(keyword, keywordPlural string, columns, adminColumns *Co return &ResourceManager{man} } +type IClusterResourceManager interface { + modulebase.Manager + GetRaw(s *mcclient.ClientSession, id string, params *jsonutils.JSONDict) (jsonutils.JSONObject, error) + UpdateRaw(s *mcclient.ClientSession, id string, query, body *jsonutils.JSONDict) (jsonutils.JSONObject, error) +} + type ClusterResourceManager struct { *ResourceManager } @@ -50,6 +56,14 @@ func (man ClusterResourceManager) GetCluster(obj jsonutils.JSONObject) interface return cluster } +func (man ClusterResourceManager) GetRaw(s *mcclient.ClientSession, id string, params *jsonutils.JSONDict) (jsonutils.JSONObject, error) { + return man.GetSpecific(s, id, "rawdata", params) +} + +func (man ClusterResourceManager) UpdateRaw(s *mcclient.ClientSession, id string, query, rawdata *jsonutils.JSONDict) (jsonutils.JSONObject, error) { + return man.PutSpecific(s, id, "rawdata", query, rawdata) +} + type MetaResourceManager struct { *ClusterResourceManager nameGetter diff --git a/pkg/mcclient/modules/k8s/event.go b/pkg/mcclient/modules/k8s/event.go index d1833378fa..2170e58531 100644 --- a/pkg/mcclient/modules/k8s/event.go +++ b/pkg/mcclient/modules/k8s/event.go @@ -14,12 +14,64 @@ package k8s -var ( - Logs *ResourceManager +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient/modules" ) +var ( + Logs *ResourceManager + Events *EventManager +) + +type EventManager struct { + *NamespaceResourceManager +} + func init() { Logs = NewResourceManager("event", "events", NewColumns("id", "ops_time", "obj_id", "obj_type", "obj_name", "user", "user_id", "tenant", "tenant_id", "owner_tenant_id", "action", "notes"), NewColumns()) + + Events = &EventManager{ + + NamespaceResourceManager: NewNamespaceResourceManager("k8s_event", "k8s_events", + NewNamespaceCols("Source", "Type", "Action", "Object", "Message"), + NewColumns()), + } + + modules.Register(Events) +} + +func (m EventManager) GetSource(obj jsonutils.JSONObject) interface{} { + src, _ := obj.GetString("source") + return src +} + +func (m EventManager) GetType(obj jsonutils.JSONObject) interface{} { + typ, _ := obj.GetString("type") + return typ +} + +func (m EventManager) GetAction(obj jsonutils.JSONObject) interface{} { + act, _ := obj.Get("action") + return act +} + +func (m EventManager) GetObject(obj jsonutils.JSONObject) interface{} { + refObj, _ := obj.Get("involvedObject") + if refObj == nil { + return "" + } + kind, _ := refObj.GetString("kind") + name, _ := refObj.GetString("name") + return fmt.Sprintf("%s/%s", kind, name) +} + +func (m EventManager) GetMessage(obj jsonutils.JSONObject) interface{} { + msg, _ := obj.GetString("message") + return msg }