huawei.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package regiondrivers
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "yunion.io/x/cloudmux/pkg/cloudprovider"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/billing"
  23. "yunion.io/x/pkg/utils"
  24. "yunion.io/x/sqlchemy"
  25. api "yunion.io/x/onecloud/pkg/apis/compute"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  29. "yunion.io/x/onecloud/pkg/compute/models"
  30. "yunion.io/x/onecloud/pkg/httperrors"
  31. "yunion.io/x/onecloud/pkg/mcclient"
  32. )
  33. type SHuaWeiRegionDriver struct {
  34. SManagedVirtualizationRegionDriver
  35. }
  36. func init() {
  37. driver := SHuaWeiRegionDriver{}
  38. models.RegisterRegionDriver(&driver)
  39. }
  40. func (self *SHuaWeiRegionDriver) GetProvider() string {
  41. return api.CLOUD_PROVIDER_HUAWEI
  42. }
  43. func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input *api.LoadbalancerCreateInput) (*api.LoadbalancerCreateInput, error) {
  44. // 公网ELB需要指定EIP
  45. if input.AddressType == api.LB_ADDR_TYPE_INTERNET && len(input.EipId) == 0 {
  46. return nil, httperrors.NewMissingParameterError("eip_id")
  47. }
  48. return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerData(ctx, userCred, ownerId, input)
  49. }
  50. func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerBackendGroupData(ctx context.Context, userCred mcclient.TokenCredential, lb *models.SLoadbalancer, input *api.LoadbalancerBackendGroupCreateInput) (*api.LoadbalancerBackendGroupCreateInput, error) {
  51. return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerBackendGroupData(ctx, userCred, lb, input)
  52. }
  53. func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerBackendGroup(ctx context.Context, userCred mcclient.TokenCredential, lbbg *models.SLoadbalancerBackendGroup, task taskman.ITask) error {
  54. return task.ScheduleRun(nil)
  55. }
  56. func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential,
  57. lb *models.SLoadbalancer, lbbg *models.SLoadbalancerBackendGroup,
  58. input *api.LoadbalancerBackendCreateInput) (*api.LoadbalancerBackendCreateInput, error) {
  59. return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerBackendData(ctx, userCred, lb, lbbg, input)
  60. }
  61. func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential,
  62. ownerId mcclient.IIdentityProvider, input *api.LoadbalancerListenerCreateInput,
  63. lb *models.SLoadbalancer, lbbg *models.SLoadbalancerBackendGroup) (*api.LoadbalancerListenerCreateInput, error) {
  64. if len(lbbg.ExternalId) > 0 {
  65. return input, httperrors.NewResourceBusyError("loadbalancer backend group %s has aleady used by other listener", lbbg.Name)
  66. }
  67. return input, nil
  68. }
  69. func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *models.SLoadbalancerListener, task taskman.ITask) error {
  70. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  71. provider := lblis.GetCloudprovider()
  72. if provider == nil {
  73. return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name)
  74. }
  75. lbbg, err := lblis.GetLoadbalancerBackendGroup()
  76. if err != nil {
  77. return nil, errors.Wrapf(err, "GetLoadbalancerBackendGroup")
  78. }
  79. lb, err := lblis.GetLoadbalancer()
  80. if err != nil {
  81. return nil, errors.Wrapf(err, "GetLoadbalancer")
  82. }
  83. iLb, err := lb.GetILoadbalancer(ctx)
  84. if err != nil {
  85. return nil, errors.Wrapf(err, "GetILoadbalancer")
  86. }
  87. opts, err := lblis.GetLoadbalancerListenerParams()
  88. if err != nil {
  89. return nil, errors.Wrapf(err, "GetLoadbalancerListenerParams")
  90. }
  91. {
  92. if lblis.ListenerType == api.LB_LISTENER_TYPE_HTTPS && len(lblis.CertificateId) > 0 {
  93. cert, err := lblis.GetCertificate()
  94. if err != nil {
  95. return nil, errors.Wrapf(err, "GetCertificate")
  96. }
  97. opts.CertificateId = cert.ExternalId
  98. }
  99. }
  100. if len(lbbg.ExternalId) == 0 {
  101. lbbgOpts := &cloudprovider.SLoadbalancerBackendGroup{
  102. Name: lbbg.Name,
  103. Scheduler: lblis.Scheduler,
  104. Protocol: lblis.ListenerType,
  105. }
  106. iLbbg, err := iLb.CreateILoadBalancerBackendGroup(lbbgOpts)
  107. if err != nil {
  108. return nil, errors.Wrapf(err, "CreateILoadBalancerBackendGroup")
  109. }
  110. err = db.SetExternalId(lbbg, userCred, iLbbg.GetGlobalId())
  111. if err != nil {
  112. return nil, errors.Wrapf(err, "db.SetExternalId")
  113. }
  114. opts.BackendGroupId = iLbbg.GetGlobalId()
  115. }
  116. iLis, err := iLb.CreateILoadBalancerListener(ctx, opts)
  117. if err != nil {
  118. return nil, errors.Wrapf(err, "CreateILoadBalancerListener")
  119. }
  120. err = db.SetExternalId(lbbg, userCred, iLis.GetGlobalId())
  121. if err != nil {
  122. return nil, errors.Wrapf(err, "lbbg.SetExternalId")
  123. }
  124. err = db.SetExternalId(lblis, userCred, iLis.GetGlobalId())
  125. if err != nil {
  126. return nil, errors.Wrapf(err, "lblis.SetExternalId")
  127. }
  128. if lblis.HealthCheck == api.LB_BOOL_ON {
  129. err := iLis.SetHealthCheck(ctx, &opts.ListenerHealthCheckOptions)
  130. if err != nil {
  131. return nil, err
  132. }
  133. }
  134. backends, err := lbbg.GetBackends()
  135. if err != nil {
  136. return nil, errors.Wrapf(err, "GetBackends")
  137. }
  138. if len(backends) == 0 {
  139. return nil, nil
  140. }
  141. iLbbg, err := lbbg.GetICloudLoadbalancerBackendGroup(ctx)
  142. if err != nil {
  143. return nil, errors.Wrapf(err, "GetICloudLoadbalancerBackendGroup")
  144. }
  145. for i := range backends {
  146. opts := &cloudprovider.SLoadbalancerBackend{
  147. Weight: backends[i].Weight,
  148. Port: backends[i].Port,
  149. ExternalId: backends[i].ExternalId,
  150. }
  151. _, err := iLbbg.AddBackendServer(opts)
  152. if err != nil {
  153. return nil, errors.Wrapf(err, "AddBackendServer")
  154. }
  155. }
  156. return nil, nil
  157. })
  158. return nil
  159. }
  160. func (self *SHuaWeiRegionDriver) RequestDeleteLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *models.SLoadbalancerListener, task taskman.ITask) error {
  161. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  162. lbbg, err := lblis.GetLoadbalancerBackendGroup()
  163. if err != nil {
  164. return nil, errors.Wrapf(err, "GetLoadbalancerBackendGroup")
  165. }
  166. if len(lbbg.ExternalId) > 0 {
  167. iLbbg, err := lbbg.GetICloudLoadbalancerBackendGroup(ctx)
  168. if err != nil {
  169. if errors.Cause(err) == cloudprovider.ErrNotFound {
  170. return nil, db.SetExternalId(lbbg, userCred, "")
  171. }
  172. return nil, errors.Wrapf(err, "GetICloudLoadbalancerBackendGroup")
  173. }
  174. err = iLbbg.Delete(ctx)
  175. if err != nil {
  176. return nil, errors.Wrapf(err, "iLbbg.Delete")
  177. }
  178. return nil, db.SetExternalId(lbbg, userCred, "")
  179. }
  180. if len(lblis.ExternalId) == 0 {
  181. return nil, nil
  182. }
  183. lb, err := lblis.GetLoadbalancer()
  184. if err != nil {
  185. return nil, err
  186. }
  187. iLb, err := lb.GetILoadbalancer(ctx)
  188. if err != nil {
  189. return nil, errors.Wrapf(err, "GetILoadbalancer")
  190. }
  191. iListener, err := iLb.GetILoadBalancerListenerById(lblis.ExternalId)
  192. if err != nil {
  193. if errors.Cause(err) == cloudprovider.ErrNotFound {
  194. return nil, nil
  195. }
  196. return nil, errors.Wrapf(err, "GetILoadBalancerListenerById(%s)", lblis.ExternalId)
  197. }
  198. return nil, iListener.Delete(ctx)
  199. })
  200. return nil
  201. }
  202. func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input *api.LoadbalancerListenerRuleCreateInput) (*api.LoadbalancerListenerRuleCreateInput, error) {
  203. if input.Domain == "" && input.Path == "" {
  204. return input, fmt.Errorf("'domain' or 'path' should not be empty.")
  205. }
  206. return input, nil
  207. }
  208. func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, input *api.LoadbalancerListenerRuleUpdateInput) (*api.LoadbalancerListenerRuleUpdateInput, error) {
  209. return input, nil
  210. }
  211. func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, lbbg *models.SLoadbalancerBackendGroup, input *api.LoadbalancerBackendUpdateInput) (*api.LoadbalancerBackendUpdateInput, error) {
  212. if input.Port != nil {
  213. return input, fmt.Errorf("can not update backend port.")
  214. }
  215. return input, nil
  216. }
  217. func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential,
  218. lblis *models.SLoadbalancerListener, input *api.LoadbalancerListenerUpdateInput) (*api.LoadbalancerListenerUpdateInput, error) {
  219. return input, nil
  220. }
  221. func (self *SHuaWeiRegionDriver) ValidateCreateDBInstanceData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input api.DBInstanceCreateInput, skus []models.SDBInstanceSku, network *models.SNetwork) (api.DBInstanceCreateInput, error) {
  222. if len(input.MasterInstanceId) > 0 && input.Engine == api.DBINSTANCE_TYPE_SQLSERVER {
  223. return input, httperrors.NewInputParameterError("Not support create read-only dbinstance for %s", input.Engine)
  224. }
  225. if len(input.Name) < 4 || len(input.Name) > 64 {
  226. return input, httperrors.NewInputParameterError("Huawei dbinstance name length shoud be 4~64 characters")
  227. }
  228. if input.DiskSizeGB < 40 || input.DiskSizeGB > 4000 {
  229. return input, httperrors.NewInputParameterError("%s require disk size must in 40 ~ 4000 GB", self.GetProvider())
  230. }
  231. if input.DiskSizeGB%10 > 0 {
  232. return input, httperrors.NewInputParameterError("The disk_size_gb must be an integer multiple of 10")
  233. }
  234. if len(input.Password) == 0 { // 华为云RDS必须要有密码
  235. resetPassword := true
  236. input.ResetPassword = &resetPassword
  237. }
  238. if len(input.SecgroupIds) == 0 {
  239. input.SecgroupIds = []string{api.SECGROUP_DEFAULT_ID}
  240. }
  241. return input, nil
  242. }
  243. func (self *SHuaWeiRegionDriver) InitDBInstanceUser(ctx context.Context, instance *models.SDBInstance, task taskman.ITask, desc *cloudprovider.SManagedDBInstanceCreateConfig) error {
  244. user := "root"
  245. if desc.Engine == api.DBINSTANCE_TYPE_SQLSERVER {
  246. user = "rdsuser"
  247. }
  248. account := models.SDBInstanceAccount{}
  249. account.DBInstanceId = instance.Id
  250. account.Name = user
  251. account.Status = api.DBINSTANCE_USER_AVAILABLE
  252. account.SetModelManager(models.DBInstanceAccountManager, &account)
  253. err := models.DBInstanceAccountManager.TableSpec().Insert(ctx, &account)
  254. if err != nil {
  255. return err
  256. }
  257. return account.SetPassword(desc.Password)
  258. }
  259. func (self *SHuaWeiRegionDriver) IsSupportedBillingCycle(bc billing.SBillingCycle, resource string) bool {
  260. switch resource {
  261. case models.DBInstanceManager.KeywordPlural():
  262. years := bc.GetYears()
  263. months := bc.GetMonths()
  264. if (years >= 1 && years <= 3) || (months >= 1 && months <= 9) {
  265. return true
  266. }
  267. }
  268. return false
  269. }
  270. func (self *SHuaWeiRegionDriver) ValidateCreateDBInstanceAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceAccountCreateInput) (api.DBInstanceAccountCreateInput, error) {
  271. if utils.IsInStringArray(instance.Engine, []string{api.DBINSTANCE_TYPE_POSTGRESQL, api.DBINSTANCE_TYPE_SQLSERVER}) {
  272. return input, httperrors.NewInputParameterError("Not support create account for huawei cloud %s instance", instance.Engine)
  273. }
  274. if len(input.Name) == len(input.Password) {
  275. for i := range input.Name {
  276. if input.Name[i] != input.Password[len(input.Password)-i-1] {
  277. return input, nil
  278. }
  279. }
  280. return input, httperrors.NewInputParameterError("Huawei rds password cannot be in the same reverse order as the account")
  281. }
  282. return input, nil
  283. }
  284. func (self *SHuaWeiRegionDriver) ValidateCreateDBInstanceDatabaseData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceDatabaseCreateInput) (api.DBInstanceDatabaseCreateInput, error) {
  285. if utils.IsInStringArray(instance.Engine, []string{api.DBINSTANCE_TYPE_POSTGRESQL, api.DBINSTANCE_TYPE_SQLSERVER}) {
  286. return input, httperrors.NewInputParameterError("Not support create database for huawei cloud %s instance", instance.Engine)
  287. }
  288. return input, nil
  289. }
  290. func (self *SHuaWeiRegionDriver) ValidateCreateDBInstanceBackupData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceBackupCreateInput) (api.DBInstanceBackupCreateInput, error) {
  291. if len(input.Name) < 4 || len(input.Name) > 64 {
  292. return input, httperrors.NewInputParameterError("Huawei DBInstance backup name length shoud be 4~64 characters")
  293. }
  294. if len(input.Databases) > 0 && instance.Engine != api.DBINSTANCE_TYPE_SQLSERVER {
  295. return input, httperrors.NewInputParameterError("Huawei only supports specified databases with %s", api.DBINSTANCE_TYPE_SQLSERVER)
  296. }
  297. return input, nil
  298. }
  299. func (self *SHuaWeiRegionDriver) ValidateChangeDBInstanceConfigData(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SDBInstance, input *api.SDBInstanceChangeConfigInput) error {
  300. if input.DiskSizeGB != 0 && input.DiskSizeGB < instance.DiskSizeGB {
  301. return httperrors.NewUnsupportOperationError("Huawei DBInstance Disk cannot be thrink")
  302. }
  303. return nil
  304. }
  305. func (self *SHuaWeiRegionDriver) IsSupportDBInstancePublicConnection() bool {
  306. //目前华为云未对外开放打开远程连接的API接口
  307. return false
  308. }
  309. func (self *SHuaWeiRegionDriver) ValidateResetDBInstancePassword(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SDBInstance, account string) error {
  310. return httperrors.NewUnsupportOperationError("Huawei current not support reset dbinstance account password")
  311. }
  312. func (self *SHuaWeiRegionDriver) IsSupportKeepDBInstanceManualBackup() bool {
  313. return true
  314. }
  315. func (self *SHuaWeiRegionDriver) ValidateDBInstanceAccountPrivilege(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SDBInstance, account string, privilege string) error {
  316. if account == "root" {
  317. return httperrors.NewInputParameterError("No need to grant or revoke privilege for admin account")
  318. }
  319. if !utils.IsInStringArray(privilege, []string{api.DATABASE_PRIVILEGE_RW, api.DATABASE_PRIVILEGE_R}) {
  320. return httperrors.NewInputParameterError("Unknown privilege %s", privilege)
  321. }
  322. return nil
  323. }
  324. // https://support.huaweicloud.com/api-rds/rds_09_0009.html
  325. func (self *SHuaWeiRegionDriver) ValidateDBInstanceRecovery(ctx context.Context, userCred mcclient.TokenCredential, instance *models.SDBInstance, backup *models.SDBInstanceBackup, input api.SDBInstanceRecoveryConfigInput) error {
  326. if backup.Engine == api.DBINSTANCE_TYPE_POSTGRESQL {
  327. return httperrors.NewNotSupportedError("%s not support recovery", backup.Engine)
  328. }
  329. if backup.DBInstanceId == instance.Id && instance.Engine != api.DBINSTANCE_TYPE_SQLSERVER {
  330. return httperrors.NewNotSupportedError("Huawei %s rds not support recovery from it self rds backup", instance.Engine)
  331. }
  332. if len(input.Databases) > 0 {
  333. if instance.Engine != api.DBINSTANCE_TYPE_SQLSERVER {
  334. return httperrors.NewInputParameterError("Huawei only %s engine support databases recovery", instance.Engine)
  335. }
  336. invalidDbs := []string{"rdsadmin", "master", "msdb", "tempdb", "model"}
  337. for _, db := range input.Databases {
  338. if utils.IsInStringArray(strings.ToLower(db), invalidDbs) {
  339. return httperrors.NewInputParameterError("New databases name can not be one of %s", invalidDbs)
  340. }
  341. }
  342. }
  343. return nil
  344. }
  345. func validatorSlaveZones(ctx context.Context, ownerId mcclient.IIdentityProvider, regionId string, data *jsonutils.JSONDict, optional bool) error {
  346. s, err := data.GetString("slave_zones")
  347. if err != nil {
  348. if optional {
  349. return nil
  350. }
  351. return fmt.Errorf("missing parameter slave_zones")
  352. }
  353. zones := strings.Split(s, ",")
  354. ret := []string{}
  355. zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId)
  356. for i := range zones {
  357. _data := jsonutils.NewDict()
  358. _data.Set("zone", jsonutils.NewString(zones[i]))
  359. if err := zoneV.Validate(ctx, _data); err != nil {
  360. return errors.Wrap(err, "validatorSlaveZones")
  361. } else {
  362. if zoneV.Model.(*models.SZone).GetCloudRegionId() != regionId {
  363. return errors.Wrap(fmt.Errorf("zone %s is not in region %s", zoneV.Model.GetName(), regionId), "GetCloudRegionId")
  364. }
  365. ret = append(ret, zoneV.Model.GetId())
  366. }
  367. }
  368. //if sku, err := data.GetString("sku"); err != nil || len(sku) == 0 {
  369. // return httperrors.NewMissingParameterError("sku")
  370. //} else {
  371. // chargeType, _ := data.GetString("charge_type")
  372. //
  373. // _skuModel, err := db.FetchByIdOrName(models.ElasticcacheSkuManager, ownerId, sku)
  374. // if err != nil {
  375. // return err
  376. // }
  377. //
  378. // skuModel := _skuModel.(*models.SElasticcacheSku)
  379. // for _, zoneId := range zones {
  380. // if err := ValidateElasticcacheSku(zoneId, chargeType, skuModel, nil); err != nil {
  381. // return err
  382. // }
  383. // }
  384. //}
  385. data.Set("slave_zones", jsonutils.NewString(strings.Join(ret, ",")))
  386. return nil
  387. }
  388. func (self *SHuaWeiRegionDriver) ValidateCreateElasticcacheData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input *api.ElasticcacheCreateInput) (*api.ElasticcacheCreateInput, error) {
  389. if !utils.IsInStringArray(input.Engine, []string{"redis", "memcache"}) {
  390. return nil, httperrors.NewInputParameterError("invalid engine %s", input.Engine)
  391. }
  392. if len(input.MaintainStartTime) > 0 && !utils.IsInStringArray(input.MaintainStartTime, []string{"22:00:00", "02:00:00", "06:00:00", "10:00:00", "14:00:00", "18:00:00"}) {
  393. return nil, httperrors.NewInputParameterError("invalid maintain_start_time %s", input.MaintainStartTime)
  394. }
  395. if input.CapacityMb == 0 {
  396. return nil, httperrors.NewMissingParameterError("capacity_mb")
  397. }
  398. return self.SManagedVirtualizationRegionDriver.ValidateCreateElasticcacheData(ctx, userCred, ownerId, input)
  399. }
  400. func (self *SHuaWeiRegionDriver) ValidateCreateElasticcacheAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
  401. return nil, httperrors.NewUnsupportOperationError("%s not support create account", self.GetProvider())
  402. }
  403. func (self *SHuaWeiRegionDriver) RequestElasticcacheAccountResetPassword(ctx context.Context, userCred mcclient.TokenCredential, ea *models.SElasticcacheAccount, task taskman.ITask) error {
  404. iregion, err := ea.GetIRegion(ctx)
  405. if err != nil {
  406. return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetIRegion")
  407. }
  408. _ec, err := db.FetchById(models.ElasticcacheManager, ea.ElasticcacheId)
  409. if err != nil {
  410. return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.FetchById")
  411. }
  412. ec := _ec.(*models.SElasticcache)
  413. iec, err := iregion.GetIElasticcacheById(ec.GetExternalId())
  414. if errors.Cause(err) == cloudprovider.ErrNotFound {
  415. return nil
  416. } else if err != nil {
  417. return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetIElasticcacheById")
  418. }
  419. iea, err := iec.GetICloudElasticcacheAccount(ea.GetExternalId())
  420. if err != nil {
  421. return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetICloudElasticcacheBackup")
  422. }
  423. data := task.GetParams()
  424. if data == nil {
  425. return errors.Wrap(fmt.Errorf("data is nil"), "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetParams")
  426. }
  427. input, err := ea.GetUpdateHuaweiElasticcacheAccountParams(*data)
  428. if err != nil {
  429. return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.GetUpdateHuaweiElasticcacheAccountParams")
  430. }
  431. err = iea.UpdateAccount(input)
  432. if err != nil {
  433. return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.UpdateAccount")
  434. }
  435. if input.Password != nil {
  436. err = ea.SavePassword(*input.Password)
  437. if err != nil {
  438. return errors.Wrap(err, "huaweiRegionDriver.RequestElasticcacheAccountResetPassword.SavePassword")
  439. }
  440. }
  441. return ea.SetStatus(ctx, userCred, api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE, "")
  442. }
  443. func (self *SHuaWeiRegionDriver) RequestUpdateElasticcacheAuthMode(ctx context.Context, userCred mcclient.TokenCredential, ec *models.SElasticcache, task taskman.ITask) error {
  444. return errors.Wrap(fmt.Errorf("not support update huawei elastic cache auth_mode"), "HuaWeiRegionDriver.RequestUpdateElasticcacheAuthMode")
  445. }
  446. func (self *SHuaWeiRegionDriver) AllowCreateElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, elasticcache *models.SElasticcache) error {
  447. if elasticcache.LocalCategory == api.ELASTIC_CACHE_ARCH_TYPE_SINGLE {
  448. return httperrors.NewBadRequestError("huawei %s mode elastic not support create backup", elasticcache.LocalCategory)
  449. }
  450. return nil
  451. }
  452. func (self *SHuaWeiRegionDriver) AllowUpdateElasticcacheAuthMode(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, elasticcache *models.SElasticcache) error {
  453. return fmt.Errorf("not support update huawei elastic cache auth_mode")
  454. }
  455. func (self *SHuaWeiRegionDriver) IsSupportedDBInstance() bool {
  456. return true
  457. }
  458. func (self *SHuaWeiRegionDriver) IsSupportedElasticcache() bool {
  459. return true
  460. }
  461. func (self *SHuaWeiRegionDriver) IsSupportedElasticcacheSecgroup() bool {
  462. return false
  463. }
  464. func (self *SHuaWeiRegionDriver) GetMaxElasticcacheSecurityGroupCount() int {
  465. return 0
  466. }
  467. func (self *SHuaWeiRegionDriver) GetBackendStatusForAdd() []string {
  468. return []string{api.VM_RUNNING, api.VM_READY}
  469. }
  470. func (self *SHuaWeiRegionDriver) GetRdsSupportSecgroupCount() int {
  471. return 1
  472. }
  473. func (self *SHuaWeiRegionDriver) IsSupportedElasticcacheAutoRenew() bool {
  474. return false
  475. }
  476. func (self *SHuaWeiRegionDriver) ValidateCreateVpcData(ctx context.Context, userCred mcclient.TokenCredential, input api.VpcCreateInput) (api.VpcCreateInput, error) {
  477. var cidrV = validators.NewIPv4PrefixValidator("cidr_block")
  478. if err := cidrV.Validate(ctx, jsonutils.Marshal(input).(*jsonutils.JSONDict)); err != nil {
  479. return input, err
  480. }
  481. err := IsInPrivateIpRange(cidrV.Value.ToIPRange())
  482. if err != nil {
  483. return input, err
  484. }
  485. if cidrV.Value.MaskLen > 24 {
  486. return input, httperrors.NewInputParameterError("invalid cidr range %s, mask length should less than or equal to 24", cidrV.Value.String())
  487. }
  488. return input, nil
  489. }
  490. func (self *SHuaWeiRegionDriver) OnNatEntryDeleteComplete(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip) error {
  491. return models.StartResourceSyncStatusTask(ctx, userCred, eip, "EipSyncstatusTask", "")
  492. }
  493. func (self *SHuaWeiRegionDriver) RequestAssociateEipForNAT(ctx context.Context, userCred mcclient.TokenCredential, nat *models.SNatGateway, eip *models.SElasticip, task taskman.ITask) error {
  494. _, err := db.Update(eip, func() error {
  495. eip.AssociateType = api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY
  496. eip.AssociateId = nat.Id
  497. return nil
  498. })
  499. if err != nil {
  500. return errors.Wrapf(err, "db.Update")
  501. }
  502. return task.ScheduleRun(nil)
  503. }
  504. func (self *SHuaWeiRegionDriver) ValidateCreateNatGateway(ctx context.Context, userCred mcclient.TokenCredential, input api.NatgatewayCreateInput) (api.NatgatewayCreateInput, error) {
  505. if len(input.Eip) > 0 || input.EipBw > 0 {
  506. return input, httperrors.NewInputParameterError("Huawei nat not support associate eip")
  507. }
  508. return input, nil
  509. }
  510. func (self *SHuaWeiRegionDriver) IsSupportedNatGateway() bool {
  511. return true
  512. }
  513. func (self *SHuaWeiRegionDriver) IsSupportedNas() bool {
  514. return true
  515. }
  516. func (self *SHuaWeiRegionDriver) ValidateCreateSecurityGroupInput(ctx context.Context, userCred mcclient.TokenCredential, input *api.SSecgroupCreateInput) (*api.SSecgroupCreateInput, error) {
  517. for i := range input.Rules {
  518. rule := input.Rules[i]
  519. if input.Rules[i].Priority == nil {
  520. return nil, httperrors.NewMissingParameterError("priority")
  521. }
  522. if *input.Rules[i].Priority < 1 || *input.Rules[i].Priority > 100 {
  523. return nil, httperrors.NewInputParameterError("invalid priority %d, range 1-100", *input.Rules[i].Priority)
  524. }
  525. if len(rule.Ports) > 0 && strings.Contains(input.Rules[i].Ports, ",") {
  526. return nil, httperrors.NewInputParameterError("invalid ports %s", input.Rules[i].Ports)
  527. }
  528. }
  529. return input, nil
  530. }
  531. func (self *SHuaWeiRegionDriver) ValidateUpdateSecurityGroupRuleInput(ctx context.Context, userCred mcclient.TokenCredential, input *api.SSecgroupRuleUpdateInput) (*api.SSecgroupRuleUpdateInput, error) {
  532. return nil, httperrors.NewNotSupportedError("not support update security group rule")
  533. }
  534. func (self *SHuaWeiRegionDriver) GetSecurityGroupFilter(vpc *models.SVpc) (func(q *sqlchemy.SQuery) *sqlchemy.SQuery, error) {
  535. return func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  536. return q.Equals("cloudregion_id", vpc.CloudregionId).Equals("manager_id", vpc.ManagerId)
  537. }, nil
  538. }