diff --git a/cmd/climc/shell/k8s/releases.go b/cmd/climc/shell/k8s/releases.go index eaa4e41652..e5480029fa 100644 --- a/cmd/climc/shell/k8s/releases.go +++ b/cmd/climc/shell/k8s/releases.go @@ -66,4 +66,22 @@ func initRelease() { _, err := k8s.Releases.Delete(s, args.NAME, args.Params()) return err }) + + R(&o.ReleaseHistoryOptions{}, cmdN("history"), "Get release history", func(s *mcclient.ClientSession, args *o.ReleaseHistoryOptions) error { + ret, err := k8s.Releases.GetSpecific(s, args.NAME, "history", args.Params()) + if err != nil { + return err + } + printObjectYAML(ret) + return nil + }) + + R(&o.ReleaseRollbackOptions{}, cmdN("rollback"), "Rollback release by history revision number", func(s *mcclient.ClientSession, args *o.ReleaseRollbackOptions) error { + ret, err := k8s.Releases.PerformAction(s, args.NAME, "rollback", args.Params()) + if err != nil { + return err + } + printObjectYAML(ret) + return nil + }) } diff --git a/cmd/climc/shell/servers.go b/cmd/climc/shell/servers.go index dbab60769a..5013e7c5c4 100644 --- a/cmd/climc/shell/servers.go +++ b/cmd/climc/shell/servers.go @@ -544,4 +544,35 @@ func init() { printObject(result) return nil }) + + type ServerAddExtraOption struct { + ID string `help:"ID or name of server"` + KEY string `help:"Option key"` + VALUE string `help:"Option value"` + } + R(&ServerAddExtraOption{}, "server-add-extra-options", "Add server extra options", func(s *mcclient.ClientSession, args *ServerAddExtraOption) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.KEY), "key") + params.Add(jsonutils.NewString(args.VALUE), "value") + result, err := modules.Servers.PerformAction(s, args.ID, "set-extra-option", params) + if err != nil { + return err + } + printObject(result) + return nil + }) + type ServerRemoveExtraOption struct { + ID string `help:"ID or name of server"` + KEY string `help:"Option key"` + } + R(&ServerRemoveExtraOption{}, "server-remove-extra-options", "Remove server extra options", func(s *mcclient.ClientSession, args *ServerRemoveExtraOption) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.KEY), "key") + result, err := modules.Servers.PerformAction(s, args.ID, "del-extra-option", params) + if err != nil { + return err + } + printObject(result) + return nil + }) } diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 7c218f9753..c1f4b5dc9e 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -16,6 +16,8 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" ) @@ -264,6 +266,10 @@ func (self *SAzureGuestDriver) RequestSyncConfigOnHost(ctx context.Context, gues if err != nil { return nil, err } + + lockman.LockRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcID)) + defer lockman.ReleaseRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcID)) + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), guest.SecgrpId, vpcID, host.GetRegion().Id, host.ManagerId) if secgroupCache == nil { return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s vpc: %s", guest.SecgrpId, vpcID) diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 24bd8f127f..902539b257 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -11,6 +11,7 @@ import ( "yunion.io/x/pkg/util/secrules" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -448,6 +449,10 @@ func (self *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context. if err != nil { return nil, err } + + lockman.LockRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcId)) + defer lockman.ReleaseRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-%s", guest.SecgrpId, vpcId)) + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), guest.SecgrpId, vpcId, host.GetRegion().Id, host.ManagerId) if secgroupCache == nil { return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s vpc: %s", guest.SecgrpId, vpcId) diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index cebffa5dfc..49fe9fe0cb 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -9,8 +9,11 @@ import ( "yunion.io/x/log" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -289,6 +292,72 @@ func (self *SQcloudGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu return nil } +func (self *SQcloudGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + ihost, err := host.GetIHost() + if err != nil { + return nil, err + } + iVM, err := ihost.GetIVMById(guest.ExternalId) + if err != nil { + return nil, err + } + + if fwOnly, _ := task.GetParams().Bool("fw_only"); fwOnly { + iregion, err := host.GetIRegion() + if err != nil { + return nil, err + } + lockman.LockRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-normal", guest.SecgrpId)) + defer lockman.ReleaseRawObject(ctx, "secgroupcache", fmt.Sprintf("%s-normal", guest.SecgrpId)) + + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), guest.SecgrpId, "normal", host.GetRegion().Id, host.ManagerId) + if secgroupCache == nil { + return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s", guest.SecgrpId) + } + extID, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, "normal", guest.GetSecgroupName(), "", guest.GetSecRules()) + if err != nil { + return nil, err + } + if err = secgroupCache.SetExternalId(extID); err != nil { + return nil, err + } + return nil, iVM.AssignSecurityGroup(extID) + } + + iDisks, err := iVM.GetIDisks() + if err != nil { + return nil, err + } + disks := make([]models.SDisk, 0) + for _, guestdisk := range guest.GetDisks() { + disk := guestdisk.GetDisk() + disks = append(disks, *disk) + } + + added := make([]models.SDisk, 0) + commondb := make([]models.SDisk, 0) + commonext := make([]cloudprovider.ICloudDisk, 0) + removed := make([]cloudprovider.ICloudDisk, 0) + + if err := compare.CompareSets(disks, iDisks, &added, &commondb, &commonext, &removed); err != nil { + return nil, err + } + for _, disk := range removed { + if err := iVM.DetachDisk(disk.GetId()); err != nil { + return nil, err + } + } + for _, disk := range added { + if err := iVM.AttachDisk(disk.ExternalId); err != nil { + return nil, err + } + } + return nil, nil + }) + return nil +} + func (self *SQcloudGuestDriver) AllowReconfigGuest() bool { return true } diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 79fb5d5124..74885e8940 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1905,3 +1905,45 @@ func (self *SGuest) StartCreateBackup(ctx context.Context, userCred mcclient.Tok } return nil } + +func (self *SGuest) AllowPerformSetExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return userCred.IsSystemAdmin() +} + +func (self *SGuest) PerformSetExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + key, err := data.GetString("key") + if err != nil { + return nil, httperrors.NewBadRequestError("Option key required") + } + value, _ := data.GetString("value") + extraOptions := self.GetExtraOptions(userCred) + extraOptions.Set(key, jsonutils.NewString(value)) + return nil, self.SetExtraOptions(ctx, userCred, extraOptions) +} + +func (self *SGuest) GetExtraOptions(userCred mcclient.TokenCredential) *jsonutils.JSONDict { + options := self.GetMetadataJson("extra_options", userCred) + o, ok := options.(*jsonutils.JSONDict) + if ok { + return o + } + return jsonutils.NewDict() +} + +func (self *SGuest) SetExtraOptions(ctx context.Context, userCred mcclient.TokenCredential, extraOptions *jsonutils.JSONDict) error { + return self.SetMetadata(ctx, "extra_options", extraOptions, userCred) +} + +func (self *SGuest) AllowPerformDelExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return userCred.IsSystemAdmin() +} + +func (self *SGuest) PerformDelExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + key, err := data.GetString("key") + if err != nil { + return nil, httperrors.NewBadRequestError("Option key required") + } + extraOptions := self.GetExtraOptions(userCred) + extraOptions.Remove(key) + return nil, self.SetExtraOptions(ctx, userCred, extraOptions) +} diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index a47f76d641..0b0fd1013f 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -108,8 +108,10 @@ const ( VM_RESTORE_STATE = "restore_state" VM_RESTORE_FAILED = "restore_failed" - VM_ASSOCIATE_EIP = "associate_eip" - VM_DISSOCIATE_EIP = "dissociate_eip" + VM_ASSOCIATE_EIP = "associate_eip" + VM_ASSOCIATE_EIP_FAILED = "associate_eip_failed" + VM_DISSOCIATE_EIP = "dissociate_eip" + VM_DISSOCIATE_EIP_FAILED = "dissociate_eip_failed" VM_REMOVE_STATEFILE = "remove_state" diff --git a/pkg/compute/tasks/eip_associate_task.go b/pkg/compute/tasks/eip_associate_task.go index fba01a4efc..483fb0f686 100644 --- a/pkg/compute/tasks/eip_associate_task.go +++ b/pkg/compute/tasks/eip_associate_task.go @@ -20,10 +20,10 @@ func init() { } func (self *EipAssociateTask) TaskFail(ctx context.Context, eip *models.SElasticip, msg string, vm *models.SGuest) { - eip.SetStatus(self.UserCred, models.EIP_STATUS_ASSOCIATE_FAIL, msg) + eip.SetStatus(self.UserCred, models.EIP_STATUS_READY, msg) self.SetStageFailed(ctx, msg) if vm != nil { - vm.StartSyncstatus(ctx, self.UserCred, "") + vm.SetStatus(self.UserCred, models.VM_ASSOCIATE_EIP_FAILED, msg) } } diff --git a/pkg/compute/tasks/eip_dissociate_task.go b/pkg/compute/tasks/eip_dissociate_task.go index 39390d458b..f91d7569eb 100644 --- a/pkg/compute/tasks/eip_dissociate_task.go +++ b/pkg/compute/tasks/eip_dissociate_task.go @@ -20,10 +20,10 @@ func init() { } func (self *EipDissociateTask) TaskFail(ctx context.Context, eip *models.SElasticip, msg string, vm *models.SGuest) { - eip.SetStatus(self.UserCred, models.EIP_STATUS_DISSOCIATE_FAIL, msg) + eip.SetStatus(self.UserCred, models.EIP_STATUS_READY, msg) self.SetStageFailed(ctx, msg) if vm != nil { - vm.StartSyncstatus(ctx, self.UserCred, "") + vm.SetStatus(self.UserCred, models.VM_DISSOCIATE_EIP_FAILED, msg) } } diff --git a/pkg/mcclient/options/k8s/release.go b/pkg/mcclient/options/k8s/release.go index d6714a8216..2663e6ee57 100644 --- a/pkg/mcclient/options/k8s/release.go +++ b/pkg/mcclient/options/k8s/release.go @@ -128,3 +128,33 @@ type ReleaseDeleteOptions struct { ClusterBaseOptions NAME string `help:"Release instance name"` } + +type ReleaseHistoryOptions struct { + ClusterBaseOptions + NAME string `help:"Release instance name"` + Max int64 `help:"History limit size"` +} + +func (o ReleaseHistoryOptions) Params() *jsonutils.JSONDict { + params := o.ClusterBaseOptions.Params() + if o.Max >= 1 { + params.Add(jsonutils.NewInt(o.Max), "max") + } + return params +} + +type ReleaseRollbackOptions struct { + ClusterBaseOptions + NAME string `help:"Release instance name"` + REVISION int64 `help:"Release history revision number"` + Description string `help:"Release rollback description string"` +} + +func (o ReleaseRollbackOptions) Params() *jsonutils.JSONDict { + params := o.ClusterBaseOptions.Params() + params.Add(jsonutils.NewInt(o.REVISION), "revision") + if o.Description != "" { + params.Add(jsonutils.NewString(o.Description), "description") + } + return params +}