diff --git a/cmd/climc/shell/cloudnet/common.go b/cmd/climc/shell/cloudnet/common.go index 0ea0709712..2e1ad2e489 100644 --- a/cmd/climc/shell/cloudnet/common.go +++ b/cmd/climc/shell/cloudnet/common.go @@ -1,3 +1,17 @@ +// 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 cloudnet import ( diff --git a/cmd/climc/shell/elasticcache.go b/cmd/climc/shell/elasticcache.go new file mode 100644 index 0000000000..3e9851e472 --- /dev/null +++ b/cmd/climc/shell/elasticcache.go @@ -0,0 +1,386 @@ +// 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 shell + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +func init() { + R(&options.BaseListOptions{}, "elastic-cache-list", "List elastisc cache instance", func(s *mcclient.ClientSession, opts *options.BaseListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCache.List(s, params) + if err != nil { + return err + } + + printList(result, nil) + return nil + }) + + R(&options.ElasticCacheCreateOptions{}, "elastic-cache-create", "Create elastisc cache instance", func(s *mcclient.ClientSession, opts *options.ElasticCacheCreateOptions) error { + params, err := options.StructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCache.Create(s, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-restart", "Restart elastisc cache instance", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCache.PerformAction(s, opts.ID, "restart", nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-flush-instance", "Flush elastisc cache instance", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCache.PerformAction(s, opts.ID, "flush-instance", nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-delete", "Delete elastisc cache instance", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCache.Delete(s, opts.ID, nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + type ElasticCacheChangeSpecOptions struct { + options.ElasticCacheIdOptions + Sku string `help:"elastic cache sku id"` + } + + R(&ElasticCacheChangeSpecOptions{}, "elastic-cache-change-spec", "Change elastisc cache instance specification", func(s *mcclient.ClientSession, opts *ElasticCacheChangeSpecOptions) error { + params := jsonutils.NewDict() + params.Set("sku", jsonutils.NewString(opts.Sku)) + result, err := modules.ElasticCache.PerformAction(s, opts.ID, "change-spec", params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + type ElasticCacheMainteananceTimeOptions struct { + options.ElasticCacheIdOptions + START_TIME string `help:"elastic cache sku maintenance start time,format: HH:mm"` + END_TIME string `help:"elastic cache sku maintenance end time, format: HH:mm"` + } + + R(&ElasticCacheMainteananceTimeOptions{}, "elastic-cache-set-maintenance-time", "set elastisc cache instance maintenance time", func(s *mcclient.ClientSession, opts *ElasticCacheMainteananceTimeOptions) error { + params := jsonutils.NewDict() + start := fmt.Sprintf("%sZ", opts.START_TIME) + end := fmt.Sprintf("%sZ", opts.END_TIME) + params.Set("maintain_start_time", jsonutils.NewString(start)) + params.Set("maintain_end_time", jsonutils.NewString(end)) + result, err := modules.ElasticCache.PerformAction(s, opts.ID, "set-maintain-time", params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-allocate-public-connect", "Allocate elastisc cache instance public access connection", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCache.PerformAction(s, opts.ID, "allocate-public-connection", nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-enable-auth", "Enable elastisc cache instance auth", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + params := jsonutils.NewDict() + params.Set("auth_mode", jsonutils.NewString("on")) + result, err := modules.ElasticCache.PerformAction(s, opts.ID, "update-auth-mode", params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-disable-auth", "Disable elastisc cache instance auth", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + params := jsonutils.NewDict() + params.Set("auth_mode", jsonutils.NewString("off")) + result, err := modules.ElasticCache.PerformAction(s, opts.ID, "update-auth-mode", params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + type ElasticCacheAccountResetPasswordOptions struct { + options.ElasticCacheIdOptions + PASSWORD string `help:"elastic cache account password."` + } + + R(&ElasticCacheAccountResetPasswordOptions{}, "elastic-cache-account-reset-password", "Reset elastisc cache instance account password", func(s *mcclient.ClientSession, opts *ElasticCacheAccountResetPasswordOptions) error { + params := jsonutils.NewDict() + params.Set("password", jsonutils.NewString(opts.PASSWORD)) + result, err := modules.ElasticCacheAccount.PerformAction(s, opts.ID, "reset-password", params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + type ElasticCacheBaseListOptions struct { + options.BaseListOptions + ElasticcacheId string `help:"elastic cache id"` + } + + R(&ElasticCacheBaseListOptions{}, "elastic-cache-account-list", "List elastisc cache account", func(s *mcclient.ClientSession, opts *ElasticCacheBaseListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCacheAccount.List(s, params) + if err != nil { + return err + } + + printList(result, nil) + return nil + }) + + R(&options.ElasticCacheAccountCreateOptions{}, "elastic-cache-account-create", "Create elastisc cache account", func(s *mcclient.ClientSession, opts *options.ElasticCacheAccountCreateOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCacheAccount.Create(s, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-account-delete", "Delete elastisc cache account", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCacheAccount.Delete(s, opts.ID, nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheBackupCreateOptions{}, "elastic-cache-backup-create", "Create elastisc cache backup", func(s *mcclient.ClientSession, opts *options.ElasticCacheBackupCreateOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCacheBackup.Create(s, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.BaseListOptions{}, "elastic-cache-backup-list", "List elastisc cache backup", func(s *mcclient.ClientSession, opts *options.BaseListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCacheBackup.List(s, params) + if err != nil { + return err + } + + printList(result, nil) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-backup-delete", "Delete elastisc cache backup", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCacheBackup.Delete(s, opts.ID, nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-backup-restore", "Restore elastisc cache backup", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCacheBackup.PerformAction(s, opts.ID, "restore-instance", nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheAclCreateOptions{}, "elastic-cache-acl-create", "Create elastisc cache acl", func(s *mcclient.ClientSession, opts *options.ElasticCacheAclCreateOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCacheAcl.Create(s, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.ElasticCacheIdOptions{}, "elastic-cache-acl-delete", "Delete elastisc cache acl", func(s *mcclient.ClientSession, opts *options.ElasticCacheIdOptions) error { + result, err := modules.ElasticCacheAcl.Delete(s, opts.ID, nil) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.BaseListOptions{}, "elastic-cache-acl-list", "List elastisc cache acl", func(s *mcclient.ClientSession, opts *options.BaseListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCacheAcl.List(s, params) + if err != nil { + return err + } + + printList(result, nil) + return nil + }) + + R(&options.ElasticCacheAclUpdateOptions{}, "elastic-cache-acl-update", "Update elastisc cache acl", func(s *mcclient.ClientSession, opts *options.ElasticCacheAclUpdateOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + params.Remove("id") + result, err := modules.ElasticCacheAcl.Update(s, opts.Id, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + R(&options.BaseListOptions{}, "elastic-cache-parameter-list", "List elastisc cache parameters", func(s *mcclient.ClientSession, opts *options.BaseListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticCacheParameter.List(s, params) + if err != nil { + return err + } + + printList(result, nil) + return nil + }) + + R(&options.ElasticCacheParameterUpdateOptions{}, "elastic-cache-parameter-update", "Update elastisc cache parameter", func(s *mcclient.ClientSession, opts *options.ElasticCacheParameterUpdateOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + params.Remove("id") + result, err := modules.ElasticCacheParameter.Update(s, opts.Id, params) + if err != nil { + return err + } + + printObject(result) + return nil + }) + + type ElasticCacheSkusListOptions struct { + options.BaseListOptions + Cloudregion string `help:"region Id or name"` + Usable bool `help:"Filter usable sku"` + Zone string `help:"zone Id or name"` + City *string `help:"city name,eg. BeiJing"` + LocalCategory *string `help:"local category,eg. single"` + EngineVersion *string `help:"engine version,eg. 3.0"` + Cpu *int `help:"Cpu core count" json:"cpu_core_count"` + Mem *int `help:"Memory size in MB" json:"memory_size_mb"` + Name string `help:"Name of Sku"` + } + + R(&ElasticCacheSkusListOptions{}, "elastic-cache-sku-list", "List elastisc cache sku", func(s *mcclient.ClientSession, opts *ElasticCacheSkusListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ElasticcacheSkus.List(s, params) + if err != nil { + return err + } + + printList(result, nil) + return nil + }) +} diff --git a/cmd/climc/shell/instance_snapshots.go b/cmd/climc/shell/instance_snapshots.go index f5039e9c6b..6c7a97682f 100644 --- a/cmd/climc/shell/instance_snapshots.go +++ b/cmd/climc/shell/instance_snapshots.go @@ -1,3 +1,17 @@ +// 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 shell import ( diff --git a/docs/cloudaccount/disable-auto-sync.yaml b/docs/cloudaccount/disable-auto-sync.yaml index 3b505fff66..27c8b61a21 100644 --- a/docs/cloudaccount/disable-auto-sync.yaml +++ b/docs/cloudaccount/disable-auto-sync.yaml @@ -1,12 +1,12 @@ post: summary: 关闭云账号自动同步 - parameters: + parameters: - $ref: "../parameters/cloudaccount.yaml#/cloudaccountId" responses: 200: description: 云账号信息 schema: - $ref: "../schemas/cloudaccount.yaml#CloudaccountResponse" + $ref: "../schemas/cloudaccount.yaml#/CloudaccountResponse" tags: - - cloudaccount \ No newline at end of file + - cloudaccount diff --git a/docs/cloudaccount/disable.yaml b/docs/cloudaccount/disable.yaml index 1d91fa4b49..adb205ac5f 100644 --- a/docs/cloudaccount/disable.yaml +++ b/docs/cloudaccount/disable.yaml @@ -1,12 +1,12 @@ post: summary: 禁用云账号 - parameters: + parameters: - $ref: "../parameters/cloudaccount.yaml#/cloudaccountId" responses: 200: description: 禁用的云账号信息 schema: - $ref: "../schemas/cloudaccount.yaml#CloudaccountResponse" + $ref: "../schemas/cloudaccount.yaml#/CloudaccountResponse" tags: - - cloudaccount \ No newline at end of file + - cloudaccount diff --git a/docs/cloudaccount/enable-auto-sync.yaml b/docs/cloudaccount/enable-auto-sync.yaml index 087019716a..3132b86a4c 100644 --- a/docs/cloudaccount/enable-auto-sync.yaml +++ b/docs/cloudaccount/enable-auto-sync.yaml @@ -1,17 +1,17 @@ post: summary: 开启云账号自动同步 - parameters: + parameters: - $ref: "../parameters/cloudaccount.yaml#/cloudaccountId" - in: body name: cloudaccount required: true schema: - $ref: '../schemas/cloudaccount.yaml#/CloudaccountEnableAutoSync' + $ref: "../schemas/cloudaccount.yaml#/CloudaccountEnableAutoSync" responses: 200: description: 云账号信息 schema: - $ref: "../schemas/cloudaccount.yaml#CloudaccountResponse" + $ref: "../schemas/cloudaccount.yaml#/CloudaccountResponse" tags: - - cloudaccount \ No newline at end of file + - cloudaccount diff --git a/docs/cloudaccount/enable.yaml b/docs/cloudaccount/enable.yaml index 26606f3f42..af70250539 100644 --- a/docs/cloudaccount/enable.yaml +++ b/docs/cloudaccount/enable.yaml @@ -1,12 +1,12 @@ post: summary: 启用云账号 - parameters: + parameters: - $ref: "../parameters/cloudaccount.yaml#/cloudaccountId" responses: 200: description: 启用的云账号信息 schema: - $ref: "../schemas/cloudaccount.yaml#CloudaccountResponse" + $ref: "../schemas/cloudaccount.yaml#/CloudaccountResponse" tags: - - cloudaccount \ No newline at end of file + - cloudaccount diff --git a/docs/cloudaccount/private.yaml b/docs/cloudaccount/private.yaml index 50d067b3f5..0f5e4867ac 100644 --- a/docs/cloudaccount/private.yaml +++ b/docs/cloudaccount/private.yaml @@ -1,12 +1,12 @@ post: summary: 取消云账号共享 - parameters: + parameters: - $ref: "../parameters/cloudaccount.yaml#/cloudaccountId" responses: 200: description: 云账号信息 schema: - $ref: "../schemas/cloudaccount.yaml#CloudaccountResponse" + $ref: "../schemas/cloudaccount.yaml#/CloudaccountResponse" tags: - - cloudaccount \ No newline at end of file + - cloudaccount diff --git a/docs/dbinstance/change-config.yaml b/docs/dbinstance/change-config.yaml index 758a9e9fd5..92e46713d7 100644 --- a/docs/dbinstance/change-config.yaml +++ b/docs/dbinstance/change-config.yaml @@ -1,16 +1,16 @@ post: summary: 调整RDS实例配置 - parameters: - - $ref: '../parameters/dbinstance.yaml#/dbinstanceId' - - in: body - name: dbinstance - required: true + parameters: + - $ref: "../parameters/dbinstance.yaml#/dbinstanceId" + - in: body + name: dbinstance + required: true schema: - $ref: '../schemas/dbinstance.yaml#DBInstanceChangeConfig' + $ref: "../schemas/dbinstance.yaml#/DBInstanceChangeConfig" responses: 200: description: RDS实例信息 schema: - $ref: '../schemas/dbinstance.yaml#/DBInstanceResponse' + $ref: "../schemas/dbinstance.yaml#/DBInstanceResponse" tags: - dbinstance diff --git a/docs/dbinstance/public-connection.yaml b/docs/dbinstance/public-connection.yaml index 56ca8c79cc..4c9195b28e 100644 --- a/docs/dbinstance/public-connection.yaml +++ b/docs/dbinstance/public-connection.yaml @@ -1,16 +1,16 @@ post: summary: 开放关闭RDS实例外网地址 - parameters: - - $ref: '../parameters/dbinstance.yaml#/dbinstanceId' - - in: body - name: dbinstance - required: true + parameters: + - $ref: "../parameters/dbinstance.yaml#/dbinstanceId" + - in: body + name: dbinstance + required: true schema: - $ref: '../schemas/dbinstance.yaml#DBInstancePublicConnection' + $ref: "../schemas/dbinstance.yaml#/DBInstancePublicConnection" responses: 200: description: RDS实例信息 schema: - $ref: '../schemas/dbinstance.yaml#/DBInstanceResponse' + $ref: "../schemas/dbinstance.yaml#/DBInstanceResponse" tags: - dbinstance diff --git a/docs/dbinstance/recovery.yaml b/docs/dbinstance/recovery.yaml index 01728226b3..97db12cc8f 100644 --- a/docs/dbinstance/recovery.yaml +++ b/docs/dbinstance/recovery.yaml @@ -1,17 +1,17 @@ post: summary: 从备份恢复实例数据库 description: 要求RDS实例状态正常 - parameters: - - $ref: '../parameters/dbinstance.yaml#/dbinstanceId' - - in: body + parameters: + - $ref: "../parameters/dbinstance.yaml#/dbinstanceId" + - in: body name: dbinstance - required: true + required: true schema: - $ref: '../schemas/dbinstance.yaml#DBInstanceRecovery' + $ref: "../schemas/dbinstance.yaml#/DBInstanceRecovery" responses: 200: description: RDS实例信息 schema: - $ref: '../schemas/dbinstance.yaml#/DBInstanceResponse' + $ref: "../schemas/dbinstance.yaml#/DBInstanceResponse" tags: - dbinstance diff --git a/docs/dbinstanceaccount/grant-privilege.yaml b/docs/dbinstanceaccount/grant-privilege.yaml index 6a31a6b94e..0b357cac50 100644 --- a/docs/dbinstanceaccount/grant-privilege.yaml +++ b/docs/dbinstanceaccount/grant-privilege.yaml @@ -1,17 +1,17 @@ post: summary: 赋予RDS实例的数据库权限 description: 要求RDS实例状态正常 - parameters: - - $ref: '../parameters/dbinstance.yaml#/accountId' - - in: body + parameters: + - $ref: "../parameters/dbinstance.yaml#/accountId" + - in: body name: dbinstanceaccount - required: true + required: true schema: - $ref: '../schemas/dbinstance_account.yaml#DBInstanceAccountGrantPrivilege' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountGrantPrivilege" responses: 200: description: RDS实例账户信息 schema: - $ref: '../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse" tags: - dbinstanceaccount diff --git a/docs/dbinstanceaccount/reset-password.yaml b/docs/dbinstanceaccount/reset-password.yaml index 7d644b29ad..8a9974fd58 100644 --- a/docs/dbinstanceaccount/reset-password.yaml +++ b/docs/dbinstanceaccount/reset-password.yaml @@ -1,17 +1,17 @@ post: summary: 重置RDS实例用户密码 description: 要求RDS实例状态正常 - parameters: - - $ref: '../parameters/dbinstance.yaml#/accountId' - - in: body + parameters: + - $ref: "../parameters/dbinstance.yaml#/accountId" + - in: body name: dbinstanceaccount - required: true + required: true schema: - $ref: '../schemas/dbinstance_account.yaml#DBInstanceAccountResetPassword' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountResetPassword" responses: 200: description: RDS实例账户信息 schema: - $ref: '../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse" tags: - dbinstanceaccount diff --git a/docs/dbinstanceaccount/revoke-privilege.yaml b/docs/dbinstanceaccount/revoke-privilege.yaml index 6ee97b9ad6..550ff5f924 100644 --- a/docs/dbinstanceaccount/revoke-privilege.yaml +++ b/docs/dbinstanceaccount/revoke-privilege.yaml @@ -1,17 +1,17 @@ post: summary: 解除RDS实例的数据库权限 description: 要求RDS实例状态正常 - parameters: - - $ref: '../parameters/dbinstance.yaml#/accountId' - - in: body + parameters: + - $ref: "../parameters/dbinstance.yaml#/accountId" + - in: body name: dbinstanceaccount - required: true + required: true schema: - $ref: '../schemas/dbinstance_account.yaml#DBInstanceAccountRevokePrivilege' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountRevokePrivilege" responses: 200: description: RDS实例账户信息 schema: - $ref: '../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse" tags: - dbinstanceaccount diff --git a/docs/dbinstanceaccount/set-privileges.yaml b/docs/dbinstanceaccount/set-privileges.yaml index 00a8222fe6..63a03a27d9 100644 --- a/docs/dbinstanceaccount/set-privileges.yaml +++ b/docs/dbinstanceaccount/set-privileges.yaml @@ -1,17 +1,17 @@ post: summary: 设置RDS实例的数据库权限 description: 要求RDS实例及账号状态正常 - parameters: - - $ref: '../parameters/dbinstance.yaml#/accountId' - - in: body + parameters: + - $ref: "../parameters/dbinstance.yaml#/accountId" + - in: body name: dbinstanceaccount - required: true + required: true schema: - $ref: '../schemas/dbinstance_account.yaml#DBInstanceAccountSetPrivileges' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountSetPrivileges" responses: 200: description: RDS实例账户信息 schema: - $ref: '../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse' + $ref: "../schemas/dbinstance_account.yaml#/DBInstanceAccountResponse" tags: - dbinstanceaccount diff --git a/docs/disk/private.yaml b/docs/disk/private.yaml index bac2f32358..497f968541 100644 --- a/docs/disk/private.yaml +++ b/docs/disk/private.yaml @@ -1,11 +1,11 @@ post: summary: 取消磁盘共享 - parameters: + parameters: - $ref: "../parameters/disk.yaml#/diskId" responses: 200: description: 磁盘信息 schema: - $ref: "../schemas/disk.yaml#DiskResponse" + $ref: "../schemas/disk.yaml#/DiskResponse" tags: - - disk \ No newline at end of file + - disk diff --git a/docs/disk/public.yaml b/docs/disk/public.yaml index f787eb58b5..b8882516e8 100644 --- a/docs/disk/public.yaml +++ b/docs/disk/public.yaml @@ -1,12 +1,12 @@ post: summary: 磁盘共享 - parameters: + parameters: - $ref: "../parameters/disk.yaml#/diskId" responses: 200: description: 磁盘信息 schema: - $ref: "../schemas/disk.yaml#DiskResponse" + $ref: "../schemas/disk.yaml#/DiskResponse" tags: - - disk \ No newline at end of file + - disk diff --git a/docs/disk/purge.yaml b/docs/disk/purge.yaml index a63eced78c..5a14452e5d 100644 --- a/docs/disk/purge.yaml +++ b/docs/disk/purge.yaml @@ -1,12 +1,12 @@ post: summary: 清除磁盘数据库记录 - parameters: + parameters: - $ref: "../parameters/disk.yaml#/diskId" responses: 200: description: 磁盘信息 schema: - $ref: "../schemas/disk.yaml#DiskResponse" + $ref: "../schemas/disk.yaml#/DiskResponse" tags: - - disk \ No newline at end of file + - disk diff --git a/docs/disk/reset.yaml b/docs/disk/reset.yaml index fbe9059467..41807b49ab 100644 --- a/docs/disk/reset.yaml +++ b/docs/disk/reset.yaml @@ -1,17 +1,17 @@ post: summary: 回滚磁盘到指定快照 - parameters: + parameters: - $ref: "../parameters/disk.yaml#/diskId" - in: body name: disk required: true schema: - $ref: '../schemas/disk.yaml#/DiskReset' + $ref: "../schemas/disk.yaml#/DiskReset" responses: 200: description: 磁盘信息 schema: - $ref: "../schemas/disk.yaml#DiskResponse" + $ref: "../schemas/disk.yaml#/DiskResponse" tags: - - disk \ No newline at end of file + - disk diff --git a/docs/elasticcache/allocate-public-connection.yaml b/docs/elasticcache/allocate-public-connection.yaml new file mode 100644 index 0000000000..a615c880b9 --- /dev/null +++ b/docs/elasticcache/allocate-public-connection.yaml @@ -0,0 +1,15 @@ +post: + summary: 获取ElasticCache实例公网访问地址 + parameters: + - in: body + name: elasticcache + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAllocatePublicConnection" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/change-spec.yaml b/docs/elasticcache/change-spec.yaml new file mode 100644 index 0000000000..eeec75f2e8 --- /dev/null +++ b/docs/elasticcache/change-spec.yaml @@ -0,0 +1,15 @@ +post: + summary: 变更ElasticCache实例规格 + parameters: + - in: body + name: elasticcache + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheChangeSpec" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/elasticcache.yaml b/docs/elasticcache/elasticcache.yaml new file mode 100644 index 0000000000..bd28ad32b1 --- /dev/null +++ b/docs/elasticcache/elasticcache.yaml @@ -0,0 +1,23 @@ +get: + summary: 获取指定ElasticCache实例详情信息 + parameters: + - $ref: "../parameters/elasticcache.yaml#/elasticcacheId" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache + +delete: + summary: 删除指定ElasticCache实例 + parameters: + - $ref: "../parameters/elasticcache.yaml#/elasticcacheId" + responses: + 200: + description: 被删除ElasticCache实例的信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/elasticcacheaccount.yaml b/docs/elasticcache/elasticcacheaccount.yaml new file mode 100644 index 0000000000..dccff3df9e --- /dev/null +++ b/docs/elasticcache/elasticcacheaccount.yaml @@ -0,0 +1,23 @@ +get: + summary: 获取指定ElasticCache实例用户详情信息 + parameters: + - $ref: "../parameters/elasticcache.yaml#/accountId" + responses: + 200: + description: ElasticCache实例用户信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAccountResponse" + tags: + - elasticcacheaccount + +delete: + summary: 删除指定ElasticCache实例用户 + parameters: + - $ref: "../parameters/elasticcache.yaml#/accountId" + responses: + 200: + description: 被删除ElasticCache实例的用户信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAccountResponse" + tags: + - elasticcacheaccount diff --git a/docs/elasticcache/elasticcacheaccounts.yaml b/docs/elasticcache/elasticcacheaccounts.yaml new file mode 100644 index 0000000000..2647e0f7f9 --- /dev/null +++ b/docs/elasticcache/elasticcacheaccounts.yaml @@ -0,0 +1,30 @@ +get: + summary: 按指定条件列出ElasticCache实例用户列表 + parameters: + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/elasticcache.yaml#/elasticcache_id" + + responses: + 200: + description: ElasticCache实例用户列表信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAccountListResponse" + tags: + - elasticcacheaccount + +post: + summary: 创建ElasticCache实例管理账号 + parameters: + - in: body + name: elasticcacheaccount + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAccountCreate" + responses: + 200: + description: 新创建的ElasticCache实例账号信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAccountResponse" + tags: + - elasticcacheaccount diff --git a/docs/elasticcache/elasticcacheacl.yaml b/docs/elasticcache/elasticcacheacl.yaml new file mode 100644 index 0000000000..c2f47384ed --- /dev/null +++ b/docs/elasticcache/elasticcacheacl.yaml @@ -0,0 +1,40 @@ +get: + summary: 获取指定ElasticCache实例访问控制详情信息 + parameters: + - $ref: "../parameters/elasticcache.yaml#/aclId" + responses: + 200: + description: ElasticCache实例访问控制信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAclResponse" + tags: + - elasticcacheacl + +put: + summary: 更新指定ElasticCache实例访问控制 + parameters: + - $ref: "../parameters/elasticcache.yaml#/aclId" + - in: body + name: elasticcacheacl + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAclUpdate" + responses: + 200: + description: 被删除ElasticCache实例的访问控制信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAclResponse" + tags: + - elasticcacheacl + +delete: + summary: 删除指定ElasticCache实例访问控制 + parameters: + - $ref: "../parameters/elasticcache.yaml#/aclId" + responses: + 200: + description: 被删除ElasticCache实例的访问控制信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAclResponse" + tags: + - elasticcacheacl diff --git a/docs/elasticcache/elasticcacheacls.yaml b/docs/elasticcache/elasticcacheacls.yaml new file mode 100644 index 0000000000..d39ad142b7 --- /dev/null +++ b/docs/elasticcache/elasticcacheacls.yaml @@ -0,0 +1,30 @@ +get: + summary: 按指定条件列出ElasticCache实例访问控制列表 + parameters: + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/elasticcache.yaml#/elasticcache_id" + + responses: + 200: + description: ElasticCache实例访问控制列表信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAclListResponse" + tags: + - elasticcacheacl + +post: + summary: 创建ElasticCache实例ACL + parameters: + - in: body + name: elasticcacheacl + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAclCreate" + responses: + 200: + description: 新创建的ElasticCache实例ACL信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAclResponse" + tags: + - elasticcacheacl diff --git a/docs/elasticcache/elasticcachebackup.yaml b/docs/elasticcache/elasticcachebackup.yaml new file mode 100644 index 0000000000..d81088af36 --- /dev/null +++ b/docs/elasticcache/elasticcachebackup.yaml @@ -0,0 +1,23 @@ +get: + summary: 获取指定ElasticCache实例备份详情信息 + parameters: + - $ref: "../parameters/elasticcache.yaml#/backupId" + responses: + 200: + description: ElasticCache实例备份信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheBackupResponse" + tags: + - elasticcachebackup + +delete: + summary: 删除指定ElasticCache实例备份 + parameters: + - $ref: "../parameters/elasticcache.yaml#/backupId" + responses: + 200: + description: 被删除ElasticCache实例的备份信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheBackupResponse" + tags: + - elasticcachebackup diff --git a/docs/elasticcache/elasticcachebackups.yaml b/docs/elasticcache/elasticcachebackups.yaml new file mode 100644 index 0000000000..8abe35e860 --- /dev/null +++ b/docs/elasticcache/elasticcachebackups.yaml @@ -0,0 +1,25 @@ +get: + summary: 按指定条件列出ElasticCache实例备份列表 + parameters: + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/common.yaml#/cloudregion" + - $ref: "../parameters/elasticcache.yaml#/elasticcache_id" + + responses: + 200: + description: ElasticCache实例备份列表信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheBackupListResponse" + tags: + - elasticcachebackup + +post: + summary: 创建ElasticCache实例备份 + responses: + 200: + description: 新创建的ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheBackupResponse" + tags: + - elasticcachebackup diff --git a/docs/elasticcache/elasticcacheparameter.yaml b/docs/elasticcache/elasticcacheparameter.yaml new file mode 100644 index 0000000000..86a24fc9f7 --- /dev/null +++ b/docs/elasticcache/elasticcacheparameter.yaml @@ -0,0 +1,40 @@ +get: + summary: 获取指定ElasticCache实例参数详情信息 + parameters: + - $ref: "../parameters/elasticcache.yaml#/parameterId" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheParameterResponse" + tags: + - elasticcacheparameter + +put: + summary: 更新ElasticCache实例配置参数 + parameters: + - $ref: "../parameters/elasticcache.yaml#/parameterId" + - in: body + name: elasticcacheparameter + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheParameterUpdate" + responses: + 200: + description: ElasticCache实例配置参数信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheParameterResponse" + tags: + - elasticcacheparameter + +delete: + summary: 删除指定ElasticCache实例参数 + parameters: + - $ref: "../parameters/elasticcache.yaml#/parameterId" + responses: + 200: + description: 被删除ElasticCache实例的参数信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheParameterResponse" + tags: + - elasticcacheparameter diff --git a/docs/elasticcache/elasticcacheparameters.yaml b/docs/elasticcache/elasticcacheparameters.yaml new file mode 100644 index 0000000000..a0ceefe94d --- /dev/null +++ b/docs/elasticcache/elasticcacheparameters.yaml @@ -0,0 +1,14 @@ +get: + summary: 按指定条件列出ElasticCache实例参数列表 + parameters: + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/elasticcache.yaml#/elasticcache_id" + + responses: + 200: + description: ElasticCache实例参数列表信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheParameterListResponse" + tags: + - elasticcacheparameter diff --git a/docs/elasticcache/elasticcaches.yaml b/docs/elasticcache/elasticcaches.yaml new file mode 100644 index 0000000000..082ff90bdb --- /dev/null +++ b/docs/elasticcache/elasticcaches.yaml @@ -0,0 +1,36 @@ +get: + summary: 按指定条件列出ElasticCache实例 + parameters: + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/common.yaml#/provider" + - $ref: "../parameters/common.yaml#/account" + - $ref: "../parameters/common.yaml#/cloudprovider" + - $ref: "../parameters/common.yaml#/billing_type" + - $ref: "../parameters/common.yaml#/cloudregion" + - $ref: "../parameters/common.yaml#/zone" + - $ref: "../parameters/common.yaml#/vpc" + + responses: + 200: + description: ElasticCache实例列表信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheListResponse" + tags: + - elasticcache + +post: + summary: 创建ElasticCache实例 + parameters: + - in: body + name: elasticcache + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheCreate" + responses: + 200: + description: 新创建的ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/elasticcacheskus.yaml b/docs/elasticcache/elasticcacheskus.yaml new file mode 100644 index 0000000000..b6a0458a42 --- /dev/null +++ b/docs/elasticcache/elasticcacheskus.yaml @@ -0,0 +1,19 @@ +get: + summary: 按指定条件列出ElasticCaches实例套餐列表 + parameters: + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/common.yaml#/provider" + - $ref: "../parameters/common.yaml#/zone" + - $ref: "../parameters/common.yaml#/city" + - $ref: "../parameters/common.yaml#/cloudregion" + - $ref: "../parameters/elasticcache.yaml#/engine_version" + - $ref: "../parameters/elasticcache.yaml#/local_category" + + responses: + 200: + description: ElasticCache实例套餐信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheSkuListResponse" + tags: + - elasticcachesku diff --git a/docs/elasticcache/flush-instance.yaml b/docs/elasticcache/flush-instance.yaml new file mode 100644 index 0000000000..c720e038c7 --- /dev/null +++ b/docs/elasticcache/flush-instance.yaml @@ -0,0 +1,9 @@ +post: + summary: 清空ElasticCache实例 + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/login-info.yaml b/docs/elasticcache/login-info.yaml new file mode 100644 index 0000000000..7821b8707e --- /dev/null +++ b/docs/elasticcache/login-info.yaml @@ -0,0 +1,9 @@ +get: + summary: 获取指定ElasticCache实例管理员密码 + responses: + 200: + description: ElasticCache实例密码信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheLoginInfoResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/release-public-connection.yaml b/docs/elasticcache/release-public-connection.yaml new file mode 100644 index 0000000000..f587c8fee9 --- /dev/null +++ b/docs/elasticcache/release-public-connection.yaml @@ -0,0 +1,9 @@ +post: + summary: 释放ElasticCache实例公网访问地址 + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/reset-password.yaml b/docs/elasticcache/reset-password.yaml new file mode 100644 index 0000000000..c16e0cd7c8 --- /dev/null +++ b/docs/elasticcache/reset-password.yaml @@ -0,0 +1,15 @@ +post: + summary: 重置ElasticCache实例账号密码 + parameters: + - in: body + name: elasticcacheaccount + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResetPassword" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAccountResponse" + tags: + - elasticcacheaccount diff --git a/docs/elasticcache/restart.yaml b/docs/elasticcache/restart.yaml new file mode 100644 index 0000000000..1b70c928b9 --- /dev/null +++ b/docs/elasticcache/restart.yaml @@ -0,0 +1,9 @@ +post: + summary: 重启ElasticCache实例 + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/restore-instance.yaml b/docs/elasticcache/restore-instance.yaml new file mode 100644 index 0000000000..a906f41321 --- /dev/null +++ b/docs/elasticcache/restore-instance.yaml @@ -0,0 +1,9 @@ +post: + summary: ElasticCache实例备份恢复 + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheBackupResponse" + tags: + - elasticcachebackup diff --git a/docs/elasticcache/set-maintain-time.yaml b/docs/elasticcache/set-maintain-time.yaml new file mode 100644 index 0000000000..b1128cd0a2 --- /dev/null +++ b/docs/elasticcache/set-maintain-time.yaml @@ -0,0 +1,15 @@ +post: + summary: 设置ElasticCache实例维护时间段 + parameters: + - in: body + name: elasticcache + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheSetMaintainTime" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/update-auth-mode.yaml b/docs/elasticcache/update-auth-mode.yaml new file mode 100644 index 0000000000..2156f940ae --- /dev/null +++ b/docs/elasticcache/update-auth-mode.yaml @@ -0,0 +1,15 @@ +post: + summary: 设置ElasticCache实例密码认证 + parameters: + - in: body + name: elasticcache + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheAuthMode" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/update-backup-policy.yaml b/docs/elasticcache/update-backup-policy.yaml new file mode 100644 index 0000000000..c1c98c31a1 --- /dev/null +++ b/docs/elasticcache/update-backup-policy.yaml @@ -0,0 +1,15 @@ +post: + summary: 设置ElasticCache实例备份策略 + parameters: + - in: body + name: elasticcache + required: true + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheBackupPolicy" + responses: + 200: + description: ElasticCache实例信息 + schema: + $ref: "../schemas/elasticcache.yaml#/ElasticCacheResponse" + tags: + - elasticcache diff --git a/docs/elasticcache/update-instance-parameters.yaml b/docs/elasticcache/update-instance-parameters.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/elasticip/associate.yaml b/docs/elasticip/associate.yaml index 29c262421b..8ae065f413 100644 --- a/docs/elasticip/associate.yaml +++ b/docs/elasticip/associate.yaml @@ -1,6 +1,6 @@ post: summary: 绑定资源 - parameters: + parameters: - $ref: "../parameters/elasticip.yaml#/elasticipId" - $ref: "../parameters/elasticip.yaml#/instance_id" - $ref: "../parameters/elasticip.yaml#/instance_type" @@ -8,7 +8,7 @@ post: 200: description: 弹性IP信息 schema: - $ref: "../schemas/elasticip.yaml#ElasticIpResponse" + $ref: "../schemas/elasticip.yaml#/ElasticIpResponse" tags: - - elasticips \ No newline at end of file + - elasticips diff --git a/docs/elasticip/change-bandwidth.yaml b/docs/elasticip/change-bandwidth.yaml index dce76dbbc1..4ef31af512 100644 --- a/docs/elasticip/change-bandwidth.yaml +++ b/docs/elasticip/change-bandwidth.yaml @@ -1,13 +1,13 @@ post: summary: 更改弹性IP带宽大小 - parameters: + parameters: - $ref: "../parameters/elasticip.yaml#/elasticipId" - $ref: "../parameters/elasticip.yaml#/bandwidth" responses: 200: description: 弹性IP信息 schema: - $ref: "../schemas/elasticip.yaml#ElasticIpResponse" + $ref: "../schemas/elasticip.yaml#/ElasticIpResponse" tags: - - elasticips \ No newline at end of file + - elasticips diff --git a/docs/elasticip/dissociate.yaml b/docs/elasticip/dissociate.yaml index 87a8d42d88..5e33707f06 100644 --- a/docs/elasticip/dissociate.yaml +++ b/docs/elasticip/dissociate.yaml @@ -1,13 +1,13 @@ post: summary: 解绑弹性EIP - parameters: + parameters: - $ref: "../parameters/elasticip.yaml#/elasticipId" - $ref: "../parameters/elasticip.yaml#/auto_delete" responses: 200: description: 弹性IP信息 schema: - $ref: "../schemas/elasticip.yaml#ElasticIpResponse" + $ref: "../schemas/elasticip.yaml#/ElasticIpResponse" tags: - - elasticips \ No newline at end of file + - elasticips diff --git a/docs/elasticip/purge.yaml b/docs/elasticip/purge.yaml index c10890ab1e..8088db8c74 100644 --- a/docs/elasticip/purge.yaml +++ b/docs/elasticip/purge.yaml @@ -1,12 +1,12 @@ post: summary: 清除弹性EIP数据库记录(并不真正删除资源) - parameters: + parameters: - $ref: "../parameters/elasticip.yaml#/elasticipId" responses: 200: description: 弹性IP信息 schema: - $ref: "../schemas/elasticip.yaml#ElasticIpResponse" + $ref: "../schemas/elasticip.yaml#/ElasticIpResponse" tags: - - elasticips \ No newline at end of file + - elasticips diff --git a/docs/elasticip/sync.yaml b/docs/elasticip/sync.yaml index 61cef855f4..3d241cbb2a 100644 --- a/docs/elasticip/sync.yaml +++ b/docs/elasticip/sync.yaml @@ -6,7 +6,7 @@ post: 200: description: 弹性IP信息 schema: - $ref: "../schemas/elasticip.yaml#ElasticIpResponse" + $ref: "../schemas/elasticip.yaml#/ElasticIpResponse" tags: - elasticips \ No newline at end of file diff --git a/docs/host/add-netif.yaml b/docs/host/add-netif.yaml index 7333bbb36a..6bfee0d9f2 100644 --- a/docs/host/add-netif.yaml +++ b/docs/host/add-netif.yaml @@ -1,16 +1,16 @@ post: summary: 物理机添加网卡 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" - in: body name: host required: true schema: - $ref: '../schemas/host.yaml#/HostAddNetif' + $ref: "../schemas/host.yaml#/HostAddNetif" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/convert-hypervisor.yaml b/docs/host/convert-hypervisor.yaml index 66bea7a64d..9a52e94833 100644 --- a/docs/host/convert-hypervisor.yaml +++ b/docs/host/convert-hypervisor.yaml @@ -1,16 +1,16 @@ post: summary: 将物理机转换成宿主机 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" - in: body name: host required: true schema: - $ref: '../schemas/host.yaml#/HostConvertHypervisor' + $ref: "../schemas/host.yaml#/HostConvertHypervisor" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/disable.yaml b/docs/host/disable.yaml index 8dd74854b1..a5316f4ecb 100644 --- a/docs/host/disable.yaml +++ b/docs/host/disable.yaml @@ -1,11 +1,11 @@ post: summary: 禁用宿主机 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/enable.yaml b/docs/host/enable.yaml index bf334eee7b..b49ed4ae26 100644 --- a/docs/host/enable.yaml +++ b/docs/host/enable.yaml @@ -1,11 +1,11 @@ post: summary: 启用宿主机 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/ipmi.yaml b/docs/host/ipmi.yaml index 9cd3108dec..42aa0ee471 100644 --- a/docs/host/ipmi.yaml +++ b/docs/host/ipmi.yaml @@ -1,11 +1,11 @@ get: summary: 获取物理机IPMI信息 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: ipmi信息 schema: - $ref: "../schemas/host.yaml#HostIpmi" + $ref: "../schemas/host.yaml#/HostIpmi" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/maintenance.yaml b/docs/host/maintenance.yaml index 31d76e31b4..6d728760d4 100644 --- a/docs/host/maintenance.yaml +++ b/docs/host/maintenance.yaml @@ -1,11 +1,11 @@ post: summary: 重启物理机进入PXE系统,做维护工作 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/ping.yaml b/docs/host/ping.yaml index cb85cc2347..0aa9850471 100644 --- a/docs/host/ping.yaml +++ b/docs/host/ping.yaml @@ -1,11 +1,11 @@ post: summary: ping Host - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/prepare.yaml b/docs/host/prepare.yaml index fb5e048f46..309b5b4879 100644 --- a/docs/host/prepare.yaml +++ b/docs/host/prepare.yaml @@ -1,11 +1,11 @@ post: summary: 重新收集物理机信息 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/remove-netif.yaml b/docs/host/remove-netif.yaml index 4b1ee94a20..22bb686744 100644 --- a/docs/host/remove-netif.yaml +++ b/docs/host/remove-netif.yaml @@ -1,16 +1,16 @@ post: summary: 物理机删除网卡 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" - in: body name: host required: true schema: - $ref: '../schemas/host.yaml#/HostRemoveNetif' + $ref: "../schemas/host.yaml#/HostRemoveNetif" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/renew-prepaid-recycle.yaml b/docs/host/renew-prepaid-recycle.yaml index 407c8bbf73..b8a1128c94 100644 --- a/docs/host/renew-prepaid-recycle.yaml +++ b/docs/host/renew-prepaid-recycle.yaml @@ -1,11 +1,11 @@ post: summary: 为预付费宿主机续费 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/reset.yaml b/docs/host/reset.yaml index 2f8f015dd6..6d00c7c48b 100644 --- a/docs/host/reset.yaml +++ b/docs/host/reset.yaml @@ -1,11 +1,11 @@ post: summary: 物理机重启 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/spec.yaml b/docs/host/spec.yaml index d6a066aa46..d91c3f033a 100644 --- a/docs/host/spec.yaml +++ b/docs/host/spec.yaml @@ -1,11 +1,11 @@ get: summary: 获取宿主机缩略信息 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机缩略信息 schema: - $ref: "../schemas/host.yaml#HostSpec" + $ref: "../schemas/host.yaml#/HostSpec" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/start.yaml b/docs/host/start.yaml index c23db2ba0d..af4df801df 100644 --- a/docs/host/start.yaml +++ b/docs/host/start.yaml @@ -1,11 +1,11 @@ post: summary: 启动物理机 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/stop.yaml b/docs/host/stop.yaml index 8dd6889e90..38c87c5597 100644 --- a/docs/host/stop.yaml +++ b/docs/host/stop.yaml @@ -1,11 +1,11 @@ post: summary: 物理机关机 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/syncstatus.yaml b/docs/host/syncstatus.yaml index f3a268a5a8..f4f32b554f 100644 --- a/docs/host/syncstatus.yaml +++ b/docs/host/syncstatus.yaml @@ -1,11 +1,11 @@ post: summary: 同步物理机状态 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/undo-convert.yaml b/docs/host/undo-convert.yaml index 8805137a5a..c51169c817 100644 --- a/docs/host/undo-convert.yaml +++ b/docs/host/undo-convert.yaml @@ -1,11 +1,11 @@ post: summary: 将转换成宿主机的物理机转回成物理机 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/undo-prepaid-recycle.yaml b/docs/host/undo-prepaid-recycle.yaml index df78378779..a827a154ee 100644 --- a/docs/host/undo-prepaid-recycle.yaml +++ b/docs/host/undo-prepaid-recycle.yaml @@ -1,11 +1,11 @@ post: summary: 从预付费资源池中移除 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/host/unmaintenance.yaml b/docs/host/unmaintenance.yaml index a51762d806..e24ee1db89 100644 --- a/docs/host/unmaintenance.yaml +++ b/docs/host/unmaintenance.yaml @@ -1,11 +1,11 @@ post: summary: 重启物理机,进入磁盘安装的操作系统 - parameters: + parameters: - $ref: "../parameters/host.yaml#/hostId" responses: 200: description: 宿主机信息 schema: - $ref: "../schemas/host.yaml#HostResponse" + $ref: "../schemas/host.yaml#/HostResponse" tags: - - host \ No newline at end of file + - host diff --git a/docs/image/images.yaml b/docs/image/images.yaml index b3eb63463e..29ce2a76ba 100644 --- a/docs/image/images.yaml +++ b/docs/image/images.yaml @@ -1,14 +1,14 @@ get: summary: 按指定条件列出镜像 parameters: - - $ref: '../parameters/common.yaml#/offset' - - $ref: '../parameters/common.yaml#/limit' - - $ref: '../parameters/common.yaml#/pending_delete' - - $ref: '../parameters/image.yaml#/is_public' - - $ref: '../parameters/image.yaml#/owner' - - $ref: '../parameters/image.yaml#/name' - - $ref: '../parameters/image.yaml#/disk_format' - - $ref: '../parameters/image.yaml#/disk_formats' + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/pending_delete" + - $ref: "../parameters/image.yaml#/is_public" + - $ref: "../parameters/image.yaml#/owner" + - $ref: "../parameters/image.yaml#/name" + - $ref: "../parameters/image.yaml#/disk_format" + - $ref: "../parameters/image.yaml#/disk_formats" responses: 200: description: 镜像列表信息 @@ -20,16 +20,16 @@ get: post: summary: 上传或创建镜像 parameters: - - $ref: '../parameters/image.yaml#content-type' - - $ref: '../parameters/image.yaml#x-image-meta-name' - - $ref: '../parameters/image.yaml#x-image-meta-description' - - in: body - type: file + - $ref: "../parameters/image.yaml#/content-type" + - $ref: "../parameters/image.yaml#/x-image-meta-name" + - $ref: "../parameters/image.yaml#/x-image-meta-description" + - in: body + type: file description: 镜像二进制文件内容,若body为空,仅创建镜像数据库字段,可以通过put接口再次上传body内容 responses: 200: description: 上传的镜像信息 schema: - $ref: "../schemas/image.yaml#ImageResponse" + $ref: "../schemas/image.yaml#/ImageResponse" tags: - images diff --git a/docs/index.yaml b/docs/index.yaml index e16c5d316f..dc952f606e 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -579,6 +579,52 @@ paths: $ref: "./dbinstanceaccount/set-privileges.yaml" + /elasticcaches: + $ref: "./elasticcache/elasticcaches.yaml" + /elasticcaches/{elasticcacheId}: + $ref: "./elasticcache/elasticcache.yaml" + /elasticcaches/{elasticcacheId}/allocate-public-connection: + $ref: "./elasticcache/allocate-public-connection.yaml" + /elasticcaches/{elasticcacheId}/release-public-connection: + $ref: "./elasticcache/release-public-connection.yaml" + /elasticcaches/{elasticcacheId}/change-spec: + $ref: "./elasticcache/change-spec.yaml" + /elasticcaches/{elasticcacheId}/login-info: + $ref: "./elasticcache/login-info.yaml" + /elasticcaches/{elasticcacheId}/flush-instance: + $ref: "./elasticcache/flush-instance.yaml" + /elasticcaches/{elasticcacheId}/restart: + $ref: "./elasticcache/restart.yaml" + /elasticcaches/{elasticcacheId}/set-maintain-time: + $ref: "./elasticcache/set-maintain-time.yaml" + /elasticcaches/{elasticcacheId}/update-auth-mode: + $ref: "./elasticcache/update-auth-mode.yaml" + /elasticcaches/{elasticcacheId}/update-backup-policy: + $ref: "./elasticcache/update-backup-policy.yaml" + /elasticcaches/{elasticcacheId}/update-instance-parameters: + $ref: "./elasticcache/update-instance-parameters.yaml" + /elasticcacheparameters: + $ref: "./elasticcache/elasticcacheparameters.yaml" + /elasticcacheparameters/{parameterId}: + $ref: "./elasticcache/elasticcacheparameter.yaml" + /elasticcacheacls: + $ref: "./elasticcache/elasticcacheacls.yaml" + /elasticcacheacls/{aclId}: + $ref: "./elasticcache/elasticcacheacl.yaml" + /elasticcachebackups: + $ref: "./elasticcache/elasticcachebackups.yaml" + /elasticcachebackups/{backupId}: + $ref: "./elasticcache/elasticcachebackup.yaml" + /elasticcachebackups/{backupId}/restore-instance: + $ref: "./elasticcache/restore-instance.yaml" + /elasticcacheaccounts: + $ref: "./elasticcache/elasticcacheaccounts.yaml" + /elasticcacheaccounts/{accountId}: + $ref: "./elasticcache/elasticcacheaccount.yaml" + /elasticcacheaccounts/{accountId}/reset-password: + $ref: "./elasticcache/reset-password.yaml" + /elasticcacheskus: + $ref: "./elasticcache/elasticcacheskus.yaml" /cloudaccounts: $ref: "./cloudaccount/cloudaccounts.yaml" diff --git a/docs/parameters/elasticcache.yaml b/docs/parameters/elasticcache.yaml new file mode 100644 index 0000000000..dd3e8cf8ca --- /dev/null +++ b/docs/parameters/elasticcache.yaml @@ -0,0 +1,52 @@ +elasticcacheId: + name: elasticcacheId + required: true + in: path + type: string + description: ElasticCache实例名称或ID,建议使用ID + +parameterId: + name: parameterId + required: true + in: path + type: string + description: ElasticCache实例参数名称或ID,建议使用ID + +aclId: + name: aclId + required: true + in: path + type: string + description: ElasticCache实例访问控制名称或ID,建议使用ID + +backupId: + name: backupId + required: true + in: path + type: string + description: ElasticCache实例备份名称或ID,建议使用ID + +accountId: + name: accountId + required: true + in: path + type: string + description: ElasticCache实例用户名称或ID,建议使用ID + +elasticcache_id: + name: elasticcache_id + in: query + type: string + description: 根据ElasticCache实例名称或ID过滤资源 + +engine_version: + name: engine_version + in: query + type: string + description: 根据ElasticCache实例版本过滤资源 + +local_category: + name: local_category + in: query + type: string + description: 根据ElasticCache类型过滤资源 diff --git a/docs/schemas/common.yaml b/docs/schemas/common.yaml index 617313e843..805cd8227c 100644 --- a/docs/schemas/common.yaml +++ b/docs/schemas/common.yaml @@ -181,4 +181,32 @@ BillingBaseResponse: type: string example: "2019-06-11T03:39:02.000000Z" description: 资源到期时间,仅对预付费类型资源有效 + +ProviderBaseResponse: + type: object + properties: + region_id: + type: string + example: 5fbbdfaa-46ba-433a-81be-b3581ac55bfa + description: 区域ID + region_external_id: + type: string + example: 5fbbdfaa-46ba-433a-81be-b3581ac55bfa + description: 区域云端ID + region: + type: string + example: 阿里云 马来西亚(吉隆坡) + description: 区域名称 + project_domain: + type: string + example: Default + description: 项目 + manager: + type: string + example: Default + description: 云账号 + manager_id: + type: string + example: 7b972be9-fd8a-43f5-8058-3820553f61c4 + description: 云账号ID \ No newline at end of file diff --git a/docs/schemas/elasticcache.yaml b/docs/schemas/elasticcache.yaml new file mode 100644 index 0000000000..22acc7dd91 --- /dev/null +++ b/docs/schemas/elasticcache.yaml @@ -0,0 +1,626 @@ +ElasticCache: + allOf: + - $ref: "./common.yaml#/VirtualResourceBaseResponse" + - $ref: "./common.yaml#/BillingResourceBaseResponse" + - $ref: "./common.yaml#/ManagedResourceBaseResponse" + - $ref: "./common.yaml#/ProviderBaseResponse" + - $ref: "./common.yaml#/ZoneResourceBaseResponse" + - $ref: "./common.yaml#/ExternalizedResourceBaseResponse" + - type: object + description: ElasticCache实例 + properties: + engine: + type: string + example: Redis + description: ElasticCache实例引擎 + readOnly: true + engine_version: + type: string + example: "3.0" + description: ElasticCache实例引擎版本 + instance_type: + type: string + example: redis.master.micro.default + description: ElasticCache实例规格 + arch_type: + type: string + example: cluster + description: ElasticCache实例架构类型 + network_id: + type: string + example: 39326a92-8691-49e9-886a-097125c48067 + description: ElasticCache实例子网ID + vcpu_count: + type: integer + example: 1 + description: ElasticCache实例CPU核数 + capacity_mb: + type: integer + example: 1024 + description: ElasticCache实例内存大小 + vpc_id: + type: string + example: 5d0a3589-4ec5-4509-8e53-6505457577b0 + description: ElasticCache实例VPC ID + vpc: + type: string + example: vpc-2zecuo9v4idebme295ofy + description: ElasticCache实例VPC ID + private_connect_port: + type: integer + example: 6379 + description: ElasticCache实例内网端口 + private_ip_addr: + type: string + example: 192.168.0.100 + description: ElasticCache实例内网IP + private_dns: + type: string + example: redisx.aliyuncs.com + description: ElasticCache实例内网域名 + public_connect_port: + type: integer + example: 6379 + description: ElasticCache实例公网端口 + public_ip_addr: + type: string + example: 192.168.0.100 + description: ElasticCache实例公网IP + public_dns: + type: string + example: redisx.aliyuncs.com + description: ElasticCache实例公网域名 + maintain_start_time: + type: string + example: 00:00Z + description: ElasticCache实例维护开始时间 + maintain_end_time: + type: string + example: 02:00Z + description: ElasticCache实例维护结束时间 + +ElasticCacheListResponse: + type: object + properties: + limit: + type: integer + example: 20 + elasticcaches: + type: array + items: + $ref: "#/ElasticCache" + total: + type: integer + example: 124 + +ElasticCacheResponse: + type: object + properties: + elasticcache: + type: object + $ref: "#/ElasticCache" + +ElasticCacheNetwork: + allOf: + - $ref: "./common.yaml#/ResourceBaseResponse" + - type: object + description: ElasticCache实例网络 + properties: + elasticcache_id: + type: string + example: "20f8b552-1b86-4595-89e3-49d123b25215" + description: ElasticCache实例ID + ip_addr: + type: string + example: 10.10.140.141 + description: 实例内网IP地址 + network_id: + type: string + example: "38897a74-17b4-4c21-86b3-4f8528ced003" + description: 实例子网ID + +ElasticCacheNetworkListResponse: + type: object + properties: + limit: + type: integer + example: 20 + elasticcachenetworks: + type: array + items: + $ref: "#/ElasticCacheNetwork" + total: + type: integer + example: 124 + +ElasticCacheNetworkResponse: + type: object + properties: + elasticcachenetwork: + type: object + $ref: "#/ElasticCacheNetwork" + +ElasticCacheParameter: + allOf: + - $ref: "./common.yaml#/StandaloneResponse" + - $ref: "./common.yaml#/ExternalizedResourceBaseResponse" + - type: object + description: ElasticCache实例参数 + properties: + key: + type: string + example: read_buffer_size + description: ElasticCache实例参数 + value: + type: string + example: "131072" + description: ElasticCache实例参数值 + readOnly: true + force_restart: + type: boolean + example: false + description: 重启生效, True(重启生效)/False + readOnly: true + modifiable: + type: boolean + example: false + description: 参数可修改, True(可修改)/False(不可修改) + readOnly: true + +ElasticCacheParameterListResponse: + type: object + properties: + limit: + type: integer + example: 20 + elasticcacheparameters: + type: array + items: + $ref: "#/ElasticCacheParameter" + total: + type: integer + example: 124 + +ElasticCacheParameterResponse: + type: object + properties: + elasticcacheparameter: + type: object + $ref: "#/ElasticCacheParameter" + +ElasticCacheAcl: + allOf: + - $ref: "./common.yaml#/StatusStandaloneResponse" + - $ref: "./common.yaml#/ExternalizedResourceBaseResponse" + - type: object + description: ElasticCache实例访问控制参数 + properties: + Name: + type: string + example: web_acl + description: ElasticCache实例访问控制Name参数 + IpList: + type: string + example: 192.168.0.1,192.168.0.2 + description: ElasticCache实例访问控制IpList参数 + elasticcache_id: + type: string + example: d0fe1519-8de5-4e13-844a-7367f4210f83 + description: ElasticCache实例ID + readOnly: true + +ElasticCacheAclListResponse: + type: object + properties: + limit: + type: integer + example: 20 + elasticcacheacls: + type: array + items: + $ref: "#/ElasticCacheAcl" + total: + type: integer + example: 124 + +ElasticCacheAclResponse: + type: object + properties: + elasticcacheacl: + type: object + $ref: "#/ElasticCacheAcl" + +ElasticCacheBackup: + allOf: + - $ref: "./common.yaml#/StatusStandaloneResponse" + - $ref: "./common.yaml#/ExternalizedResourceBaseResponse" + - type: object + description: ElasticCache实例备份参数 + properties: + start_time: + type: string + example: "2019-06-22T02:31:08.000000Z" + description: ElasticCache实例备份开始时间 + end_time: + type: string + example: "2019-06-22T02:33:24.000000Z" + description: ElasticCache实例备份结束时间 + backup_type: + type: string + example: full_backup + description: ElasticCache实例备份类型, 全量|增量额 + backup_mode: + type: string + example: manual + description: ElasticCache实例备份类型, 自动|手动 + backup_size_mb: + type: integer + example: 21 + description: 备份大小 + elasticcache_id: + type: string + example: d0fe1519-8de5-4e13-844a-7367f4210f83 + description: ElasticCache实例ID + readOnly: true + download_url: + type: string + example: redisx.aliyuncs.com/redis.bak + description: ElasticCache备份下载链接 + readOnly: true + +ElasticCacheBackupListResponse: + type: object + properties: + limit: + type: integer + example: 20 + elasticcachebackups: + type: array + items: + $ref: "#/ElasticCacheBackup" + total: + type: integer + example: 124 + +ElasticCacheBackupResponse: + type: object + properties: + elasticcachebackup: + type: object + $ref: "#/ElasticCacheBackup" + +ElasticCacheAccount: + allOf: + - $ref: "./common.yaml#/StandaloneResponse" + - $ref: "./common.yaml#/ExternalizedResourceBaseResponse" + - type: object + description: ElasticCache实例账号参数 + properties: + password: + type: string + example: abcFFFssx + description: 账号密码 + account_privilege: + type: string + example: read + description: 账号权限 read | write | repl(复制, 复制权限支持读写,且开放SYNC/PSYNC命令) + account_type: + type: string + example: normal + description: 账号类型 normal |admin + elasticcache_id: + type: string + example: d0fe1519-8de5-4e13-844a-7367f4210f83 + description: ElasticCache实例ID + readOnly: true + +ElasticCacheAccountListResponse: + type: object + properties: + limit: + type: integer + example: 20 + elasticcacheaccounts: + type: array + items: + $ref: "#/ElasticCacheAccount" + total: + type: integer + example: 124 + +ElasticCacheAccountResponse: + type: object + properties: + elasticcacheaccount: + type: object + $ref: "#/ElasticCacheAccount" + +ElasticCacheSku: + allOf: + - $ref: "./common.yaml#/StandaloneResponse" + - $ref: "./common.yaml#/ExternalizedResourceBaseResponse" + - type: object + description: ElasticCache实例套餐信息 + properties: + cloudregion_id: + type: string + example: 2c328dbb-dc40-41f0-8fbd-20a0cbe1829b + description: 实例所在区域ID + engine: + type: string + example: redis + description: 实例引擎 + engine_arch: + type: string + example: cluster + description: 实例架构 + engine_version: + type: string + example: "2.8" + description: 实例版本 + readOnly: true + id: + type: string + example: de76d65b-6134-4945-8ce7-0789d37b5072 + description: 实例ID + readOnly: true + instance_spec: + type: string + example: redis.sharding.basic.small.defaut + description: 实例规格 + readOnly: true + name: + type: string + example: redis.sharding.basic.small.default:v2.8 + description: 实例规格名称 + readOnly: true + local_category: + type: string + example: cluster + description: 实例在Onecloud中所属类别 + readOnly: true + memory_size_mb: + type: integer + example: 16384 + description: 实例内存大小MB + readOnly: true + postpaid_status: + type: string + example: available + description: 实例按需付费可用状态 available|soldout + readOnly: true + prepaid_status: + type: string + example: available + description: 实例预付费可用状态 available|soldout + readOnly: true + provider: + type: string + example: Aliyun + description: 实例Provider + readOnly: true + zone_id: + type: string + example: Aliyun + description: 实例所在可用区ID + readOnly: true + storage_type: + type: string + example: inmemory + description: 实例存储类型 + readOnly: true + max_connections: + type: integer + example: 1000000 + description: 实例最大连接数 + readOnly: true + +ElasticCacheSkuListResponse: + type: object + properties: + limit: + type: integer + example: 20 + elasticcacheskus: + type: array + items: + $ref: "#/ElasticCacheSku" + total: + type: integer + example: 124 + +ElasticCacheSkuResponse: + type: object + properties: + elasticcachesku: + type: object + $ref: "#/ElasticCacheSku" + +ElasticCacheCreate: + type: object + properties: + name: + type: string + example: test-instance + description: 实例名称 + cloudregion: + type: string + example: ebb5abd3-8ffb-42ec-8bc6-38ba5b949885 + description: 实例所在区域 Id + zone: + type: string + example: 70802da8-affe-4247-8ce8-610f205019ca + description: 实例所在可用区 Id + network: + type: string + example: 70802da8-affe-4247-8ce8-610f205019ca + description: 实例所在子网 Id + engine: + type: string + example: redis + description: 实例引擎 redis + engine_version: + type: string + example: "4.0" + enum: ["2.8", "3.0", "4.0", "5.0"] + password: + type: string + example: dfdf11AAZ + description: 实例访问密码 + instance_type: + type: string + example: 80802da8-affe-4247-8ce8-610f205019ca + description: 实例规格ID + billing_type: + type: string + example: postpaid + description: 计费类型, postpaid|prepaid + billing_cycle: + type: string + example: 1M + description: 计费周期, eg. 1M 1Y + +ElasticCacheAccountCreate: + type: object + properties: + name: + type: string + example: test-instance + description: 账号名称 + password: + type: string + example: dfdf11AAZ + description: 账号访问密码 + account_privilege: + type: string + example: read + description: 账号权限 read|write|repl + elasticache: + type: string + example: 90802da8-affe-4247-8ce8-610f205019ca + description: 实例ID + +ElasticCacheAclCreate: + type: object + properties: + name: + type: string + example: test-instance + description: 访问控制名称 + ip_list: + type: string + example: 192.168.0.1,192.168.0.2 + description: 访问控制IP列表,逗号分隔 + elasticache: + type: string + example: 90802da8-affe-4247-8ce8-610f205019ca + description: 实例ID + +ElasticCacheAclUpdate: + type: object + properties: + ip_list: + type: string + example: 192.168.0.1,192.168.0.2 + description: 访问控制IP列表,逗号分隔 + +ElasticCacheParameterUpdate: + type: object + properties: + id: + type: string + example: 10802da8-affe-4247-8ce8-610f205019ca + description: 参数ID + value: + type: string + example: 1000 + description: 参数值 + +ElasticCacheAllocatePublicConnection: + type: object + properties: + port: + type: integer + required: false + example: 6379 + description: 公网访问端口号, 1024~65535 + +ElasticCacheChangeSpec: + type: object + properties: + sku: + type: string + required: true + example: 10802da8-affe-4247-8ce8-610f205019ca + description: 规格ID + +ElasticCacheSetMaintainTime: + type: object + properties: + maintain_start_time: + type: string + required: true + example: "00:00" + description: 维护开始时间, 格式:'HH:mm' + maintain_end_time: + type: string + required: true + example: "02:00" + description: 维护结束时间, 格式:'HH:mm' + +ElasticCacheAuthMode: + type: object + properties: + auth_mode: + type: string + required: true + example: on + description: 认证模式, on(开启密码认证)|off(关闭密码认证) + +ElasticCacheBackupPolicy: + type: object + properties: + backup_type: + type: string + required: false + example: automated + description: 备份类型, automated | manual + backup_reserved_days: + type: integer + required: false + example: 7 + description: 备份保留天数, 1~7 + preferred_backup_period: + type: string + required: true + example: Monday + description: 备份周期, Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday + preferred_backup_time: + type: string + required: true + example: 00:00Z-02:00Z + description: 备份时间段, 格式: 'HH:mmZ-HH:mmZ' + +ElasticCacheResetPassword: + type: object + properties: + password: + type: string + required: false + example: pxxxword + description: 新密码 + reset_password: + type: boolean + required: false + example: true + description: 新密码 + +ElasticCacheLoginInfoResponse: + type: object + properties: + password: + type: string + example: 1111111 + username: + type: string + example: testUser diff --git a/docs/schemas/loadbalancer.yaml b/docs/schemas/loadbalancer.yaml index 2a6d68922b..99fcbeb190 100644 --- a/docs/schemas/loadbalancer.yaml +++ b/docs/schemas/loadbalancer.yaml @@ -227,6 +227,7 @@ LoadbalancerAclEntries: type: array items: $ref: "#/LoadbalancerAclEntry" + LoadbalancerCachedAclCreateRequest: type: object properties: @@ -249,6 +250,7 @@ LoadbalancerCachedAclCreateRequest: listener: type: string description: 指定负载均衡监听器ID,华为云必须指定该参数。 + LoadbalancerCachedAcl: allOf: - $ref: "./common.yaml#/SharableVirtualResourceBaseResponse" @@ -635,7 +637,7 @@ LoadbalancerAgentDeployRequest: type: object properties: host: - $ref: "./ansibleplaybook.yaml#AnsiblePlaybookInventoryHost" + $ref: "./ansibleplaybook.yaml#/AnsiblePlaybookInventoryHost" deploy_method: type: string description: 部署方法 diff --git a/docs/secgroup/private.yaml b/docs/secgroup/private.yaml index a474f92ba9..ae652daaf0 100644 --- a/docs/secgroup/private.yaml +++ b/docs/secgroup/private.yaml @@ -1,12 +1,12 @@ post: summary: 取消安全组共享 - parameters: + parameters: - $ref: "../parameters/secgroup.yaml#/secgroupId" responses: 200: description: 安全组信息 schema: - $ref: "../schemas/secgroup.yaml#SecgroupResponse" + $ref: "../schemas/secgroup.yaml#/SecgroupResponse" tags: - - secgroups \ No newline at end of file + - secgroups diff --git a/docs/secgroup/public.yaml b/docs/secgroup/public.yaml index 14b21ee9ba..3a28158c2c 100644 --- a/docs/secgroup/public.yaml +++ b/docs/secgroup/public.yaml @@ -1,6 +1,6 @@ post: summary: 共享安全组 - parameters: + parameters: - $ref: "../parameters/secgroup.yaml#/secgroupId" - $ref: "../parameters/secgroup.yaml#/scope" - $ref: "../parameters/secgroup.yaml#/shared_projects" @@ -8,7 +8,7 @@ post: 200: description: 安全组信息 schema: - $ref: "../schemas/secgroup.yaml#SecgroupResponse" + $ref: "../schemas/secgroup.yaml#/SecgroupResponse" tags: - - secgroups \ No newline at end of file + - secgroups diff --git a/docs/serversku/disable.yaml b/docs/serversku/disable.yaml index 67ae758b50..43e9dd7a31 100644 --- a/docs/serversku/disable.yaml +++ b/docs/serversku/disable.yaml @@ -1,12 +1,12 @@ post: summary: 禁用实例套餐 - parameters: + parameters: - $ref: "../parameters/serversku.yaml#/serverskuId" responses: 200: description: 禁用的实例套餐信息 schema: - $ref: "../schemas/serversku.yaml#ServerSkuResponse" + $ref: "../schemas/serversku.yaml#/ServerSkuResponse" tags: - - serverskus \ No newline at end of file + - serverskus diff --git a/docs/serversku/enable.yaml b/docs/serversku/enable.yaml index 175b555f75..85c164e5c0 100644 --- a/docs/serversku/enable.yaml +++ b/docs/serversku/enable.yaml @@ -1,12 +1,12 @@ post: summary: 启用实例套餐 - parameters: + parameters: - $ref: "../parameters/serversku.yaml#/serverskuId" responses: 200: description: 启用的实例套餐信息 schema: - $ref: "../schemas/serversku.yaml#ServerSkuResponse" + $ref: "../schemas/serversku.yaml#/ServerSkuResponse" tags: - - serverskus \ No newline at end of file + - serverskus diff --git a/docs/serversku/serverskus.yaml b/docs/serversku/serverskus.yaml index 663bb4491b..b762407e7f 100644 --- a/docs/serversku/serverskus.yaml +++ b/docs/serversku/serverskus.yaml @@ -1,15 +1,15 @@ get: summary: 按指定条件列出实例套餐 parameters: - - $ref: '../parameters/common.yaml#/limit' - - $ref: '../parameters/common.yaml#/offset' - - $ref: '../parameters/common.yaml#/cloud_env' - - $ref: '../parameters/common.yaml#/cloudregion' - - $ref: '../parameters/common.yaml#/zone' - - $ref: '../parameters/common.yaml#/city' - - $ref: '../parameters/serversku.yaml#/provider' - - $ref: '../parameters/serversku.yaml#/memory_size_mb' - - $ref: '../parameters/serversku.yaml#/usable' + - $ref: "../parameters/common.yaml#/limit" + - $ref: "../parameters/common.yaml#/offset" + - $ref: "../parameters/common.yaml#/cloud_env" + - $ref: "../parameters/common.yaml#/cloudregion" + - $ref: "../parameters/common.yaml#/zone" + - $ref: "../parameters/common.yaml#/city" + - $ref: "../parameters/serversku.yaml#/provider" + - $ref: "../parameters/serversku.yaml#/memory_size_mb" + - $ref: "../parameters/serversku.yaml#/usable" responses: 200: description: 实例套餐列表信息 @@ -24,12 +24,12 @@ post: name: serversku required: true schema: - $ref: '../schemas/serversku.yaml#/ServerSkuCreate' + $ref: "../schemas/serversku.yaml#/ServerSkuCreate" responses: 200: description: 新创建的实例套餐信息 schema: - $ref: "../schemas/serversku.yaml#ServerSkuResponse" + $ref: "../schemas/serversku.yaml#/ServerSkuResponse" tags: - serverskus diff --git a/docs/storagecache/cache-image.yaml b/docs/storagecache/cache-image.yaml index 6fff7528e7..e99aa028bb 100644 --- a/docs/storagecache/cache-image.yaml +++ b/docs/storagecache/cache-image.yaml @@ -1,6 +1,6 @@ post: summary: 缓存镜像到此存储缓存上 - parameters: + parameters: - $ref: "../parameters/storagecache.yaml#/storagecacheId" - $ref: "../parameters/storagecache.yaml#/image" - $ref: "../parameters/storagecache.yaml#/is_force" @@ -9,6 +9,6 @@ post: 200: description: 存储缓存信息 schema: - $ref: "../schemas/storagecache.yaml#StorageCacheResponse" + $ref: "../schemas/storagecache.yaml#/StorageCacheResponse" tags: - storagecaches diff --git a/pkg/apis/compute/dbinstance.go b/pkg/apis/compute/dbinstance.go index 8d533be414..ca00853a09 100644 --- a/pkg/apis/compute/dbinstance.go +++ b/pkg/apis/compute/dbinstance.go @@ -1,3 +1,17 @@ +// 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 compute import "yunion.io/x/onecloud/pkg/apis" diff --git a/pkg/apis/compute/dbinstance_account.go b/pkg/apis/compute/dbinstance_account.go index 608b7c3bd3..abe1fe5b0b 100644 --- a/pkg/apis/compute/dbinstance_account.go +++ b/pkg/apis/compute/dbinstance_account.go @@ -1,3 +1,17 @@ +// 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 compute import "yunion.io/x/onecloud/pkg/apis" diff --git a/pkg/apis/compute/dbinstance_backup.go b/pkg/apis/compute/dbinstance_backup.go index 9d481fb0ac..4374e3893a 100644 --- a/pkg/apis/compute/dbinstance_backup.go +++ b/pkg/apis/compute/dbinstance_backup.go @@ -1,3 +1,17 @@ +// 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 compute import "yunion.io/x/onecloud/pkg/apis" diff --git a/pkg/apis/compute/dbinstance_database.go b/pkg/apis/compute/dbinstance_database.go index 74ee30dab1..955b46b769 100644 --- a/pkg/apis/compute/dbinstance_database.go +++ b/pkg/apis/compute/dbinstance_database.go @@ -1,3 +1,17 @@ +// 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 compute import "yunion.io/x/onecloud/pkg/apis" diff --git a/pkg/apis/compute/dbinstance_sku_const.go b/pkg/apis/compute/dbinstance_sku_const.go index 0435ea6745..f4d9dc903a 100644 --- a/pkg/apis/compute/dbinstance_sku_const.go +++ b/pkg/apis/compute/dbinstance_sku_const.go @@ -1,3 +1,17 @@ +// 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 compute const ( diff --git a/pkg/apis/compute/elasticcache_const.go b/pkg/apis/compute/elasticcache_const.go index 0a0941ef1a..e2099600d0 100644 --- a/pkg/apis/compute/elasticcache_const.go +++ b/pkg/apis/compute/elasticcache_const.go @@ -16,25 +16,81 @@ package compute const ( ELASTIC_CACHE_STATUS_RUNNING = "running" //(正常) + ELASTIC_CACHE_STATUS_RESTARTING = "restarting" //(重启中) + ELASTIC_CACHE_STATUS_RESTART_FAILED = "restart_failed" //(重启失败) ELASTIC_CACHE_STATUS_DEPLOYING = "deploying" //(创建中) + ELASTIC_CACHE_STATUS_CREATE_FAILED = "create_failed" //(创建失败) ELASTIC_CACHE_STATUS_CHANGING = "changing" //(修改中) + ELASTIC_CACHE_STATUS_CHANGE_FAILED = "change_failed" //(修改失败) ELASTIC_CACHE_STATUS_INACTIVE = "inactive" //(被禁用) ELASTIC_CACHE_STATUS_FLUSHING = "flushing" //(清除中) ELASTIC_CACHE_STATUS_RELEASED = "released" //(已释放) + ELASTIC_CACHE_STATUS_RELEASE_FAILED = "release_failed" //(释放失败) ELASTIC_CACHE_STATUS_TRANSFORMING = "transforming" //(转换中) ELASTIC_CACHE_STATUS_UNAVAILABLE = "unavailable" //(服务停止) - ELASTIC_CACHE_STATUS_ERROR = "error" //(创建失败) + ELASTIC_CACHE_STATUS_ERROR = "error" //(删除失败) ELASTIC_CACHE_STATUS_MIGRATING = "migrating" //(迁移中) ELASTIC_CACHE_STATUS_BACKUPRECOVERING = "backuprecovering" //(备份恢复中) ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING = "minorversionupgrading" //(小版本升级中) ELASTIC_CACHE_STATUS_NETWORKMODIFYING = "networkmodifying" //(网络变更中) ELASTIC_CACHE_STATUS_SSLMODIFYING = "sslmodifying" //(SSL变更中) ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING = "majorversionupgrading" //(大版本升级中,可正常访问) + ELASTIC_CACHE_STATUS_UNKNOWN = "unknown" //(未知状态) + ELASTIC_CACHE_STATUS_SYNCING = "syncing" //(同步中) + ELASTIC_CACHE_STATUS_SYNC_FAILED = "sync_failed" //(同步失败) ) const ( - ELASTIC_CACHE_ARCH_TYPE_STAND_ALONE = "standalone" // - ELASTIC_CACHE_ARCH_TYPE_MASTER_SLAVE = "master_slave" // - ELASTIC_CACHE_ARCH_TYPE_CLUSTER = "cluster" // 集群 - ELASTIC_CACHE_ARCH_TYPE_PROXY = "proxy" // 代理集群 + ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE = "available" // 正常可用 + ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE = "unavailable" // 不可用 + ELASTIC_CACHE_ACCOUNT_STATUS_CREATING = "creating" // 创建中 + ELASTIC_CACHE_ACCOUNT_STATUS_CREATE_FAILED = "create_failed" //(创建失败) + ELASTIC_CACHE_ACCOUNT_STATUS_DELETING = "deleting" // 删除中 + ELASTIC_CACHE_ACCOUNT_STATUS_DELETE_FAILED = "delete_failed" // 删除失败 +) + +const ( + ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL = "normal" // 普通账号 + ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN = "admin" // 管理账号 +) + +const ( + ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ = "read" // 只读 + ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE = "write" // 读写 + ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL = "repl" // 复制,复制权限支持读写,且支持使用SYNC/PSYNC命令。 +) + +const ( + ELASTIC_CACHE_BACKUP_STATUS_CREATING = "creating" // 备份中 + ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED = "expired" //(备份文件已过期) + ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED = "deleted" //(备份文件已删除) + ELASTIC_CACHE_BACKUP_STATUS_DELETING = "deleting" // 删除中 + ELASTIC_CACHE_BACKUP_STATUS_SUCCESS = "success" // 备份成功 + ELASTIC_CACHE_BACKUP_STATUS_FAILED = "failed" // 备份失败 +) + +const ( + ELASTIC_CACHE_BACKUP_TYPE_FULL = "full" // 全量备份 + ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL = "incremental" // 增量备份 +) + +const ( + ELASTIC_CACHE_BACKUP_MODE_AUTOMATED = "automated" // 自动备份 + ELASTIC_CACHE_BACKUP_MODE_MANUAL = "manual" // 手动触发备份 +) + +const ( + ELASTIC_CACHE_ACL_STATUS_AVAILABLE = "available" // 正常可用 + ELASTIC_CACHE_ACL_STATUS_CREATING = "creating" // 创建中 + ELASTIC_CACHE_ACL_STATUS_CREATE_FAILED = "create_failed" //(创建失败) + ELASTIC_CACHE_ACL_STATUS_DELETING = "deleting" // 删除中 + ELASTIC_CACHE_ACL_STATUS_DELETE_FAILED = "delete_failed" // 删除失败 + ELASTIC_CACHE_ACL_STATUS_UPDATING = "updating" // 更新中 + ELASTIC_CACHE_ACL_STATUS_UPDATE_FAILED = "update_failed" // 更新失败 +) + +const ( + ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE = "available" // 正常可用 + ELASTIC_CACHE_PARAMETER_STATUS_UPDATING = "updating" // 更新中 + ELASTIC_CACHE_PARAMETER_STATUS_UPDATE_FAILED = "update_failed" // 更新失败 ) diff --git a/pkg/apis/compute/secgroup.go b/pkg/apis/compute/secgroup.go index daa831960d..a7dfae1d19 100644 --- a/pkg/apis/compute/secgroup.go +++ b/pkg/apis/compute/secgroup.go @@ -1,3 +1,17 @@ +// 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 compute import ( diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index 0622bddd25..35947d4838 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -65,6 +65,9 @@ const ( ACT_BACKUP_START = "backup_start" ACT_BACKUP_START_FAILED = "backup_start_fail" + ACT_RESTARING = "restarting" + ACT_RESTART_FAIL = "restart_fail" + ACT_STOPPING = "stopping" ACT_STOP = "stop" ACT_STOP_FAIL = "stop_fail" diff --git a/pkg/cloudnet/models/util_errors.go b/pkg/cloudnet/models/util_errors.go index add47bdfb1..1dd6b78f01 100644 --- a/pkg/cloudnet/models/util_errors.go +++ b/pkg/cloudnet/models/util_errors.go @@ -1,3 +1,17 @@ +// 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 models type ( diff --git a/pkg/cloudnet/models/util_subnets.go b/pkg/cloudnet/models/util_subnets.go index 1b0d664f74..9216e08233 100644 --- a/pkg/cloudnet/models/util_subnets.go +++ b/pkg/cloudnet/models/util_subnets.go @@ -1,3 +1,17 @@ +// 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 models import ( diff --git a/pkg/cloudnet/utils/doc.go b/pkg/cloudnet/utils/doc.go index bd6ede3e15..fad7b48d0f 100644 --- a/pkg/cloudnet/utils/doc.go +++ b/pkg/cloudnet/utils/doc.go @@ -1 +1,15 @@ +// 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 utils // import "yunion.io/x/onecloud/pkg/cloudnet/utils" diff --git a/pkg/cloudnet/utils/key.go b/pkg/cloudnet/utils/key.go index 1f2cee8fc8..e6990bae2f 100644 --- a/pkg/cloudnet/utils/key.go +++ b/pkg/cloudnet/utils/key.go @@ -1,3 +1,17 @@ +// 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 utils import ( diff --git a/pkg/cloudnet/utils/key_test.go b/pkg/cloudnet/utils/key_test.go index f2c2f39ace..9a71e3e552 100644 --- a/pkg/cloudnet/utils/key_test.go +++ b/pkg/cloudnet/utils/key_test.go @@ -1,3 +1,17 @@ +// 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 utils import ( diff --git a/pkg/cloudprovider/elasticcache.go b/pkg/cloudprovider/elasticcache.go new file mode 100644 index 0000000000..f7d096e8c5 --- /dev/null +++ b/pkg/cloudprovider/elasticcache.go @@ -0,0 +1,70 @@ +// 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 cloudprovider + +import "yunion.io/x/onecloud/pkg/util/billing" + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html +// https://help.aliyun.com/document_detail/60873.html?spm=a2c4g.11174283.6.715.7412dce0qSYemb +type SCloudElasticCacheInput struct { + RegionId string // 地域 + InstanceType string // 实例规格 redis.master.small.default + CapacityGB int64 // 缓存容量 华为云此项参数必选 + InstanceName string // 实例名称 + UserName string // redis 用户名,可选 + Password string // redis 用户密码,可选 + ZoneIds []string // 可用区, 可选 + ChargeType string // 计费类型,可选 + NodeType string // 节点类型,可选 + NetworkType string // 网络类型 VPC|CLASSIC,可选 + VpcId string // VPC ,可选 + NetworkId string // 子网ID,可选 + Engine string // Redis|Memcache + EngineVersion string // 版本类型 + PrivateIpAddress string // 指定新实例的内网IP地址。 + SecurityGroupId string // 安全组ID + EipId string // 绑定弹性IP + MaintainBegin string // 维护时间窗开始时间,格式为HH:mm:ss + MaintainEnd string // 维护时间窗结束时间,格式为HH:mm:ss + BC *billing.SBillingCycle // 包年包月 +} + +type SCloudElasticCacheAccountInput struct { + AccountName string // 账号名称 + AccountPassword string // 账号密码 + AccountPrivilege string // 账号权限 + Description string // 账号描述 +} + +type SCloudElasticCacheAccountResetPasswordInput struct { + NoPasswordAccess *bool // 免密码访问 + NewPassword string // 新密码 + OldPassword *string // 旧密码。required by huawei +} + +type SCloudElasticCacheAccountUpdateInput struct { + NoPasswordAccess *bool // 免密码访问 + Password *string // 新密码 + OldPassword *string // 旧密码。required by huawei + AccountPrivilege *string + Description *string +} + +type SCloudElasticCacheBackupPolicyUpdateInput struct { + BackupType string // auto:自动备份 / manual:手动备份 + BackupReservedDays int // 1-7 + PreferredBackupPeriod string // Monday(周一) / Tuesday(周二) / Wednesday(周三) / Thursday(周四) / Friday(周五) / Saturday(周六) / Sunday(周日) + PreferredBackupTime string // 备份时间,格式:HH:mmZ-HH:mmZ +} diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 3984b34382..e66bc8c14a 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -128,6 +128,8 @@ type ICloudRegion interface { CreateIDBInstance(desc *SManagedDBInstanceCreateConfig) (ICloudDBInstance, error) GetIElasticcaches() ([]ICloudElasticcache, error) + GetIElasticcacheById(id string) (ICloudElasticcache, error) + CreateIElasticcaches(ec *SCloudElasticCacheInput) (ICloudElasticcache, error) GetProvider() string } @@ -839,10 +841,31 @@ type ICloudElasticcache interface { GetMaintainStartTime() string GetMaintainEndTime() string + GetAuthMode() string + GetICloudElasticcacheAccounts() ([]ICloudElasticcacheAccount, error) GetICloudElasticcacheAcls() ([]ICloudElasticcacheAcl, error) GetICloudElasticcacheBackups() ([]ICloudElasticcacheBackup, error) GetICloudElasticcacheParameters() ([]ICloudElasticcacheParameter, error) + + GetICloudElasticcacheAccount(accountId string) (ICloudElasticcacheAccount, error) + GetICloudElasticcacheAcl(aclId string) (ICloudElasticcacheAcl, error) + GetICloudElasticcacheBackup(backupId string) (ICloudElasticcacheBackup, error) + + Restart() error + Delete() error + ChangeInstanceSpec(spec string) error + SetMaintainTime(maintainStartTime, maintainEndTime string) error + AllocatePublicConnection(port int) (string, error) // return url & error info + ReleasePublicConnection() error + + CreateAccount(account SCloudElasticCacheAccountInput) (ICloudElasticcacheAccount, error) + CreateAcl(aclName, securityIps string) (ICloudElasticcacheAcl, error) + CreateBackup() (ICloudElasticcacheBackup, error) + FlushInstance() error + UpdateAuthMode(noPasswordAccess bool) error + UpdateInstanceParameters(config jsonutils.JSONObject) error + UpdateBackupPolicy(config SCloudElasticCacheBackupPolicyUpdateInput) error } type ICloudElasticcacheAccount interface { @@ -850,12 +873,19 @@ type ICloudElasticcacheAccount interface { GetAccountType() string GetAccountPrivilege() string + + Delete() error + ResetPassword(input SCloudElasticCacheAccountResetPasswordInput) error + UpdateAccount(input SCloudElasticCacheAccountUpdateInput) error } type ICloudElasticcacheAcl interface { ICloudResource GetIpList() string + + Delete() error + UpdateAcl(securityIps string) error } type ICloudElasticcacheBackup interface { @@ -868,6 +898,9 @@ type ICloudElasticcacheBackup interface { GetStartTime() time.Time GetEndTime() time.Time + + Delete() error + RestoreInstance(instanceId string) error } type ICloudElasticcacheParameter interface { diff --git a/pkg/compute/models/cloudsync.go b/pkg/compute/models/cloudsync.go index 9bce73c65a..55b4d86164 100644 --- a/pkg/compute/models/cloudsync.go +++ b/pkg/compute/models/cloudsync.go @@ -126,6 +126,8 @@ func syncRegionSkus(ctx context.Context, localRegion *SCloudregion) { if err != nil { log.Errorf("SchedManager SyncSku %s", err) } + + syncElasticCacheSkusByRegion(localRegion) } func syncProjects(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, driver cloudprovider.ICloudProvider, provider *SCloudprovider) { diff --git a/pkg/compute/models/dbinstance_skus.go b/pkg/compute/models/dbinstance_skus.go index 9cc4f2e0f7..bd8a342f46 100644 --- a/pkg/compute/models/dbinstance_skus.go +++ b/pkg/compute/models/dbinstance_skus.go @@ -1,3 +1,17 @@ +// 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 models import ( diff --git a/pkg/compute/models/elasticcache_accounts.go b/pkg/compute/models/elasticcache_accounts.go index 4dd263846f..6547589521 100644 --- a/pkg/compute/models/elasticcache_accounts.go +++ b/pkg/compute/models/elasticcache_accounts.go @@ -16,14 +16,24 @@ package models import ( "context" + "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" + "yunion.io/x/pkg/utils" + api "yunion.io/x/onecloud/pkg/apis/compute" "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/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/choices" + "yunion.io/x/onecloud/pkg/util/seclib2" ) // SElasticcache.Account @@ -51,8 +61,9 @@ type SElasticcacheAccount struct { ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id - AccountType string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"` // 账号类型 normal |admin - AccountPrivilege string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"` // 账号权限 read | write + AccountType string `width:"16" charset:"ascii" nullable:"false" list:"user" update:"user" create:"optional"` // 账号类型 normal |admin + AccountPrivilege string `width:"16" charset:"ascii" nullable:"false" list:"user" update:"user" create:"optional"` // 账号权限 read | write | repl(复制, 复制权限支持读写,且开放SYNC/PSYNC命令) + Password string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 账号密码 } func (manager *SElasticcacheAccountManager) SyncElasticcacheAccounts(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, cloudElasticcacheAccounts []cloudprovider.ICloudElasticcacheAccount) compare.SyncResult { @@ -133,6 +144,15 @@ func (self *SElasticcacheAccount) SyncWithCloudElasticcacheAccount(ctx context.C return nil } +func (self *SElasticcacheAccount) GetRegion() *SCloudregion { + iec, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return nil + } + + return iec.(*SElasticcache).GetRegion() +} + func (manager *SElasticcacheAccountManager) newFromCloudElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, extAccount cloudprovider.ICloudElasticcacheAccount) (*SElasticcacheAccount, error) { lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred)) defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred)) @@ -154,3 +174,222 @@ func (manager *SElasticcacheAccountManager) newFromCloudElasticcacheAccount(ctx return &account, nil } + +func (manager *SElasticcacheAccountManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return db.IsAdminAllowCreate(userCred, manager) +} + +func (manager *SElasticcacheAccountManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + var region *SCloudregion + if id, _ := data.GetString("elasticcache"); len(id) > 0 { + ec, err := db.FetchByIdOrName(ElasticcacheManager, userCred, id) + if err != nil { + return nil, fmt.Errorf("getting elastic cache instance failed") + } + region = ec.(*SElasticcache).GetRegion() + } else { + return nil, httperrors.NewMissingParameterError("elasticcache_id") + } + + data, err := manager.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data) + if err != nil { + return nil, err + } + + return region.GetDriver().ValidateCreateElasticcacheAccountData(ctx, userCred, ownerId, data) +} + +func (self *SElasticcacheAccount) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { + self.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + if len(self.Password) > 0 { + self.SavePassword(self.Password) + } + + self.SetStatus(userCred, api.ELASTIC_CACHE_ACCOUNT_STATUS_CREATING, "") + if err := self.StartElasticcacheAccountCreateTask(ctx, userCred, data.(*jsonutils.JSONDict), ""); err != nil { + log.Errorf("Failed to create elastic account cache error: %v", err) + } +} + +func (self *SElasticcacheAccount) StartElasticcacheAccountCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAccountCreateTask", self, userCred, jsonutils.NewDict(), parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcacheAccount) GetCreateAliyunElasticcacheAccountParams() (cloudprovider.SCloudElasticCacheAccountInput, error) { + ret := cloudprovider.SCloudElasticCacheAccountInput{} + ret.AccountName = self.Name + ret.Description = self.Description + passwd, err := self.GetDecodedPassword() + if err != nil { + return ret, err + } + + ret.AccountPassword = passwd + + switch self.AccountPrivilege { + case "read": + ret.AccountPrivilege = "RoleReadOnly" + case "write": + ret.AccountPrivilege = "RoleReadWrite" + case "repl": + ret.AccountPrivilege = "RoleRepl" + } + + return ret, nil +} + +func (self *SElasticcacheAccount) GetUpdateAliyunElasticcacheAccountParams(data jsonutils.JSONDict) (cloudprovider.SCloudElasticCacheAccountUpdateInput, error) { + ret := cloudprovider.SCloudElasticCacheAccountUpdateInput{} + + if desc, _ := data.GetString("description"); len(desc) > 0 { + ret.Description = &desc + } + + if password, _ := data.GetString("password"); len(password) > 0 { + ret.Password = &password + } + + if ok := data.Contains("no_password_access"); ok { + passwordAccess, _ := data.Bool("no_password_access") + ret.NoPasswordAccess = &passwordAccess + } + + if privilege, _ := data.GetString("account_privilege"); len(privilege) > 0 { + var p string + switch privilege { + case "read": + p = "RoleReadOnly" + case "write": + p = "RoleReadWrite" + case "repl": + p = "RoleRepl" + default: + return ret, fmt.Errorf("ElasticcacheAccount.GetUpdateAliyunElasticcacheAccountParams invalid account_privilege %s", privilege) + } + + ret.AccountPrivilege = &p + } + + return ret, nil +} + +func (self *SElasticcacheAccount) GetUpdateHuaweiElasticcacheAccountParams(data jsonutils.JSONDict) (cloudprovider.SCloudElasticCacheAccountUpdateInput, error) { + ret := cloudprovider.SCloudElasticCacheAccountUpdateInput{} + + if desc, _ := data.GetString("description"); len(desc) > 0 { + ret.Description = &desc + } + + if password, _ := data.GetString("password"); len(password) > 0 { + ret.Password = &password + oldpasswd, err := self.GetDecodedPassword() + if err != nil { + return ret, err + } + + ret.OldPassword = &oldpasswd + } + + if ok := data.Contains("no_password_access"); ok { + passwordAccess, _ := data.Bool("no_password_access") + ret.NoPasswordAccess = &passwordAccess + } + + return ret, nil +} + +func (self *SElasticcacheAccount) SavePassword(passwd string) error { + passwd, err := utils.EncryptAESBase64(self.Id, passwd) + if err != nil { + return err + } + + _, err = db.Update(self, func() error { + self.Password = passwd + return nil + }) + + return err +} + +func (self *SElasticcacheAccount) GetDecodedPassword() (string, error) { + return utils.DescryptAESBase64(self.Id, self.Password) +} + +func (self *SElasticcacheAccount) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + self.SetStatus(userCred, api.ELASTIC_CACHE_ACCOUNT_STATUS_DELETING, "") + return self.StartDeleteElasticcacheAccountTask(ctx, userCred, jsonutils.NewDict(), "") +} + +func (self *SElasticcacheAccount) StartDeleteElasticcacheAccountTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAccountDeleteTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcacheAccount) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + return nil +} + +func (self *SElasticcacheAccount) GetIRegion() (cloudprovider.ICloudRegion, error) { + _ec, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return nil, err + } + + ec := _ec.(*SElasticcache) + provider, err := ec.GetDriver() + if err != nil { + return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", ec.Name, err) + } + region := self.GetRegion() + if region == nil { + return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) + } + return provider.GetIRegionById(region.ExternalId) +} + +func (self *SElasticcacheAccount) AllowPerformResetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return db.IsAdminAllowPerform(userCred, self, "reset_password") +} + +func (self *SElasticcacheAccount) ValidatorResetPasswordData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + passwd, err := data.GetString("password") + if err == nil && !seclib2.MeetComplxity(passwd) { + return nil, httperrors.NewWeakPasswordError() + } + + privilegeV := validators.NewStringChoicesValidator("account_privilege", choices.NewChoices(api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ, api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE, api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL)).Optional(true) + if err := privilegeV.Validate(data.(*jsonutils.JSONDict)); err != nil { + return nil, err + } + return data, nil +} + +func (self *SElasticcacheAccount) PerformResetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + self.SetStatus(userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "") + data, err := self.ValidatorResetPasswordData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + return nil, self.StartResetPasswordTask(ctx, userCred, data.(*jsonutils.JSONDict), "") +} + +func (self *SElasticcacheAccount) StartResetPasswordTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAccountResetPasswordTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} diff --git a/pkg/compute/models/elasticcache_acls.go b/pkg/compute/models/elasticcache_acls.go index 1dc358de49..04c0a16a30 100644 --- a/pkg/compute/models/elasticcache_acls.go +++ b/pkg/compute/models/elasticcache_acls.go @@ -16,13 +16,21 @@ package models import ( "context" + "fmt" + "strings" + "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" + api "yunion.io/x/onecloud/pkg/apis/compute" "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/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -46,7 +54,7 @@ func init() { } type SElasticcacheAcl struct { - db.SStandaloneResourceBase + db.SStatusStandaloneResourceBase db.SExternalizedResourceBase ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id @@ -120,7 +128,7 @@ func (self *SElasticcacheAcl) syncRemoveCloudElasticcacheAcl(ctx context.Context func (self *SElasticcacheAcl) SyncWithCloudElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, extAcl cloudprovider.ICloudElasticcacheAcl) error { _, err := db.UpdateWithLock(ctx, self, func() error { self.IpList = extAcl.GetIpList() - + self.Status = extAcl.GetStatus() return nil }) if err != nil { @@ -138,6 +146,7 @@ func (manager *SElasticcacheAclManager) newFromCloudElasticcacheAcl(ctx context. acl.SetModelManager(manager, &acl) acl.ElasticcacheId = elasticcache.GetId() + acl.Status = extAcl.GetStatus() acl.Name = extAcl.GetName() acl.ExternalId = extAcl.GetGlobalId() acl.IpList = extAcl.GetIpList() @@ -149,3 +158,139 @@ func (manager *SElasticcacheAclManager) newFromCloudElasticcacheAcl(ctx context. return &acl, nil } + +func (manager *SElasticcacheAclManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return db.IsAdminAllowCreate(userCred, manager) +} + +func (manager *SElasticcacheAclManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + var region *SCloudregion + if id, _ := data.GetString("elasticcache"); len(id) > 0 { + ec, err := db.FetchByIdOrName(ElasticcacheManager, userCred, id) + if err != nil { + return nil, fmt.Errorf("getting elastic cache instance failed") + } + region = ec.(*SElasticcache).GetRegion() + + if region == nil { + return nil, fmt.Errorf("getting elastic cache region failed") + } + } else { + return nil, httperrors.NewMissingParameterError("elasticcache") + } + + data, err := manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data) + if err != nil { + return nil, err + } + + return region.GetDriver().ValidateCreateElasticcacheAclData(ctx, userCred, ownerId, data) +} + +func (self *SElasticcacheAcl) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { + self.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + self.SetStatus(userCred, api.ELASTIC_CACHE_ACL_STATUS_CREATING, "") + if err := self.StartElasticcacheAclCreateTask(ctx, userCred, data.(*jsonutils.JSONDict), ""); err != nil { + log.Errorf("Failed to create elastic cache acl error: %v", err) + } +} + +func (self *SElasticcacheAcl) StartElasticcacheAclCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAclCreateTask", self, userCred, jsonutils.NewDict(), parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcacheAcl) GetIRegion() (cloudprovider.ICloudRegion, error) { + _ec, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return nil, err + } + + ec := _ec.(*SElasticcache) + provider, err := ec.GetDriver() + if err != nil { + return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", ec.Name, err) + } + region := ec.GetRegion() + if region == nil { + return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) + } + return provider.GetIRegionById(region.ExternalId) +} + +func (self *SElasticcacheAcl) GetRegion() *SCloudregion { + ieb, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return nil + } + + return ieb.(*SElasticcache).GetRegion() +} + +func (self *SElasticcacheAcl) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { + // todo: fix me self.IsOwner(userCred) || + return db.IsAdminAllowUpdate(userCred, self) +} + +func (self *SElasticcacheAcl) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + ips, err := data.GetString("ip_list") + if err != nil || ips == "" { + return nil, httperrors.NewMissingParameterError("ip_list") + } + + ipV := validators.NewIPv4AddrValidator("ip") + _ips := strings.Split(ips, ",") + for _, ip := range _ips { + params := jsonutils.NewDict() + params.Set("ip", jsonutils.NewString(ip)) + if err := ipV.Validate(params); err != nil { + return nil, err + } + } + + return data, nil +} + +func (self *SElasticcacheAcl) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { + self.SetStatus(userCred, api.ELASTIC_CACHE_ACL_STATUS_UPDATING, "") + if err := self.StartUpdateElasticcacheAclTask(ctx, userCred, data.(*jsonutils.JSONDict), ""); err != nil { + log.Errorf("ElasticcacheAcl %s", err.Error()) + } + + return +} + +func (self *SElasticcacheAcl) StartUpdateElasticcacheAclTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAclUpdateTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcacheAcl) ValidateDeleteCondition(ctx context.Context) error { + return nil +} + +func (self *SElasticcacheAcl) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + self.SetStatus(userCred, api.ELASTIC_CACHE_ACL_STATUS_DELETING, "") + return self.StartDeleteElasticcacheAclTask(ctx, userCred, jsonutils.NewDict(), "") +} + +func (self *SElasticcacheAcl) StartDeleteElasticcacheAclTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAclDeleteTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcacheAcl) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + return nil +} diff --git a/pkg/compute/models/elasticcache_backups.go b/pkg/compute/models/elasticcache_backups.go index 7dfba2f5bd..41a453d5de 100644 --- a/pkg/compute/models/elasticcache_backups.go +++ b/pkg/compute/models/elasticcache_backups.go @@ -16,14 +16,20 @@ package models import ( "context" + "fmt" "time" + "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" + api "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -52,13 +58,13 @@ type SElasticcacheBackup struct { ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id - BackupSizeMb int `nullable:"false" list:"user"` - BackupType string `width:"32" charset:"ascii" nullable:"true" list:"user"` // 全量|增量额 - BackupMode string `width:"32" charset:"ascii" nullable:"true" list:"user"` // 自动|手动 - DownloadURL string `width:"512" charset:"ascii" nullable:"true" list:"user"` + BackupSizeMb int `nullable:"false" list:"user" create:"optional"` + BackupType string `width:"32" charset:"ascii" nullable:"true" create:"optional" list:"user"` // 全量|增量额 + BackupMode string `width:"32" charset:"ascii" nullable:"true" create:"optional" list:"user"` // 自动|手动 + DownloadURL string `width:"512" charset:"ascii" nullable:"true" create:"optional" list:"user"` - StartTime time.Time `list:"user"` - EndTime time.Time `list:"user"` + StartTime time.Time `list:"user" create:"optional"` + EndTime time.Time `list:"user" create:"optional"` } func (manager *SElasticcacheBackupManager) SyncElasticcacheBackups(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, cloudElasticcacheBackups []cloudprovider.ICloudElasticcacheBackup) compare.SyncResult { @@ -113,6 +119,26 @@ func (manager *SElasticcacheBackupManager) SyncElasticcacheBackups(ctx context.C return syncResult } +func (self *SElasticcacheBackup) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SStatusStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) + icache, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err == nil { + ec := icache.(*SElasticcache) + provider := ec.GetCloudprovider() + region := ec.GetRegion() + zone := ec.GetZone() + info := MakeCloudProviderInfo(region, zone, provider) + extra.Update(jsonutils.Marshal(&info)) + + info2 := jsonutils.NewDict() + info2.Set("engine", jsonutils.NewString(ec.Engine)) + info2.Set("engine_version", jsonutils.NewString(ec.EngineVersion)) + extra.Update(info2) + } + + return extra +} + func (self *SElasticcacheBackup) syncRemoveCloudElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential) error { lockman.LockObject(ctx, self) defer lockman.ReleaseObject(ctx, self) @@ -127,9 +153,15 @@ func (self *SElasticcacheBackup) syncRemoveCloudElasticcacheBackup(ctx context.C func (self *SElasticcacheBackup) SyncWithCloudElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, extBackup cloudprovider.ICloudElasticcacheBackup) error { _, err := db.UpdateWithLock(ctx, self, func() error { self.Status = extBackup.GetStatus() + self.BackupSizeMb = extBackup.GetBackupSizeMb() + self.BackupType = extBackup.GetBackupType() + self.BackupMode = extBackup.GetBackupMode() self.DownloadURL = extBackup.GetDownloadURL() + self.StartTime = extBackup.GetStartTime() + self.EndTime = extBackup.GetEndTime() + return nil }) if err != nil { @@ -166,3 +198,121 @@ func (manager *SElasticcacheBackupManager) newFromCloudElasticcacheBackup(ctx co return &backup, nil } + +func (manager *SElasticcacheBackupManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return db.IsAdminAllowCreate(userCred, manager) +} + +func (manager *SElasticcacheBackupManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + var region *SCloudregion + if id, _ := data.GetString("elasticcache"); len(id) > 0 { + ec, err := db.FetchByIdOrName(ElasticcacheManager, userCred, id) + if err != nil { + return nil, fmt.Errorf("getting elastic cache instance failed") + } + region = ec.(*SElasticcache).GetRegion() + } else { + return nil, httperrors.NewMissingParameterError("elasticcache") + } + + data, err := manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data) + if err != nil { + return nil, err + } + + return region.GetDriver().ValidateCreateElasticcacheBackupData(ctx, userCred, ownerId, data) +} + +func (self *SElasticcacheBackup) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { + self.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + self.SetStatus(userCred, api.ELASTIC_CACHE_BACKUP_STATUS_CREATING, "") + if err := self.StartElasticcacheBackupCreateTask(ctx, userCred, data.(*jsonutils.JSONDict), ""); err != nil { + log.Errorf("Failed to create elastic cache backup error: %v", err) + } +} + +func (self *SElasticcacheBackup) StartElasticcacheBackupCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheBackupCreateTask", self, userCred, jsonutils.NewDict(), parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcacheBackup) GetIRegion() (cloudprovider.ICloudRegion, error) { + _eb, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return nil, err + } + + eb := _eb.(*SElasticcache) + provider, err := eb.GetDriver() + if err != nil { + return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", eb.Name, err) + } + region := eb.GetRegion() + if region == nil { + return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) + } + return provider.GetIRegionById(region.ExternalId) +} + +func (self *SElasticcacheBackup) AllowPerformRestoreInstance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + // todo : fix me self.IsOwner(userCred) || + return db.IsAdminAllowPerform(userCred, self, "restore_instance") +} + +func (self *SElasticcacheBackup) ValidatorRestoreInstanceData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + ec, err := db.FetchByIdOrName(ElasticcacheManager, userCred, self.ElasticcacheId) + if err != nil { + return nil, fmt.Errorf("getting elastic cache instance failed") + } + + if ec.(*SElasticcache).Status != api.ELASTIC_CACHE_STATUS_RUNNING { + return nil, httperrors.NewConflictError("can't restore elastic cache in status %s", ec.(*SElasticcache).Status) + } + + return data, nil +} + +func (self *SElasticcacheBackup) PerformRestoreInstance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorRestoreInstanceData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + return nil, self.StartRestoreInstanceTask(ctx, userCred, data.(*jsonutils.JSONDict), "") +} + +func (self *SElasticcacheBackup) StartRestoreInstanceTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheBackupRestoreInstanceTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcacheBackup) GetRegion() *SCloudregion { + ieb, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return nil + } + + return ieb.(*SElasticcache).GetRegion() +} + +func (self *SElasticcacheBackup) ValidateDeleteCondition(ctx context.Context) error { + icache, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return err + } + + if icache.(*SElasticcache).GetProviderName() == api.CLOUD_PROVIDER_ALIYUN && len(self.ExternalId) == 0 { + return httperrors.NewUnsupportOperationError("unsupport delete %s backups", api.CLOUD_PROVIDER_ALIYUN) + } + + return nil +} diff --git a/pkg/compute/models/elasticcache_instances.go b/pkg/compute/models/elasticcache_instances.go index d2a0157376..a124e407ac 100644 --- a/pkg/compute/models/elasticcache_instances.go +++ b/pkg/compute/models/elasticcache_instances.go @@ -16,16 +16,29 @@ package models import ( "context" + "fmt" + "regexp" + "strings" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" + "yunion.io/x/pkg/utils" + "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "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/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + bc "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/choices" + "yunion.io/x/onecloud/pkg/util/seclib2" ) type SElasticcacheManager struct { @@ -53,18 +66,20 @@ type SElasticcache struct { SManagedResourceBase SCloudregionResourceBase - SZoneResourceBase + SZoneResourceBase // 主可用区. + SlaveZones string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 备可用区 - InstanceType string `width:"64" charset:"ascii" nullable:"true" list:"user" create:"optional"` // redis.master.micro.default - CapacityMB int `nullable:"true" list:"user" create:"optional"` // 1024 - ArchType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 集群版 | 标准版 | 读写分离版 | 单机 ? - NodeType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` // STAND_ALONE(单节点) MASTER_SLAVE(多节点) ? + InstanceType string `width:"96" charset:"ascii" nullable:"true" list:"user" create:"optional"` // redis.master.micro.default + CapacityMB int `nullable:"false" list:"user" create:"optional"` // 1024 + LocalCategory string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 对应Sku local_category + NodeType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"` // single(单副本) | double(双副本) | readone (单可读) | readthree (3可读) | readfive(5只读) Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` // Redis | Memcache EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` // 4.0 5.0 - VpcId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - NetworkType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` // CLASSIC(经典网络) VPC(专有网络) - NetworkId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` + NetworkType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"` // CLASSIC(经典网络) VPC(专有网络) + NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` + SecurityGroupId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` PrivateDNS string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 内网DNS PrivateIpAddr string `width:"17" charset:"ascii" list:"user" create:"optional"` // 内网IP地址 @@ -76,12 +91,33 @@ type SElasticcache struct { MaintainStartTime string `width:"8" charset:"ascii" nullable:"true" list:"user" create:"optional"` // HH:mmZ eg. 02:00Z MaintainEndTime string `width:"8" charset:"ascii" nullable:"true" list:"user" create:"optional"` + AuthMode string `width:"8" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 访问密码? on (开启密码)|off (免密码访问) // AutoRenew // 自动续费 // AutoRenewPeriod // 自动续费周期 } +func (self *SElasticcache) getCloudProviderInfo() SCloudProviderInfo { + region := self.GetRegion() + provider := self.GetCloudprovider() + zone := self.GetZone() + return MakeCloudProviderInfo(region, zone, provider) +} + +func (self *SElasticcache) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) { + extra, err := self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query) + if err != nil { + return nil, err + } + + info := self.getCloudProviderInfo() + extra.Update(jsonutils.Marshal(&info)) + return extra, nil +} + func (self *SElasticcache) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { extra := self.SStatusStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) + info := self.getCloudProviderInfo() + extra.Update(jsonutils.Marshal(&info)) return extra } @@ -125,6 +161,48 @@ func (self *SElasticcache) GetElasticcacheBackups() ([]SElasticcacheBackup, erro return ret, nil } +func (self *SElasticcache) AllowGetDetailsLoginInfo(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowGetSpec(userCred, self, "login-info") +} + +func (self *SElasticcache) GetDetailsLoginInfo(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + account, err := self.GetAdminAccount() + if err != nil { + return nil, err + } + + password, err := account.GetDecodedPassword() + if err != nil { + return nil, err + } + + ret := jsonutils.NewDict() + ret.Add(jsonutils.NewString(account.Name), "username") + ret.Add(jsonutils.NewString(password), "password") + return ret, nil +} + +func (manager *SElasticcacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { + q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query) + if err != nil { + return nil, err + } + data := query.(*jsonutils.JSONDict) + q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ + {Key: "vpc", ModelKeyword: "vpc", OwnerId: userCred}, + {Key: "zone", ModelKeyword: "zone", OwnerId: userCred}, + {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, + }) + if err != nil { + return nil, err + } + q, err = managedResourceFilterByAccount(q, query, "", nil) + if err != nil { + return nil, err + } + return q, nil +} + func (manager *SElasticcacheManager) SyncElasticcaches(ctx context.Context, userCred mcclient.TokenCredential, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider, region *SCloudregion, cloudElasticcaches []cloudprovider.ICloudElasticcache) ([]SElasticcache, []cloudprovider.ICloudElasticcache, compare.SyncResult) { lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, provider.GetOwnerId())) defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, provider.GetOwnerId())) @@ -199,7 +277,7 @@ func (self *SElasticcache) SyncWithCloudElasticcache(ctx context.Context, userCr self.Status = extInstance.GetStatus() self.InstanceType = extInstance.GetInstanceType() self.CapacityMB = extInstance.GetCapacityMB() - self.ArchType = extInstance.GetArchType() + self.LocalCategory = extInstance.GetArchType() self.NodeType = extInstance.GetNodeType() self.Engine = extInstance.GetEngine() self.EngineVersion = extInstance.GetEngineVersion() @@ -213,6 +291,7 @@ func (self *SElasticcache) SyncWithCloudElasticcache(ctx context.Context, userCr self.PublicConnectPort = extInstance.GetPublicConnectPort() self.MaintainStartTime = extInstance.GetMaintainStartTime() self.MaintainEndTime = extInstance.GetMaintainEndTime() + self.AuthMode = extInstance.GetAuthMode() return nil }) @@ -244,7 +323,7 @@ func (manager *SElasticcacheManager) newFromCloudElasticcache(ctx context.Contex instance.InstanceType = extInstance.GetInstanceType() instance.CapacityMB = extInstance.GetCapacityMB() - instance.ArchType = extInstance.GetArchType() + instance.LocalCategory = extInstance.GetArchType() instance.NodeType = extInstance.GetNodeType() instance.Engine = extInstance.GetEngine() instance.EngineVersion = extInstance.GetEngineVersion() @@ -258,6 +337,7 @@ func (manager *SElasticcacheManager) newFromCloudElasticcache(ctx context.Contex instance.PublicConnectPort = extInstance.GetPublicConnectPort() instance.MaintainStartTime = extInstance.GetMaintainStartTime() instance.MaintainEndTime = extInstance.GetMaintainEndTime() + instance.AuthMode = extInstance.GetAuthMode() if zoneId := extInstance.GetZoneId(); len(zoneId) > 0 { zone, err := db.FetchByExternalId(ZoneManager, zoneId) @@ -316,3 +396,738 @@ func (manager *SElasticcacheManager) getElasticcachesByProviderId(providerId str } return instances, nil } + +func (manager *SElasticcacheManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return db.IsAdminAllowCreate(userCred, manager) +} + +func (manager *SElasticcacheManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + var region *SCloudregion + if id, _ := data.GetString("network"); len(id) > 0 { + network, err := db.FetchByIdOrName(NetworkManager, userCred, strings.Split(id, ",")[0]) + if err != nil { + return nil, fmt.Errorf("getting network failed") + } + region = network.(*SNetwork).getRegion() + } + + if region == nil { + return nil, fmt.Errorf("getting region failed") + } + + data, err := manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data) + if err != nil { + return nil, err + } + + if reset, _ := data.Bool("reset_password"); reset { + if _, err := data.GetString("password"); err != nil { + randomPasswd := seclib2.RandomPassword2(12) + data.Set("password", jsonutils.NewString(randomPasswd)) + } + } + + return region.GetDriver().ValidateCreateElasticcacheData(ctx, userCred, nil, data) +} + +func (self *SElasticcache) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { + self.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + + self.SetStatus(userCred, api.LB_CREATING, "") + if err := self.StartElasticcacheCreateTask(ctx, userCred, data.(*jsonutils.JSONDict), ""); err != nil { + log.Errorf("Failed to create elastic cache error: %v", err) + } +} + +func (self *SElasticcache) StartElasticcacheCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheCreateTask", self, userCred, jsonutils.NewDict(), parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) GetIRegion() (cloudprovider.ICloudRegion, error) { + provider, err := self.GetDriver() + if err != nil { + return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", self.Name, err) + } + region := self.GetRegion() + if region == nil { + return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) + } + return provider.GetIRegionById(region.ExternalId) +} + +func (self *SElasticcache) GetCreateAliyunElasticcacheParams() (*cloudprovider.SCloudElasticCacheInput, error) { + input := &cloudprovider.SCloudElasticCacheInput{} + iregion, err := self.GetIRegion() + if err != nil { + return nil, fmt.Errorf("elastic cache %s(%s) region not found", self.Name, self.Id) + } else { + input.RegionId = iregion.GetId() + } + + input.InstanceType = self.InstanceType + input.InstanceName = self.GetName() + + // todo: inject password here + // input.Password = "xxxx" + input.Engine = strings.Title(self.Engine) + input.EngineVersion = self.EngineVersion + input.PrivateIpAddress = self.PrivateIpAddr + + zone := self.GetZone() + if zone != nil { + izone, err := iregion.GetIZoneById(zone.ExternalId) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateAliyunElasticcacheParams.Zone") + } + input.ZoneIds = []string{izone.GetId()} + } + + switch self.BillingType { + case billing.BILLING_TYPE_PREPAID: + input.ChargeType = "PrePaid" + billingCycle, err := bc.ParseBillingCycle(self.BillingCycle) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateAliyunElasticcacheParams.BillingCycle") + } + input.BC = &billingCycle + default: + input.ChargeType = "PostPaid" + } + + // todo: fix me + if len(self.NodeType) > 0 { + switch self.NodeType { + case "single": + input.NodeType = "STAND_ALONE" + case "double": + input.NodeType = "MASTER_SLAVE" + default: + input.NodeType = "" + } + } + + switch self.NetworkType { + case api.LB_NETWORK_TYPE_CLASSIC: + input.NetworkType = "CLASSIC" + default: + input.NetworkType = "VPC" + } + + if ivpc, err := db.FetchById(VpcManager, self.VpcId); err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateAliyunElasticcacheParams.Vpc") + } else { + if ivpc != nil { + vpc := ivpc.(*SVpc) + input.VpcId = vpc.ExternalId + } + } + + if inetwork, err := db.FetchById(NetworkManager, self.NetworkId); err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateAliyunElasticcacheParams.Network") + } else { + if inetwork != nil { + network := inetwork.(*SNetwork) + input.NetworkId = network.ExternalId + } + } + + return input, nil +} + +func (self *SElasticcache) GetCreateHuaweiElasticcacheParams() (*cloudprovider.SCloudElasticCacheInput, error) { + input := &cloudprovider.SCloudElasticCacheInput{} + iregion, err := self.GetIRegion() + if err != nil { + return nil, fmt.Errorf("elastic cache %s(%s) region not found", self.Name, self.Id) + } else { + input.RegionId = iregion.GetId() + } + + if self.CapacityMB > 0 { + input.CapacityGB = int64(self.CapacityMB / 1024) + } + + sku, err := db.FetchById(ElasticcacheSkuManager, self.InstanceType) + if err != nil { + return nil, err + } + + input.InstanceType = sku.(*SElasticcacheSku).InstanceSpec + input.InstanceName = self.GetName() + + // todo: inject password here + // input.Password = "xxxx" + switch self.Engine { + case "redis": + input.Engine = "Redis" + case "memcache": + input.Engine = "Memcached" + } + input.EngineVersion = self.EngineVersion + input.PrivateIpAddress = self.PrivateIpAddr + + zone := self.GetZone() + if zone != nil { + izone, err := iregion.GetIZoneById(zone.ExternalId) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateHuaweiElasticcacheParams.Zone") + } + input.ZoneIds = []string{izone.GetId()} + } + + switch self.BillingType { + case billing.BILLING_TYPE_PREPAID: + input.ChargeType = "PrePaid" + billingCycle, err := bc.ParseBillingCycle(self.BillingCycle) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateHuaweiElasticcacheParams.BillingCycle") + } + input.BC = &billingCycle + default: + input.ChargeType = "PostPaid" + } + + if len(self.NodeType) > 0 { + input.NodeType = self.NodeType + } + + switch self.NetworkType { + case api.LB_NETWORK_TYPE_CLASSIC: + input.NetworkType = "CLASSIC" + default: + input.NetworkType = "VPC" + } + + if ivpc, err := db.FetchById(VpcManager, self.VpcId); err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateHuaweiElasticcacheParams.Vpc") + } else { + if ivpc != nil { + vpc := ivpc.(*SVpc) + input.VpcId = vpc.ExternalId + } + } + + if inetwork, err := db.FetchById(NetworkManager, self.NetworkId); err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateHuaweiElasticcacheParams.Network") + } else { + if inetwork != nil { + network := inetwork.(*SNetwork) + input.NetworkId = network.ExternalId + } + } + + // fill security group here + if len(self.SecurityGroupId) > 0 { + sgCache, err := SecurityGroupCacheManager.GetSecgroupCache(context.Background(), nil, self.SecurityGroupId, self.VpcId, self.CloudregionId, self.ManagerId) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetCreateHuaweiElasticcacheParams.SecurityGroup") + } + + if sgCache == nil { + return nil, errors.Wrap(fmt.Errorf("cached security group not found"), "elasticcache.GetCreateHuaweiElasticcacheParams.SecurityGroup") + } + + input.SecurityGroupId = sgCache.GetExternalId() + } + + if len(self.MaintainEndTime) > 0 { + input.MaintainBegin = self.MaintainStartTime + input.MaintainEnd = self.MaintainEndTime + } + return input, nil +} + +func (self *SElasticcache) AllowPerformRestart(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "restart") +} + +func (self *SElasticcache) PerformRestart(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if utils.IsInStringArray(self.Status, []string{api.ELASTIC_CACHE_STATUS_RUNNING, api.ELASTIC_CACHE_STATUS_INACTIVE}) { + return nil, self.StartRestartTask(ctx, userCred, "", data) + } else { + return nil, httperrors.NewInvalidStatusError("Cannot do restart elasticcache instance in status %s", self.Status) + } +} + +func (self *SElasticcache) StartRestartTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, data jsonutils.JSONObject) error { + self.SetStatus(userCred, api.ELASTIC_CACHE_STATUS_RESTARTING, "") + if task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheRestartTask", self, userCred, data.(*jsonutils.JSONDict), parentTaskId, "", nil); err != nil { + log.Errorln(err) + return err + } else { + task.ScheduleRun(nil) + } + + return nil +} + +func (self *SElasticcache) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + return self.StartDeleteElasticcacheTask(ctx, userCred, jsonutils.NewDict(), "") +} + +func (self *SElasticcache) StartDeleteElasticcacheTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheDeleteTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformChangeSpec(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "change_spec") +} + +func (self *SElasticcache) ValidatorChangeSpecData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + skuV := validators.NewModelIdOrNameValidator("sku", "elasticcachesku", self.GetOwnerId()) + if err := skuV.Optional(false).Validate(data.(*jsonutils.JSONDict)); err != nil { + return nil, err + } + + sku := skuV.Model.(*SElasticcacheSku) + if sku.Provider != self.GetProviderName() { + return nil, httperrors.NewInputParameterError("provider mismatch: %s instance can't use %s sku", self.GetProviderName(), sku.Provider) + } + + if sku.CloudregionId != self.CloudregionId { + return nil, httperrors.NewInputParameterError("region mismatch: instance region %s, sku region %s", self.CloudregionId, sku.CloudregionId) + } + + if sku.ZoneId != "" && sku.ZoneId != self.ZoneId { + return nil, httperrors.NewInputParameterError("zone mismatch: instance zone %s, sku zone %s", self.ZoneId, sku.ZoneId) + } + + if self.EngineVersion != "" && sku.EngineVersion != self.EngineVersion { + return nil, httperrors.NewInputParameterError("engine version mismatch: instance version %s, sku version %s", self.EngineVersion, sku.EngineVersion) + } + + data.(*jsonutils.JSONDict).Set("sku_ext_id", jsonutils.NewString(skuV.Model.(*SElasticcacheSku).GetName())) + return data, nil +} + +func (self *SElasticcache) PerformChangeSpec(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if !utils.IsInStringArray(self.Status, []string{api.ELASTIC_CACHE_STATUS_RUNNING}) { + return nil, httperrors.NewResourceNotReadyError("can not change specification in status %s", self.Status) + } + + data, err := self.ValidatorChangeSpecData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + params := jsonutils.NewDict() + sku, _ := data.GetString("sku_ext_id") + params.Set("sku_ext_id", jsonutils.NewString(sku)) + return nil, self.StartChangeSpecTask(ctx, userCred, params, "") +} + +func (self *SElasticcache) StartChangeSpecTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + self.SetStatus(userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "") + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheChangeSpecTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformUpdateAuthMode(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "update_auth_mode") +} + +func (self *SElasticcache) ValidatorUpdateAuthModeData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + authModeV := validators.NewStringChoicesValidator("auth_mode", choices.NewChoices("on", "off")) + if err := authModeV.Optional(false).Validate(data.(*jsonutils.JSONDict)); err != nil { + return nil, err + } + + if authModeV.Value == self.AuthMode { + return nil, httperrors.NewConflictError("auth mode aready in status %s", self.AuthMode) + } + + return data, nil +} + +func (self *SElasticcache) PerformUpdateAuthMode(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorUpdateAuthModeData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + params := jsonutils.NewDict() + authMode, _ := data.GetString("auth_mode") + params.Set("auth_mode", jsonutils.NewString(authMode)) + return nil, self.StartUpdateAuthModeTask(ctx, userCred, params, "") +} + +func (self *SElasticcache) StartUpdateAuthModeTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheUpdateAuthModeTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformResetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "reset-password") +} + +func (self *SElasticcache) ValidatorResetPasswordData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if reset, _ := data.Bool("reset_password"); reset { + if _, err := data.GetString("password"); err != nil { + randomPasswd := seclib2.RandomPassword2(12) + data.(*jsonutils.JSONDict).Set("password", jsonutils.NewString(randomPasswd)) + } + } + + if password, err := data.GetString("password"); err != nil || len(password) == 0 { + return nil, httperrors.NewMissingParameterError("password") + } else { + if !seclib2.MeetComplxity(password) { + return nil, httperrors.NewWeakPasswordError() + } + } + + return data, nil +} + +func (self *SElasticcache) PerformResetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorResetPasswordData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + return nil, self.StartResetPasswordTask(ctx, userCred, data.(*jsonutils.JSONDict), "") +} + +func (self *SElasticcache) GetAdminAccount() (*SElasticcacheAccount, error) { + accounts, err := self.GetElasticcacheAccounts() + if err != nil { + return nil, err + } + + for i := range accounts { + if accounts[i].AccountType == api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN { + return &accounts[i], nil + } + } + + return nil, fmt.Errorf("no admin account found for elastic cache %s", self.Id) +} + +func (self *SElasticcache) StartResetPasswordTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + account, err := self.GetAdminAccount() + if err != nil { + return err + } + + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAccountResetPasswordTask", account, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformSetMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "set_maintain_time") +} + +func (self *SElasticcache) ValidatorSetMaintainTimeData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + timeReg, _ := regexp.Compile("^(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]Z$") + startTimeV := validators.NewRegexpValidator("maintain_start_time", timeReg) + endTimeV := validators.NewRegexpValidator("maintain_end_time", timeReg) + keyV := map[string]validators.IValidator{ + "maintain_start_time": startTimeV.Optional(false), + "maintain_end_time": endTimeV.Optional(false), + } + + for _, v := range keyV { + if err := v.Validate(data.(*jsonutils.JSONDict)); err != nil { + return nil, err + } + } + + if startTimeV.Value == self.MaintainStartTime && endTimeV.Value == self.MaintainEndTime { + return nil, httperrors.NewInputParameterError("maintain time has no change") + } + + return data, nil +} + +func (self *SElasticcache) PerformSetMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorSetMaintainTimeData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + params := jsonutils.NewDict() + startTime, _ := data.GetString("maintain_start_time") + endTime, _ := data.GetString("maintain_end_time") + params.Set("maintain_start_time", jsonutils.NewString(startTime)) + params.Set("maintain_end_time", jsonutils.NewString(endTime)) + return nil, self.StartSetMaintainTimeTask(ctx, userCred, params, "") +} + +func (self *SElasticcache) StartSetMaintainTimeTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheSetMaintainTimeTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformAllocatePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "allocate_public_connection") +} + +func (self *SElasticcache) ValidatorAllocatePublicConnectionData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if self.PublicDNS != "" || self.PublicIpAddr != "" { + return nil, httperrors.NewConflictError("public connection aready allocated") + } + + portV := validators.NewRangeValidator("port", 1024, 65535) + portV.Default(6379).Optional(true) + if err := portV.Validate(data.(*jsonutils.JSONDict)); err != nil { + return nil, err + } + + return data, nil +} + +func (self *SElasticcache) PerformAllocatePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorAllocatePublicConnectionData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + params := jsonutils.NewDict() + port, _ := data.Int("port") + params.Set("port", jsonutils.NewInt(port)) + return nil, self.StartAllocatePublicConnectionTask(ctx, userCred, params, "") +} + +func (self *SElasticcache) StartAllocatePublicConnectionTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAllocatePublicConnectionTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformReleasePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "release_public_connection") +} + +func (self *SElasticcache) ValidatorReleasePublicConnectionData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if self.PublicIpAddr == "" && self.PublicDNS == "" { + return nil, httperrors.NewConflictError("release public connection aready released") + } + + return data, nil +} + +func (self *SElasticcache) PerformReleasePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorReleasePublicConnectionData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + return nil, self.StartReleasePublicConnectionTask(ctx, userCred, jsonutils.NewDict(), "") +} + +func (self *SElasticcache) StartReleasePublicConnectionTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheReleasePublicConnectionTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformFlushInstance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "flush_instance") +} + +func (self *SElasticcache) PerformFlushInstance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + self.SetStatus(userCred, api.ELASTIC_CACHE_STATUS_FLUSHING, "") + return nil, self.StartFlushInstanceTask(ctx, userCred, jsonutils.NewDict(), "") +} + +func (self *SElasticcache) StartFlushInstanceTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheFlushInstanceTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformUpdateInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "update_instance_parameters") +} + +func (self *SElasticcache) ValidatorUpdateInstanceParametersData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + parameters, err := data.Get("parameters") + if err != nil { + return nil, httperrors.NewMissingParameterError("parameters") + } + + _, ok := parameters.(*jsonutils.JSONDict) + if !ok { + return nil, httperrors.NewInputParameterError("invalid parameter format. json dict required") + } + + return data, nil +} + +func (self *SElasticcache) PerformUpdateInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorUpdateInstanceParametersData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + params := jsonutils.NewDict() + parameters, _ := data.Get("parameters") + params.Set("parameters", parameters) + return nil, self.StartUpdateInstanceParametersTask(ctx, userCred, params, "") +} + +func (self *SElasticcache) StartUpdateInstanceParametersTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheUpdateInstanceParametersTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformUpdateBackupPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "update_backup_policy") +} + +func (self *SElasticcache) ValidatorUpdateBackupPolicyData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + timeReg, _ := regexp.Compile("^(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]Z-(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]Z$") + backupTypeV := validators.NewStringChoicesValidator("backup_type", choices.NewChoices(api.BACKUP_MODE_AUTOMATED, api.ELASTIC_CACHE_BACKUP_MODE_MANUAL)) + BackupReservedDaysV := validators.NewRangeValidator("backup_reserved_days", 1, 7).Default(7) + PreferredBackupPeriodV := validators.NewStringChoicesValidator("preferred_backup_period", choices.NewChoices("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")) + PreferredBackupTimeV := validators.NewRegexpValidator("preferred_backup_time", timeReg) + + keyV := map[string]validators.IValidator{ + "backup_type": backupTypeV.Optional(true), + "backup_reserved_days": BackupReservedDaysV.Optional(true), + "preferred_backup_period": PreferredBackupPeriodV.Optional(false), + "preferred_backup_time": PreferredBackupTimeV.Optional(false), + } + + for _, v := range keyV { + if err := v.Validate(data.(*jsonutils.JSONDict)); err != nil { + return nil, err + } + } + + return data, nil +} + +func (self *SElasticcache) PerformUpdateBackupPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + data, err := self.ValidatorUpdateBackupPolicyData(ctx, userCred, query, data) + if err != nil { + return nil, err + } + + return nil, self.StartUpdateBackupPolicyTask(ctx, userCred, data.(*jsonutils.JSONDict), "") +} + +func (self *SElasticcache) StartUpdateBackupPolicyTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheUpdateBackupPolicyTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +func (self *SElasticcache) AllowPerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "sync") +} + +func (self *SElasticcache) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return nil, self.StartSyncTask(ctx, userCred, data.(*jsonutils.JSONDict), "") +} + +func (self *SElasticcache) StartSyncTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheSyncTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + + task.ScheduleRun(nil) + return nil +} + +// 清理所有关联资源记录 +func (self *SElasticcache) DeleteSubResources(ctx context.Context, userCred mcclient.TokenCredential) { + ms := []db.IResourceModelManager{ + ElasticcacheAccountManager, + ElasticcacheAclManager, + ElasticcacheBackupManager, + ElasticcacheParameterManager, + } + + ownerId := self.GetOwnerId() + for _, m := range ms { + func(man db.IResourceModelManager) { + lockman.LockClass(ctx, man, db.GetLockClassKey(man, ownerId)) + defer lockman.ReleaseClass(ctx, man, db.GetLockClassKey(man, ownerId)) + q := man.Query().IsFalse("deleted").Equals("elasticcache_id", self.GetId()) + + models := make([]interface{}, 0) + err := db.FetchModelObjects(man, q, &models) + if err != nil { + log.Errorf("elasticcache.DeleteSubResources.FetchModelObjects %s", err) + } + + for i := range models { + var imodel db.IModel + switch models[i].(type) { + case SElasticcacheAccount: + _m := models[i].(SElasticcacheAccount) + imodel = &_m + case SElasticcacheAcl: + _m := models[i].(SElasticcacheAcl) + imodel = &_m + case SElasticcacheBackup: + _m := models[i].(SElasticcacheBackup) + imodel = &_m + case SElasticcacheParameter: + _m := models[i].(SElasticcacheParameter) + imodel = &_m + default: + log.Errorf("elasticcache.DeleteSubResources.UnknownModelType %s", models[i]) + } + + err = db.DeleteModel(ctx, userCred, imodel) + if err != nil { + log.Errorf("elasticcache.DeleteSubResources.DeleteModel %s", err) + } + } + }(m) + } +} diff --git a/pkg/compute/models/elasticcache_parameters.go b/pkg/compute/models/elasticcache_parameters.go index a98615b2ab..d8e26f4255 100644 --- a/pkg/compute/models/elasticcache_parameters.go +++ b/pkg/compute/models/elasticcache_parameters.go @@ -17,12 +17,17 @@ package models import ( "context" + "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" + api "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -46,7 +51,7 @@ func init() { } type SElasticcacheParameter struct { - db.SStandaloneResourceBase + db.SStatusStandaloneResourceBase db.SExternalizedResourceBase ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id @@ -123,6 +128,7 @@ func (self *SElasticcacheParameter) syncRemoveCloudElasticcacheParameter(ctx con func (self *SElasticcacheParameter) SyncWithCloudElasticcacheParameter(ctx context.Context, userCred mcclient.TokenCredential, extParameter cloudprovider.ICloudElasticcacheParameter) error { _, err := db.UpdateWithLock(ctx, self, func() error { + self.Status = extParameter.GetStatus() self.Key = extParameter.GetParameterKey() self.Value = extParameter.GetParameterValue() self.Modifiable = extParameter.GetModifiable() @@ -144,6 +150,7 @@ func (manager *SElasticcacheParameterManager) newFromCloudElasticcacheParameter( parameter.SetModelManager(manager, ¶meter) parameter.ElasticcacheId = elasticcache.Id + parameter.Status = extParameter.GetStatus() parameter.Name = extParameter.GetName() parameter.ExternalId = extParameter.GetGlobalId() parameter.Key = extParameter.GetParameterKey() @@ -160,3 +167,49 @@ func (manager *SElasticcacheParameterManager) newFromCloudElasticcacheParameter( return ¶meter, nil } + +func (self *SElasticcacheParameter) GetRegion() *SCloudregion { + ieb, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) + if err != nil { + return nil + } + + return ieb.(*SElasticcache).GetRegion() +} + +func (self *SElasticcacheParameter) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + if !self.Modifiable { + return nil, httperrors.NewConflictError("%s is not modifiable", self.Name) + } + + _, err := data.GetString("value") + if err != nil { + return nil, httperrors.NewMissingParameterError("value") + } + + return data, nil +} + +func (self *SElasticcacheParameter) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { + v, _ := data.Get("value") + params := jsonutils.NewDict() + paramsObj := jsonutils.NewDict() + paramsObj.Add(v, self.Name) + params.Add(paramsObj, "parameters") + + self.SetStatus(userCred, api.ELASTIC_CACHE_PARAMETER_STATUS_UPDATING, "") + if err := self.StartUpdateElasticcacheParameterTask(ctx, userCred, params, ""); err != nil { + log.Errorf("ElasticcacheParameter %s", err.Error()) + } + + return +} + +func (self *SElasticcacheParameter) StartUpdateElasticcacheParameterTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheParameterUpdateTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} diff --git a/pkg/compute/models/elasticcache_skus.go b/pkg/compute/models/elasticcache_skus.go new file mode 100644 index 0000000000..a90312d1d7 --- /dev/null +++ b/pkg/compute/models/elasticcache_skus.go @@ -0,0 +1,275 @@ +// 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 models + +import ( + "context" + "database/sql" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/validators" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SElasticcacheSkuManager struct { + db.SStatusStandaloneResourceBaseManager +} + +var ElasticcacheSkuManager *SElasticcacheSkuManager + +func init() { + ElasticcacheSkuManager = &SElasticcacheSkuManager{ + SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager( + SElasticcacheSku{}, + "elasticcacheskus_tbl", + "elasticcachesku", + "elasticcacheskus", + ), + } + ElasticcacheSkuManager.NameRequireAscii = false + ElasticcacheSkuManager.SetVirtualObject(ElasticcacheSkuManager) +} + +type SElasticcacheSku struct { + db.SStatusStandaloneResourceBase + db.SExternalizedResourceBase + + SCloudregionResourceBase // 区域 + SZoneResourceBase // 主可用区 + SlaveZoneId string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 备可用区 + + InstanceSpec string `width:"96" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` + EngineArch string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin"` + LocalCategory string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:""` + + PrepaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` + PostpaidStatus string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin" default:"available"` + + Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 引擎 redis|memcached + EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 引擎版本 3.0 + CpuArch string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // CPU 架构 x86|ARM + StorageType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 存储类型 DRAM|SCM + PerformanceType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // standrad|enhanced + NodeType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // single(单副本) | double(双副本) | readone (单可读) | readthree (3可读) | readfive(5只读) + + MemorySizeMB int `nullable:"false" list:"user" create:"admin_required" update:"admin"` // 内存容量 + DiskSizeGB int `nullable:"false" list:"user" create:"admin_required" update:"admin"` // 套餐附带硬盘容量 + ShardNum int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 最小分片数量 + MaxShardNum int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 最大分片数量 + ReplicasNum int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 最小副本数量 + MaxReplicasNum int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 最大副本数量 + + MaxClients int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 最大客户端数 + MaxConnections int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 最大连接数 + MaxInBandwidthMb int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 最大内网带宽 + MaxMemoryMB int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 实际可使用的最大内存 + QPS int `nullable:"false" list:"user" create:"admin_optional" update:"admin"` // QPS参考值 + + Provider string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"admin_required" update:"admin"` // 公有云厂商 Aliyun/Azure/AWS/Qcloud/... +} + +func (self *SElasticcacheSku) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + return self.SStatusStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) +} + +func (manager *SElasticcacheSkuManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { + regions := map[string]string{} + for i := range objs { + cloudregionId := objs[i].(*SElasticcacheSku).CloudregionId + if _, ok := regions[cloudregionId]; !ok { + regions[cloudregionId] = cloudregionId + } + } + + regionIds := []string{} + for k, _ := range regions { + regionIds = append(regionIds, regions[k]) + } + + if len(regionIds) == 0 { + return nil + } + + regionObjs := []SCloudregion{} + err := CloudregionManager.Query().In("id", regionIds).All(®ionObjs) + if err != nil { + log.Errorf("elasticcacheSkuManager.FetchCustomizeColumns %s", err) + return nil + } + + for i := range regionObjs { + regionObj := regionObjs[i] + regions[regionObj.Id] = regionObj.Name + } + + ret := []*jsonutils.JSONDict{} + for i := range objs { + cloudregionId := objs[i].(*SElasticcacheSku).CloudregionId + + fileds := jsonutils.NewDict() + fileds.Set("region", jsonutils.NewString(regions[cloudregionId])) + + ret = append(ret, fileds) + } + + return ret +} + +func (manager *SElasticcacheSkuManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { + data := query.(*jsonutils.JSONDict) + brands := jsonutils.GetQueryStringArray(query, "brand") + if len(brands) > 0 { + q = q.Filter(sqlchemy.In(q.Field("brand"), brands)) + data.Remove("brand") + } + + q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, data) + if err != nil { + return nil, err + } + + if usable, _ := query.Bool("usable"); usable { + q = usableFilter(q, true) + q = q.Equals("postpaid_status", "available") + q = q.Equals("prepaid_status", "available") + } + + q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ + {Key: "zone", ModelKeyword: "zone", OwnerId: userCred}, + {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, + }) + if err != nil { + return nil, err + } + + city, _ := query.GetString("city") + if len(city) > 0 { + regionTable := CloudregionManager.Query().SubQuery() + q = q.Join(regionTable, sqlchemy.Equals(regionTable.Field("id"), q.Field("cloudregion_id"))).Filter(sqlchemy.Equals(regionTable.Field("city"), city)) + } + + return q, err +} + +// 获取所有Available状态的sku id +func (manager *SElasticcacheSkuManager) FetchAllAvailableSkuId() ([]string, error) { + q := manager.Query() + q = q.Filter(sqlchemy.OR( + sqlchemy.Equals(q.Field("prepaid_status"), api.SkuStatusAvailable), + sqlchemy.Equals(q.Field("postpaid_status"), api.SkuStatusAvailable))) + + skus := make([]SElasticcacheSku, 0) + err := db.FetchModelObjects(manager, q, &skus) + if err != nil { + return nil, err + } + + ids := make([]string, len(skus)) + for i := range skus { + ids[i] = skus[i].GetId() + } + + return ids, nil +} + +// 获取region下所有Available状态的sku id +func (manager *SElasticcacheSkuManager) FetchAllAvailableSkuIdByRegion(regionID string) ([]string, error) { + q := manager.Query() + q = q.Filter(sqlchemy.OR( + sqlchemy.Equals(q.Field("prepaid_status"), api.SkuStatusAvailable), + sqlchemy.Equals(q.Field("postpaid_status"), api.SkuStatusAvailable))) + q = q.Equals("cloudregion_id", regionID) + + skus := make([]SElasticcacheSku, 0) + err := db.FetchModelObjects(manager, q, &skus) + if err != nil { + return nil, err + } + + ids := make([]string, len(skus)) + for i := range skus { + ids[i] = skus[i].GetId() + } + + return ids, nil +} + +func (manager *SElasticcacheSkuManager) InitializeData() error { + count, err := manager.Query().Limit(1).CountWithError() + if err != nil && err != sql.ErrNoRows { + return err + } + + if count > 0 { + return nil + } + + count, err = CloudaccountManager.Query().IsTrue("is_public_cloud").CountWithError() + if count > 0 { + SyncElasticCacheSkus(nil, nil, true) + } + + return nil +} + +// sku标记为soldout状态。 +func (manager *SElasticcacheSkuManager) MarkAsSoldout(id string) error { + if len(id) == 0 { + log.Debugf("MarkAsSoldout sku id should not be emtpy") + return nil + } + + isku, err := manager.FetchById(id) + if err != nil { + return err + } + + sku, ok := isku.(*SServerSku) + if !ok { + return fmt.Errorf("%s is not a sku object", id) + } + + _, err = manager.TableSpec().Update(sku, func() error { + sku.PrepaidStatus = api.SkuStatusSoldout + sku.PostpaidStatus = api.SkuStatusSoldout + return nil + }) + + if err != nil { + return err + } + + return nil +} + +// sku标记为soldout状态。 +func (manager *SElasticcacheSkuManager) MarkAllAsSoldout(ids []string) error { + var err error + for _, id := range ids { + err = manager.MarkAsSoldout(id) + if err != nil { + return err + } + } + + return nil +} diff --git a/pkg/compute/models/initdb.go b/pkg/compute/models/initdb.go index 644ac12556..84d4e44dd2 100644 --- a/pkg/compute/models/initdb.go +++ b/pkg/compute/models/initdb.go @@ -50,6 +50,7 @@ func InitDB() error { SchedtagManager, DynamicschedtagManager, ServerSkuManager, + ElasticcacheSkuManager, } { err := manager.InitializeData() if err != nil { diff --git a/pkg/compute/models/instance_snapshot_joint.go b/pkg/compute/models/instance_snapshot_joint.go index cc0ef989de..ee22653deb 100644 --- a/pkg/compute/models/instance_snapshot_joint.go +++ b/pkg/compute/models/instance_snapshot_joint.go @@ -1,3 +1,17 @@ +// 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 models import "yunion.io/x/onecloud/pkg/cloudcommon/db" diff --git a/pkg/compute/models/instance_snapshots.go b/pkg/compute/models/instance_snapshots.go index 36c59a560c..2bd8c34e5c 100644 --- a/pkg/compute/models/instance_snapshots.go +++ b/pkg/compute/models/instance_snapshots.go @@ -1,3 +1,17 @@ +// 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 models import ( diff --git a/pkg/compute/models/regiondrivers.go b/pkg/compute/models/regiondrivers.go index be5bf0290a..5d9a2bce2b 100644 --- a/pkg/compute/models/regiondrivers.go +++ b/pkg/compute/models/regiondrivers.go @@ -32,6 +32,11 @@ import ( type IRegionDriver interface { GetProvider() string + IElasticcacheDriver + IElasticcacheAccount + IElasticcacheAcl + IElasticcacheBackup + ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) ValidateDeleteLoadbalancerCondition(ctx context.Context, lb *SLoadbalancer) error RequestCreateLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, task taskman.ITask) error @@ -133,6 +138,45 @@ type IRegionDriver interface { RequestChangeDBInstanceConfig(ctx context.Context, userCred mcclient.TokenCredential, instance *SDBInstance, task taskman.ITask) error } +type IElasticcacheDriver interface { + ValidateCreateElasticcacheData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) + ValidateCreateElasticcacheAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) + ValidateCreateElasticcacheAclData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) + ValidateCreateElasticcacheBackupData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) + RequestCreateElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestCreateElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheAccount *SElasticcacheAccount, task taskman.ITask) error + RequestCreateElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheAcl *SElasticcacheAcl, task taskman.ITask) error + RequestCreateElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheBackup *SElasticcacheBackup, task taskman.ITask) error + RequestRestartElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestSyncElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestDeleteElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestDeleteElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, ea *SElasticcacheAccount, task taskman.ITask) error + RequestDeleteElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, ea *SElasticcacheAcl, task taskman.ITask) error + RequestDeleteElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, eb *SElasticcacheBackup, task taskman.ITask) error + RequestChangeElasticcacheSpec(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error // 变更实例规格 + RequestSetElasticcacheMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestElasticcacheChangeSpec(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestUpdateElasticcacheAuthMode(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestElasticcacheSetMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestElasticcacheAllocatePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestElasticcacheReleasePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestElasticcacheFlushInstance(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestElasticcacheUpdateInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error + RequestElasticcacheUpdateBackupPolicy(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, task taskman.ITask) error +} + +type IElasticcacheAccount interface { + RequestElasticcacheAccountResetPassword(ctx context.Context, userCred mcclient.TokenCredential, ea *SElasticcacheAccount, task taskman.ITask) error +} + +type IElasticcacheAcl interface { + RequestElasticcacheAclUpdate(ctx context.Context, userCred mcclient.TokenCredential, ea *SElasticcacheAcl, task taskman.ITask) error +} + +type IElasticcacheBackup interface { + RequestElasticcacheBackupRestoreInstance(ctx context.Context, userCred mcclient.TokenCredential, ea *SElasticcacheBackup, task taskman.ITask) error +} + var regionDrivers map[string]IRegionDriver func init() { diff --git a/pkg/compute/models/skustools.go b/pkg/compute/models/skustools.go index a1ef50dc64..bce0ab5c31 100644 --- a/pkg/compute/models/skustools.go +++ b/pkg/compute/models/skustools.go @@ -18,10 +18,13 @@ import ( "context" "database/sql" "fmt" + "io/ioutil" + "net/http" "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -33,16 +36,34 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/modules" ) +const ( + ELASTICCACHE_SKUS_URL = "http://10.168.222.228:8000/ec.json" +) + +type ServerSkus struct { + zone *SkusZone + skus []jsonutils.JSONObject + total int + updated int + created int +} + +type ElasticCacheSkus struct { + zone *SkusZone + skus []jsonutils.JSONObject + total int + updated int + created int +} + type SkusZone struct { Provider string RegionId string ZoneId string ExternalZoneId string ExternalRegionId string - skus []jsonutils.JSONObject - total int - updated int - created int + + serverSkus ServerSkus } func mergeSkuData(odata, ndata jsonutils.JSONObject) jsonutils.JSONObject { @@ -112,9 +133,9 @@ func processSkuData(ndata jsonutils.JSONObject) jsonutils.JSONObject { return data } -func (self *SkusZone) Init() error { +func (self *ServerSkus) Init() error { s := auth.GetAdminSession(context.Background(), options.Options.Region, "") - p, r, z := self.getExternalZone() + p, r, z := self.zone.getExternalZone() limit := 1024 offset := 0 total := 1024 @@ -155,48 +176,10 @@ func (self *SkusZone) Init() error { return nil } -func (self *SkusZone) doCreate(data SServerSku) error { - data.CloudregionId = self.RegionId - data.ZoneId = self.ZoneId - data.Provider = self.Provider - data.Status = api.SkuStatusReady - data.Enabled = true - if err := ServerSkuManager.TableSpec().Insert(&data); err != nil { - log.Debugf("SkusZone doCreate fail: %s", err.Error()) - return err - } - - self.created += 1 - return nil -} - -func (self *SkusZone) doUpdate(odata *SServerSku, sku jsonutils.JSONObject) error { - _, err := db.Update(odata, func() error { - if err := sku.Unmarshal(&odata); err != nil { - return err - } - odata.CloudregionId = self.RegionId - odata.ZoneId = self.ZoneId - odata.Provider = self.Provider - // 公有云默认都是ready并启用 - odata.Status = api.SkuStatusReady - odata.Enabled = true - return nil - }) - - if err != nil { - log.Debugf("SkusZone doUpdate fail: %s", err.Error()) - return err - } - - self.updated += 1 - return nil -} - -func (self *SkusZone) SyncToLocalDB() error { - log.Debugf("SkusZone %s start sync.", self.ExternalZoneId) +func (self *ServerSkus) SyncToLocalDB() error { + log.Debugf("SkusZone %s start sync.", self.zone.ExternalZoneId) // 更新已经soldout的sku - localIds, err := ServerSkuManager.FetchAllAvailableSkuIdByZoneId(self.ZoneId) + localIds, err := ServerSkuManager.FetchAllAvailableSkuIdByZoneId(self.zone.ZoneId) if err != nil { return err } @@ -206,9 +189,9 @@ func (self *SkusZone) SyncToLocalDB() error { for _, sku := range self.skus { name, _ := sku.GetString("name") - if obj, err := ServerSkuManager.FetchByZoneId(self.ZoneId, name); err != nil { + if obj, err := ServerSkuManager.FetchByZoneId(self.zone.ZoneId, name); err != nil { if err != sql.ErrNoRows { - log.Debugf("SyncToLocalDB zone %s name %s : %s", self.ZoneId, name, err.Error()) + log.Debugf("SyncToLocalDB zone %s name %s : %s", self.zone.ZoneId, name, err.Error()) return err } data := SServerSku{} @@ -241,7 +224,65 @@ func (self *SkusZone) SyncToLocalDB() error { return err } - defer log.Debugf("SkusZone %s sync to local db.total %d,created %d,updated %d. abandoned %d", self.ExternalZoneId, self.total, self.created, self.updated, len(abandonIds)) + defer log.Debugf("SkusZone %s sync to local db.total %d,created %d,updated %d. abandoned %d", self.zone.ExternalZoneId, self.total, self.created, self.updated, len(abandonIds)) + return nil +} + +func (self *ServerSkus) doCreate(data SServerSku) error { + data.CloudregionId = self.zone.RegionId + data.ZoneId = self.zone.ZoneId + data.Provider = self.zone.Provider + data.Status = api.SkuStatusReady + data.Enabled = true + if err := ServerSkuManager.TableSpec().Insert(&data); err != nil { + log.Debugf("SkusZone doCreate fail: %s", err.Error()) + return err + } + + self.created += 1 + return nil +} + +func (self *ServerSkus) doUpdate(odata *SServerSku, sku jsonutils.JSONObject) error { + _, err := db.Update(odata, func() error { + if err := sku.Unmarshal(&odata); err != nil { + return err + } + odata.CloudregionId = self.zone.RegionId + odata.ZoneId = self.zone.ZoneId + odata.Provider = self.zone.Provider + // 公有云默认都是ready并启用 + odata.Status = api.SkuStatusReady + odata.Enabled = true + return nil + }) + + if err != nil { + log.Debugf("SkusZone doUpdate fail: %s", err.Error()) + return err + } + + self.updated += 1 + return nil +} + +func (self *SkusZone) Init() error { + self.serverSkus = ServerSkus{zone: self} + + err := self.serverSkus.Init() + if err != nil { + return errors.Wrap(err, "SkusZone.Init.serverSkus") + } + + return nil +} + +func (self *SkusZone) SyncToLocalDB() error { + err := self.serverSkus.SyncToLocalDB() + if err != nil { + return err + } + return nil } @@ -415,3 +456,215 @@ func diff(origins, compares []string) []string { return ret } + +func doCreateElasticCacheSku(data SElasticcacheSku) error { + if err := ElasticcacheSkuManager.TableSpec().Insert(&data); err != nil { + log.Debugf("SkusZone doCreate fail: %s", err.Error()) + return err + } + + return nil +} + +func doUpdateElasticCacheSku(odata *SElasticcacheSku, sku jsonutils.JSONObject) error { + _, err := db.Update(odata, func() error { + if err := sku.Unmarshal(&odata); err != nil { + return err + } + + return nil + }) + + if err != nil { + log.Debugf("SkusZone doUpdate fail: %s", err.Error()) + return err + } + + return nil +} + +func processElasticCacheSkuData(ndata jsonutils.JSONObject) (jsonutils.JSONObject, error) { + // 将external_id 统一替换成 id + data, ok := ndata.(*jsonutils.JSONDict) + if !ok { + log.Debugf("invalid sku dict data: %s", ndata) + } + + // 将external_id 统一替换成 id. + id, err := ndata.GetString("id") + if err != nil { + data.Set("external_id", jsonutils.NewString("")) + } else { + data.Set("external_id", jsonutils.NewString(id)) + data.Remove("id") + } + + provider, _ := ndata.GetString("provider") + region, _ := ndata.GetString("region_id") + masterZone, _ := ndata.GetString("master_zone_id") + slaveZone, _ := ndata.GetString("slave_zone_id") + + if len(masterZone) > 0 { + masterZoneId := strings.Join([]string{provider, region, masterZone}, "/") + obj, err := db.FetchByExternalId(ZoneManager, masterZoneId) + if err == nil { + zone := obj.(*SZone) + data.Set("cloudregion_id", jsonutils.NewString(zone.CloudregionId)) + data.Set("zone_id", jsonutils.NewString(zone.Id)) + + if len(slaveZone) > 0 { + slaveZoneId := strings.Join([]string{provider, region, slaveZone}, "/") + obj, err := db.FetchByExternalId(ZoneManager, slaveZoneId) + if err == nil { + zone := obj.(*SZone) + data.Set("slave_zone_id", jsonutils.NewString(zone.Id)) + } else { + return nil, fmt.Errorf("slave zone with external id %s not found", slaveZoneId) + } + } + } else { + return nil, fmt.Errorf("master zone with external id %s not found", masterZoneId) + } + } else { + regionId := strings.Join([]string{provider, region}, "/") + obj, err := db.FetchByExternalId(CloudregionManager, regionId) + if err == nil { + region := obj.(*SCloudregion) + data.Set("cloudregion_id", jsonutils.NewString(region.Id)) + data.Set("zone_id", jsonutils.NewString("")) + } else { + return nil, fmt.Errorf("region with external id %s not found", regionId) + } + } + + return data, nil +} + +// 全量同步elasticcache sku列表. +func SyncElasticCacheSkus(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) { + skus := fetchExternalElasticCacheSkus() + filtedSkus := []jsonutils.JSONObject{} + for i := range skus { + if data, err := processElasticCacheSkuData(skus[i]); err == nil { + filtedSkus = append(filtedSkus, data) + } else { + log.Debugf("%s", err) + } + } + + // 更新已经soldout的sku + localIds, err := ElasticcacheSkuManager.FetchAllAvailableSkuId() + if err != nil { + log.Errorf("SyncElasticCacheSkus FetchAllAvailableSkuId %s", err) + return + } + + updateElasticCacheSkus(localIds, filtedSkus) +} + +// 同步Region elasticcache sku列表. +func syncElasticCacheSkusByRegion(region *SCloudregion) { + skus := fetchExternalElasticCacheSkus() + filtedSkus := []jsonutils.JSONObject{} + for i := range skus { + provider, _ := skus[i].GetString("provider") + regionId, _ := skus[i].GetString("region_id") + if region.GetExternalId() != fmt.Sprintf("%s/%s", provider, regionId) { + continue + } + + if data, err := processElasticCacheSkuData(skus[i]); err == nil { + filtedSkus = append(filtedSkus, data) + } else { + log.Debugf("%s", err) + } + } + + // 更新已经soldout的sku + localIds, err := ElasticcacheSkuManager.FetchAllAvailableSkuId() + if err != nil { + log.Errorf("SyncElasticCacheSkus FetchAllAvailableSkuId %s", err) + return + } + + updateElasticCacheSkus(localIds, filtedSkus) +} + +func fetchExternalElasticCacheSkus() []jsonutils.JSONObject { + resp, err := http.Get(ELASTICCACHE_SKUS_URL) + if err != nil { + log.Errorf("SyncElasticCacheSkus %s", err) + return nil + } + + defer resp.Body.Close() + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Errorf("SyncElasticCacheSkus ReadAll %s", err) + return nil + } + + elasticcache, err := jsonutils.Parse(content) + if err != nil { + log.Errorf("SyncElasticCacheSkus Parse %s", err) + return nil + } + + skus := []jsonutils.JSONObject{} + err = elasticcache.Unmarshal(&skus) + if err != nil { + log.Errorf("SyncElasticCacheSkus Unmarshal %s", err) + return nil + } + + return skus +} + +func updateElasticCacheSkus(localSkuIds []string, extSkus []jsonutils.JSONObject) { + // 本次已被更新的sku id + updatedIds := make([]string, 0) + for _, sku := range extSkus { + name, _ := sku.GetString("name") + extId, _ := sku.GetString("external_id") + if obj, err := db.FetchByExternalId(ElasticcacheSkuManager, extId); err != nil { + if err != sql.ErrNoRows { + log.Debugf("SyncToLocalDB external id %s name %s : %s", extId, name, err.Error()) + return + } + + data := SElasticcacheSku{} + if e := sku.Unmarshal(&data); e != nil { + log.Debugf("sku Unmarshal failed: %s, %s", sku, e.Error()) + return + } + + if err := doCreateElasticCacheSku(data); err != nil { + log.Debugf("sku doCreate failed: %s, %s", sku, err) + return + } + } else { + odata, ok := obj.(*SElasticcacheSku) + if !ok { + log.Debugf("SkusZone model assertion error. %s", obj) + return + } + + if err := doUpdateElasticCacheSku(odata, sku); err != nil { + log.Debugf("SkusZone model doUpdate error. %s", err) + return + } + + updatedIds = append(updatedIds, odata.Id) + } + } + + // 处理已经下架的sku: 将本次未更新且处于available状态的sku置为soldout状态 + abandonIds := diff(localSkuIds, updatedIds) + log.Debugf("SyncToLocalDB abandon sku %s", abandonIds) + err := ElasticcacheSkuManager.MarkAllAsSoldout(abandonIds) + if err != nil { + return + } + + return +} diff --git a/pkg/compute/regiondrivers/aliyun.go b/pkg/compute/regiondrivers/aliyun.go index 08dd918dcf..14f233a6e9 100644 --- a/pkg/compute/regiondrivers/aliyun.go +++ b/pkg/compute/regiondrivers/aliyun.go @@ -40,6 +40,7 @@ import ( "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/choices" "yunion.io/x/onecloud/pkg/util/rand" + "yunion.io/x/onecloud/pkg/util/seclib2" ) type SAliyunRegionDriver struct { @@ -1172,3 +1173,361 @@ func (self *SAliyunRegionDriver) ValidateDBInstanceAccountPrivilege(ctx context. } return nil } + +func (self *SAliyunRegionDriver) ValidateCreateElasticcacheData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId) + networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId) + + // billing cycle + billingTypeV := validators.NewStringChoicesValidator("billing_type", choices.NewChoices(billing_api.BILLING_TYPE_PREPAID, billing_api.BILLING_TYPE_POSTPAID)) + networkTypeV := validators.NewStringChoicesValidator("network_type", choices.NewChoices(api.LB_NETWORK_TYPE_VPC, api.LB_NETWORK_TYPE_CLASSIC)).Default(api.LB_NETWORK_TYPE_VPC).Optional(true) + engineV := validators.NewStringChoicesValidator("engine", choices.NewChoices("redis", "memcache")) + engineVersionV := validators.NewStringChoicesValidator("engine_version", choices.NewChoices("2.8", "4.0", "5.0")) + privateIpV := validators.NewIPv4AddrValidator("private_ip").Optional(true) + + keyV := map[string]validators.IValidator{ + "zone": zoneV, + "billing_type": billingTypeV, + "network_type": networkTypeV, + "network": networkV, + "engine": engineV, + "engine_version": engineVersionV, + "private_ip": privateIpV, + } + if err := RunValidators(keyV, data, false); err != nil { + return nil, err + } + + // validate password + if password, _ := data.GetString("password"); len(password) > 0 { + if !seclib2.MeetComplxity(password) { + return nil, httperrors.NewWeakPasswordError() + } + } + + // validate sku + billingType, _ := data.GetString("billing_type") + zone := zoneV.Model.(*models.SZone) + if sku, err := data.GetString("instance_type"); err != nil || len(sku) == 0 { + return nil, httperrors.NewMissingParameterError("instance_type") + } else { + _skuModel, err := db.FetchByIdOrName(models.ElasticcacheSkuManager, userCred, sku) + if err != nil { + return nil, err + } + + skuModel := _skuModel.(*models.SElasticcacheSku) + if err := ValidateElasticcacheSku(zone.Id, billingType, skuModel); err != nil { + return nil, err + } else { + data.Set("instance_type", jsonutils.NewString(skuModel.InstanceSpec)) + data.Set("node_type", jsonutils.NewString(skuModel.NodeType)) + data.Set("local_category", jsonutils.NewString(skuModel.LocalCategory)) + } + } + + // billing cycle + if billingType == billing_api.BILLING_TYPE_PREPAID { + billingCycle, err := data.GetString("billing_cycle") + if err != nil { + return nil, httperrors.NewMissingParameterError("billing_cycle") + } + + cycle, err := billing.ParseBillingCycle(billingCycle) + if err != nil { + return nil, httperrors.NewInputParameterError("invalid billing_cycle %s", billingCycle) + } + + data.Set("billing_cycle", jsonutils.NewString(cycle.String())) + } + + network := networkV.Model.(*models.SNetwork) + vpc := network.GetVpc() + if vpc == nil { + return nil, httperrors.NewNotFoundError("network %s related vpc not found", network.GetId()) + } + data.Set("vpc_id", jsonutils.NewString(vpc.Id)) + data.Set("manager_id", jsonutils.NewString(vpc.ManagerId)) + data.Set("cloudregion_id", jsonutils.NewString(zone.GetCloudRegionId())) + return data, nil +} + +func (self *SAliyunRegionDriver) RequestCreateElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + iRegion, err := ec.GetIRegion() + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetIRegion") + } + + iprovider, err := db.FetchById(models.CloudproviderManager, ec.ManagerId) + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetProvider") + } + + provider := iprovider.(*models.SCloudprovider) + + params, err := ec.GetCreateAliyunElasticcacheParams() + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetCreateAliyunElasticcacheParams") + } + + iec, err := iRegion.CreateIElasticcaches(params) + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.CreateIElasticcaches") + } + + err = cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 30*time.Second, 15*time.Second, 600*time.Second) + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.WaitStatusWithDelay") + } + + ec.SetModelManager(models.ElasticcacheManager, ec) + if err := db.SetExternalId(ec, userCred, iec.GetGlobalId()); err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.SetExternalId") + } + + { + // todo: 开启外网访问 + } + + if err := ec.SyncWithCloudElasticcache(ctx, userCred, provider, iec); err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.SyncWithCloudElasticcache") + } + + // sync accounts + { + iaccounts, err := iec.GetICloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetICloudElasticcacheAccounts") + } + + result := models.ElasticcacheAccountManager.SyncElasticcacheAccounts(ctx, userCred, ec, iaccounts) + log.Debugf("aliyunRegionDriver.CreateElasticcache.SyncElasticcacheAccounts %s", result.Result()) + + account, err := ec.GetAdminAccount() + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetAdminAccount") + } + + err = account.SavePassword(params.Password) + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.SavePassword") + } + } + + // sync acl + { + iacls, err := iec.GetICloudElasticcacheAcls() + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetICloudElasticcacheAcls") + } + + result := models.ElasticcacheAclManager.SyncElasticcacheAcls(ctx, userCred, ec, iacls) + log.Debugf("aliyunRegionDriver.CreateElasticcache.SyncElasticcacheAcls %s", result.Result()) + } + + // sync parameters + { + iparams, err := iec.GetICloudElasticcacheParameters() + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetICloudElasticcacheParameters") + } + + result := models.ElasticcacheParameterManager.SyncElasticcacheParameters(ctx, userCred, ec, iparams) + log.Debugf("aliyunRegionDriver.CreateElasticcache.SyncElasticcacheParameters %s", result.Result()) + } + + return nil, nil + }) + return nil +} + +func (self *SAliyunRegionDriver) ValidateCreateElasticcacheAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + elasticCacheV := validators.NewModelIdOrNameValidator("elasticcache", "elasticcache", ownerId) + accountTypeV := validators.NewStringChoicesValidator("account_type", choices.NewChoices("normal", "admin")).Default("normal") + accountPrivilegeV := validators.NewStringChoicesValidator("account_privilege", choices.NewChoices("read", "write", "repl")) + + keyV := map[string]validators.IValidator{ + "elasticcache": elasticCacheV, + "account_type": accountTypeV, + "account_privilege": accountPrivilegeV.Default("read"), + } + + for _, v := range keyV { + if err := v.Validate(data); err != nil { + return nil, err + } + } + + passwd, _ := data.GetString("password") + if !seclib2.MeetComplxity(passwd) { + return nil, httperrors.NewWeakPasswordError() + } + + if accountPrivilegeV.Value == "repl" && elasticCacheV.Model.(*models.SElasticcache).EngineVersion != "4.0" { + return nil, httperrors.NewInputParameterError("account_privilege %s only support redis version 4.0") + } + + return data, nil +} + +func (self *SAliyunRegionDriver) RequestCreateElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return nil, errors.Wrap(nil, "aliyunRegionDriver.CreateElasticcacheAccount.GetElasticcache") + } + + ec := _ec.(*models.SElasticcache) + iregion, err := ec.GetIRegion() + if err != nil { + return nil, errors.Wrap(nil, "aliyunRegionDriver.CreateElasticcacheAccount.GetIRegion") + } + + params, err := ea.GetCreateAliyunElasticcacheAccountParams() + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcacheAccount.GetCreateAliyunElasticcacheAccountParams") + } + + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcacheAccount.GetIElasticcacheById") + } + + iea, err := iec.CreateAccount(params) + if err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcacheAccount.CreateAccount") + } + + ea.SetModelManager(models.ElasticcacheAccountManager, ea) + if err := db.SetExternalId(ea, userCred, iea.GetGlobalId()); err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcacheAccount.SetExternalId") + } + + if err := ea.SyncWithCloudElasticcacheAccount(ctx, userCred, iea); err != nil { + return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcacheAccount.SyncWithCloudElasticcache") + } + + return nil, nil + }) + + return nil +} + +func (self *SAliyunRegionDriver) RequestCreateElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, eb *models.SElasticcacheBackup, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + _ec, err := db.FetchById(models.ElasticcacheManager, eb.ElasticcacheId) + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.GetElasticcache") + } + + ec := _ec.(*models.SElasticcache) + iregion, err := ec.GetIRegion() + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.GetIElasticcacheById") + } + + oBackups, err := iec.GetICloudElasticcacheBackups() + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.GetICloudElasticcacheBackups") + } + + backupIds := []string{} + for i := range oBackups { + backupIds = append(backupIds, oBackups[i].GetGlobalId()) + } + + _, err = iec.CreateBackup() + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.CreateBackup") + } + + var ieb cloudprovider.ICloudElasticcacheBackup + cloudprovider.Wait(30*time.Second, 1800*time.Second, func() (b bool, e error) { + backups, err := iec.GetICloudElasticcacheBackups() + if err != nil { + return false, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.WaitCreated") + } + + for i := range backups { + if !utils.IsInStringArray(backups[i].GetGlobalId(), backupIds) && backups[i].GetStatus() == api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS { + ieb = backups[i] + return true, nil + } + } + + return false, nil + }) + + eb.SetModelManager(models.ElasticcacheBackupManager, eb) + if err := db.SetExternalId(eb, userCred, ieb.GetGlobalId()); err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.SetExternalId") + } + + if err := eb.SyncWithCloudElasticcacheBackup(ctx, userCred, ieb); err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.SyncWithCloudElasticcacheBackup") + } + + return nil, nil + }) + return nil +} + +func (self *SAliyunRegionDriver) RequestElasticcacheAccountResetPassword(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error { + iregion, err := ea.GetIRegion() + if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.GetIRegion") + } + + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.FetchById") + } + + ec := _ec.(*models.SElasticcache) + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.GetIElasticcacheById") + } + + iea, err := iec.GetICloudElasticcacheAccount(ea.GetExternalId()) + if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.GetICloudElasticcacheBackup") + } + + data := task.GetParams() + if data == nil { + return errors.Wrap(fmt.Errorf("data is nil"), "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.GetParams") + } + + input, err := ea.GetUpdateAliyunElasticcacheAccountParams(*data) + if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.GetUpdateAliyunElasticcacheAccountParams") + } + + err = iea.UpdateAccount(input) + if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.UpdateAccount") + } + + if input.Password != nil { + err = ea.SavePassword(*input.Password) + if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.SavePassword") + } + } + + err = cloudprovider.WaitStatusWithDelay(iea, api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE, 10*time.Second, 5*time.Second, 60*time.Second) + if err != nil { + return errors.Wrap(err, "aliyunRegionDriver.RequestElasticcacheAccountResetPassword.WaitStatusWithDelay") + } + + return ea.SyncWithCloudElasticcacheAccount(ctx, userCred, iea) +} diff --git a/pkg/compute/regiondrivers/huawei.go b/pkg/compute/regiondrivers/huawei.go index e09bb9f5d2..dfbb2f85a7 100644 --- a/pkg/compute/regiondrivers/huawei.go +++ b/pkg/compute/regiondrivers/huawei.go @@ -19,11 +19,15 @@ import ( "database/sql" "fmt" "regexp" + "strings" + "time" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" + billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -34,6 +38,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/choices" "yunion.io/x/onecloud/pkg/util/rand" "yunion.io/x/onecloud/pkg/util/seclib2" ) @@ -1548,7 +1553,7 @@ func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerListenerRule(ctx conte if err != nil { return nil, errors.Wrap(err, "huaweiRegionDriver.RequestCreateLoadbalancerListenerRule.CreateILoadBalancerListenerRule") } - + // lbr.SetModelManager(models.LoadbalancerListenerRuleManager, lbr) if err := db.SetExternalId(lbr, userCred, iListenerRule.GetGlobalId()); err != nil { return nil, errors.Wrap(err, "huaweiRegionDriver.RequestCreateLoadbalancerListenerRule.SetExternalId") @@ -1569,7 +1574,7 @@ func (self *SHuaWeiRegionDriver) DealNatGatewaySpec(spec string) string { case "4": return api.NAT_SPEC_XLARGE } - //can't arrive + // can't arrive return "" } @@ -1681,3 +1686,314 @@ func (self *SHuaWeiRegionDriver) ValidateResetDBInstancePassword(ctx context.Con func (self *SHuaWeiRegionDriver) IsSupportKeepDBInstanceManualBackup() bool { return true } + +func validatorSlaveZones(ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, optional bool) error { + s, err := data.GetString("slave_zones") + if err != nil { + if optional { + return nil + } + + return fmt.Errorf("missing parameter slave_zones") + } + + zones := strings.Split(s, ",") + ret := []string{} + zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId) + for _, zone := range zones { + _data := jsonutils.NewDict() + _data.Add(jsonutils.NewString(zone), "zone") + if err := zoneV.Validate(_data); err != nil { + return errors.Wrap(err, "validatorSlaveZones") + } else { + ret = append(ret, zoneV.Model.GetId()) + } + } + + if sku, err := data.GetString("sku"); err != nil || len(sku) == 0 { + return httperrors.NewMissingParameterError("sku") + } else { + chargeType, _ := data.GetString("charge_type") + + _skuModel, err := db.FetchByIdOrName(models.ElasticcacheSkuManager, ownerId, sku) + if err != nil { + return err + } + + skuModel := _skuModel.(*models.SElasticcacheSku) + for _, zoneId := range zones { + if err := ValidateElasticcacheSku(zoneId, chargeType, skuModel); err != nil { + return err + } + } + } + + data.Set("slave_zones", jsonutils.NewString(strings.Join(ret, ","))) + return nil +} + +func ValidateElasticcacheSku(zoneId string, chargeType string, sku *models.SElasticcacheSku) error { + if sku.ZoneId != zoneId { + return httperrors.NewResourceNotFoundError("zone mismatch, elastic cache sku zone %s != %s", sku.ZoneId, zoneId) + } + + if chargeType == billing_api.BILLING_TYPE_PREPAID { + if sku.PrepaidStatus != api.SkuStatusAvailable { + return httperrors.NewOutOfResourceError("sku %s is soldout", sku.Name) + } + } else { + if sku.PostpaidStatus != api.SkuStatusAvailable { + return httperrors.NewOutOfResourceError("sku %s is soldout", sku.Name) + } + } + + return nil +} + +func (self *SHuaWeiRegionDriver) ValidateCreateElasticcacheData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId) + networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId) + // secgroupV := validators.NewModelIdOrNameValidator("security_group", "secgroup", ownerId) + + // todo: fix me + instanceTypeV := validators.NewModelIdOrNameValidator("instance_type", "elasticcachesku", ownerId) + chargeTypeV := validators.NewStringChoicesValidator("billing_type", choices.NewChoices(billing_api.BILLING_TYPE_PREPAID, billing_api.BILLING_TYPE_POSTPAID)) + networkTypeV := validators.NewStringChoicesValidator("network_type", choices.NewChoices(api.LB_NETWORK_TYPE_VPC, api.LB_NETWORK_TYPE_CLASSIC)).Default(api.LB_NETWORK_TYPE_VPC).Optional(true) + engineV := validators.NewStringChoicesValidator("engine", choices.NewChoices("redis", "memcache")) + engineVersionV := validators.NewStringChoicesValidator("engine_version", choices.NewChoices("3.0", "4.0", "5.0")) + privateIpV := validators.NewIPv4AddrValidator("private_ip").Optional(true) + maintainStartTimeV := validators.NewStringChoicesValidator("maintain_start_time", choices.NewChoices("22:00:00", "02:00:00", "06:00:00", "10:00:00", "14:00:00", "18:00:00")).Default("02:00:00").Optional(true) + + keyV := map[string]validators.IValidator{ + "zone": zoneV, + "billing_type": chargeTypeV, + "network_type": networkTypeV, + "network": networkV, + "instance_type": instanceTypeV, + // "security_group": secgroupV, + "engine": engineV, + "engine_version": engineVersionV, + "private_ip": privateIpV, + "mantain_start_time": maintainStartTimeV, + } + if err := RunValidators(keyV, data, false); err != nil { + return nil, err + } + + // validate password + if password, _ := data.GetString("password"); len(password) > 0 { + if !seclib2.MeetComplxity(password) { + return nil, httperrors.NewWeakPasswordError() + } + } + + // validate sku + sku := instanceTypeV.Model.(*models.SElasticcacheSku) + zoneId, _ := data.GetString("zone_id") + billingType, _ := data.GetString("billing_type") + + if err := ValidateElasticcacheSku(zoneId, billingType, sku); err != nil { + return nil, err + } else { + data.Set("instance_type", jsonutils.NewString(sku.InstanceSpec)) + data.Set("node_type", jsonutils.NewString(sku.NodeType)) + data.Set("local_category", jsonutils.NewString(sku.LocalCategory)) + data.Set("capacity_mb", jsonutils.NewInt(int64(sku.MemorySizeMB))) + } + + // validate slave zones + if err := validatorSlaveZones(ownerId, data, true); err != nil { + return nil, err + } + + // validate capacity + if capacityMB, err := data.Int("capacity_mb"); err != nil { + return nil, errors.Wrap(err, "invalid parameter capacity_mb") + } else { + // todo: fix me + // Redis引擎:单机和主备类型实例取值:2、4、8、16、32、64。集群实例规格支持64G、128G、256G、512G和1024G。 + data.Set("capacity_mb", jsonutils.NewInt(capacityMB)) + } + + // MaintainEndTime + // 开始时间必须为22:00:00、02:00:00、06:00:00、10:00:00、14:00:00和18:00:00。 + data.Remove("mantain_end_time") + if startTime, err := data.GetString("maintain_start_time"); err == nil { + maintainTimes := []string{"22:00:00", "02:00:00", "06:00:00", "10:00:00", "14:00:00", "18:00:00", "22:00:00"} + + for i := range maintainTimes { + if maintainTimes[i] == startTime { + data.Add(jsonutils.NewString(maintainTimes[i+1]), "mantain_end_time") + break + } + } + } + + // billing cycle + if billingType == billing_api.BILLING_TYPE_PREPAID { + billingCycle, err := data.GetString("billing_cycle") + if err != nil { + return nil, httperrors.NewMissingParameterError("billing_cycle") + } + + cycle, err := billing.ParseBillingCycle(billingCycle) + if err != nil { + return nil, httperrors.NewInputParameterError("invalid billing_cycle %s", billingCycle) + } + + data.Set("billing_cycle", jsonutils.NewString(cycle.String())) + } + + network := networkV.Model.(*models.SNetwork) + vpc := network.GetVpc() + if vpc == nil { + return nil, httperrors.NewNotFoundError("network %s related vpc not found", network.GetId()) + } + data.Set("vpc_id", jsonutils.NewString(vpc.Id)) + data.Set("manager_id", jsonutils.NewString(vpc.ManagerId)) + data.Set("cloudregion_id", jsonutils.NewString(sku.CloudregionId)) + return data, nil +} + +func (self *SHuaWeiRegionDriver) RequestCreateElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + iRegion, err := ec.GetIRegion() + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetIRegion") + } + + iprovider, err := db.FetchById(models.CloudproviderManager, ec.ManagerId) + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetProvider") + } + + provider := iprovider.(*models.SCloudprovider) + + params, err := ec.GetCreateHuaweiElasticcacheParams() + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetCreateHuaweiElasticcacheParams") + } + + iec, err := iRegion.CreateIElasticcaches(params) + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.CreateIElasticcaches") + } + + err = cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 30*time.Second, 15*time.Second, 600*time.Second) + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.WaitStatusWithDelay") + } + + ec.SetModelManager(models.ElasticcacheManager, ec) + if err := db.SetExternalId(ec, userCred, iec.GetGlobalId()); err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.SetExternalId") + } + + { + // todo: 开启外网访问 + } + + if err := ec.SyncWithCloudElasticcache(ctx, userCred, provider, iec); err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.SyncWithCloudElasticcache") + } + + // sync accounts + { + iaccounts, err := iec.GetICloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetICloudElasticcacheAccounts") + } + + result := models.ElasticcacheAccountManager.SyncElasticcacheAccounts(ctx, userCred, ec, iaccounts) + log.Debugf("huaweiRegionDriver.CreateElasticcache.SyncElasticcacheAccounts %s", result.Result()) + + account, err := ec.GetAdminAccount() + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetAdminAccount") + } + + err = account.SavePassword(params.Password) + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.SavePassword") + } + } + + // sync acl + { + iacls, err := iec.GetICloudElasticcacheAcls() + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetICloudElasticcacheAcls") + } + + result := models.ElasticcacheAclManager.SyncElasticcacheAcls(ctx, userCred, ec, iacls) + log.Debugf("huaweiRegionDriver.CreateElasticcache.SyncElasticcacheAcls %s", result.Result()) + } + + // sync parameters + { + iparams, err := iec.GetICloudElasticcacheParameters() + if err != nil { + return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetICloudElasticcacheParameters") + } + + result := models.ElasticcacheParameterManager.SyncElasticcacheParameters(ctx, userCred, ec, iparams) + log.Debugf("huaweiRegionDriver.CreateElasticcache.SyncElasticcacheParameters %s", result.Result()) + } + + return nil, nil + }) + return nil +} + +func (self *SHuaWeiRegionDriver) ValidateCreateElasticcacheAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return nil, httperrors.NewUnsupportOperationError("% not support create account", self.GetProvider()) +} + +func (self *SHuaWeiRegionDriver) RequestElasticcacheAccountResetPassword(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error { + iregion, err := ea.GetIRegion() + if err != nil { + return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetIRegion") + } + + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.FetchById") + } + + ec := _ec.(*models.SElasticcache) + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetIElasticcacheById") + } + + iea, err := iec.GetICloudElasticcacheAccount(ea.GetExternalId()) + if err != nil { + return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetICloudElasticcacheBackup") + } + + data := task.GetParams() + if data == nil { + return errors.Wrap(fmt.Errorf("data is nil"), "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetParams") + } + + input, err := ea.GetUpdateHuaweiElasticcacheAccountParams(*data) + if err != nil { + return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetUpdateHuaweiElasticcacheAccountParams") + } + + err = iea.UpdateAccount(input) + if err != nil { + return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.UpdateAccount") + } + + if input.Password != nil { + err = ea.SavePassword(*input.Password) + if err != nil { + return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.SavePassword") + } + } + + return ea.SetStatus(userCred, api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE, "") +} diff --git a/pkg/compute/regiondrivers/kvm.go b/pkg/compute/regiondrivers/kvm.go index a1c481ac09..fa1055cd47 100644 --- a/pkg/compute/regiondrivers/kvm.go +++ b/pkg/compute/regiondrivers/kvm.go @@ -861,3 +861,111 @@ func (self *SKVMRegionDriver) BindIPToNatgatewayRollback(ctx context.Context, ei func (self *SKVMRegionDriver) ValidateCacheSecgroup(ctx context.Context, userCred mcclient.TokenCredential, secgroup *models.SSecurityGroup, vpc *models.SVpc, classic bool) error { return fmt.Errorf("No need to cache secgroup for onecloud region") } + +func (self *SKVMRegionDriver) RequestCreateElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) ValidateCreateElasticcacheData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return data, nil +} + +func (self *SKVMRegionDriver) RequestRestartElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestSyncElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestDeleteElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestChangeElasticcacheSpec(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestSetElasticcacheMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheChangeSpec(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestUpdateElasticcacheAuthMode(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheSetMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheAllocatePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheReleasePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheFlushInstance(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheUpdateInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheUpdateBackupPolicy(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) ValidateCreateElasticcacheAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return nil, nil +} + +func (self *SKVMRegionDriver) ValidateCreateElasticcacheAclData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return nil, nil +} + +func (self *SKVMRegionDriver) ValidateCreateElasticcacheBackupData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return nil, nil +} + +func (self *SKVMRegionDriver) RequestCreateElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheAccount *models.SElasticcacheAccount, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestCreateElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheAcl *models.SElasticcacheAcl, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestCreateElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheBackup *models.SElasticcacheBackup, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestDeleteElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestDeleteElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAcl, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestDeleteElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, eb *models.SElasticcacheBackup, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheAccountResetPassword(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheAclUpdate(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAcl, task taskman.ITask) error { + return nil +} + +func (self *SKVMRegionDriver) RequestElasticcacheBackupRestoreInstance(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheBackup, task taskman.ITask) error { + return nil +} diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index fb67083760..17f6f84d9e 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -31,6 +31,7 @@ import ( "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/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" @@ -1601,6 +1602,492 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateDBInstance(ctx cont return nil } +func (self *SManagedVirtualizationRegionDriver) RequestCreateElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, task taskman.ITask) error { + return nil +} + +func (self *SManagedVirtualizationRegionDriver) ValidateCreateElasticcacheData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return self.ValidateManagerId(ctx, userCred, data) +} + +func (self *SManagedVirtualizationRegionDriver) RequestRestartElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestRestartElasticcache.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestRestartElasticcache.GetIElasticcacheById") + } + + err = iec.Restart() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestRestartElasticcache.Restart") + } + + err = cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) + if err != nil { + return err + } + + return ec.SetStatus(userCred, api.ELASTIC_CACHE_STATUS_RUNNING, "") +} + +func (self *SManagedVirtualizationRegionDriver) RequestSyncElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetIElasticcacheById") + } + + provider := ec.GetCloudprovider() + if provider == nil { + return errors.Wrap(fmt.Errorf("provider is nil"), "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetCloudprovider") + } + + lockman.LockClass(ctx, models.ElasticcacheManager, db.GetLockClassKey(models.ElasticcacheManager, provider.GetOwnerId())) + defer lockman.ReleaseClass(ctx, models.ElasticcacheManager, db.GetLockClassKey(models.ElasticcacheManager, provider.GetOwnerId())) + + err = ec.SyncWithCloudElasticcache(ctx, userCred, provider, iec) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetIElasticcacheById") + } + + if fullsync, _ := task.GetParams().Bool("full"); fullsync { + lockman.LockObject(ctx, ec) + defer lockman.ReleaseObject(ctx, ec) + + parameters, err := iec.GetICloudElasticcacheParameters() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetICloudElasticcacheParameters") + } + + result := models.ElasticcacheParameterManager.SyncElasticcacheParameters(ctx, userCred, ec, parameters) + log.Debugf("managedVirtualizationRegionDriver.RequestSyncElasticcache.SyncElasticcacheParameters %s", result.Result()) + + // acl + acls, err := iec.GetICloudElasticcacheAcls() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetICloudElasticcacheAcls") + } + + result = models.ElasticcacheAclManager.SyncElasticcacheAcls(ctx, userCred, ec, acls) + log.Debugf("managedVirtualizationRegionDriver.RequestSyncElasticcache.SyncElasticcacheAcls %s", result.Result()) + + // account + accounts, err := iec.GetICloudElasticcacheAccounts() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetICloudElasticcacheAccounts") + } + + result = models.ElasticcacheAccountManager.SyncElasticcacheAccounts(ctx, userCred, ec, accounts) + log.Debugf("managedVirtualizationRegionDriver.RequestSyncElasticcache.SyncElasticcacheAccounts %s", result.Result()) + + // backups + backups, err := iec.GetICloudElasticcacheBackups() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSyncElasticcache.GetICloudElasticcacheBackups") + } + + result = models.ElasticcacheBackupManager.SyncElasticcacheBackups(ctx, userCred, ec, backups) + log.Debugf("managedVirtualizationRegionDriver.RequestSyncElasticcache.SyncElasticcacheBackups %s", result.Result()) + } + + return ec.SetStatus(userCred, api.ELASTIC_CACHE_STATUS_RUNNING, "") +} + +func (self *SManagedVirtualizationRegionDriver) RequestDeleteElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcache.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcache.GetIElasticcacheById") + } + + err = iec.Delete() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcache.Delete") + } + + return cloudprovider.WaitDeleted(iec, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestChangeElasticcacheSpec(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + sku, err := task.GetParams().GetString("sku") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter sku"), "managedVirtualizationRegionDriver.RequestChangeElasticcacheSpec") + } + + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestChangeElasticcacheSpec.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestChangeElasticcacheSpec.GetIElasticcacheById") + } + + err = iec.ChangeInstanceSpec(sku) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestChangeElasticcacheSpec.ChangeInstanceSpec") + } + + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestSetElasticcacheMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + mStart, err := task.GetParams().GetString("maintain_start_time") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter maintain_start_time"), "managedVirtualizationRegionDriver.RequestSetElasticcacheMaintainTime") + } + + mEnd, err := task.GetParams().GetString("maintain_end_time") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter maintain_end_time"), "managedVirtualizationRegionDriver.RequestSetElasticcacheMaintainTime") + } + + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSetElasticcacheMaintainTime.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSetElasticcacheMaintainTime.GetIElasticcacheById") + } + + err = iec.SetMaintainTime(mStart, mEnd) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestSetElasticcacheMaintainTime.SetMaintainTime") + } + + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheChangeSpec(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + sku, err := task.GetParams().GetString("sku_ext_id") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter sku"), "managedVirtualizationRegionDriver.RequestElasticcacheChangeSpec") + } + + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheChangeSpec.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheChangeSpec.GetIElasticcacheById") + } + + err = iec.ChangeInstanceSpec(sku) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheChangeSpec.ChangeInstanceSpec") + } + + err = cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 1800*time.Second) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheChangeSpec.ChangeInstanceSpec") + } + + err = ec.SyncWithCloudElasticcache(ctx, userCred, nil, iec) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheChangeSpec.SyncWithCloudElasticcache") + } + + return nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestUpdateElasticcacheAuthMode(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + authMode, err := task.GetParams().GetString("auth_mode") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter auth_mode"), "managedVirtualizationRegionDriver.RequestUpdateElasticcacheAuthMode") + } + + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestUpdateElasticcacheAuthMode.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestUpdateElasticcacheAuthMode.GetIElasticcacheById") + } + + noPassword := true + if authMode == "on" { + noPassword = false + } + + err = iec.UpdateAuthMode(noPassword) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestUpdateElasticcacheAuthMode.UpdateAuthMode") + } + + _, err = db.Update(ec, func() error { + ec.AuthMode = authMode + return nil + }) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestUpdateElasticcacheAuthMode.UpdatedbAuthMode") + } + + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheSetMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + startTime, err := task.GetParams().GetString("maintain_start_time") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter maintain_start_time"), "managedVirtualizationRegionDriver.RequestElasticcacheSetMaintainTime") + } + + endTime, err := task.GetParams().GetString("maintain_end_time") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter maintain_end_time"), "managedVirtualizationRegionDriver.RequestElasticcacheSetMaintainTime") + } + + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheSetMaintainTime.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheSetMaintainTime.GetIElasticcacheById") + } + + err = iec.SetMaintainTime(startTime, endTime) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheSetMaintainTime.SetMaintainTime") + } + + // todo: sync instance spec + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheAllocatePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + port, _ := task.GetParams().Int("port") + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAllocatePublicConnection.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAllocatePublicConnection.GetIElasticcacheById") + } + + _, err = iec.AllocatePublicConnection(int(port)) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAllocatePublicConnection.AllocatePublicConnection") + } + + err = cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAllocatePublicConnection.WaitStatusWithDelay") + } + + err = ec.SyncWithCloudElasticcache(ctx, task.GetUserCred(), nil, iec) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAllocatePublicConnection.SyncWithCloudElasticcache") + } + + return nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheReleasePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheReleasePublicConnection.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheReleasePublicConnection.GetIElasticcacheById") + } + + err = iec.ReleasePublicConnection() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheReleasePublicConnection.AllocatePublicConnection") + } + + // todo: sync instance spec + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheFlushInstance(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheFlushInstance.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheFlushInstance.GetIElasticcacheById") + } + + err = iec.FlushInstance() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheFlushInstance.FlushInstance") + } + + // todo: sync instance spec + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheUpdateInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + parameters, err := task.GetParams().Get("parameters") + if err != nil { + return errors.Wrap(fmt.Errorf("missing parameter parameters"), "managedVirtualizationRegionDriver.RequestElasticcacheUpdateInstanceParameters") + } + + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheUpdateInstanceParameters.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheUpdateInstanceParameters.GetIElasticcacheById") + } + + err = iec.UpdateInstanceParameters(parameters) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheUpdateInstanceParameters.UpdateInstanceParameters") + } + + // todo: sync instance spec + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheUpdateBackupPolicy(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error { + backupType, _ := task.GetParams().GetString("backup_type") + backupReservedDays, _ := task.GetParams().Int("backup_reserved_days") + preferredBackupPeriod, _ := task.GetParams().GetString("preferred_backup_period") + preferredBackupTime, _ := task.GetParams().GetString("preferred_backup_time") + + config := cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput{ + BackupType: backupType, + BackupReservedDays: int(backupReservedDays), + PreferredBackupPeriod: preferredBackupPeriod, + PreferredBackupTime: preferredBackupTime, + } + + iregion, err := ec.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheUpdateBackupPolicy.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheUpdateBackupPolicy.GetIElasticcacheById") + } + + err = iec.UpdateBackupPolicy(config) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheUpdateBackupPolicy.UpdateBackupPolicy") + } + + // todo: sync instance spec + return cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 10*time.Second, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) ValidateCreateElasticcacheAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return nil, nil +} + +func (self *SManagedVirtualizationRegionDriver) ValidateCreateElasticcacheAclData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + ips, err := data.GetString("ip_list") + if err != nil || ips == "" { + return nil, httperrors.NewMissingParameterError("ip_list") + } + + ipV := validators.NewIPv4AddrValidator("ip") + _ips := strings.Split(ips, ",") + for _, ip := range _ips { + params := jsonutils.NewDict() + params.Set("ip", jsonutils.NewString(ip)) + if err := ipV.Validate(params); err != nil { + return nil, err + } + } + + elasticcacheV := validators.NewModelIdOrNameValidator("elasticcache", "elasticcache", ownerId) + if err := elasticcacheV.Validate(data); err != nil { + return nil, err + } + + return data, nil +} + +func (self *SManagedVirtualizationRegionDriver) ValidateCreateElasticcacheBackupData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + elasticcacheV := validators.NewModelIdOrNameValidator("elasticcache", "elasticcache", ownerId) + if err := elasticcacheV.Validate(data); err != nil { + return nil, err + } + + ec := elasticcacheV.Model.(*models.SElasticcache) + if !utils.IsInStringArray(ec.Status, []string{api.ELASTIC_CACHE_STATUS_RUNNING}) { + return nil, httperrors.NewInputParameterError("can not make backup in status %s", ec.Status) + } + + return data, nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestCreateElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, elasticcacheAccount *models.SElasticcacheAccount, task taskman.ITask) error { + return nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestCreateElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAcl, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.GetElasticcache") + } + + ec := _ec.(*models.SElasticcache) + iregion, err := ec.GetIRegion() + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.GetIElasticcacheById") + } + + iea, err := iec.CreateAcl(ea.Name, ea.IpList) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.CreateAcl") + } + + // todo: wait elastic cache instance running + ea.SetModelManager(models.ElasticcacheAclManager, ea) + if err := db.SetExternalId(ea, userCred, iea.GetGlobalId()); err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.SetExternalId") + } + + if err := ea.SyncWithCloudElasticcacheAcl(ctx, userCred, iea); err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.SyncWithCloudElasticcache") + } + + return nil, nil + }) + + return nil +} + func (self *SManagedVirtualizationRegionDriver) RequestChangeDBInstanceConfig(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SDBInstance, task taskman.ITask) error { taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { input := &api.SDBInstanceChangeConfigInput{} @@ -1741,3 +2228,274 @@ func (self *SManagedVirtualizationRegionDriver) ValidateChangeDBInstanceConfigDa func (self *SManagedVirtualizationRegionDriver) ValidateResetDBInstancePassword(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SDBInstance, account string) error { return nil } + +func (self *SManagedVirtualizationRegionDriver) RequestCreateElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, eb *models.SElasticcacheBackup, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + _ec, err := db.FetchById(models.ElasticcacheManager, eb.ElasticcacheId) + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.GetElasticcache") + } + + ec := _ec.(*models.SElasticcache) + iregion, err := ec.GetIRegion() + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.GetIElasticcacheById") + } + + ieb, err := iec.CreateBackup() + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.CreateBackup") + } + + err = cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 30*time.Second, 30*time.Second, 1800*time.Second) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.WaitStatusWithDelay") + } + + eb.SetModelManager(models.ElasticcacheBackupManager, eb) + if err := db.SetExternalId(eb, userCred, ieb.GetGlobalId()); err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.SetExternalId") + } + + if err := eb.SyncWithCloudElasticcacheBackup(ctx, userCred, ieb); err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheBackup.SyncWithCloudElasticcacheBackup") + } + + return nil, nil + }) + + return nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestDeleteElasticcacheAccount(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error { + iregion, err := ea.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAccount.GetIRegion") + } + + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAccount.FetchById") + } + + ec := _ec.(*models.SElasticcache) + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAccount.GetIElasticcacheById") + } + + iea, err := iec.GetICloudElasticcacheAccount(ea.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAccount.GetICloudElasticcacheAccount") + } + + err = iea.Delete() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAccount.Delete") + } + + err = cloudprovider.WaitDeleted(iea, 10*time.Second, 300*time.Second) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAccount.WaitDeleted") + } + + return nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestDeleteElasticcacheAcl(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAcl, task taskman.ITask) error { + iregion, err := ea.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAcl.GetIRegion") + } + + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAcl.FetchElasticcacheById") + } + + ec := _ec.(*models.SElasticcache) + + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAcl.GetIElasticcacheById") + } + + iea, err := iec.GetICloudElasticcacheAcl(ea.GetExternalId()) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAcl.GetICloudElasticcacheAccount") + } + + err = iea.Delete() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheAcl.Delete") + } + + return cloudprovider.WaitDeleted(iea, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestDeleteElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, eb *models.SElasticcacheBackup, task taskman.ITask) error { + iregion, err := eb.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheBackup.GetIRegion") + } + + _ec, err := db.FetchById(models.ElasticcacheAclManager, eb.ElasticcacheId) + if err != nil { + return err + } + + ec := _ec.(*models.SElasticcache) + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheBackup.GetIElasticcacheById") + } + + ieb, err := iec.GetICloudElasticcacheBackup(eb.GetExternalId()) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheBackup.GetICloudElasticcacheBackup") + } + + err = ieb.Delete() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestDeleteElasticcacheBackup.Delete") + } + + return cloudprovider.WaitDeleted(ieb, 10*time.Second, 300*time.Second) +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheAccountResetPassword(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error { + iregion, err := ea.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAccountResetPassword.GetIRegion") + } + + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAccountResetPassword.FetchById") + } + + ec := _ec.(*models.SElasticcache) + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAccountResetPassword.GetIElasticcacheById") + } + + iea, err := iec.GetICloudElasticcacheAccount(ea.GetExternalId()) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAccountResetPassword.GetICloudElasticcacheBackup") + } + + input := cloudprovider.SCloudElasticCacheAccountUpdateInput{} + passwd, _ := task.GetParams().GetString("password") + input.Password = &passwd + + err = iea.UpdateAccount(input) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAccountResetPassword.UpdateAccount") + } + + err = ea.SavePassword(passwd) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheAccountResetPassword.SavePassword") + } + + return ea.SetStatus(userCred, api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE, "") +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheAclUpdate(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAcl, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId) + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.GetElasticcache") + } + + ec := _ec.(*models.SElasticcache) + iregion, err := ec.GetIRegion() + if err != nil { + return nil, errors.Wrap(nil, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.GetIRegion") + } + + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.GetIElasticcacheById") + } + + iea, err := iec.GetICloudElasticcacheAcl(ea.ExternalId) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.GetICloudElasticcacheAcl") + } + + ipList, _ := task.GetParams().GetString("ip_list") + err = iea.UpdateAcl(ipList) + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.UpdateAcl") + } + + err = ea.SetStatus(userCred, api.ELASTIC_CACHE_ACL_STATUS_AVAILABLE, "") + if err != nil { + return nil, errors.Wrap(err, "managedVirtualizationRegionDriver.CreateElasticcacheAcl.UpdateAclStatus") + } + return nil, nil + }) + + return nil +} + +func (self *SManagedVirtualizationRegionDriver) RequestElasticcacheBackupRestoreInstance(ctx context.Context, userCred mcclient.TokenCredential, eb *models.SElasticcacheBackup, task taskman.ITask) error { + iregion, err := eb.GetIRegion() + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheBackupRestoreInstance.GetIRegion") + } + + _ec, err := db.FetchById(models.ElasticcacheManager, eb.ElasticcacheId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheBackupRestoreInstance.FetchById") + } + + ec := _ec.(*models.SElasticcache) + iec, err := iregion.GetIElasticcacheById(ec.GetExternalId()) + if err == cloudprovider.ErrNotFound { + return nil + } else if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheBackupRestoreInstance.GetIElasticcacheById") + } + + ieb, err := iec.GetICloudElasticcacheBackup(eb.GetExternalId()) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheBackupRestoreInstance.GetICloudElasticcacheBackup") + } + + err = ieb.RestoreInstance(ec.ExternalId) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheBackupRestoreInstance.RestoreInstance") + } + + _, err = db.Update(ec, func() error { + ec.Status = api.ELASTIC_CACHE_STATUS_BACKUPRECOVERING + return nil + }) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheBackupRestoreInstance.UpdateStatus") + } + + err = cloudprovider.WaitStatusWithDelay(iec, api.ELASTIC_CACHE_STATUS_RUNNING, 30*time.Second, 30*time.Second, 1800*time.Second) + if err != nil { + return errors.Wrap(err, "managedVirtualizationRegionDriver.RequestElasticcacheBackupRestoreInstance.WaitStatusWithDelay") + } + return nil +} diff --git a/pkg/compute/service/handlers.go b/pkg/compute/service/handlers.go index 9d7b6f85b3..1b7924fdfd 100644 --- a/pkg/compute/service/handlers.go +++ b/pkg/compute/service/handlers.go @@ -134,6 +134,7 @@ func InitHandlers(app *appsrv.Application) { models.ElasticcacheAccountManager, models.ElasticcacheParameterManager, models.ElasticcacheBackupManager, + models.ElasticcacheSkuManager, } { db.RegisterModelManager(manager) handler := db.NewModelHandler(manager) diff --git a/pkg/compute/tasks/elasticcache_account_create_task.go b/pkg/compute/tasks/elasticcache_account_create_task.go new file mode 100644 index 0000000000..c9ffb0e521 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_account_create_task.go @@ -0,0 +1,68 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheAccountCreateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheAccountCreateTask{}) +} + +func (self *ElasticcacheAccountCreateTask) taskFail(ctx context.Context, elasticcache *models.SElasticcacheAccount, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_ACCOUNT_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_CREATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_ACCOUNT_STATUS_CREATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheAccountCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ea := obj.(*models.SElasticcacheAccount) + region := ea.GetRegion() + if region == nil { + self.taskFail(ctx, ea, fmt.Sprintf("failed to find region for elastic cache account %s", ea.GetName())) + return + } + + self.SetStage("OnElasticcacheAccountCreateComplete", nil) + if err := region.GetDriver().RequestCreateElasticcacheAccount(ctx, self.GetUserCred(), ea, self); err != nil { + self.taskFail(ctx, ea, err.Error()) + return + } +} + +func (self *ElasticcacheAccountCreateTask) OnElasticcacheAccountCreateComplete(ctx context.Context, ea *models.SElasticcacheAccount, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheAccountCreateTask) OnElasticcacheAccountCreateCompleteFailed(ctx context.Context, ea *models.SElasticcacheAccount, reason string) { + self.taskFail(ctx, ea, reason) +} diff --git a/pkg/compute/tasks/elasticcache_account_delete_task.go b/pkg/compute/tasks/elasticcache_account_delete_task.go new file mode 100644 index 0000000000..b1672a34b5 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_account_delete_task.go @@ -0,0 +1,67 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheAccountDeleteTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheAccountDeleteTask{}) +} + +func (self *ElasticcacheAccountDeleteTask) taskFail(ctx context.Context, ea *models.SElasticcacheAccount, reason string) { + ea.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_ACCOUNT_STATUS_DELETE_FAILED, reason) + db.OpsLog.LogEvent(ea, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, ea, logclient.ACT_CREATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(ea.Id, ea.Name, api.ELASTIC_CACHE_ACCOUNT_STATUS_DELETE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheAccountDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ea := obj.(*models.SElasticcacheAccount) + region := ea.GetRegion() + if region == nil { + self.taskFail(ctx, ea, fmt.Sprintf("failed to find region for elastic cache account %s", ea.GetName())) + return + } + + self.SetStage("OnElasticcacheAccountDeleteComplete", nil) + if err := region.GetDriver().RequestDeleteElasticcacheAccount(ctx, self.GetUserCred(), ea, self); err != nil { + self.taskFail(ctx, ea, err.Error()) + return + } else { + err = db.DeleteModel(ctx, self.GetUserCred(), ea) + if err != nil { + self.taskFail(ctx, ea, err.Error()) + return + } + self.SetStageComplete(ctx, nil) + } +} diff --git a/pkg/compute/tasks/elasticcache_account_reset_password_task.go b/pkg/compute/tasks/elasticcache_account_reset_password_task.go new file mode 100644 index 0000000000..0a05e62254 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_account_reset_password_task.go @@ -0,0 +1,62 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheAccountResetPasswordTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheAccountResetPasswordTask{}) +} + +func (self *ElasticcacheAccountResetPasswordTask) taskFail(ctx context.Context, elasticcache *models.SElasticcacheAccount, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_UNAVAILABLE, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_CREATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheAccountResetPasswordTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ec := obj.(*models.SElasticcacheAccount) + region := ec.GetRegion() + if region == nil { + self.taskFail(ctx, ec, fmt.Sprintf("failed to find region for elastic cache %s", ec.GetName())) + return + } + + self.SetStage("OnElasticcacheAccountResetPasswordComplete", nil) + if err := region.GetDriver().RequestElasticcacheAccountResetPassword(ctx, self.GetUserCred(), ec, self); err != nil { + self.taskFail(ctx, ec, err.Error()) + return + } else { + self.SetStageComplete(ctx, nil) + } +} diff --git a/pkg/compute/tasks/elasticcache_acl_create_task.go b/pkg/compute/tasks/elasticcache_acl_create_task.go new file mode 100644 index 0000000000..98a2156ed1 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_acl_create_task.go @@ -0,0 +1,67 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheAclCreateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheAclCreateTask{}) +} + +func (self *ElasticcacheAclCreateTask) taskFail(ctx context.Context, ea *models.SElasticcacheAcl, reason string) { + db.OpsLog.LogEvent(ea, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, ea, logclient.ACT_CREATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(ea.Id, ea.Name, api.ELASTIC_CACHE_ACL_STATUS_CREATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheAclCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ea := obj.(*models.SElasticcacheAcl) + region := ea.GetRegion() + if region == nil { + self.taskFail(ctx, ea, fmt.Sprintf("failed to find region for elastic cache backup %s", ea.GetName())) + return + } + + self.SetStage("OnElasticcacheAclCreateComplete", nil) + if err := region.GetDriver().RequestCreateElasticcacheAcl(ctx, self.GetUserCred(), ea, self); err != nil { + self.taskFail(ctx, ea, err.Error()) + return + } +} + +func (self *ElasticcacheAclCreateTask) OnElasticcacheAclCreateComplete(ctx context.Context, ea *models.SElasticcacheAcl, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheAclCreateTask) OnElasticcacheAclCreateCompleteFailed(ctx context.Context, ea *models.SElasticcacheAcl, reason string) { + self.taskFail(ctx, ea, reason) +} diff --git a/pkg/compute/tasks/elasticcache_acl_delete_task.go b/pkg/compute/tasks/elasticcache_acl_delete_task.go new file mode 100644 index 0000000000..466f64e24b --- /dev/null +++ b/pkg/compute/tasks/elasticcache_acl_delete_task.go @@ -0,0 +1,66 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheAclDeleteTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheAclDeleteTask{}) +} + +func (self *ElasticcacheAclDeleteTask) taskFail(ctx context.Context, ea *models.SElasticcacheAcl, reason string) { + db.OpsLog.LogEvent(ea, db.ACT_DELOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, ea, logclient.ACT_DELETE, reason, self.UserCred, false) + notifyclient.NotifySystemError(ea.Id, ea.Name, api.ELASTIC_CACHE_ACL_STATUS_DELETE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheAclDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ea := obj.(*models.SElasticcacheAcl) + region := ea.GetRegion() + if region == nil { + self.taskFail(ctx, ea, fmt.Sprintf("failed to find region for elastic cache account %s", ea.GetName())) + return + } + + self.SetStage("OnElasticcacheAclDeleteComplete", nil) + if err := region.GetDriver().RequestDeleteElasticcacheAcl(ctx, self.GetUserCred(), ea, self); err != nil { + self.taskFail(ctx, ea, err.Error()) + return + } else { + err = db.DeleteModel(ctx, self.GetUserCred(), ea) + if err != nil { + self.taskFail(ctx, ea, err.Error()) + return + } + self.SetStageComplete(ctx, nil) + } +} diff --git a/pkg/compute/tasks/elasticcache_acl_update_task.go b/pkg/compute/tasks/elasticcache_acl_update_task.go new file mode 100644 index 0000000000..0487242eb2 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_acl_update_task.go @@ -0,0 +1,67 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheAclUpdateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheAclUpdateTask{}) +} + +func (self *ElasticcacheAclUpdateTask) taskFail(ctx context.Context, ea *models.SElasticcacheAcl, reason string) { + db.OpsLog.LogEvent(ea, db.ACT_UPDATE, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, ea, logclient.ACT_UPDATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(ea.Id, ea.Name, api.ELASTIC_CACHE_ACL_STATUS_UPDATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheAclUpdateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ea := obj.(*models.SElasticcacheAcl) + region := ea.GetRegion() + if region == nil { + self.taskFail(ctx, ea, fmt.Sprintf("failed to find region for elastic cache backup %s", ea.GetName())) + return + } + + self.SetStage("OnElasticcacheAclUpdateComplete", nil) + if err := region.GetDriver().RequestElasticcacheAclUpdate(ctx, self.GetUserCred(), ea, self); err != nil { + self.taskFail(ctx, ea, err.Error()) + return + } +} + +func (self *ElasticcacheAclUpdateTask) OnElasticcacheAclUpdateComplete(ctx context.Context, ea *models.SElasticcacheAcl, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheAclUpdateTask) OnElasticcacheAclUpdateCompleteFailed(ctx context.Context, ea *models.SElasticcacheAcl, reason string) { + self.taskFail(ctx, ea, reason) +} diff --git a/pkg/compute/tasks/elasticcache_allocate_public_connection_task.go b/pkg/compute/tasks/elasticcache_allocate_public_connection_task.go new file mode 100644 index 0000000000..f40616f09f --- /dev/null +++ b/pkg/compute/tasks/elasticcache_allocate_public_connection_task.go @@ -0,0 +1,72 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheAllocatePublicConnectionTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheAllocatePublicConnectionTask{}) +} + +func (self *ElasticcacheAllocatePublicConnectionTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CHANGING, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_ALLOCATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_CHANGE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheAllocatePublicConnectionTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + elasticcache := obj.(*models.SElasticcache) + region := elasticcache.GetRegion() + if region == nil { + self.taskFail(ctx, elasticcache, fmt.Sprintf("failed to find region for elastic cache %s", elasticcache.GetName())) + return + } + + self.SetStage("OnElasticcacheAllocatePublicConnectionComplete", nil) + if err := region.GetDriver().RequestElasticcacheAllocatePublicConnection(ctx, self.GetUserCred(), elasticcache, self); err != nil { + self.OnElasticcacheAllocatePublicConnectionCompleteFailed(ctx, elasticcache, err.Error()) + return + } + + self.OnElasticcacheAllocatePublicConnectionComplete(ctx, elasticcache, data) + return +} + +func (self *ElasticcacheAllocatePublicConnectionTask) OnElasticcacheAllocatePublicConnectionComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheAllocatePublicConnectionTask) OnElasticcacheAllocatePublicConnectionCompleteFailed(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + self.taskFail(ctx, elasticcache, reason) +} diff --git a/pkg/compute/tasks/elasticcache_backup_create_task.go b/pkg/compute/tasks/elasticcache_backup_create_task.go new file mode 100644 index 0000000000..9d39f4e3d7 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_backup_create_task.go @@ -0,0 +1,69 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheBackupCreateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheBackupCreateTask{}) +} + +func (self *ElasticcacheBackupCreateTask) taskFail(ctx context.Context, elasticcache *models.SElasticcacheBackup, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_CREATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheBackupCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + eb := obj.(*models.SElasticcacheBackup) + region := eb.GetRegion() + if region == nil { + self.taskFail(ctx, eb, fmt.Sprintf("failed to find region for elastic cache backup %s", eb.GetName())) + return + } + + self.SetStage("OnElasticcacheBackupCreateComplete", nil) + if err := region.GetDriver().RequestCreateElasticcacheBackup(ctx, self.GetUserCred(), eb, self); err != nil { + self.taskFail(ctx, eb, err.Error()) + return + } +} + +func (self *ElasticcacheBackupCreateTask) OnElasticcacheBackupCreateComplete(ctx context.Context, ea *models.SElasticcacheBackup, data jsonutils.JSONObject) { + ea.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheBackupCreateTask) OnElasticcacheBackupCreateCompleteFailed(ctx context.Context, ea *models.SElasticcacheBackup, reason string) { + self.taskFail(ctx, ea, reason) +} diff --git a/pkg/compute/tasks/elasticcache_backup_delete_task.go b/pkg/compute/tasks/elasticcache_backup_delete_task.go new file mode 100644 index 0000000000..650aaa1037 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_backup_delete_task.go @@ -0,0 +1,15 @@ +// 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 diff --git a/pkg/compute/tasks/elasticcache_backup_restore_instance_task.go b/pkg/compute/tasks/elasticcache_backup_restore_instance_task.go new file mode 100644 index 0000000000..477e9e4a55 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_backup_restore_instance_task.go @@ -0,0 +1,72 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheBackupRestoreInstanceTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheBackupRestoreInstanceTask{}) +} + +func (self *ElasticcacheBackupRestoreInstanceTask) taskFail(ctx context.Context, eb *models.SElasticcacheBackup, reason string) { + eb.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(eb, db.ACT_CONVERT_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, eb, logclient.ACT_RESTORE, reason, self.UserCred, false) + notifyclient.NotifySystemError(eb.Id, eb.Name, api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheBackupRestoreInstanceTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + eb := obj.(*models.SElasticcacheBackup) + region := eb.GetRegion() + if region == nil { + self.taskFail(ctx, eb, fmt.Sprintf("failed to find region for elastic cache backup %s", eb.GetName())) + return + } + + self.SetStage("OnElasticcacheBackupRestoreInstanceComplete", nil) + if err := region.GetDriver().RequestElasticcacheBackupRestoreInstance(ctx, self.GetUserCred(), eb, self); err != nil { + self.OnElasticcacheBackupRestoreInstanceCompleteFailed(ctx, eb, err.Error()) + return + } + + self.OnElasticcacheBackupRestoreInstanceComplete(ctx, eb, data) + return +} + +func (self *ElasticcacheBackupRestoreInstanceTask) OnElasticcacheBackupRestoreInstanceComplete(ctx context.Context, eb *models.SElasticcacheBackup, data jsonutils.JSONObject) { + eb.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheBackupRestoreInstanceTask) OnElasticcacheBackupRestoreInstanceCompleteFailed(ctx context.Context, eb *models.SElasticcacheBackup, reason string) { + self.taskFail(ctx, eb, reason) +} diff --git a/pkg/compute/tasks/elasticcache_change_spec_task.go b/pkg/compute/tasks/elasticcache_change_spec_task.go new file mode 100644 index 0000000000..5fb66e5b82 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_change_spec_task.go @@ -0,0 +1,72 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheChangeSpecTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheChangeSpecTask{}) +} + +func (self *ElasticcacheChangeSpecTask) taskFail(ctx context.Context, ec *models.SElasticcache, reason string) { + ec.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CHANGE_FAILED, reason) + db.OpsLog.LogEvent(ec, db.ACT_CHANGE_FLAVOR, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, ec, logclient.ACT_VM_CHANGE_FLAVOR, reason, self.UserCred, false) + notifyclient.NotifySystemError(ec.Id, ec.Name, api.ELASTIC_CACHE_STATUS_CHANGE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheChangeSpecTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + elasticcache := obj.(*models.SElasticcache) + region := elasticcache.GetRegion() + if region == nil { + self.taskFail(ctx, elasticcache, fmt.Sprintf("failed to find region for elastic cache %s", elasticcache.GetName())) + return + } + + self.SetStage("OnElasticcacheChangeSpecComplete", nil) + if err := region.GetDriver().RequestElasticcacheChangeSpec(ctx, self.GetUserCred(), elasticcache, self); err != nil { + self.OnElasticcacheChangeSpecCompleteFailed(ctx, elasticcache, err.Error()) + return + } + + self.OnElasticcacheChangeSpecComplete(ctx, elasticcache, data) + return +} + +func (self *ElasticcacheChangeSpecTask) OnElasticcacheChangeSpecComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheChangeSpecTask) OnElasticcacheChangeSpecCompleteFailed(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + self.taskFail(ctx, elasticcache, reason) +} diff --git a/pkg/compute/tasks/elasticcache_create_task.go b/pkg/compute/tasks/elasticcache_create_task.go new file mode 100644 index 0000000000..85cc25c781 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_create_task.go @@ -0,0 +1,75 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheCreateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheCreateTask{}) +} + +func (self *ElasticcacheCreateTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_CREATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + elasticcache := obj.(*models.SElasticcache) + region := elasticcache.GetRegion() + if region == nil { + self.taskFail(ctx, elasticcache, fmt.Sprintf("failed to find region for elastic cache %s", elasticcache.GetName())) + return + } + + // sync security group here + self.SetStage("OnSyncSecurityGroupComplete", nil) + self.OnSyncSecurityGroupComplete(ctx, elasticcache, data) +} + +func (self *ElasticcacheCreateTask) OnSyncSecurityGroupComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + region := elasticcache.GetRegion() + self.SetStage("OnElasticcacheCreateComplete", nil) + if err := region.GetDriver().RequestCreateElasticcache(ctx, self.GetUserCred(), elasticcache, self); err != nil { + self.taskFail(ctx, elasticcache, err.Error()) + return + } +} + +func (self *ElasticcacheCreateTask) OnElasticcacheCreateComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheCreateTask) OnElasticcacheCreateCompleteFailed(ctx context.Context, elasticcache *models.SElasticcache, reason jsonutils.JSONObject) { + self.taskFail(ctx, elasticcache, reason.String()) +} diff --git a/pkg/compute/tasks/elasticcache_delete_task.go b/pkg/compute/tasks/elasticcache_delete_task.go new file mode 100644 index 0000000000..2b1c548cce --- /dev/null +++ b/pkg/compute/tasks/elasticcache_delete_task.go @@ -0,0 +1,65 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheDeleteTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheDeleteTask{}) +} + +func (self *ElasticcacheDeleteTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RELEASE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_DELOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_DELETE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_RELEASE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ec := obj.(*models.SElasticcache) + region := ec.GetRegion() + if region == nil { + self.taskFail(ctx, ec, fmt.Sprintf("failed to find region for elastic cache %s", ec.GetName())) + return + } + + self.SetStage("OnElasticcacheDeleteComplete", nil) + if err := region.GetDriver().RequestDeleteElasticcache(ctx, self.GetUserCred(), ec, self); err != nil { + self.taskFail(ctx, ec, err.Error()) + return + } else { + ec.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RELEASED, "") + // delete related resources + ec.DeleteSubResources(ctx, self.UserCred) + self.SetStageComplete(ctx, nil) + } +} diff --git a/pkg/compute/tasks/elasticcache_flush_instance.go b/pkg/compute/tasks/elasticcache_flush_instance.go new file mode 100644 index 0000000000..f075ab0c33 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_flush_instance.go @@ -0,0 +1,72 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheFlushInstanceTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheFlushInstanceTask{}) +} + +func (self *ElasticcacheFlushInstanceTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_REW_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_UNCACHED_IMAGE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_ACL_STATUS_UPDATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheFlushInstanceTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + elasticcache := obj.(*models.SElasticcache) + region := elasticcache.GetRegion() + if region == nil { + self.taskFail(ctx, elasticcache, fmt.Sprintf("failed to find region for elastic cache %s", elasticcache.GetName())) + return + } + + self.SetStage("OnElasticcacheFlushInstanceComplete", nil) + if err := region.GetDriver().RequestElasticcacheFlushInstance(ctx, self.GetUserCred(), elasticcache, self); err != nil { + self.OnElasticcacheFlushInstanceCompleteFailed(ctx, elasticcache, err.Error()) + return + } + + self.OnElasticcacheFlushInstanceComplete(ctx, elasticcache, data) + return +} + +func (self *ElasticcacheFlushInstanceTask) OnElasticcacheFlushInstanceComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheFlushInstanceTask) OnElasticcacheFlushInstanceCompleteFailed(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + self.taskFail(ctx, elasticcache, reason) +} diff --git a/pkg/compute/tasks/elasticcache_parameter_update_task.go b/pkg/compute/tasks/elasticcache_parameter_update_task.go new file mode 100644 index 0000000000..b14cb6fe70 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_parameter_update_task.go @@ -0,0 +1,73 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheParameterUpdateTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheParameterUpdateTask{}) +} + +func (self *ElasticcacheParameterUpdateTask) taskFail(ctx context.Context, ep *models.SElasticcacheParameter, reason string) { + db.OpsLog.LogEvent(ep, db.ACT_UPDATE, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, ep, logclient.ACT_UPDATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(ep.Id, ep.Name, api.ELASTIC_CACHE_PARAMETER_STATUS_UPDATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheParameterUpdateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ep := obj.(*models.SElasticcacheParameter) + region := ep.GetRegion() + if region == nil { + self.taskFail(ctx, ep, fmt.Sprintf("failed to find region for elastic cache parameter %s", ep.GetName())) + return + } + + iec, err := db.FetchById(models.ElasticcacheManager, ep.ElasticcacheId) + if err != nil { + self.taskFail(ctx, ep, fmt.Sprintf("failed to find elastic instance for parameter %s", ep.GetName())) + return + } + + self.SetStage("OnElasticcacheParameterUpdateComplete", nil) + if err := region.GetDriver().RequestElasticcacheUpdateInstanceParameters(ctx, self.GetUserCred(), iec.(*models.SElasticcache), self); err != nil { + self.taskFail(ctx, ep, err.Error()) + return + } +} + +func (self *ElasticcacheParameterUpdateTask) OnElasticcacheParameterUpdateComplete(ctx context.Context, ea *models.SElasticcacheParameter, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheParameterUpdateTask) OnElasticcacheParameterUpdateCompleteFailed(ctx context.Context, ea *models.SElasticcacheParameter, reason string) { + self.taskFail(ctx, ea, reason) +} diff --git a/pkg/compute/tasks/elasticcache_restart_task.go b/pkg/compute/tasks/elasticcache_restart_task.go new file mode 100644 index 0000000000..e43089eee5 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_restart_task.go @@ -0,0 +1,62 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheRestartTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheRestartTask{}) +} + +func (self *ElasticcacheRestartTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RESTART_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_RESTART_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_VM_RESTART, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_RESTART_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheRestartTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ec := obj.(*models.SElasticcache) + region := ec.GetRegion() + if region == nil { + self.taskFail(ctx, ec, fmt.Sprintf("failed to find region for elastic cache %s", ec.GetName())) + return + } + + self.SetStage("OnElasticcacheRestartComplete", nil) + if err := region.GetDriver().RequestRestartElasticcache(ctx, self.GetUserCred(), ec, self); err != nil { + self.taskFail(ctx, ec, err.Error()) + return + } else { + self.SetStageComplete(ctx, nil) + } +} diff --git a/pkg/compute/tasks/elasticcache_set_maintain_time_task.go b/pkg/compute/tasks/elasticcache_set_maintain_time_task.go new file mode 100644 index 0000000000..68ff0657a7 --- /dev/null +++ b/pkg/compute/tasks/elasticcache_set_maintain_time_task.go @@ -0,0 +1,72 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheSetMaintainTimeTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheSetMaintainTimeTask{}) +} + +func (self *ElasticcacheSetMaintainTimeTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_ALLOCATE_FAIL, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_UPDATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_ACL_STATUS_UPDATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheSetMaintainTimeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + elasticcache := obj.(*models.SElasticcache) + region := elasticcache.GetRegion() + if region == nil { + self.taskFail(ctx, elasticcache, fmt.Sprintf("failed to find region for elastic cache %s", elasticcache.GetName())) + return + } + + self.SetStage("OnElasticcacheSetMaintainTimeComplete", nil) + if err := region.GetDriver().RequestElasticcacheSetMaintainTime(ctx, self.GetUserCred(), elasticcache, self); err != nil { + self.OnElasticcacheSetMaintainTimeCompleteFailed(ctx, elasticcache, err.Error()) + return + } + + self.OnElasticcacheSetMaintainTimeComplete(ctx, elasticcache, data) + return +} + +func (self *ElasticcacheSetMaintainTimeTask) OnElasticcacheSetMaintainTimeComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheSetMaintainTimeTask) OnElasticcacheSetMaintainTimeCompleteFailed(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + self.taskFail(ctx, elasticcache, reason) +} diff --git a/pkg/compute/tasks/elasticcache_sync_task.go b/pkg/compute/tasks/elasticcache_sync_task.go new file mode 100644 index 0000000000..673576669d --- /dev/null +++ b/pkg/compute/tasks/elasticcache_sync_task.go @@ -0,0 +1,62 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheSyncTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheSyncTask{}) +} + +func (self *ElasticcacheSyncTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_SYNC_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_SYNC_CONF, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_SYNC_CONF, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_STATUS_SYNC_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheSyncTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + ec := obj.(*models.SElasticcache) + region := ec.GetRegion() + if region == nil { + self.taskFail(ctx, ec, fmt.Sprintf("failed to find region for elastic cache %s", ec.GetName())) + return + } + + self.SetStage("OnElasticcacheSyncComplete", nil) + if err := region.GetDriver().RequestSyncElasticcache(ctx, self.GetUserCred(), ec, self); err != nil { + self.taskFail(ctx, ec, err.Error()) + return + } else { + self.SetStageComplete(ctx, nil) + } +} diff --git a/pkg/compute/tasks/elasticcache_update_auth_mode_task.go b/pkg/compute/tasks/elasticcache_update_auth_mode_task.go new file mode 100644 index 0000000000..269ca3ad6a --- /dev/null +++ b/pkg/compute/tasks/elasticcache_update_auth_mode_task.go @@ -0,0 +1,72 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheUpdateAuthModeTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheUpdateAuthModeTask{}) +} + +func (self *ElasticcacheUpdateAuthModeTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_UPDATE, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_UPDATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_ACL_STATUS_UPDATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheUpdateAuthModeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + elasticcache := obj.(*models.SElasticcache) + region := elasticcache.GetRegion() + if region == nil { + self.taskFail(ctx, elasticcache, fmt.Sprintf("failed to find region for elastic cache %s", elasticcache.GetName())) + return + } + + self.SetStage("OnElasticcacheUpdateAuthModeComplete", nil) + if err := region.GetDriver().RequestUpdateElasticcacheAuthMode(ctx, self.GetUserCred(), elasticcache, self); err != nil { + self.OnElasticcacheUpdateAuthModeCompleteFailed(ctx, elasticcache, err.Error()) + return + } + + self.OnElasticcacheUpdateAuthModeComplete(ctx, elasticcache, data) + return +} + +func (self *ElasticcacheUpdateAuthModeTask) OnElasticcacheUpdateAuthModeComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheUpdateAuthModeTask) OnElasticcacheUpdateAuthModeCompleteFailed(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + self.taskFail(ctx, elasticcache, reason) +} diff --git a/pkg/compute/tasks/elasticcache_update_backup_policy_task.go b/pkg/compute/tasks/elasticcache_update_backup_policy_task.go new file mode 100644 index 0000000000..de5412a94a --- /dev/null +++ b/pkg/compute/tasks/elasticcache_update_backup_policy_task.go @@ -0,0 +1,72 @@ +// 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" + "fmt" + + "yunion.io/x/jsonutils" + + 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/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type ElasticcacheUpdateBackupPolicyTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(ElasticcacheUpdateBackupPolicyTask{}) +} + +func (self *ElasticcacheUpdateBackupPolicyTask) taskFail(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_CREATE_FAILED, reason) + db.OpsLog.LogEvent(elasticcache, db.ACT_UPDATE, reason, self.UserCred) + logclient.AddActionLogWithStartable(self, elasticcache, logclient.ACT_UPDATE, reason, self.UserCred, false) + notifyclient.NotifySystemError(elasticcache.Id, elasticcache.Name, api.ELASTIC_CACHE_ACL_STATUS_UPDATE_FAILED, reason) + self.SetStageFailed(ctx, reason) +} + +func (self *ElasticcacheUpdateBackupPolicyTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + elasticcache := obj.(*models.SElasticcache) + region := elasticcache.GetRegion() + if region == nil { + self.taskFail(ctx, elasticcache, fmt.Sprintf("failed to find region for elastic cache %s", elasticcache.GetName())) + return + } + + self.SetStage("OnElasticcacheUpdateBackupPolicyComplete", nil) + if err := region.GetDriver().RequestElasticcacheUpdateBackupPolicy(ctx, self.GetUserCred(), elasticcache, self); err != nil { + self.OnElasticcacheUpdateBackupPolicyCompleteFailed(ctx, elasticcache, err.Error()) + return + } + + self.OnElasticcacheUpdateBackupPolicyComplete(ctx, elasticcache, data) + return +} + +func (self *ElasticcacheUpdateBackupPolicyTask) OnElasticcacheUpdateBackupPolicyComplete(ctx context.Context, elasticcache *models.SElasticcache, data jsonutils.JSONObject) { + elasticcache.SetStatus(self.GetUserCred(), api.ELASTIC_CACHE_STATUS_RUNNING, "") + self.SetStageComplete(ctx, nil) +} + +func (self *ElasticcacheUpdateBackupPolicyTask) OnElasticcacheUpdateBackupPolicyCompleteFailed(ctx context.Context, elasticcache *models.SElasticcache, reason string) { + self.taskFail(ctx, elasticcache, reason) +} diff --git a/pkg/compute/tasks/instance_snapshot_and_clone_task.go b/pkg/compute/tasks/instance_snapshot_and_clone_task.go index c4cb16d9b4..1288f63670 100644 --- a/pkg/compute/tasks/instance_snapshot_and_clone_task.go +++ b/pkg/compute/tasks/instance_snapshot_and_clone_task.go @@ -1,3 +1,17 @@ +// 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 ( diff --git a/pkg/compute/tasks/instance_snapshot_create_task.go b/pkg/compute/tasks/instance_snapshot_create_task.go index caaba53fd8..8e4e4e8c12 100644 --- a/pkg/compute/tasks/instance_snapshot_create_task.go +++ b/pkg/compute/tasks/instance_snapshot_create_task.go @@ -1,3 +1,17 @@ +// 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 ( diff --git a/pkg/compute/tasks/instance_snapshot_delete_task.go b/pkg/compute/tasks/instance_snapshot_delete_task.go index 9813048d28..8aef979468 100644 --- a/pkg/compute/tasks/instance_snapshot_delete_task.go +++ b/pkg/compute/tasks/instance_snapshot_delete_task.go @@ -1,3 +1,17 @@ +// 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 ( diff --git a/pkg/compute/tasks/instance_snapshot_reset_task.go b/pkg/compute/tasks/instance_snapshot_reset_task.go index c102c6f237..74415779d5 100644 --- a/pkg/compute/tasks/instance_snapshot_reset_task.go +++ b/pkg/compute/tasks/instance_snapshot_reset_task.go @@ -1,3 +1,17 @@ +// 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 ( diff --git a/pkg/mcclient/modules/cloudnet/doc.go b/pkg/mcclient/modules/cloudnet/doc.go index 219682d62a..cb9f4e2ea0 100644 --- a/pkg/mcclient/modules/cloudnet/doc.go +++ b/pkg/mcclient/modules/cloudnet/doc.go @@ -1 +1,15 @@ +// 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 cloudnet // import "yunion.io/x/onecloud/pkg/mcclient/modules/cloudnet" diff --git a/pkg/mcclient/modules/managers.go b/pkg/mcclient/modules/managers.go index 6e5a1d0df0..0dd8677393 100644 --- a/pkg/mcclient/modules/managers.go +++ b/pkg/mcclient/modules/managers.go @@ -145,6 +145,7 @@ func NewWebsocketManager(keyword, keywordPlural string, columns, adminColumns [] Keyword: keyword, KeywordPlural: keywordPlural} } +// deprecate func NewCloudmetaManager(keyword, keywordPlural string, columns, adminColumns []string) modulebase.ResourceManager { return modulebase.ResourceManager{ BaseManager: *modulebase.NewBaseManager("cloudmeta", "", "", columns, adminColumns), diff --git a/pkg/mcclient/modules/mod_elasticcache.go b/pkg/mcclient/modules/mod_elasticcache.go new file mode 100644 index 0000000000..8626c06506 --- /dev/null +++ b/pkg/mcclient/modules/mod_elasticcache.go @@ -0,0 +1,66 @@ +// 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 modules + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modulebase" +) + +var ( + ElasticCache ElasticCacheManager + ElasticCacheAccount modulebase.ResourceManager + ElasticCacheBackup modulebase.ResourceManager + ElasticCacheAcl modulebase.ResourceManager + ElasticCacheParameter modulebase.ResourceManager +) + +type ElasticCacheManager struct { + modulebase.ResourceManager +} + +func init() { + ElasticCache = ElasticCacheManager{NewComputeManager("elasticcache", "elasticcaches", + []string{"ID", "Name", "Cloudregion_Id", "Status", "InstanceType", "CapacityMB", "Engine", "EngineVersion"}, + []string{})} + + ElasticCacheAccount = NewComputeManager("elasticcacheaccount", "elasticcacheaccounts", + []string{}, + []string{}) + + ElasticCacheBackup = NewComputeManager("elasticcachebackup", "elasticcachebackups", + []string{}, + []string{}) + + ElasticCacheAcl = NewComputeManager("elasticcacheacl", "elasticcacheacls", + []string{}, + []string{}) + + ElasticCacheParameter = NewComputeManager("elasticcacheparameter", "elasticcacheparameters", + []string{}, + []string{}) + + registerCompute(&ElasticCache) + registerCompute(&ElasticCacheAccount) + registerCompute(&ElasticCacheAcl) + registerCompute(&ElasticCacheBackup) + registerCompute(&ElasticCacheParameter) +} + +func (self *ElasticCacheManager) GetLoginInfo(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.GetSpecific(s, id, "login-info", params) +} diff --git a/pkg/mcclient/modules/mod_instance_snapshots.go b/pkg/mcclient/modules/mod_instance_snapshots.go index 0ddadab932..2ffba0efaf 100644 --- a/pkg/mcclient/modules/mod_instance_snapshots.go +++ b/pkg/mcclient/modules/mod_instance_snapshots.go @@ -1,3 +1,17 @@ +// 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 modules import "yunion.io/x/onecloud/pkg/mcclient/modulebase" diff --git a/pkg/mcclient/modules/mod_skus.go b/pkg/mcclient/modules/mod_skus.go index 746177f504..514fdfeb87 100644 --- a/pkg/mcclient/modules/mod_skus.go +++ b/pkg/mcclient/modules/mod_skus.go @@ -30,9 +30,14 @@ type ServerSkusManager struct { modulebase.ResourceManager } +type ElasticcacheSkusManager struct { + modulebase.ResourceManager +} + var ( - CloudmetaSkus SkusManager - ServerSkus ServerSkusManager + CloudmetaSkus SkusManager + ServerSkus ServerSkusManager + ElasticcacheSkus ElasticcacheSkusManager ) func init() { @@ -49,8 +54,13 @@ func init() { "Provider", "Postpaid_status", "Prepaid_status", "Region", "Region_ext_id", "Zone", "Zone_ext_id"}, []string{"Total_guest_count"})} + ElasticcacheSkus = ElasticcacheSkusManager{NewComputeManager("elasticcachesku", "elasticcacheskus", + []string{}, + []string{})} + register(&CloudmetaSkus) registerCompute(&ServerSkus) + registerCompute(&ElasticcacheSkus) } func (self *SkusManager) GetSkus(s *mcclient.ClientSession, providerId, regionId, zoneId string, limit, offset int) (*modulebase.ListResult, error) { diff --git a/pkg/mcclient/options/cloudnet/doc.go b/pkg/mcclient/options/cloudnet/doc.go index 923a95ad11..f0f2f58408 100644 --- a/pkg/mcclient/options/cloudnet/doc.go +++ b/pkg/mcclient/options/cloudnet/doc.go @@ -1 +1,15 @@ +// 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 cloudnet // import "yunion.io/x/onecloud/pkg/mcclient/options/cloudnet" diff --git a/pkg/mcclient/options/elasticcache.go b/pkg/mcclient/options/elasticcache.go new file mode 100644 index 0000000000..481039f3c4 --- /dev/null +++ b/pkg/mcclient/options/elasticcache.go @@ -0,0 +1,65 @@ +// 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 options + +type ElasticCacheCreateOptions struct { + NAME string + Manager string + Cloudregion string + Zone string + VpcId string + Network string `help:"network id"` + SecurityGroup string `help:"elastic cache security group. required by huawei."` + Engine string `choices:"redis"` + EngineVersion string `choices:"2.8|3.0|4.0|5.0"` + PrivateIP string `help:"private ip address in specificated network"` + Password string `help:"set auth password"` + InstanceType string + CapacityMB string `help:"elastic cache capacity. required by huawei."` + BillingType string `choices:"postpaid|prepaid" default:"postpaid"` + Month int `help:"billing duration (unit:month)"` +} + +type ElasticCacheAccountCreateOptions struct { + Elasticcache string `help:"elastic cache instance id"` + Name string + Password string + AccountPrivilege string `help:"account privilege" choices:"read|write|repl" default:"read"` +} + +type ElasticCacheBackupCreateOptions struct { + Elasticcache string `help:"elastic cache instance id"` + Name string +} + +type ElasticCacheAclCreateOptions struct { + Elasticcache string `help:"elastic cache instance id"` + Name string + IpList string `help:"elastic cache acl ip list, split by ','"` +} + +type ElasticCacheAclUpdateOptions struct { + Id string `help:"elastic cache acl id"` + IpList string `help:"elastic cache acl ip list, split by ','"` +} + +type ElasticCacheParameterUpdateOptions struct { + Id string `help:"elastic cache parameter id"` + Value string `help:"elastic cache parameter value"` +} + +type ElasticCacheIdOptions struct { + ID string +} diff --git a/pkg/multicloud/aliyun/elasticcache_account.go b/pkg/multicloud/aliyun/elasticcache_account.go index bba6ac4078..97ca31576f 100644 --- a/pkg/multicloud/aliyun/elasticcache_account.go +++ b/pkg/multicloud/aliyun/elasticcache_account.go @@ -17,6 +17,11 @@ package aliyun import ( "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud" ) @@ -55,11 +60,43 @@ func (self *SElasticcacheAccount) GetGlobalId() string { } func (self *SElasticcacheAccount) GetStatus() string { - return self.AccountStatus + switch self.AccountStatus { + case "Unavailable": + return api.ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE + case "Available": + return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE + default: + return self.AccountStatus + } +} + +func (self *SElasticcacheAccount) Refresh() error { + iaccount, err := self.cacheDB.GetICloudElasticcacheAccountByName(self.GetName()) + if err != nil { + return err + } + + err = jsonutils.Update(self, iaccount.(*SElasticcacheAccount)) + if err != nil { + return err + } + + return nil } func (self *SElasticcacheAccount) GetAccountType() string { - return self.AccountType + if self.AccountName == self.cacheDB.InstanceID { + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN + } + + switch self.AccountType { + case "Normal": + return api.ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL + case "Super": + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN + default: + return self.AccountType + } } func (self *SElasticcacheAccount) GetAccountPrivilege() string { @@ -67,5 +104,107 @@ func (self *SElasticcacheAccount) GetAccountPrivilege() string { return "" } - return self.DatabasePrivileges.DatabasePrivilege[0].AccountPrivilege + privilege := self.DatabasePrivileges.DatabasePrivilege[0].AccountPrivilege + switch privilege { + case "RoleReadOnly": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ + case "RoleReadWrite": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE + case "RoleRepl": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL + default: + return privilege + } +} + +// https://help.aliyun.com/document_detail/95941.html?spm=a2c4g.11186623.6.746.523555d8D8Whxq +// https://help.aliyun.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO +func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountPassword"] = input.NewPassword + + err := DoAction(self.cacheDB.region.kvsRequest, "ResetAccountPassword", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ResetPassword") + } + + if input.NoPasswordAccess != nil { + return cloudprovider.ErrNotSupported + } + + return nil +} + +func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { + if input.Password != nil { + inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} + inputPassword.NewPassword = *input.Password + inputPassword.NoPasswordAccess = input.NoPasswordAccess + err := self.ResetPassword(inputPassword) + if err != nil { + return err + } + } + + if input.Description != nil { + err := self.ModifyAccountDescription(*input.Description) + if err != nil { + return err + } + } + + if input.AccountPrivilege != nil { + err := self.GrantAccountPrivilege(*input.AccountPrivilege) + if err != nil { + return err + } + } + + return nil +} + +// https://help.aliyun.com/document_detail/96020.html?spm=a2c4g.11186623.6.747.5c6f1c717weYEX +func (self *SElasticcacheAccount) ModifyAccountDescription(desc string) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountDescription"] = desc + + err := DoAction(self.cacheDB.region.kvsRequest, "ModifyAccountDescription", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ModifyAccountDescription") + } + + return nil +} + +// https://help.aliyun.com/document_detail/95897.html?spm=a2c4g.11186623.6.745.28576cf9IqM44R +func (self *SElasticcacheAccount) GrantAccountPrivilege(privilege string) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountPrivilege"] = privilege + + err := DoAction(self.cacheDB.region.kvsRequest, "GrantAccountPrivilege", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.GrantAccountPrivilege") + } + + return nil +} + +// https://help.aliyun.com/document_detail/95988.html?spm=a2c4g.11186623.6.743.cb291c71D1Hlmu +func (self *SElasticcacheAccount) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + + err := DoAction(self.cacheDB.region.kvsRequest, "DeleteAccount", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.Delete") + } + + return nil } diff --git a/pkg/multicloud/aliyun/elasticcache_acl.go b/pkg/multicloud/aliyun/elasticcache_acl.go index 0f2b72ad26..bc17c8d8e1 100644 --- a/pkg/multicloud/aliyun/elasticcache_acl.go +++ b/pkg/multicloud/aliyun/elasticcache_acl.go @@ -17,6 +17,10 @@ package aliyun import ( "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/multicloud" ) @@ -43,9 +47,59 @@ func (self *SElasticcacheAcl) GetGlobalId() string { } func (self *SElasticcacheAcl) GetStatus() string { - return "" + return api.ELASTIC_CACHE_ACL_STATUS_AVAILABLE +} + +func (self *SElasticcacheAcl) Refresh() error { + iacl, err := self.cacheDB.GetICloudElasticcacheAcl(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, iacl.(*SElasticcacheAcl)) + if err != nil { + return err + } + + return nil } func (self *SElasticcacheAcl) GetIpList() string { return self.SecurityIPList } + +// https://help.aliyun.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH +func (self *SElasticcacheAcl) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["ModifyMode"] = "Delete" + params["SecurityIpGroupName"] = self.GetName() + params["SecurityIps"] = self.SecurityIPList + + err := DoAction(self.cacheDB.region.kvsRequest, "ModifySecurityIps", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAcl.Delete") + } + + return nil +} + +// https://help.aliyun.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH +func (self *SElasticcacheAcl) UpdateAcl(securityIps string) error { + return self.cacheDB.region.createAcl(self.cacheDB.GetId(), self.GetName(), securityIps) +} + +func (self *SRegion) createAcl(instanceId, aclName, securityIps string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["SecurityIpGroupName"] = aclName + params["ModifyMode"] = "Cover" + params["SecurityIps"] = securityIps + + err := DoAction(self.kvsRequest, "ModifySecurityIps", params, nil, nil) + if err != nil { + return errors.Wrap(err, "region.UpdateAcl") + } + + return nil +} diff --git a/pkg/multicloud/aliyun/elasticcache_backup.go b/pkg/multicloud/aliyun/elasticcache_backup.go index e3a025af62..7081f95886 100644 --- a/pkg/multicloud/aliyun/elasticcache_backup.go +++ b/pkg/multicloud/aliyun/elasticcache_backup.go @@ -18,9 +18,15 @@ import ( "fmt" "time" + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud" ) +// https://help.aliyun.com/document_detail/61081.html?spm=a2c4g.11186623.6.752.3d7630beuL57kI type SElasticcacheBackup struct { multicloud.SElasticcacheBackupBase @@ -54,7 +60,28 @@ func (self *SElasticcacheBackup) GetGlobalId() string { } func (self *SElasticcacheBackup) GetStatus() string { - return "" + switch self.BackupStatus { + case "Success", "running": + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + case "Failed": + return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED + default: + return self.BackupStatus + } +} + +func (self *SElasticcacheBackup) Refresh() error { + ibackup, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, ibackup.(*SElasticcacheBackup)) + if err != nil { + return err + } + + return nil } func (self *SElasticcacheBackup) GetBackupSizeMb() int { @@ -62,11 +89,25 @@ func (self *SElasticcacheBackup) GetBackupSizeMb() int { } func (self *SElasticcacheBackup) GetBackupType() string { - return self.BackupType + switch self.BackupType { + case "FullBackup": + return api.ELASTIC_CACHE_BACKUP_TYPE_FULL + case "IncrementalBackup": + return api.ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL + default: + return self.BackupType + } } func (self *SElasticcacheBackup) GetBackupMode() string { - return self.BackupMode + switch self.BackupMode { + case "Automated": + return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED + case "Manual": + return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL + default: + return self.BackupMode + } } func (self *SElasticcacheBackup) GetDownloadURL() string { @@ -80,3 +121,22 @@ func (self *SElasticcacheBackup) GetStartTime() time.Time { func (self *SElasticcacheBackup) GetEndTime() time.Time { return self.BackupEndTime } + +func (self *SElasticcacheBackup) Delete() error { + return cloudprovider.ErrNotSupported +} + +// https://help.aliyun.com/document_detail/61083.html?spm=a2c4g.11186623.6.753.216f67ddzpyvTL +func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["BackupId"] = self.GetId() + + // 目前没有查询备份ID的接口,因此,备份ID没什么用 + err := DoAction(self.cacheDB.region.kvsRequest, "RestoreInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.RestoreInstance") + } + + return nil +} diff --git a/pkg/multicloud/aliyun/elasticcache_instance.go b/pkg/multicloud/aliyun/elasticcache_instance.go index 69e93340e6..5e8e79e964 100644 --- a/pkg/multicloud/aliyun/elasticcache_instance.go +++ b/pkg/multicloud/aliyun/elasticcache_instance.go @@ -15,14 +15,18 @@ package aliyun import ( + "fmt" "strconv" + "strings" "time" + "github.com/aokoli/goutils" "github.com/pkg/errors" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud" @@ -132,8 +136,54 @@ func (self *SElasticcache) GetGlobalId() string { } func (self *SElasticcache) GetStatus() string { - // todo: fix - return self.InstanceStatus + switch self.InstanceStatus { + case "Normal": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "Creating": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "Changing": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "Inactive": + return api.ELASTIC_CACHE_STATUS_INACTIVE + case "Flushing": + return api.ELASTIC_CACHE_STATUS_FLUSHING + case "Released": + return api.ELASTIC_CACHE_STATUS_RELEASED + case "Transforming": + return api.ELASTIC_CACHE_STATUS_TRANSFORMING + case "Unavailable": + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case "Error": + return api.ELASTIC_CACHE_STATUS_ERROR + case "Migrating": + return api.ELASTIC_CACHE_STATUS_MIGRATING + case "BackupRecovering": + return api.ELASTIC_CACHE_STATUS_BACKUPRECOVERING + case "MinorVersionUpgrading": + return api.ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING + case "NetworkModifying": + return api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING + case "SSLModifying": + return api.ELASTIC_CACHE_STATUS_SSLMODIFYING + case "MajorVersionUpgrading": + return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING + default: + return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING + } +} + +func (self *SElasticcache) Refresh() error { + cache, err := self.region.GetElasticCacheById(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, cache) + if err != nil { + return err + } + + return nil } func (self *SElasticcache) GetBillingType() string { @@ -157,7 +207,20 @@ func (self *SElasticcache) GetCapacityMB() int { } func (self *SElasticcache) GetArchType() string { - return self.ArchitectureType + switch self.ArchitectureType { + case "rwsplit": + return "rwsplit" + case "cluster": + return "cluster" + case "standard": + if self.NodeType == "single" { + return "single" + } else if self.NodeType == "double" { + return "master" + } + } + + return "" } func (self *SElasticcache) GetNodeType() string { @@ -294,6 +357,16 @@ func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.IClo return iaccounts, nil } +func (self *SElasticcache) GetICloudElasticcacheAccountByName(accountName string) (cloudprovider.ICloudElasticcacheAccount, error) { + account, err := self.region.GetElasticCacheAccountByName(self.GetId(), accountName) + if err != nil { + return nil, err + } + + account.cacheDB = self + return account, nil +} + func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { acls, err := self.region.GetElasticCacheAcls(self.GetId()) if err != nil { @@ -357,13 +430,11 @@ func (self *SElasticcache) GetAttribute() (*SElasticcacheAttribute, error) { } count := len(rets) - if count == 1 { + if count >= 1 { self.attribute = &rets[0] return self.attribute, nil - } else if count == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "elasticcache.GetAttribute %s", self.GetId()) } else { - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "elasticcache.GetAttribute %s.expect 1 found %d ", self.GetId(), count) + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "elasticcache.GetAttribute %s", self.GetId()) } } @@ -393,7 +464,7 @@ func (self *SElasticcache) GetPublicNetInfo() (*SNetInfo, error) { } for i := range nets { - if nets[i].DBInstanceNetType == "2" || nets[i].IPType == "Public" { + if nets[i].DBInstanceNetType == "2" && nets[i].IPType == "Public" { return &nets[i], nil } } @@ -405,7 +476,7 @@ func (self *SRegion) GetElasticCaches(instanceIds []string) ([]SElasticcache, er params := make(map[string]string) params["RegionId"] = self.RegionId if instanceIds != nil && len(instanceIds) > 0 { - params["InstanceIds"] = jsonutils.Marshal(instanceIds).String() + params["InstanceIds"] = strings.Join(instanceIds, ",") } ret := []SElasticcache{} @@ -430,12 +501,21 @@ func (self *SRegion) GetElasticCacheById(instanceId string) (*SElasticcache, err if len(caches) == 1 { return &caches[0], nil } else if len(caches) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "region.GetElasticCacheById %s", instanceId) + return nil, cloudprovider.ErrNotFound } else { return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "region.GetElasticCacheById %s.expect 1 found %d ", instanceId, len(caches)) } } +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + ec, err := self.GetElasticCacheById(id) + if err != nil { + return nil, err + } + + return ec, nil +} + // https://help.aliyun.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.143e782f3Pfkfg func (self *SRegion) GetElasticCacheAccounts(instanceId string) ([]SElasticcacheAccount, error) { params := make(map[string]string) @@ -451,6 +531,27 @@ func (self *SRegion) GetElasticCacheAccounts(instanceId string) ([]SElasticcache return ret, nil } +func (self *SRegion) GetElasticCacheAccountByName(instanceId string, accountName string) (*SElasticcacheAccount, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["AccountName"] = accountName + + ret := []SElasticcacheAccount{} + err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") + } + + if len(ret) == 1 { + return &ret[0], nil + } else if len(ret) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, errors.Wrap(fmt.Errorf("%d account with name %s found", len(ret), accountName), "region.GetElasticCacheAccountByName") + } +} + // https://help.aliyun.com/document_detail/63889.html?spm=a2c4g.11186623.6.764.3cb43852R7lnoS func (self *SRegion) GetElasticCacheAcls(instanceId string) ([]SElasticcacheAcl, error) { params := make(map[string]string) @@ -497,3 +598,310 @@ func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcac return ret, nil } + +// https://help.aliyun.com/document_detail/60873.html?spm=a2c4g.11174283.6.715.7412dce0qSYemb +func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceClass"] = ec.InstanceType + params["InstanceName"] = ec.InstanceName + params["InstanceType"] = ec.Engine + params["EngineVersion"] = ec.EngineVersion + + if len(ec.Password) > 0 { + params["UserName"] = ec.UserName + params["Password"] = ec.Password + } + + if len(ec.ZoneIds) > 0 { + params["ZoneId"] = ec.ZoneIds[0] + } + + if len(ec.PrivateIpAddress) > 0 { + params["PrivateIpAddress"] = ec.PrivateIpAddress + } + + if len(ec.NodeType) > 0 { + params["NodeType"] = ec.NodeType + } + + params["NetworkType"] = ec.NetworkType + params["VpcId"] = ec.VpcId + params["VSwitchId"] = ec.NetworkId + params["ChargeType"] = ec.ChargeType + if ec.ChargeType == billing.BILLING_TYPE_PREPAID && ec.BC != nil { + if ec.BC.GetMonths() >= 1 && ec.BC.GetMonths() <= 9 { + params["Period"] = strconv.Itoa(ec.BC.GetMonths()) + } else if ec.BC.GetMonths() == 12 || ec.BC.GetMonths() == 24 || ec.BC.GetMonths() == 36 { + params["Period"] = strconv.Itoa(ec.BC.GetMonths()) + } else { + return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") + } + } + + ret := &SElasticcache{} + err := DoAction(self.kvsRequest, "CreateInstance", params, []string{}, ret) + if err != nil { + return nil, errors.Wrap(err, "region.CreateIElasticcaches") + } + + ret.region = self + return ret, nil +} + +// https://help.aliyun.com/document_detail/116215.html?spm=a2c4g.11174283.6.736.6b9ddce0c5nsw6 +func (self *SElasticcache) Restart() error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["EffectiveTime"] = "0" // 立即重启 + + err := DoAction(self.region.kvsRequest, "RestartInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Restart") + } + + return nil +} + +// https://help.aliyun.com/document_detail/60898.html?spm=a2c4g.11186623.6.713.56ec1603KS0xA0 +func (self *SElasticcache) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + err := DoAction(self.region.kvsRequest, "DeleteInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Delete") + } + + return nil +} + +// https://help.aliyun.com/document_detail/60903.html?spm=a2c4g.11186623.6.711.3f062c92aRJNfw +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["InstanceClass"] = strings.Split(spec, ":")[0] + params["AutoPay"] = "true" // 自动付款 + + err := DoAction(self.region.kvsRequest, "ModifyInstanceSpec", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") + } + + return nil +} + +// https://help.aliyun.com/document_detail/61000.html?spm=a2c4g.11186623.6.730.57d66cb0QlQS86 +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["MaintainStartTime"] = maintainStartTime + params["MaintainEndTime"] = maintainEndTime + + err := DoAction(self.region.kvsRequest, "ModifyInstanceMaintainTime", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.SetMaintainTime") + } + + return nil +} + +// https://help.aliyun.com/document_detail/125795.html?spm=a2c4g.11186623.6.719.51542b3593cDKO +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + if port < 1024 { + port = 6379 + } + + suffix, _ := goutils.RandomAlphabetic(4) + conn := self.GetId() + strings.ToLower(suffix) + + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["Port"] = strconv.Itoa(port) + params["ConnectionStringPrefix"] = conn + + err := DoAction(self.region.kvsRequest, "AllocateInstancePublicConnection", params, nil, nil) + if err != nil { + return "", errors.Wrap(err, "elasticcache.AllocatePublicConnection") + } + + return conn, nil +} + +// https://help.aliyun.com/document_detail/125796.html?spm=a2c4g.11186623.6.720.702a3b23Qayopy +func (self *SElasticcache) ReleasePublicConnection() error { + publicConn := self.GetPublicDNS() + if len(publicConn) == 0 { + log.Debugf("elasticcache.ReleasePublicConnection public connect is empty") + return nil + } + + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["CurrentConnectionString"] = publicConn + + err := DoAction(self.region.kvsRequest, "ReleaseInstancePublicConnection", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.ReleasePublicConnection") + } + + return nil +} + +// https://help.aliyun.com/document_detail/93603.html?spm=a2c4g.11186623.6.732.10666cf9UVgNPb 修改链接地址 + +// https://help.aliyun.com/document_detail/95973.html?spm=a2c4g.11186623.6.742.4698126aH0s4Q5 +func (self *SElasticcache) CreateAccount(input cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["AccountName"] = input.AccountName + params["AccountPassword"] = input.AccountPassword + if len(input.AccountPrivilege) > 0 { + params["AccountPrivilege"] = input.AccountPrivilege + } + + if len(input.Description) > 0 { + params["AccountDescription"] = input.Description + } + + err := DoAction(self.region.kvsRequest, "CreateAccount", params, nil, nil) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.CreateAccount") + } + + return self.GetICloudElasticcacheAccountByName(input.AccountName) +} + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + acl := &SElasticcacheAcl{} + acl.cacheDB = self + acl.SecurityIPGroupName = aclName + acl.SecurityIPList = securityIps + return acl, self.region.createAcl(self.GetId(), aclName, securityIps) +} + +// https://help.aliyun.com/document_detail/61113.html?spm=a2c4g.11186623.6.770.16a61e7admr0xy +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["Config"] = config.String() + + err := DoAction(self.region.kvsRequest, "ModifyInstanceConfig", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://help.aliyun.com/document_detail/61075.html?spm=a2c4g.11186623.6.749.4cba126a2U9xNa +func (self *SElasticcache) CreateBackup() (cloudprovider.ICloudElasticcacheBackup, error) { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + // 目前没有查询备份ID的接口,因此,备份ID没什么用 + err := DoAction(self.region.kvsRequest, "CreateBackup", params, []string{"BackupJobID"}, nil) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.CreateBackup") + } + + return nil, nil +} + +// https://help.aliyun.com/document_detail/61077.html?spm=a2c4g.11186623.6.750.3d7630be7ziUfg +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["PreferredBackupPeriod"] = config.PreferredBackupPeriod + params["PreferredBackupTime"] = config.PreferredBackupTime + + err := DoAction(self.region.kvsRequest, "ModifyBackupPolicy", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateBackupPolicy") + } + + return nil +} + +// https://help.aliyun.com/document_detail/60931.html?spm=a2c4g.11186623.6.728.5c57292920UKx3 +func (self *SElasticcache) FlushInstance() error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + err := DoAction(self.region.kvsRequest, "FlushInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + return nil +} + +// https://help.aliyun.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO +func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + if noPwdAccess { + params["VpcAuthMode"] = "Close" + } else { + params["VpcAuthMode"] = "Open" + } + + err := DoAction(self.region.kvsRequest, "ModifyInstanceVpcAuthMode", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.UpdateAuthMode") + } + + return nil +} + +func (self *SElasticcache) GetAuthMode() string { + attribute, err := self.GetAttribute() + if err != nil { + log.Errorf("elasticcache.GetAuthMode %s", err) + } + switch attribute.VpcAuthMode { + case "Open": + return "on" + default: + return "off" + } +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + segs := strings.Split(accountId, "/") + if len(segs) < 2 { + return nil, errors.Wrap(fmt.Errorf("%s", accountId), "elasticcache.GetICloudElasticcacheAccount invalid account id ") + } + + return self.GetICloudElasticcacheAccountByName(segs[1]) +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + acls, err := self.GetICloudElasticcacheAcls() + if err != nil { + return nil, err + } + + for _, acl := range acls { + if acl.GetId() == aclId { + return acl, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.GetICloudElasticcacheBackups() + if err != nil { + return nil, err + } + + for _, backup := range backups { + if backup.GetId() == backupId { + return backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/aliyun/elasticcache_parameter.go b/pkg/multicloud/aliyun/elasticcache_parameter.go index 606095d0aa..c52e41fccc 100644 --- a/pkg/multicloud/aliyun/elasticcache_parameter.go +++ b/pkg/multicloud/aliyun/elasticcache_parameter.go @@ -17,6 +17,7 @@ package aliyun import ( "fmt" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/multicloud" ) @@ -46,7 +47,7 @@ func (self *SElasticcacheParameter) GetGlobalId() string { } func (self *SElasticcacheParameter) GetStatus() string { - return "" + return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE } func (self *SElasticcacheParameter) GetParameterKey() string { diff --git a/pkg/multicloud/aliyun/provider/provider.go b/pkg/multicloud/aliyun/provider/provider.go index 5dc26e076c..b6457a414f 100644 --- a/pkg/multicloud/aliyun/provider/provider.go +++ b/pkg/multicloud/aliyun/provider/provider.go @@ -68,7 +68,7 @@ func (self *SAliyunProviderFactory) ValidateUpdateCloudaccountCredential(ctx con } func (self *SAliyunProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) { - client, err := aliyun.NewAliyunClient(providerId, providerName, account, secret, false) + client, err := aliyun.NewAliyunClient(providerId, providerName, account, secret, true) if err != nil { return nil, err } diff --git a/pkg/multicloud/dbinstance_account_base.go b/pkg/multicloud/dbinstance_account_base.go index 413489bfc9..3720568fbc 100644 --- a/pkg/multicloud/dbinstance_account_base.go +++ b/pkg/multicloud/dbinstance_account_base.go @@ -1,3 +1,17 @@ +// 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. + // Copyright 2019 Yunion // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/multicloud/huawei/client/client.go b/pkg/multicloud/huawei/client/client.go index 3af61d3069..315cf7947e 100644 --- a/pkg/multicloud/huawei/client/client.go +++ b/pkg/multicloud/huawei/client/client.go @@ -37,6 +37,7 @@ type Client struct { Domains *modules.SDomainManager Eips *modules.SEipManager Elasticcache *modules.SElasticcacheManager + DcsAvailableZone *modules.SDcsAvailableZoneManager Flavors *modules.SFlavorManager Images *modules.SImageManager OpenStackImages *modules.SImageManager @@ -124,6 +125,7 @@ func (self *Client) initManagers() { self.Vpcs = modules.NewVpcManager(self.regionId, self.projectId, self.signer, self.debug) self.Eips = modules.NewEipManager(self.regionId, self.projectId, self.signer, self.debug) self.Elasticcache = modules.NewElasticcacheManager(self.regionId, self.projectId, self.signer, self.debug) + self.DcsAvailableZone = modules.NewDcsAvailableZoneManager(self.regionId, self.signer, self.debug) self.Disks = modules.NewDiskManager(self.regionId, self.projectId, self.signer, self.debug) self.Domains = modules.NewDomainManager(self.signer, self.debug) self.Keypairs = modules.NewKeypairManager(self.regionId, self.projectId, self.signer, self.debug) diff --git a/pkg/multicloud/huawei/client/modules/mod_elasticcache.go b/pkg/multicloud/huawei/client/modules/mod_elasticcache.go index a0f02adac4..f91a5c5996 100644 --- a/pkg/multicloud/huawei/client/modules/mod_elasticcache.go +++ b/pkg/multicloud/huawei/client/modules/mod_elasticcache.go @@ -17,6 +17,8 @@ package modules import ( "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth" "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" ) @@ -25,6 +27,10 @@ type SElasticcacheManager struct { SResourceManager } +type SDcsAvailableZoneManager struct { + SResourceManager +} + func NewElasticcacheManager(regionId string, projectId string, signer auth.Signer, debug bool) *SElasticcacheManager { return &SElasticcacheManager{SResourceManager: SResourceManager{ SBaseManager: NewBaseManager(signer, debug), @@ -64,3 +70,48 @@ func (self *SElasticcacheManager) ListParameters(queries map[string]string) (*re delete(queries, "instance_id") return self.ListInContextWithSpec(nil, spec, queries, "redis_config") } + +func (self *SElasticcacheManager) Restart(instanceId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") + params.Add(jsonutils.NewString("restart"), "action") + return self.UpdateInContextWithSpec(nil, "", "status", params, "") +} + +// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 +func (self *SElasticcacheManager) Flush(instanceId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") + params.Add(jsonutils.NewString("flush"), "action") + return self.UpdateInContextWithSpec(nil, "", "status", params, "") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html +func (self *SElasticcacheManager) RestoreInstance(instanceId string, backupId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(backupId)), "backup_id") + + return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/restores", instanceId), params, "") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html +func (self *SElasticcacheManager) ChangeInstanceSpec(instanceId string, newCapacity string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Set("new_capacity", jsonutils.NewString(newCapacity)) + + return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/extend", instanceId), params, "") +} + +func NewDcsAvailableZoneManager(regionId string, signer auth.Signer, debug bool) *SDcsAvailableZoneManager { + return &SDcsAvailableZoneManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(signer, debug), + ServiceName: ServiceNameDCS, + Region: regionId, + ProjectId: "", + version: "v1.0", + Keyword: "available_zone", + KeywordPlural: "available_zones", + + ResourceKeyword: "availableZones", + }} +} diff --git a/pkg/multicloud/huawei/elasticcache_account.go b/pkg/multicloud/huawei/elasticcache_account.go index fd787ec85e..aeebb9b45a 100644 --- a/pkg/multicloud/huawei/elasticcache_account.go +++ b/pkg/multicloud/huawei/elasticcache_account.go @@ -17,6 +17,11 @@ package huawei import ( "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud" ) @@ -39,13 +44,67 @@ func (self *SElasticcacheAccount) GetGlobalId() string { } func (self *SElasticcacheAccount) GetStatus() string { - return "" + return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE } func (self *SElasticcacheAccount) GetAccountType() string { - return "admin" + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN } func (self *SElasticcacheAccount) GetAccountPrivilege() string { - return "write" + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html +// 未找到关闭密码的开放api +// https://console.huaweicloud.com/dcs/rest/v2/41f6bfe48d7f4455b7754f7c1b11ae34/instances/26db46e2-c7d8-4b5e-bd36-b5278d2fe17c/password/reset +// new_password: "26db46e2!" +// no_password_access: false +func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { + if input.NoPasswordAccess != nil { + params := jsonutils.NewDict() + if *input.NoPasswordAccess == true { + params.Set("no_password_access", jsonutils.JSONTrue) + } else { + params.Set("no_password_access", jsonutils.JSONFalse) + } + + params.Set("new_password", jsonutils.JSONNull) + err := DoUpdateWithSpec(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "password/reset", params) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.NoPasswordAccess") + } + + return nil + } + + if input.OldPassword == nil { + return fmt.Errorf("elasticcacheAccount.ResetPassword.input OldPassword should not be empty") + } + + params := jsonutils.NewDict() + params.Set("old_password", jsonutils.NewString(*input.OldPassword)) + params.Set("new_password", jsonutils.NewString(input.NewPassword)) + err := DoUpdateWithSpec(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "password", params) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ResetPassword") + } + + return nil +} + +func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { + if input.Password != nil { + inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} + inputPassword.NewPassword = *input.Password + inputPassword.OldPassword = input.OldPassword + inputPassword.NoPasswordAccess = input.NoPasswordAccess + return self.ResetPassword(inputPassword) + } + + return nil +} + +func (self *SElasticcacheAccount) Delete() error { + return cloudprovider.ErrNotSupported } diff --git a/pkg/multicloud/huawei/elasticcache_backup.go b/pkg/multicloud/huawei/elasticcache_backup.go index e59712753a..acc59589c3 100644 --- a/pkg/multicloud/huawei/elasticcache_backup.go +++ b/pkg/multicloud/huawei/elasticcache_backup.go @@ -17,6 +17,8 @@ package huawei import ( "time" + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/multicloud" ) @@ -55,7 +57,20 @@ func (self *SElasticcacheBackup) GetGlobalId() string { } func (self *SElasticcacheBackup) GetStatus() string { - return self.Status + switch self.Status { + case "waiting", "backuping": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING + case "succeed": + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + case "failed": + return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED + case "expired": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED + case "deleted": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED + default: + return self.Status + } } func (self *SElasticcacheBackup) GetBackupSizeMb() int { @@ -63,7 +78,15 @@ func (self *SElasticcacheBackup) GetBackupSizeMb() int { } func (self *SElasticcacheBackup) GetBackupType() string { - return self.BackupType + switch self.BackupType { + case "manual": + return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL + case "auto": + return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED + default: + return self.BackupType + } + } func (self *SElasticcacheBackup) GetBackupMode() string { @@ -81,3 +104,17 @@ func (self *SElasticcacheBackup) GetStartTime() time.Time { func (self *SElasticcacheBackup) GetEndTime() time.Time { return self.UpdatedAt } + +func (self *SElasticcacheBackup) Delete() error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html +func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { + _, err := self.cacheDB.region.ecsClient.Elasticcache.RestoreInstance(instanceId, self.GetId()) + if err != nil { + return nil + } + + return nil +} diff --git a/pkg/multicloud/huawei/elasticcache_instance.go b/pkg/multicloud/huawei/elasticcache_instance.go index fafbde5a62..0280e9b91b 100644 --- a/pkg/multicloud/huawei/elasticcache_instance.go +++ b/pkg/multicloud/huawei/elasticcache_instance.go @@ -15,10 +15,13 @@ package huawei import ( + "fmt" + "strings" "time" "github.com/pkg/errors" + "yunion.io/x/jsonutils" "yunion.io/x/log" billing_api "yunion.io/x/onecloud/pkg/apis/billing" @@ -96,7 +99,28 @@ func (self *SElasticcache) GetGlobalId() string { } func (self *SElasticcache) GetStatus() string { - return self.Status + switch self.Status { + case "RUNNING": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "CREATING": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "CREATEFAILED": + return api.ELASTIC_CACHE_STATUS_CREATE_FAILED + case "ERROR": + return api.ELASTIC_CACHE_STATUS_ERROR + case "RESTARTING": + return api.ELASTIC_CACHE_STATUS_RESTARTING + case "FROZEN": + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case "EXTENDING": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "RESTORING": + return api.ELASTIC_CACHE_STATUS_TRANSFORMING // ? + case "FLUSHING": + return api.ELASTIC_CACHE_STATUS_FLUSHING + } + + return "" } func (self *SElasticcache) GetBillingType() string { @@ -148,6 +172,15 @@ func (self *SElasticcache) GetArchType() string { dcs.master_standby:表示实例类型为主备 dcs.cluster:表示实例类型为集群 */ + if strings.Contains(self.ResourceSpecCode, "single") { + return "single" + } else if strings.Contains(self.ResourceSpecCode, "ha") { + return "master" + } else if strings.Contains(self.ResourceSpecCode, "cluster") { + return "cluster" + } else if strings.Contains(self.ResourceSpecCode, "proxy") { + return "cluster" + } return "" } @@ -333,3 +366,330 @@ func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) cache.region = self return &cache, nil } + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + ec, err := self.GetElasticCache(id) + if err != nil { + return nil, errors.Wrap(err, "region.GetIElasticCacheById.GetElasticCache") + } + + return ec, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html +func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { + type Z struct { + ID string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Port string `json:"port"` + ResourceAvailability string `json:"resource_availability"` + } + + rs := []Z{} + err := doListAll(self.ecsClient.DcsAvailableZone.List, nil, &rs) + if err != nil { + return nil, errors.Wrap(err, "region.zoneNameToDcsZoneIds") + } + + zoneMap := map[string]string{} + for i := range rs { + if rs[i].ResourceAvailability == "true" { + zoneMap[rs[i].Code] = rs[i].ID + } + } + + ret := []string{} + for _, zone := range zoneIds { + if id, ok := zoneMap[zone]; ok { + ret = append(ret, id) + } else { + return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") + } + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html +func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := jsonutils.NewDict() + params.Set("name", jsonutils.NewString(ec.InstanceName)) + params.Set("engine", jsonutils.NewString(ec.Engine)) + params.Set("engine_version", jsonutils.NewString(ec.EngineVersion)) + params.Set("capacity", jsonutils.NewInt(ec.CapacityGB)) + params.Set("vpc_id", jsonutils.NewString(ec.VpcId)) + params.Set("security_group_id", jsonutils.NewString(ec.SecurityGroupId)) + params.Set("subnet_id", jsonutils.NewString(ec.NetworkId)) + params.Set("product_id", jsonutils.NewString(ec.InstanceType)) + zones, err := self.zoneNameToDcsZoneIds(ec.ZoneIds) + if err != nil { + return nil, err + } + params.Set("available_zones", jsonutils.NewStringArray(zones)) + + if len(ec.Password) > 0 { + params.Set("no_password_access", jsonutils.NewString("false")) + params.Set("password", jsonutils.NewString(ec.Password)) + + // todo: 这里换成常量 + if ec.Engine == "Memcache" { + params.Set("access_user", jsonutils.NewString(ec.UserName)) + } + } else { + params.Set("no_password_access", jsonutils.NewString("true")) + } + + if len(ec.EipId) > 0 { + params.Set("enable_publicip", jsonutils.NewString("true")) + params.Set("publicip_id", jsonutils.NewString(ec.EipId)) + // enable_ssl + } else { + params.Set("enable_publicip", jsonutils.NewString("false")) + } + + if len(ec.PrivateIpAddress) > 0 { + params.Set("private_ip", jsonutils.NewString(ec.PrivateIpAddress)) + } + + if len(ec.MaintainBegin) > 0 { + params.Set("maintain_begin", jsonutils.NewString(ec.MaintainBegin)) + params.Set("maintain_end", jsonutils.NewString(ec.MaintainEnd)) + } + + if ec.ChargeType == billing_api.BILLING_TYPE_PREPAID && ec.BC != nil { + bssParam := jsonutils.NewDict() + bssParam.Set("charging_mode", jsonutils.NewString("prePaid")) + bssParam.Set("is_auto_pay", jsonutils.NewString("true")) + bssParam.Set("is_auto_renew", jsonutils.NewString("false")) + if ec.BC.GetMonths() >= 1 && ec.BC.GetMonths() >= 9 { + bssParam.Set("period_type", jsonutils.NewString("month")) + bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BC.GetMonths()))) + } else if ec.BC.GetYears() >= 1 && ec.BC.GetYears() <= 3 { + bssParam.Set("period_type", jsonutils.NewString("year")) + bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BC.GetYears()))) + } else { + return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") + } + + params.Set("bss_param", bssParam) + } + + ret := &SElasticcache{} + err = DoCreate(self.ecsClient.Elasticcache.Create, params, ret) + if err != nil { + return nil, errors.Wrap(err, "region.CreateIElasticcaches") + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html +func (self *SElasticcache) Restart() error { + resp, err := self.region.ecsClient.Elasticcache.Restart(self.GetId()) + if err != nil { + return errors.Wrap(err, "elasticcache.Restart") + } + + rets, err := resp.GetArray("results") + if err != nil { + return errors.Wrap(err, "elasticcache.results") + } + + for _, r := range rets { + if ret, _ := r.GetString("result"); ret != "success" { + return fmt.Errorf("elasticcache.Restart failed") + } + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423022.html +func (self *SElasticcache) Delete() error { + err := DoDelete(self.region.ecsClient.Elasticcache.Delete, self.GetId(), nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Delete") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + segs := strings.Split(spec, ":") + if len(segs) < 2 { + return fmt.Errorf("elasticcache.ChangeInstanceSpec invalid sku %s", spec) + } + + if !strings.HasPrefix(segs[1], "m") || !strings.HasSuffix(segs[1], "g") { + return fmt.Errorf("elasticcache.ChangeInstanceSpec sku %s memeory size is invalid.", spec) + } + + newCapacity := segs[1][1 : len(segs[1])-1] + _, err := self.region.ecsClient.Elasticcache.ChangeInstanceSpec(self.GetId(), newCapacity) + if err != nil { + return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + params := jsonutils.NewDict() + params.Set("maintain_begin", jsonutils.NewString(maintainStartTime)) + params.Set("maintain_end", jsonutils.NewString(maintainEndTime)) + err := DoUpdate(self.region.ecsClient.Elasticcache.Update, self.GetId(), params, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.SetMaintainTime") + } + + return nil +} + +// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html +// 目前只有Redis3.0版本密码模式的实例支持通过公网访问Redis实例,其他版本暂不支持公网访问。 +// todo: 目前没找到api +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +// todo: 目前没找到api +func (self *SElasticcache) ReleasePublicConnection() error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + params := jsonutils.NewDict() + params.Set("redis_config", config) + err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html +func (self *SElasticcache) CreateBackup() (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) *jsonutils.JSONArray { + segs := strings.Split(config.PreferredBackupPeriod, ",") + ret := jsonutils.NewArray() + for _, seg := range segs { + switch seg { + case "Monday": + ret.Add(jsonutils.NewString("1")) + case "Tuesday": + ret.Add(jsonutils.NewString("2")) + case "Wednesday": + ret.Add(jsonutils.NewString("3")) + case "Thursday": + ret.Add(jsonutils.NewString("4")) + case "Friday": + ret.Add(jsonutils.NewString("5")) + case "Saturday": + ret.Add(jsonutils.NewString("6")) + case "Sunday": + ret.Add(jsonutils.NewString("7")) + } + } + + return ret +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + params := jsonutils.NewDict() + policy := jsonutils.NewDict() + policy.Set("save_days", jsonutils.NewInt(int64(config.BackupReservedDays))) + policy.Set("backup_type", jsonutils.NewString(config.BackupType)) + plan := jsonutils.NewDict() + backTime := strings.ReplaceAll(config.PreferredBackupTime, "Z", "") + backupPeriod := backupPeriodTrans(config) + plan.Set("begin_at", jsonutils.NewString(backTime)) + plan.Set("period_type", jsonutils.NewString("weekly")) + plan.Set("backup_at", backupPeriod) + policy.Set("periodical_backup_plan", plan) + params.Set("instance_backup_policy", policy) + err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html +// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 +func (self *SElasticcache) FlushInstance() error { + resp, err := self.region.ecsClient.Elasticcache.Flush(self.GetId()) + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + rets, err := resp.GetArray("results") + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + for _, r := range rets { + if ret, _ := r.GetString("result"); ret != "success" { + return fmt.Errorf("elasticcache.FlushInstance failed") + } + } + + return nil +} + +// SElasticcacheAccount => ResetPassword +func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetAuthMode() string { + switch self.NoPasswordAccess { + case "true": + return "on" + default: + return "off" + } +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.GetICloudElasticcacheBackups() + if err != nil { + return nil, err + } + + for _, backup := range backups { + if backup.GetId() == backupId { + return backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/huawei/elasticcache_parameter.go b/pkg/multicloud/huawei/elasticcache_parameter.go index c84242eee2..8141679703 100644 --- a/pkg/multicloud/huawei/elasticcache_parameter.go +++ b/pkg/multicloud/huawei/elasticcache_parameter.go @@ -17,6 +17,7 @@ package huawei import ( "fmt" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/multicloud" ) @@ -48,7 +49,7 @@ func (self *SElasticcacheParameter) GetGlobalId() string { } func (self *SElasticcacheParameter) GetStatus() string { - return "" + return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE } func (self *SElasticcacheParameter) GetParameterKey() string { diff --git a/pkg/multicloud/region_base.go b/pkg/multicloud/region_base.go index 9257c26000..ca560e1d6d 100644 --- a/pkg/multicloud/region_base.go +++ b/pkg/multicloud/region_base.go @@ -85,3 +85,11 @@ func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, er func (self *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { return nil, fmt.Errorf("Not Implemented CreateIDBInstance") } + +func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + return nil, fmt.Errorf("Not Implemented CreateIElasticcaches") +} + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + return nil, fmt.Errorf("Not Implemented GetIElasticcacheById") +} diff --git a/pkg/util/ansiblev2/doc.go b/pkg/util/ansiblev2/doc.go index 625647ec10..bbb6c74647 100644 --- a/pkg/util/ansiblev2/doc.go +++ b/pkg/util/ansiblev2/doc.go @@ -1 +1,15 @@ +// 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 ansiblev2 // import "yunion.io/x/onecloud/pkg/util/ansiblev2" diff --git a/pkg/util/ansiblev2/inventory.go b/pkg/util/ansiblev2/inventory.go index 7808369228..4813bd1663 100644 --- a/pkg/util/ansiblev2/inventory.go +++ b/pkg/util/ansiblev2/inventory.go @@ -1,3 +1,17 @@ +// 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 ansiblev2 import ( diff --git a/pkg/util/ansiblev2/inventory_test.go b/pkg/util/ansiblev2/inventory_test.go index f99b92ec26..33b04b5a32 100644 --- a/pkg/util/ansiblev2/inventory_test.go +++ b/pkg/util/ansiblev2/inventory_test.go @@ -1,3 +1,17 @@ +// 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 ansiblev2 import ( diff --git a/pkg/util/ansiblev2/playbook.go b/pkg/util/ansiblev2/playbook.go index 3998f730db..8bbfea1db6 100644 --- a/pkg/util/ansiblev2/playbook.go +++ b/pkg/util/ansiblev2/playbook.go @@ -1,3 +1,17 @@ +// 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 ansiblev2 import ( diff --git a/pkg/util/ansiblev2/playbook_test.go b/pkg/util/ansiblev2/playbook_test.go index abea848315..87c184b66f 100644 --- a/pkg/util/ansiblev2/playbook_test.go +++ b/pkg/util/ansiblev2/playbook_test.go @@ -1,3 +1,17 @@ +// 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 ansiblev2 import ( diff --git a/pkg/util/ansiblev2/session.go b/pkg/util/ansiblev2/session.go index 1cd7575185..b4f494536f 100644 --- a/pkg/util/ansiblev2/session.go +++ b/pkg/util/ansiblev2/session.go @@ -1,3 +1,17 @@ +// 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 ansiblev2 import ( diff --git a/pkg/util/firewalld/direct.go b/pkg/util/firewalld/direct.go index b10f8746f8..9f530bdb33 100644 --- a/pkg/util/firewalld/direct.go +++ b/pkg/util/firewalld/direct.go @@ -1,3 +1,17 @@ +// 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 firewalld import ( diff --git a/pkg/util/firewalld/direct_test.go b/pkg/util/firewalld/direct_test.go index 704c748d1c..e06cfb0c28 100644 --- a/pkg/util/firewalld/direct_test.go +++ b/pkg/util/firewalld/direct_test.go @@ -1,3 +1,17 @@ +// 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 firewalld import ( diff --git a/pkg/util/firewalld/doc.go b/pkg/util/firewalld/doc.go index b0f5293754..fba9547b00 100644 --- a/pkg/util/firewalld/doc.go +++ b/pkg/util/firewalld/doc.go @@ -1 +1,15 @@ +// 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 firewalld // import "yunion.io/x/onecloud/pkg/util/firewalld" diff --git a/pkg/util/httputils/fs.go b/pkg/util/httputils/fs.go index c30af94b5b..ca6445d95a 100644 --- a/pkg/util/httputils/fs.go +++ b/pkg/util/httputils/fs.go @@ -1,3 +1,17 @@ +// 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 httputils import ( diff --git a/pkg/util/redfish/loader/loader.go b/pkg/util/redfish/loader/loader.go index f33d0b1e03..74815c8b92 100644 --- a/pkg/util/redfish/loader/loader.go +++ b/pkg/util/redfish/loader/loader.go @@ -16,7 +16,8 @@ package loader import ( "yunion.io/x/log" - _ "yunion.io/x/onecloud/pkg/util/redfish/generic" // _ "yunion.io/x/onecloud/pkg/util/redfish/hprest" + + _ "yunion.io/x/onecloud/pkg/util/redfish/generic" _ "yunion.io/x/onecloud/pkg/util/redfish/idrac" _ "yunion.io/x/onecloud/pkg/util/redfish/ilo" ) diff --git a/pkg/util/seclib2/seclib.go b/pkg/util/seclib2/seclib.go index 84ecdbd832..2ccedadfc5 100644 --- a/pkg/util/seclib2/seclib.go +++ b/pkg/util/seclib2/seclib.go @@ -25,7 +25,7 @@ const ( DIGITS = "23456789" LETTERS = "abcdefghjkmnpqrstuvwxyz" UPPERS = "ABCDEFGHJKMNPRSTUVWXYZ" - PUNC = "!@#%^*-_=+?," + PUNC = "@%^-+=" ALL_DIGITS = "0123456789" ALL_LETTERS = "abcdefghijklmnopqrstuvwxyz"