diff --git a/cmd/climc/shell/compute/modelarts_pool.go b/cmd/climc/shell/compute/modelarts_pool.go index 12c6c20a3e..d5ea141d4f 100644 --- a/cmd/climc/shell/compute/modelarts_pool.go +++ b/cmd/climc/shell/compute/modelarts_pool.go @@ -27,4 +27,5 @@ func init() { cmd.Delete(&options.BaseIdOptions{}) cmd.Create(&compute.ModelartsPoolCreateOption{}) cmd.Perform("syncstatus", &compute.ModelartsPoolSyncstatusOption{}) + cmd.Perform("change-config", &compute.ModelartsPoolChangeConfigOption{}) } diff --git a/pkg/apis/compute/modelarts_pool.go b/pkg/apis/compute/modelarts_pool.go index ab9cbef143..a892a2e3d2 100644 --- a/pkg/apis/compute/modelarts_pool.go +++ b/pkg/apis/compute/modelarts_pool.go @@ -19,12 +19,13 @@ import ( ) const ( - MODELARTS_POOL_STATUS_RUNNING = "running" - MODELARTS_POOL_STATUS_ABNORMAL = "abnormal" - MODELARTS_POOL_STATUS_CREATING = "creating" - MODELARTS_POOL_STATUS_DELETING = "deleting" - MODELARTS_POOL_STATUS_ERROR = "error" - MODELARTS_POOL_STATUS_UNKNOWN = "unknown" + MODELARTS_POOL_STATUS_RUNNING = "running" + MODELARTS_POOL_STATUS_ABNORMAL = "abnormal" + MODELARTS_POOL_STATUS_CREATING = "creating" + MODELARTS_POOL_STATUS_DELETING = "deleting" + MODELARTS_POOL_STATUS_CHANGE_CONFIG = "change_config" + MODELARTS_POOL_STATUS_ERROR = "error" + MODELARTS_POOL_STATUS_UNKNOWN = "unknown" ) type ModelartsPoolCreateInput struct { @@ -80,3 +81,7 @@ type ModelartsPoolListInput struct { type ModelartsPoolSyncstatusInput struct { } + +type ModelartsPoolChangeConfigInput struct { + NodeCount int +} diff --git a/pkg/cloudprovider/cloudprovider.go b/pkg/cloudprovider/cloudprovider.go index 9437293b4b..adc1137374 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/pkg/cloudprovider/cloudprovider.go @@ -944,6 +944,7 @@ type ICloudModelartsPool interface { GetInstanceType() string GetWorkType() string GetNodeCount() int + ChangeConfig(opts *ModelartsPoolChangeConfigOptions) error } type ICloudModelartsPoolSku interface { diff --git a/pkg/cloudprovider/modelarts_pool.go b/pkg/cloudprovider/modelarts_pool.go index da52cc6fd9..c85c02ea3a 100644 --- a/pkg/cloudprovider/modelarts_pool.go +++ b/pkg/cloudprovider/modelarts_pool.go @@ -31,3 +31,7 @@ type Azs struct { Az string `json:"az"` Count int `json:"count"` } + +type ModelartsPoolChangeConfigOptions struct { + NodeCount int +} diff --git a/pkg/compute/models/modelarts_pools.go b/pkg/compute/models/modelarts_pools.go index f244038052..052b9a3ac3 100644 --- a/pkg/compute/models/modelarts_pools.go +++ b/pkg/compute/models/modelarts_pools.go @@ -365,6 +365,23 @@ func (self *SModelartsPool) StartDeleteTask(ctx context.Context, userCred mcclie return nil } +func (self *SModelartsPool) PerformChangeConfig(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ModelartsPoolChangeConfigInput) (jsonutils.JSONObject, error) { + if input.NodeCount == self.NodeCount { + return nil, nil + } + return nil, self.StartChangeConfigTask(ctx, userCred, input) +} + +func (self *SModelartsPool) StartChangeConfigTask(ctx context.Context, userCred mcclient.TokenCredential, input api.ModelartsPoolChangeConfigInput) error { + params := jsonutils.Marshal(input).(*jsonutils.JSONDict) + task, err := taskman.TaskManager.NewTask(ctx, "ModelartsPoolChangeConfigTask", self, userCred, params, "", "", nil) + if err != nil { + return err + } + self.SetStatus(userCred, api.MODELARTS_POOL_STATUS_CHANGE_CONFIG, "") + return task.ScheduleRun(nil) +} + func (self *SModelartsPool) GetIRegion() (cloudprovider.ICloudRegion, error) { provider, err := self.GetDriver(context.Background()) if err != nil { diff --git a/pkg/compute/tasks/modelarts_pool_change_config_task.go b/pkg/compute/tasks/modelarts_pool_change_config_task.go new file mode 100644 index 0000000000..d8ed64f396 --- /dev/null +++ b/pkg/compute/tasks/modelarts_pool_change_config_task.go @@ -0,0 +1,79 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tasks + +import ( + "context" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ModelartsPoolChangeConfigTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ModelartsPoolChangeConfigTask{}) +} + +func (self *ModelartsPoolChangeConfigTask) taskFailed(ctx context.Context, mp *models.SModelartsPool, err error) { + mp.SetStatus(self.UserCred, api.MODELARTS_POOL_STATUS_UNKNOWN, err.Error()) + db.OpsLog.LogEvent(mp, db.ACT_CHANGE_CONFIG, err, self.UserCred) + logclient.AddActionLogWithStartable(self, mp, logclient.ACT_CHANGE_CONFIG, err, self.UserCred, false) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) +} + +func (self *ModelartsPoolChangeConfigTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) { + pool := obj.(*models.SModelartsPool) + iMp, err := pool.GetIModelartsPool() + if err != nil { + self.taskFailed(ctx, pool, errors.Wrapf(err, "iMp.GetIModelartsPoolById")) + return + } + input := &api.ModelartsPoolChangeConfigInput{} + self.GetParams().Unmarshal(input) + opts := &cloudprovider.ModelartsPoolChangeConfigOptions{} + opts.NodeCount = input.NodeCount + err = iMp.ChangeConfig(opts) + if err != nil { + self.taskFailed(ctx, pool, errors.Wrapf(err, "iMp.ChangeConfig")) + return + } + err = cloudprovider.WaitStatusWithDelay(iMp, api.MODELARTS_POOL_STATUS_RUNNING, 30*time.Second, 15*time.Second, 30*time.Minute) + if err != nil { + self.taskFailed(ctx, pool, errors.Wrapf(err, "WaitStatusWithDelay")) + return + } + pool.SyncWithCloudModelartsPool(ctx, self.GetUserCred(), iMp) + self.taskComplete(ctx, pool) +} + +func (self *ModelartsPoolChangeConfigTask) taskComplete(ctx context.Context, pool *models.SModelartsPool) { + notifyclient.EventNotify(ctx, self.UserCred, notifyclient.SEventNotifyParam{ + Obj: self, + Action: notifyclient.ActionChangeConfig, + }) + self.SetStageComplete(ctx, nil) +} diff --git a/pkg/compute/tasks/modelarts_pool_delete_task.go b/pkg/compute/tasks/modelarts_pool_delete_task.go index 2b0198808c..9d3e60ee53 100644 --- a/pkg/compute/tasks/modelarts_pool_delete_task.go +++ b/pkg/compute/tasks/modelarts_pool_delete_task.go @@ -21,7 +21,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" + apis "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" @@ -39,7 +39,7 @@ func init() { } func (self *ModelartsPoolDeleteTask) taskFailed(ctx context.Context, mp *models.SModelartsPool, err error) { - mp.SetStatus(self.UserCred, api.NAS_STATUS_DELETE_FAILED, err.Error()) + mp.SetStatus(self.UserCred, apis.STATUS_DELETE_FAILED, err.Error()) db.OpsLog.LogEvent(mp, db.ACT_DELETE_FAIL, err, self.UserCred) logclient.AddActionLogWithStartable(self, mp, logclient.ACT_DELOCATE, err, self.UserCred, false) self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) diff --git a/pkg/mcclient/options/compute/modelarts_pool.go b/pkg/mcclient/options/compute/modelarts_pool.go index b20772935b..f826539960 100644 --- a/pkg/mcclient/options/compute/modelarts_pool.go +++ b/pkg/mcclient/options/compute/modelarts_pool.go @@ -65,7 +65,7 @@ func (opts *ModelartsPoolUpdateOption) GetId() string { } func (opts *ModelartsPoolUpdateOption) Params() (jsonutils.JSONObject, error) { - return options.ListStructToParams(opts) + return options.StructToParams(opts) } type ModelartsPoolSyncstatusOption struct { @@ -77,5 +77,18 @@ func (opts *ModelartsPoolSyncstatusOption) GetId() string { } func (opts *ModelartsPoolSyncstatusOption) Params() (jsonutils.JSONObject, error) { - return options.ListStructToParams(opts) + return options.StructToParams(opts) +} + +type ModelartsPoolChangeConfigOption struct { + ID string `help:"Id"` + NodeCount int +} + +func (opts *ModelartsPoolChangeConfigOption) GetId() string { + return opts.ID +} + +func (opts *ModelartsPoolChangeConfigOption) Params() (jsonutils.JSONObject, error) { + return options.StructToParams(opts) } diff --git a/pkg/multicloud/hcso/modelarts.go b/pkg/multicloud/hcso/modelarts.go index 46f9c2edf4..0361ee4f5b 100644 --- a/pkg/multicloud/hcso/modelarts.go +++ b/pkg/multicloud/hcso/modelarts.go @@ -374,3 +374,21 @@ func (self *SModelartsPool) GetNodeCount() int { } return self.Spec.Resource[0].Count } + +func (self *SModelartsPool) ChangeConfig(opts *cloudprovider.ModelartsPoolChangeConfigOptions) error { + //{"spec":{"resources":[{"flavor":"modelarts.kat1.8xlarge","count":2}]}} + res := []map[string]interface{}{} + for _, re := range self.Spec.Resource { + res = append(res, map[string]interface{}{ + "flavor": re.Flavor, + "count": opts.NodeCount, + }) + } + params := map[string]interface{}{ + "spec": map[string]interface{}{ + "resources": res, + }, + } + _, err := self.region.client.modelartsPoolUpdate(self.Metadata.Name, params) + return err +} diff --git a/pkg/multicloud/huawei/modelarts_pool.go b/pkg/multicloud/huawei/modelarts_pool.go index 1d82de9c5e..61e6065a84 100644 --- a/pkg/multicloud/huawei/modelarts_pool.go +++ b/pkg/multicloud/huawei/modelarts_pool.go @@ -373,3 +373,21 @@ func (self *SModelartsPool) GetNodeCount() int { } return self.Spec.Resource[0].Count } + +func (self *SModelartsPool) ChangeConfig(opts *cloudprovider.ModelartsPoolChangeConfigOptions) error { + //{"spec":{"resources":[{"flavor":"modelarts.kat1.8xlarge","count":2}]}} + res := []map[string]interface{}{} + for _, re := range self.Spec.Resource { + res = append(res, map[string]interface{}{ + "flavor": re.Flavor, + "count": opts.NodeCount, + }) + } + params := map[string]interface{}{ + "spec": map[string]interface{}{ + "resources": res, + }, + } + _, err := self.region.client.modelartsPoolUpdate(self.Metadata.Name, params) + return err +}