From ee72b8862ffc378c6546d03635dd7aec8cfb780d Mon Sep 17 00:00:00 2001 From: mhf Date: Thu, 13 Apr 2023 16:23:51 +0800 Subject: [PATCH] fix(region): fixModelarts --- build/docker/Dockerfile.esxi-agent | 2 - go.mod | 4 +- go.sum | 8 +- pkg/compute/models/modelarts_pools.go | 3 +- .../tasks/modelarts_pool_create_task.go | 41 +++--- .../tasks/modelarts_pool_delete_task.go | 22 ++-- vendor/modules.txt | 4 +- .../pkg/cloudprovider/cloudprovider.go | 3 +- .../x/cloudmux/pkg/cloudprovider/resources.go | 2 +- .../x/cloudmux/pkg/multicloud/esxi/ovf.go | 20 ++- .../x/cloudmux/pkg/multicloud/esxi/storage.go | 6 +- .../x/cloudmux/pkg/multicloud/hcso/hcso.go | 10 +- .../cloudmux/pkg/multicloud/hcso/modelarts.go | 73 +++++++---- .../pkg/multicloud/huawei/modelarts_pool.go | 55 +++++--- .../x/cloudmux/pkg/multicloud/region_base.go | 6 +- vendor/yunion.io/x/jsonutils/marshal.go | 6 + vendor/yunion.io/x/jsonutils/std_json.go | 119 ++++++++++++++++++ vendor/yunion.io/x/jsonutils/unmarshal.go | 31 +++++ 18 files changed, 328 insertions(+), 87 deletions(-) rename build/esxi-agent/root/opt/yunion/share/vmware/ovf.xml => vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/ovf.go (82%) create mode 100644 vendor/yunion.io/x/jsonutils/std_json.go diff --git a/build/docker/Dockerfile.esxi-agent b/build/docker/Dockerfile.esxi-agent index 3f71ba6873..6ecc25ee91 100644 --- a/build/docker/Dockerfile.esxi-agent +++ b/build/docker/Dockerfile.esxi-agent @@ -1,5 +1,3 @@ FROM registry.cn-beijing.aliyuncs.com/yunionio/onecloud-base:v0.3.5-1 -COPY ./build/esxi-agent/root/opt/ /opt/ - ADD ./_output/alpine-build/bin/esxi-agent /opt/yunion/bin/esxi-agent diff --git a/go.mod b/go.mod index 2ff8791292..faca96ce61 100644 --- a/go.mod +++ b/go.mod @@ -84,9 +84,9 @@ require ( k8s.io/client-go v0.19.3 k8s.io/cluster-bootstrap v0.19.3 moul.io/http2curl/v2 v2.3.0 - yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230407102918-dd668c09f13d + yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230413051450-19d2c693bfa2 yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 - yunion.io/x/jsonutils v1.0.1-0.20220819091305-3bab322ab4fd + yunion.io/x/jsonutils v1.0.1-0.20230412125709-357258302671 yunion.io/x/log v1.0.1-0.20230411060016-feb3f46ab361 yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900 yunion.io/x/pkg v1.0.1-0.20230327034731-79f520e7d373 diff --git a/go.sum b/go.sum index f468982963..1e3a834e2e 100644 --- a/go.sum +++ b/go.sum @@ -1185,14 +1185,14 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230407102918-dd668c09f13d h1:6UQnGSIqyux7wF9qJdEXwluos8Mb9zQoEzxq2U91ugs= -yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230407102918-dd668c09f13d/go.mod h1:VBAtfyGMDW11x5JmF0vUEmn/PmNpZ8CKBAQCiyz+cDY= +yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230413051450-19d2c693bfa2 h1:/VWhFOinPOIoaA8v7eqndrrkaAzu9tWrauRXiJvrIO4= +yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230413051450-19d2c693bfa2/go.mod h1:VBAtfyGMDW11x5JmF0vUEmn/PmNpZ8CKBAQCiyz+cDY= yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 h1:0zlZD5uhZoIHgLVAWCz2aHaYk2ZrNsACCYD7R6EIBII= yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws= yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634= yunion.io/x/jsonutils v0.0.0-20220106020632-953b71a4c3a8/go.mod h1:p0nyMqGA/apTxxyLIU/o1k4V7Vujl2O6ey30L594sYE= -yunion.io/x/jsonutils v1.0.1-0.20220819091305-3bab322ab4fd h1:QUAIH9oqQoDRz/byjE8id4yZE1qbCc53QzhsfcLzQp8= -yunion.io/x/jsonutils v1.0.1-0.20220819091305-3bab322ab4fd/go.mod h1:L5QYTYqiL+f56wzir14TWHurE3Vcn9elaFiQpPWhXsg= +yunion.io/x/jsonutils v1.0.1-0.20230412125709-357258302671 h1:bx33Bs3JeAf+OF6oGXGC4x181w8f7Qwcu3XLDTwVXIA= +yunion.io/x/jsonutils v1.0.1-0.20230412125709-357258302671/go.mod h1:L5QYTYqiL+f56wzir14TWHurE3Vcn9elaFiQpPWhXsg= yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE= yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U= yunion.io/x/log v1.0.0/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U= diff --git a/pkg/compute/models/modelarts_pools.go b/pkg/compute/models/modelarts_pools.go index 15bbf63208..775f0dd191 100644 --- a/pkg/compute/models/modelarts_pools.go +++ b/pkg/compute/models/modelarts_pools.go @@ -24,6 +24,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/util/netutils" + "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" billing_api "yunion.io/x/onecloud/pkg/apis/billing" @@ -302,7 +303,7 @@ func (self *SModelartsPool) ValidateDeleteCondition(ctx context.Context, info js if self.DisableDelete.IsTrue() { return httperrors.NewInvalidStatusError("ModelartsPool is locked, cannot delete") } - if self.Status != api.MODELARTS_POOL_STATUS_RUNNING && self.Status != api.MODELARTS_POOL_STATUS_UNKNOWN { + if utils.IsInStringArray(self.Status, []string{api.MODELARTS_POOL_STATUS_CREATING, api.MODELARTS_POOL_STATUS_DELETING}) { return httperrors.NewInvalidStatusError("ModelartsPool status cannot support delete") } return self.SStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, nil) diff --git a/pkg/compute/tasks/modelarts_pool_create_task.go b/pkg/compute/tasks/modelarts_pool_create_task.go index 07aa29975f..cb07742f27 100644 --- a/pkg/compute/tasks/modelarts_pool_create_task.go +++ b/pkg/compute/tasks/modelarts_pool_create_task.go @@ -17,7 +17,6 @@ package tasks import ( "context" "strings" - "time" "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" @@ -48,11 +47,6 @@ func (modelartsCreateTask *ModelartsPoolCreateTask) taskFailed(ctx context.Conte func (modelartsCreateTask *ModelartsPoolCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) { pool := obj.(*models.SModelartsPool) - iRegion, err := pool.GetIRegion() - if err != nil { - modelartsCreateTask.taskFailed(ctx, pool, api.MODELARTS_POOL_STATUS_CREATE_FAILED, errors.Wrapf(err, "pool.GetIRegion")) - return - } opts := &cloudprovider.ModelartsPoolCreateOption{ Name: pool.Name, @@ -62,19 +56,9 @@ func (modelartsCreateTask *ModelartsPoolCreateTask) OnInit(ctx context.Context, Cidr: pool.Cidr, } - ipool, err := iRegion.CreateIModelartsPool(opts) - if err != nil { - modelartsCreateTask.taskFailed(ctx, pool, api.MODELARTS_POOL_STATUS_CREATE_FAILED, errors.Wrapf(err, "iRegion.CreateIModelartsPool")) - return - } - err = db.SetExternalId(pool, modelartsCreateTask.GetUserCred(), ipool.GetGlobalId()) - if err != nil { - modelartsCreateTask.taskFailed(ctx, pool, api.MODELARTS_POOL_STATUS_CREATE_FAILED, errors.Wrapf(err, "db.SetExternalId")) - return - } modelartsCreateTask.SetStage("OnModelartsPoolCreateComplete", nil) // withDelay - modelartsCreateTask.WaitStatus(ctx, ipool, pool) + modelartsCreateTask.WaitStatus(ctx, opts, pool) } func (modelartsCreateTask *ModelartsPoolCreateTask) taskComplete(ctx context.Context, pool *models.SModelartsPool) { @@ -85,17 +69,26 @@ func (modelartsCreateTask *ModelartsPoolCreateTask) taskComplete(ctx context.Con }) } -func (modelartsCreateTask *ModelartsPoolCreateTask) WaitStatus(ctx context.Context, ipool cloudprovider.ICloudModelartsPool, pool *models.SModelartsPool) error { +func (modelartsCreateTask *ModelartsPoolCreateTask) WaitStatus(ctx context.Context, opts *cloudprovider.ModelartsPoolCreateOption, pool *models.SModelartsPool) error { taskman.LocalTaskRun(modelartsCreateTask, func() (jsonutils.JSONObject, error) { - time.Sleep(2 * time.Minute) - err := cloudprovider.WaitMultiStatus(ipool, []string{api.MODELARTS_POOL_STATUS_RUNNING, api.MODELARTS_POOL_STATUS_CREATE_FAILED}, 15*time.Second, 2*time.Hour) + iRegion, err := pool.GetIRegion() if err != nil { - return nil, err + return nil, errors.Wrapf(err, "pool.GetIRegion") } - if ipool.GetStatus() == api.MODELARTS_POOL_STATUS_CREATE_FAILED { - return nil, errors.Error("create_failed") - } else { + callback := func(id string) { + db.SetExternalId(pool, modelartsCreateTask.GetUserCred(), id) + } + ipool, err := iRegion.CreateIModelartsPool(opts, callback) + if err != nil { + return nil, errors.Wrapf(err, "iRegion.CreateIModelartsPool") + } + switch ipool.GetStatus() { + case api.MODELARTS_POOL_STATUS_RUNNING: return nil, nil + case api.MODELARTS_POOL_STATUS_CREATE_FAILED: + return nil, errors.Errorf(ipool.GetStatusMessage()) + default: + return nil, errors.Errorf(ipool.GetStatus()) } }) return nil diff --git a/pkg/compute/tasks/modelarts_pool_delete_task.go b/pkg/compute/tasks/modelarts_pool_delete_task.go index 5f8c468a87..d84716d247 100644 --- a/pkg/compute/tasks/modelarts_pool_delete_task.go +++ b/pkg/compute/tasks/modelarts_pool_delete_task.go @@ -38,8 +38,8 @@ func init() { taskman.RegisterTask(ModelartsPoolDeleteTask{}) } -func (modelartsDeleteTask *ModelartsPoolDeleteTask) taskFailed(ctx context.Context, mp *models.SModelartsPool, err error) { - mp.SetStatus(modelartsDeleteTask.UserCred, api.MODELARTS_POOL_STATUS_DELETE_FAILED, err.Error()) +func (modelartsDeleteTask *ModelartsPoolDeleteTask) taskFailed(ctx context.Context, status string, mp *models.SModelartsPool, err error) { + mp.SetStatus(modelartsDeleteTask.UserCred, status, err.Error()) db.OpsLog.LogEvent(mp, db.ACT_DELETE_FAIL, err, modelartsDeleteTask.UserCred) logclient.AddActionLogWithStartable(modelartsDeleteTask, mp, logclient.ACT_DELOCATE, err, modelartsDeleteTask.UserCred, false) modelartsDeleteTask.SetStageFailed(ctx, jsonutils.NewString(err.Error())) @@ -58,18 +58,26 @@ func (modelartsDeleteTask *ModelartsPoolDeleteTask) OnInit(ctx context.Context, modelartsDeleteTask.taskComplete(ctx, pool) return } - modelartsDeleteTask.taskFailed(ctx, pool, errors.Wrapf(err, "iMp.GetIModelartsPoolById")) + modelartsDeleteTask.taskFailed(ctx, api.MODELARTS_POOL_STATUS_DELETE_FAILED, pool, errors.Wrapf(err, "iMp.GetIModelartsPoolById")) return } err = iMp.Delete() if err != nil { - modelartsDeleteTask.taskFailed(ctx, pool, errors.Wrapf(err, "iMp.Delete")) + modelartsDeleteTask.taskFailed(ctx, api.MODELARTS_POOL_STATUS_DELETE_FAILED, pool, errors.Wrapf(err, "iMp.Delete")) return } - err = cloudprovider.WaitDeleted(iMp, time.Second*10, time.Minute*10) + err = cloudprovider.WaitStatus(iMp, api.MODELARTS_POOL_STATUS_UNKNOWN, time.Second*15, time.Minute*20) if err != nil { - modelartsDeleteTask.taskFailed(ctx, pool, errors.Wrapf(err, "iMp.WaitDeleted")) - return + if errors.Cause(err) == errors.ErrTimeout { + modelartsDeleteTask.taskFailed(ctx, api.MODELARTS_POOL_STATUS_TIMEOUT, pool, errors.Wrapf(err, "ErrTimeout")) + return + } else if errors.Cause(err) == errors.ErrNotFound { + modelartsDeleteTask.taskComplete(ctx, pool) + return + } else { + modelartsDeleteTask.taskFailed(ctx, api.MODELARTS_POOL_STATUS_DELETE_FAILED, pool, errors.Wrapf(err, "default:")) + return + } } modelartsDeleteTask.taskComplete(ctx, pool) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 17f8c34bb6..d35306ab86 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1457,7 +1457,7 @@ sigs.k8s.io/structured-merge-diff/v4/value # sigs.k8s.io/yaml v1.2.0 ## explicit; go 1.12 sigs.k8s.io/yaml -# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230407102918-dd668c09f13d +# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20230413051450-19d2c693bfa2 ## explicit; go 1.18 yunion.io/x/cloudmux/pkg/apis yunion.io/x/cloudmux/pkg/apis/billing @@ -1536,7 +1536,7 @@ yunion.io/x/cloudmux/pkg/multicloud/zstack/provider yunion.io/x/executor/apis yunion.io/x/executor/client yunion.io/x/executor/server -# yunion.io/x/jsonutils v1.0.1-0.20220819091305-3bab322ab4fd +# yunion.io/x/jsonutils v1.0.1-0.20230412125709-357258302671 ## explicit; go 1.12 yunion.io/x/jsonutils # yunion.io/x/log v1.0.1-0.20230411060016-feb3f46ab361 diff --git a/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudprovider.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudprovider.go index 6795b21d28..3b2737d5ad 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudprovider.go +++ b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudprovider.go @@ -629,7 +629,7 @@ func (self *SBaseProvider) GetIModelartsPoolById(id string) (ICloudModelartsPool return nil, errors.Wrapf(ErrNotImplemented, "GetIModelartsPoolDetail") } -func (self *SBaseProvider) CreateIModelartsPool(pool *ModelartsPoolCreateOption) (ICloudModelartsPool, error) { +func (self *SBaseProvider) CreateIModelartsPool(pool *ModelartsPoolCreateOption, callback func(id string)) (ICloudModelartsPool, error) { return nil, errors.Wrapf(ErrNotImplemented, "CreateIModelartsPool") } @@ -938,6 +938,7 @@ type ICloudModelartsPool interface { GetWorkType() string GetNodeCount() int ChangeConfig(opts *ModelartsPoolChangeConfigOptions) error + GetStatusMessage() string } type ICloudModelartsPoolSku interface { diff --git a/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resources.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resources.go index b9ee7c3a66..a1a8d22ad6 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resources.go +++ b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resources.go @@ -194,7 +194,7 @@ type ICloudRegion interface { GetIModelartsPools() ([]ICloudModelartsPool, error) GetIModelartsPoolById(id string) (ICloudModelartsPool, error) - CreateIModelartsPool(pool *ModelartsPoolCreateOption) (ICloudModelartsPool, error) + CreateIModelartsPool(pool *ModelartsPoolCreateOption, callback func(externalId string)) (ICloudModelartsPool, error) GetIModelartsPoolSku() ([]ICloudModelartsPoolSku, error) GetIMiscResources() ([]ICloudMiscResource, error) diff --git a/build/esxi-agent/root/opt/yunion/share/vmware/ovf.xml b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/ovf.go similarity index 82% rename from build/esxi-agent/root/opt/yunion/share/vmware/ovf.xml rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/ovf.go index a62536bfe8..c3af4badb0 100644 --- a/build/esxi-agent/root/opt/yunion/share/vmware/ovf.xml +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/ovf.go @@ -1,4 +1,20 @@ - +// 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 esxi + +var ovfTemplate = ` - +` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go index 743ab5eb56..93f0bea4c4 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go @@ -1075,14 +1075,14 @@ func stat(name string) (*info, error) { func (di *info) ovf() (string, error) { var buf bytes.Buffer - tmpl, err := template.ParseFiles("/opt/yunion/share/vmware/ovf.xml") + tmpl, err := template.New("ovf").Parse(ovfTemplate) if err != nil { - return "", err + return "", errors.Wrapf(err, "template.New") } err = tmpl.Execute(&buf, di) if err != nil { - return "", err + return "", errors.Wrapf(err, "tmpl.Execute") } return buf.String(), nil diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/hcso.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/hcso.go index e83425dec4..abc59d4eff 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/hcso.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/hcso.go @@ -191,7 +191,15 @@ func (self *SHuaweiClient) modelartsPoolNetworkCreate(params map[string]interfac func (self *SHuaweiClient) modelartsPoolById(poolName string) (jsonutils.JSONObject, error) { endpoint := self.resetEndpoint(self.endpoints.Modelarts, "modelarts") uri := fmt.Sprintf("https://%s/v2/%s/pools/%s", endpoint, self.projectId, poolName) - return self.request(httputils.GET, uri, url.Values{}, nil) + res, err := self.request(httputils.GET, uri, url.Values{}, nil) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return nil, errors.ErrNotFound + } else { + return nil, err + } + } + return res, nil } func (cli *SHuaweiClient) modelartsPoolListWithStatus(resource, status string, params map[string]interface{}) (jsonutils.JSONObject, error) { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go index 06b6513fd4..58ac37e4f9 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go @@ -21,6 +21,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/billing" + "yunion.io/x/pkg/utils" billing_api "yunion.io/x/cloudmux/pkg/apis/billing" "yunion.io/x/cloudmux/pkg/apis/compute" @@ -130,7 +131,7 @@ func (self *SRegion) GetIModelartsPools() ([]cloudprovider.ICloudModelartsPool, return res, nil } -func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption) (cloudprovider.ICloudModelartsPool, error) { +func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption, callback func(id string)) (cloudprovider.ICloudModelartsPool, error) { if len(args.Cidr) == 0 { args.Cidr = "192.168.128.0/17" } @@ -196,15 +197,36 @@ func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreat if err != nil { return nil, errors.Wrap(err, "SHuaweiClient.CreatePools") } - pool := &SModelartsPool{} - obj.Unmarshal(&pool) - res := []cloudprovider.ICloudModelartsPool{} - for i := 0; i < 1; i++ { - pool.region = self - res = append(res, pool) + pool := &SModelartsPool{ + region: self, } + obj.Unmarshal(pool) + if callback != nil { + callback(pool.GetId()) + } + // 对于新建后可能会存在一段时间list查不到 + time.Sleep(2 * time.Minute) + return self.waitCreate(pool) +} - return res[0], nil +func (region *SRegion) waitCreate(pool *SModelartsPool) (cloudprovider.ICloudModelartsPool, error) { + startTime := time.Now() + for time.Since(startTime) < 2*time.Hour { + pool.RefreshForCreate() + if utils.IsInStringArray(pool.GetStatus(), []string{compute.MODELARTS_POOL_STATUS_RUNNING, compute.MODELARTS_POOL_STATUS_CREATE_FAILED}) { + return pool, nil + } + time.Sleep(15 * time.Second) + } + return nil, errors.ErrTimeout +} + +func (self *SRegion) GetIModelartsPoolsWithStatus(status string) ([]jsonutils.JSONObject, error) { + resObj, err := self.client.modelartsPoolListWithStatus("pools", status, nil) + if err != nil { + return nil, err + } + return resObj.GetArray("items") } func (self *SRegion) DeletePool(poolName string) (jsonutils.JSONObject, error) { @@ -219,14 +241,11 @@ func (self *SRegion) GetIModelartsPoolById(poolId string) (cloudprovider.ICloudM } return nil, errors.Wrap(err, "region.modelartsPoolByName") } - pool := &SModelartsPool{} - obj.Unmarshal(&pool) - res := []cloudprovider.ICloudModelartsPool{} - for i := 0; i < 1; i++ { - pool.region = self - res = append(res, pool) + pool := &SModelartsPool{ + region: self, } - return res[0], nil + obj.Unmarshal(pool) + return pool, nil } func (self *SRegion) MonitorPool(poolId string) (*SModelartsMetrics, error) { @@ -385,15 +404,14 @@ func (self *SModelartsPool) SetAutoRenew(bc billing.SBillingCycle) error { return nil } -func (self *SModelartsPool) Refresh() error { +func (self *SModelartsPool) RefreshForCreate() error { self.Status.Resource = SNodeStatus{} pool, err := self.region.client.modelartsPoolById(self.GetId()) if err == nil { - pool.Unmarshal(self) - return nil + return pool.Unmarshal(self) } - if !strings.Contains(err.Error(), "not found") { - return errors.Wrap(err, "modelartsPoolById") + if errors.Cause(err) != errors.ErrNotFound { + return err } pools := make([]SModelartsPool, 0) @@ -413,7 +431,16 @@ func (self *SModelartsPool) Refresh() error { return jsonutils.Update(self, pool) } } - return nil + return err +} + +func (self *SModelartsPool) Refresh() error { + self.Status.Resource = SNodeStatus{} + pool, err := self.region.client.modelartsPoolById(self.GetId()) + if err != nil { + return err + } + return pool.Unmarshal(self) } func (self *SModelartsPool) SetTags(tags map[string]string, replace bool) error { @@ -428,6 +455,10 @@ func (self *SModelartsPool) Delete() error { return nil } +func (self *SModelartsPool) GetStatusMessage() string { + return self.Status.Message +} + func (self *SModelartsPool) GetInstanceType() string { return self.Spec.Resource[0].Flavor diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go index c3cb175e80..c3523d8c2b 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go @@ -21,6 +21,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/billing" + "yunion.io/x/pkg/utils" billing_api "yunion.io/x/cloudmux/pkg/apis/billing" "yunion.io/x/cloudmux/pkg/apis/compute" @@ -129,7 +130,7 @@ func (self *SRegion) GetIModelartsPools() ([]cloudprovider.ICloudModelartsPool, return res, nil } -func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption) (cloudprovider.ICloudModelartsPool, error) { +func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption, callback func(id string)) (cloudprovider.ICloudModelartsPool, error) { if len(args.Cidr) == 0 { args.Cidr = "192.168.20.0/24" } @@ -195,15 +196,28 @@ func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreat if err != nil { return nil, errors.Wrap(err, "SHuaweiClient.CreatePools") } - pool := &SModelartsPool{} - obj.Unmarshal(&pool) - res := []cloudprovider.ICloudModelartsPool{} - for i := 0; i < 1; i++ { - pool.region = self - res = append(res, pool) + pool := &SModelartsPool{ + region: self, } + obj.Unmarshal(pool) + if callback != nil { + callback(pool.GetId()) + } + // 对于新建后可能会存在一段时间list查不到 + time.Sleep(2 * time.Minute) + return self.waitCreate(pool) +} - return res[0], nil +func (region *SRegion) waitCreate(pool *SModelartsPool) (cloudprovider.ICloudModelartsPool, error) { + startTime := time.Now() + for time.Since(startTime) < 2*time.Hour { + pool.RefreshForCreate() + if utils.IsInStringArray(pool.GetStatus(), []string{compute.MODELARTS_POOL_STATUS_RUNNING, compute.MODELARTS_POOL_STATUS_CREATE_FAILED}) { + return pool, nil + } + time.Sleep(15 * time.Second) + } + return nil, errors.ErrTimeout } func (self *SRegion) DeletePool(poolName string) (jsonutils.JSONObject, error) { @@ -339,6 +353,10 @@ func (self *SModelartsPool) GetStatus() string { return res } +func (self *SModelartsPool) GetStatusMessage() string { + return self.Status.Message +} + func (self *SModelartsPool) GetSysTags() map[string]string { return nil } @@ -384,15 +402,14 @@ func (self *SModelartsPool) SetAutoRenew(bc billing.SBillingCycle) error { return nil } -func (self *SModelartsPool) Refresh() error { +func (self *SModelartsPool) RefreshForCreate() error { self.Status.Resource = SNodeStatus{} pool, err := self.region.client.modelartsPoolById(self.GetId()) if err == nil { - pool.Unmarshal(self) - return nil + return pool.Unmarshal(self) } - if !strings.Contains(err.Error(), "not found") { - return errors.Wrap(err, "modelartsPoolById") + if errors.Cause(err) != errors.ErrNotFound { + return err } pools := make([]SModelartsPool, 0) @@ -412,7 +429,16 @@ func (self *SModelartsPool) Refresh() error { return jsonutils.Update(self, pool) } } - return nil + return err +} + +func (self *SModelartsPool) Refresh() error { + self.Status.Resource = SNodeStatus{} + pool, err := self.region.client.modelartsPoolById(self.GetId()) + if err != nil { + return err + } + return pool.Unmarshal(self) } func (self *SModelartsPool) SetTags(tags map[string]string, replace bool) error { @@ -429,7 +455,6 @@ func (self *SModelartsPool) Delete() error { func (self *SModelartsPool) GetInstanceType() string { return self.Spec.Resource[0].Flavor - } func (self *SModelartsPool) GetWorkType() string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/region_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/region_base.go index 4a168d0f43..3e2d7bc0ce 100644 --- a/vendor/yunion.io/x/cloudmux/pkg/multicloud/region_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/region_base.go @@ -385,10 +385,14 @@ func (self *SRegion) GetIModelartsPoolById(id string) (cloudprovider.ICloudModel return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIModelartsPoolDetail") } -func (self *SRegion) CreateIModelartsPool(pool *cloudprovider.ModelartsPoolCreateOption) (cloudprovider.ICloudModelartsPool, error) { +func (self *SRegion) CreateIModelartsPool(pool *cloudprovider.ModelartsPoolCreateOption, callback func(id string)) (cloudprovider.ICloudModelartsPool, error) { return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateIModelartsPool") } +func (self *SRegion) GetStatusMessage() string { + return "" +} + func (self *SRegion) GetIModelartsPoolSku() ([]cloudprovider.ICloudModelartsPoolSku, error) { return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetIModelartsPoolSku") } diff --git a/vendor/yunion.io/x/jsonutils/marshal.go b/vendor/yunion.io/x/jsonutils/marshal.go index c1c1279ec5..f1095fb341 100644 --- a/vendor/yunion.io/x/jsonutils/marshal.go +++ b/vendor/yunion.io/x/jsonutils/marshal.go @@ -251,6 +251,12 @@ func Marshal(obj interface{}) JSONObject { } func marshalValue(objValue reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { + return tryStdMarshal(objValue, func(v reflect.Value) JSONObject { + return _marshalValue(v, info, omitEmpty) + }) +} + +func _marshalValue(objValue reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { switch objValue.Type() { case JSONDictPtrType, JSONArrayPtrType, JSONBoolPtrType, JSONIntPtrType, JSONFloatPtrType, JSONStringPtrType, JSONObjectType: if objValue.IsNil() { diff --git a/vendor/yunion.io/x/jsonutils/std_json.go b/vendor/yunion.io/x/jsonutils/std_json.go new file mode 100644 index 0000000000..15622270df --- /dev/null +++ b/vendor/yunion.io/x/jsonutils/std_json.go @@ -0,0 +1,119 @@ +// 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 jsonutils + +import ( + "encoding/json" + "fmt" + "reflect" +) + +func tryStdUnmarshal(jo JSONObject, v reflect.Value, unmarshalFunc func(value reflect.Value) error) error { + u := IsImplementStdUnmarshaler(v) + if u != nil { + return u.UnmarshalJSON([]byte(jo.String())) + } + return unmarshalFunc(v) +} + +func IsImplementStdUnmarshaler(v reflect.Value) json.Unmarshaler { + return indirectStdUnmarshaler(v) +} + +func indirectStdUnmarshaler(v reflect.Value) json.Unmarshaler { + v0 := v + haveAddr := false + + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && e.Elem().Kind() == reflect.Ptr { + haveAddr = false + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + // Prevent infinite loop if v is an interface pointing to its own address: + // var v interface{} + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(json.Unmarshaler); ok { + return u + } + } + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } + } + + return nil +} + +func IsImplementStdMarshaler(v reflect.Value) json.Marshaler { + return indirectStdMarshaler(v) +} + +func indirectStdMarshaler(v reflect.Value) json.Marshaler { + if v.Kind() == reflect.Ptr && v.IsNil() { + return nil + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(json.Marshaler); ok { + return u + } + } + return nil +} + +func tryStdMarshal(v reflect.Value, marshalFunc func(v reflect.Value) JSONObject) JSONObject { + m := IsImplementStdMarshaler(v) + if m != nil { + data, err := m.MarshalJSON() + if err != nil { + panic(fmt.Sprintf("MarshalJSON of %q error: %v", v.String(), err)) + } + jo, err := Parse(data) + if err != nil { + panic(fmt.Sprintf("Parse data %q to json of %q error: %v", data, v.String(), err)) + } + return jo + } + return marshalFunc(v) +} diff --git a/vendor/yunion.io/x/jsonutils/unmarshal.go b/vendor/yunion.io/x/jsonutils/unmarshal.go index 9dcdc72b61..95894595b0 100644 --- a/vendor/yunion.io/x/jsonutils/unmarshal.go +++ b/vendor/yunion.io/x/jsonutils/unmarshal.go @@ -50,6 +50,10 @@ func (this *JSONDict) Unmarshal(obj interface{}, keys ...string) error { return jsonUnmarshal(this, obj, keys) } +func (this *JSONString) Unmarshal(obj interface{}, keys ...string) error { + return jsonUnmarshal(this, obj, keys) +} + func jsonUnmarshal(jo JSONObject, o interface{}, keys []string) error { if len(keys) > 0 { var err error = nil @@ -75,6 +79,10 @@ func (this *JSONValue) unmarshalValue(val reflect.Value) error { } func (this *JSONInt) unmarshalValue(val reflect.Value) error { + return tryStdUnmarshal(this, val, this._unmarshalValue) +} + +func (this *JSONInt) _unmarshalValue(val reflect.Value) error { switch val.Type() { case JSONIntType: json := val.Interface().(JSONInt) @@ -137,6 +145,10 @@ func (this *JSONInt) unmarshalValue(val reflect.Value) error { } func (this *JSONBool) unmarshalValue(val reflect.Value) error { + return tryStdUnmarshal(this, val, this._unmarshalValue) +} + +func (this *JSONBool) _unmarshalValue(val reflect.Value) error { switch val.Type() { case JSONBoolType: json := val.Interface().(JSONBool) @@ -204,6 +216,10 @@ func (this *JSONBool) unmarshalValue(val reflect.Value) error { } func (this *JSONFloat) unmarshalValue(val reflect.Value) error { + return tryStdUnmarshal(this, val, this._unmarshalValue) +} + +func (this *JSONFloat) _unmarshalValue(val reflect.Value) error { switch val.Type() { case JSONFloatType: json := val.Interface().(JSONFloat) @@ -280,6 +296,13 @@ func (this *JSONFloat) unmarshalValue(val reflect.Value) error { } func (this *JSONString) unmarshalValue(val reflect.Value) error { + if val.Type() == gotypes.TimeType { + return this._unmarshalValue(val) + } + return tryStdUnmarshal(this, val, this._unmarshalValue) +} + +func (this *JSONString) _unmarshalValue(val reflect.Value) error { switch val.Type() { case JSONStringType: json := val.Interface().(JSONString) @@ -390,6 +413,10 @@ func (this *JSONString) unmarshalValue(val reflect.Value) error { } func (this *JSONArray) unmarshalValue(val reflect.Value) error { + return tryStdUnmarshal(this, val, this._unmarshalValue) +} + +func (this *JSONArray) _unmarshalValue(val reflect.Value) error { switch val.Type() { case JSONArrayType: array := val.Interface().(JSONArray) @@ -447,6 +474,10 @@ func (this *JSONArray) unmarshalValue(val reflect.Value) error { } func (this *JSONDict) unmarshalValue(val reflect.Value) error { + return tryStdUnmarshal(this, val, this._unmarshalValue) +} + +func (this *JSONDict) _unmarshalValue(val reflect.Value) error { switch val.Type() { case JSONDictType: dict := val.Interface().(JSONDict)