diff --git a/pkg/compute/models/app.go b/pkg/compute/models/app.go index a8c755eb49..192e26ea59 100644 --- a/pkg/compute/models/app.go +++ b/pkg/compute/models/app.go @@ -20,11 +20,13 @@ import ( "time" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" "yunion.io/x/pkg/util/compare" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -416,3 +418,36 @@ func (a *SApp) GetIApp() (cloudprovider.ICloudApp, error) { } return iRegion.GetICloudAppById(a.ExternalId) } + +func (self *SApp) AllowPerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "remote-update") +} + +func (self *SApp) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.MongoDBRemoteUpdateInput) (jsonutils.JSONObject, error) { + err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "") + if err != nil { + return nil, errors.Wrap(err, "StartRemoteUpdateTask") + } + return nil, nil +} + +func (self *SApp) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error { + data := jsonutils.NewDict() + data.Add(jsonutils.NewBool(replaceTags), "replace_tags") + task, err := taskman.TaskManager.NewTask(ctx, "AppRemoteUpdateTask", self, userCred, data, parentTaskId, "", nil) + if err != nil { + return errors.Wrap(err, "NewTask") + } + self.SetStatus(userCred, apis.STATUS_UPDATE_TAGS, "StartRemoteUpdateTask") + return task.ScheduleRun(nil) +} + +func (self *SApp) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) { + if len(self.ExternalId) == 0 { + return + } + err := self.StartRemoteUpdateTask(ctx, userCred, true, "") + if err != nil { + log.Errorf("StartRemoteUpdateTask fail: %s", err) + } +} diff --git a/pkg/compute/models/waf_instances.go b/pkg/compute/models/waf_instances.go index 407be3e6a5..e64ed80225 100644 --- a/pkg/compute/models/waf_instances.go +++ b/pkg/compute/models/waf_instances.go @@ -19,10 +19,12 @@ import ( "fmt" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -493,3 +495,36 @@ func (self *SWafInstance) AllowPerformSyncstatus(ctx context.Context, userCred m func (self *SWafInstance) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.WafSyncstatusInput) (jsonutils.JSONObject, error) { return nil, StartResourceSyncStatusTask(ctx, userCred, self, "WafSyncstatusTask", "") } + +func (self *SWafInstance) AllowPerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "remote-update") +} + +func (self *SWafInstance) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.MongoDBRemoteUpdateInput) (jsonutils.JSONObject, error) { + err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "") + if err != nil { + return nil, errors.Wrap(err, "StartRemoteUpdateTask") + } + return nil, nil +} + +func (self *SWafInstance) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error { + data := jsonutils.NewDict() + data.Add(jsonutils.NewBool(replaceTags), "replace_tags") + task, err := taskman.TaskManager.NewTask(ctx, "WafInstanceRemoteUpdateTask", self, userCred, data, parentTaskId, "", nil) + if err != nil { + return errors.Wrap(err, "NewTask") + } + self.SetStatus(userCred, apis.STATUS_UPDATE_TAGS, "StartRemoteUpdateTask") + return task.ScheduleRun(nil) +} + +func (self *SWafInstance) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) { + if len(self.ExternalId) == 0 { + return + } + err := self.StartRemoteUpdateTask(ctx, userCred, true, "") + if err != nil { + log.Errorf("StartRemoteUpdateTask fail: %s", err) + } +} diff --git a/pkg/compute/tasks/app_remote_update_task.go b/pkg/compute/tasks/app_remote_update_task.go new file mode 100644 index 0000000000..9371ea0c44 --- /dev/null +++ b/pkg/compute/tasks/app_remote_update_task.go @@ -0,0 +1,94 @@ +// 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" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "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/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type AppRemoteUpdateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(AppRemoteUpdateTask{}) +} + +func (self *AppRemoteUpdateTask) taskFail(ctx context.Context, app *models.SApp, err error) { + app.SetStatus(self.UserCred, apis.STATUS_UPDATE_TAGS_FAILED, err.Error()) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) +} + +func (self *AppRemoteUpdateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + app := obj.(*models.SApp) + replaceTags := jsonutils.QueryBoolean(self.Params, "replace_tags", false) + + iApp, err := app.GetIApp() + if err != nil { + self.taskFail(ctx, app, errors.Wrapf(err, "GetIApp")) + return + } + + oldTags, err := iApp.GetTags() + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented { + self.OnRemoteUpdateComplete(ctx, app, nil) + return + } + self.taskFail(ctx, app, errors.Wrapf(err, "GetTags")) + return + } + tags, err := app.GetAllUserMetadata() + if err != nil { + self.taskFail(ctx, app, errors.Wrapf(err, "GetAllUserMetadata")) + return + } + tagsUpdateInfo := cloudprovider.TagsUpdateInfo{OldTags: oldTags, NewTags: tags} + err = cloudprovider.SetTags(ctx, iApp, app.ManagerId, tags, replaceTags) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented { + self.OnRemoteUpdateComplete(ctx, app, nil) + return + } + logclient.AddActionLogWithStartable(self, app, logclient.ACT_UPDATE_TAGS, err, self.GetUserCred(), false) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) + return + } + logclient.AddActionLogWithStartable(self, app, logclient.ACT_UPDATE_TAGS, tagsUpdateInfo, self.GetUserCred(), true) + self.OnRemoteUpdateComplete(ctx, app, nil) +} + +func (self *AppRemoteUpdateTask) OnRemoteUpdateComplete(ctx context.Context, app *models.SApp, data jsonutils.JSONObject) { + self.SetStage("OnSyncStatusComplete", nil) + models.StartResourceSyncStatusTask(ctx, self.UserCred, app, "AppSyncstatusTask", self.GetTaskId()) +} + +func (self *AppRemoteUpdateTask) OnSyncStatusComplete(ctx context.Context, app *models.SApp, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *AppRemoteUpdateTask) OnSyncStatusCompleteFailed(ctx context.Context, app *models.SApp, data jsonutils.JSONObject) { + self.SetStageFailed(ctx, data) +} diff --git a/pkg/compute/tasks/waf_instance_remote_update_task.go b/pkg/compute/tasks/waf_instance_remote_update_task.go new file mode 100644 index 0000000000..7f3187470f --- /dev/null +++ b/pkg/compute/tasks/waf_instance_remote_update_task.go @@ -0,0 +1,94 @@ +// 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" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "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/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type WafInstanceRemoteUpdateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(WafInstanceRemoteUpdateTask{}) +} + +func (self *WafInstanceRemoteUpdateTask) taskFail(ctx context.Context, waf *models.SWafInstance, err error) { + waf.SetStatus(self.UserCred, apis.STATUS_UPDATE_TAGS_FAILED, err.Error()) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) +} + +func (self *WafInstanceRemoteUpdateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + waf := obj.(*models.SWafInstance) + replaceTags := jsonutils.QueryBoolean(self.Params, "replace_tags", false) + + iWaf, err := waf.GetICloudWafInstance() + if err != nil { + self.taskFail(ctx, waf, errors.Wrapf(err, "GetICloudWafInstance")) + return + } + + oldTags, err := iWaf.GetTags() + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented { + self.OnRemoteUpdateComplete(ctx, waf, nil) + return + } + self.taskFail(ctx, waf, errors.Wrapf(err, "GetTags")) + return + } + tags, err := waf.GetAllUserMetadata() + if err != nil { + self.taskFail(ctx, waf, errors.Wrapf(err, "GetAllUserMetadata")) + return + } + tagsUpdateInfo := cloudprovider.TagsUpdateInfo{OldTags: oldTags, NewTags: tags} + err = cloudprovider.SetTags(ctx, iWaf, waf.ManagerId, tags, replaceTags) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented { + self.OnRemoteUpdateComplete(ctx, waf, nil) + return + } + logclient.AddActionLogWithStartable(self, waf, logclient.ACT_UPDATE_TAGS, err, self.GetUserCred(), false) + self.SetStageFailed(ctx, jsonutils.NewString(err.Error())) + return + } + logclient.AddActionLogWithStartable(self, waf, logclient.ACT_UPDATE_TAGS, tagsUpdateInfo, self.GetUserCred(), true) + self.OnRemoteUpdateComplete(ctx, waf, nil) +} + +func (self *WafInstanceRemoteUpdateTask) OnRemoteUpdateComplete(ctx context.Context, waf *models.SWafInstance, data jsonutils.JSONObject) { + self.SetStage("OnSyncStatusComplete", nil) + models.StartResourceSyncStatusTask(ctx, self.UserCred, waf, "WafSyncstatusTask", self.GetTaskId()) +} + +func (self *WafInstanceRemoteUpdateTask) OnSyncStatusComplete(ctx context.Context, waf *models.SWafInstance, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *WafInstanceRemoteUpdateTask) OnSyncStatusCompleteFailed(ctx context.Context, waf *models.SWafInstance, data jsonutils.JSONObject) { + self.SetStageFailed(ctx, data) +} diff --git a/pkg/multicloud/azure/waf.go b/pkg/multicloud/azure/waf.go index 82d1e3f030..3eb8c9b1ae 100644 --- a/pkg/multicloud/azure/waf.go +++ b/pkg/multicloud/azure/waf.go @@ -639,3 +639,18 @@ func (self *SAppGatewayWaf) GetCloudResources() ([]cloudprovider.SCloudResource, } return ret, nil } + +func (self *SAppGatewayWaf) SetTags(tags map[string]string, replace bool) error { + if !replace { + for k, v := range self.Tags { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + _, err := self.region.client.SetTags(self.ID, tags) + if err != nil { + return errors.Wrapf(err, "SetTags") + } + return nil +} diff --git a/pkg/multicloud/azure/web_app.go b/pkg/multicloud/azure/web_app.go index a31e6ab766..e2603b9238 100644 --- a/pkg/multicloud/azure/web_app.go +++ b/pkg/multicloud/azure/web_app.go @@ -300,3 +300,18 @@ func (a *SApp) GetOsType() cloudprovider.TOsType { } return cloudprovider.OsTypeWindows } + +func (self *SApp) SetTags(tags map[string]string, replace bool) error { + if !replace { + for k, v := range self.Tags { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + _, err := self.region.client.SetTags(self.Id, tags) + if err != nil { + return errors.Wrapf(err, "SetTags") + } + return nil +}