region.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  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 hcso
  15. import (
  16. "fmt"
  17. "net/http"
  18. "net/url"
  19. "strings"
  20. "time"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/log"
  23. "yunion.io/x/pkg/errors"
  24. api "yunion.io/x/cloudmux/pkg/apis/compute"
  25. "yunion.io/x/cloudmux/pkg/cloudprovider"
  26. "yunion.io/x/cloudmux/pkg/multicloud"
  27. "yunion.io/x/cloudmux/pkg/multicloud/hcso/client"
  28. "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs"
  29. )
  30. type Locales struct {
  31. EnUs string `json:"en-us"`
  32. ZhCN string `json:"zh-cn"`
  33. }
  34. // https://support.huaweicloud.com/api-iam/zh-cn_topic_0067148043.html
  35. type SRegion struct {
  36. multicloud.SRegion
  37. client *SHuaweiClient
  38. ecsClient *client.Client
  39. obsClient *obs.ObsClient // 对象存储client.请勿直接引用。
  40. Description string `json:"description"`
  41. ID string `json:"id"`
  42. Locales Locales `json:"locales"`
  43. ParentRegionID string `json:"parent_region_id"`
  44. Type string `json:"type"`
  45. izones []cloudprovider.ICloudZone
  46. ivpcs []cloudprovider.ICloudVpc
  47. iskus []cloudprovider.ICloudSku
  48. storageCache *SStoragecache
  49. }
  50. func (self *SRegion) list(service, resource string, query url.Values) (jsonutils.JSONObject, error) {
  51. return self.client.list(service, self.ID, resource, query)
  52. }
  53. func (self *SRegion) delete(service, resource string) (jsonutils.JSONObject, error) {
  54. return self.client.delete(service, self.ID, resource)
  55. }
  56. func (self *SRegion) put(service, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) {
  57. return self.client.put(service, self.ID, resource, params)
  58. }
  59. func (self *SRegion) post(service, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) {
  60. return self.client.post(service, self.ID, resource, params)
  61. }
  62. func (self *SRegion) GetClient() *SHuaweiClient {
  63. return self.client
  64. }
  65. func (self *SRegion) getECSClient() (*client.Client, error) {
  66. var err error
  67. if len(self.client.projectId) > 0 {
  68. project, err := self.client.GetProjectById(self.client.projectId)
  69. if err != nil {
  70. return nil, err
  71. }
  72. regionId := strings.Split(project.Name, "_")[0]
  73. if regionId != self.ID {
  74. // log.Debugf("project %s not in region %s", self.client.ProjectId, self.ID)
  75. return nil, errors.Error("region and project mismatch")
  76. }
  77. }
  78. if self.ecsClient == nil {
  79. self.ecsClient, err = self.client.newRegionAPIClient(self.ID)
  80. if err != nil {
  81. return nil, err
  82. }
  83. }
  84. return self.ecsClient, err
  85. }
  86. func (self *SRegion) getOBSEndpoint() string {
  87. return getOBSEndpoint(self.GetId())
  88. }
  89. func (self *SRegion) getOBSClient() (*obs.ObsClient, error) {
  90. if self.obsClient == nil {
  91. obsClient, err := self.client.getOBSClient(self.GetId())
  92. if err != nil {
  93. return nil, err
  94. }
  95. client := obsClient.GetClient()
  96. ts, _ := client.Transport.(*http.Transport)
  97. client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response) error, error) {
  98. if self.client.cpcfg.ReadOnly {
  99. if req.Method == "GET" || req.Method == "HEAD" {
  100. return nil, nil
  101. }
  102. return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path)
  103. }
  104. return nil, nil
  105. })
  106. self.obsClient = obsClient
  107. }
  108. return self.obsClient, nil
  109. }
  110. func (self *SRegion) fetchZones() error {
  111. zones := make([]SZone, 0)
  112. err := doListAll(self.ecsClient.Zones.List, nil, &zones)
  113. if err != nil {
  114. return err
  115. }
  116. self.izones = make([]cloudprovider.ICloudZone, 0)
  117. for i := range zones {
  118. zone := zones[i]
  119. zone.region = self
  120. self.izones = append(self.izones, &zone)
  121. }
  122. return nil
  123. }
  124. func (self *SRegion) fetchIVpcs() error {
  125. // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html
  126. vpcs := make([]SVpc, 0)
  127. querys := map[string]string{
  128. "limit": "2048",
  129. }
  130. err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs)
  131. if err != nil {
  132. return err
  133. }
  134. self.ivpcs = make([]cloudprovider.ICloudVpc, 0)
  135. for i := range vpcs {
  136. vpc := vpcs[i]
  137. vpc.region = self
  138. self.ivpcs = append(self.ivpcs, &vpc)
  139. }
  140. return nil
  141. }
  142. func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
  143. if len(id) == 0 {
  144. return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById")
  145. }
  146. instance, err := self.GetInstanceByID(id)
  147. if err != nil {
  148. return nil, err
  149. }
  150. zone, err := self.getZoneById(instance.OSEXTAZAvailabilityZone)
  151. if err != nil {
  152. return nil, errors.Wrap(err, "getZoneById")
  153. }
  154. instance.host = &SHost{
  155. zone: zone,
  156. vms: nil,
  157. projectId: self.client.projectId,
  158. Id: instance.HostID,
  159. Name: instance.OSEXTSRVATTRHost,
  160. }
  161. return &instance, err
  162. }
  163. func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
  164. return self.GetDisk(id)
  165. }
  166. func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
  167. if info, ok := LatitudeAndLongitude[self.ID]; ok {
  168. return info
  169. }
  170. return cloudprovider.SGeographicInfo{}
  171. }
  172. func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
  173. elbs, err := self.GetLoadBalancers()
  174. if err != nil {
  175. return nil, err
  176. }
  177. ielbs := make([]cloudprovider.ICloudLoadbalancer, len(elbs))
  178. for i := range elbs {
  179. ielbs[i] = &elbs[i]
  180. }
  181. return ielbs, nil
  182. }
  183. // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561531.html
  184. func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) {
  185. params := map[string]string{}
  186. if len(self.client.projectId) > 0 {
  187. params["project_id"] = self.client.projectId
  188. }
  189. ret := []SLoadbalancer{}
  190. err := doListAll(self.ecsClient.Elb.List, params, &ret)
  191. if err != nil {
  192. return nil, err
  193. }
  194. for i := range ret {
  195. ret[i].region = self
  196. }
  197. return ret, nil
  198. }
  199. func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
  200. elb, err := self.GetLoadBalancerById(loadbalancerId)
  201. if err != nil {
  202. return nil, err
  203. }
  204. return &elb, nil
  205. }
  206. func (self *SRegion) GetLoadBalancerById(loadbalancerId string) (SLoadbalancer, error) {
  207. elb := SLoadbalancer{}
  208. err := DoGet(self.ecsClient.Elb.Get, loadbalancerId, nil, &elb)
  209. if err != nil {
  210. return elb, err
  211. }
  212. elb.region = self
  213. return elb, nil
  214. }
  215. func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
  216. acl, err := self.GetLoadBalancerAclById(aclId)
  217. if err != nil {
  218. return nil, err
  219. }
  220. return &acl, nil
  221. }
  222. func (self *SRegion) GetLoadBalancerAclById(aclId string) (SElbACL, error) {
  223. acl := SElbACL{}
  224. err := DoGet(self.ecsClient.ElbWhitelist.Get, aclId, nil, &acl)
  225. if err != nil {
  226. return acl, err
  227. }
  228. acl.region = self
  229. return acl, nil
  230. }
  231. func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
  232. cert, err := self.GetLoadBalancerCertificateById(certId)
  233. if err != nil {
  234. return nil, err
  235. }
  236. return &cert, nil
  237. }
  238. func (self *SRegion) GetLoadBalancerCertificateById(certId string) (SElbCert, error) {
  239. ret := SElbCert{}
  240. err := DoGet(self.ecsClient.ElbCertificates.Get, certId, nil, &ret)
  241. if err != nil {
  242. return ret, err
  243. }
  244. ret.region = self
  245. return ret, nil
  246. }
  247. func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
  248. ret, err := self.CreateLoadBalancerCertificate(cert)
  249. if err != nil {
  250. return nil, err
  251. }
  252. return &ret, nil
  253. }
  254. // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561584.html
  255. func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (SElbCert, error) {
  256. params := jsonutils.NewDict()
  257. params.Set("name", jsonutils.NewString(cert.Name))
  258. params.Set("private_key", jsonutils.NewString(cert.PrivateKey))
  259. params.Set("certificate", jsonutils.NewString(cert.Certificate))
  260. ret := SElbCert{}
  261. err := DoCreate(self.ecsClient.ElbCertificates.Create, params, &ret)
  262. if err != nil {
  263. return ret, err
  264. }
  265. ret.region = self
  266. return ret, nil
  267. }
  268. func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
  269. ret, err := self.GetLoadBalancerAcls("")
  270. if err != nil {
  271. return nil, err
  272. }
  273. iret := make([]cloudprovider.ICloudLoadbalancerAcl, len(ret))
  274. for i := range ret {
  275. iret[i] = &ret[i]
  276. }
  277. return iret, nil
  278. }
  279. // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html
  280. func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) {
  281. params := map[string]string{}
  282. if len(listenerId) > 0 {
  283. params["listener_id"] = listenerId
  284. }
  285. ret := []SElbACL{}
  286. err := doListAll(self.ecsClient.ElbWhitelist.List, params, &ret)
  287. if err != nil {
  288. return nil, err
  289. }
  290. for i := range ret {
  291. ret[i].region = self
  292. }
  293. return ret, nil
  294. }
  295. func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
  296. ret, err := self.GetLoadBalancerCertificates()
  297. if err != nil {
  298. return nil, err
  299. }
  300. iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret))
  301. for i := range ret {
  302. iret[i] = &ret[i]
  303. }
  304. return iret, nil
  305. }
  306. func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) {
  307. ret := []SElbCert{}
  308. err := doListAll(self.ecsClient.ElbCertificates.List, nil, &ret)
  309. if err != nil {
  310. return nil, err
  311. }
  312. for i := range ret {
  313. ret[i].region = self
  314. }
  315. return ret, nil
  316. }
  317. // https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html
  318. func (self *SRegion) GetId() string {
  319. return self.ID
  320. }
  321. func (self *SRegion) GetName() string {
  322. return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN)
  323. }
  324. func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable {
  325. en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs)
  326. table := cloudprovider.SModelI18nTable{}
  327. table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en)
  328. return table
  329. }
  330. func (self *SRegion) GetGlobalId() string {
  331. return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_HCSO, self.ID)
  332. }
  333. func (self *SRegion) GetStatus() string {
  334. return api.CLOUD_REGION_STATUS_INSERVER
  335. }
  336. func (self *SRegion) Refresh() error {
  337. return nil
  338. }
  339. func (self *SRegion) IsEmulated() bool {
  340. return false
  341. }
  342. func (self *SRegion) GetLatitude() float32 {
  343. if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
  344. return locationInfo.Latitude
  345. }
  346. return 0.0
  347. }
  348. func (self *SRegion) GetLongitude() float32 {
  349. if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok {
  350. return locationInfo.Longitude
  351. }
  352. return 0.0
  353. }
  354. func (self *SRegion) fetchInfrastructure() error {
  355. _, err := self.getECSClient()
  356. if err != nil {
  357. return err
  358. }
  359. if err := self.fetchZones(); err != nil {
  360. return err
  361. }
  362. if err := self.fetchIVpcs(); err != nil {
  363. return err
  364. }
  365. for i := 0; i < len(self.ivpcs); i += 1 {
  366. vpc := self.ivpcs[i].(*SVpc)
  367. wire := SWire{region: self, vpc: vpc}
  368. vpc.addWire(&wire)
  369. for j := 0; j < len(self.izones); j += 1 {
  370. zone := self.izones[j].(*SZone)
  371. zone.addWire(&wire)
  372. }
  373. }
  374. return nil
  375. }
  376. func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
  377. if self.izones == nil {
  378. var err error
  379. err = self.fetchInfrastructure()
  380. if err != nil {
  381. return nil, err
  382. }
  383. }
  384. return self.izones, nil
  385. }
  386. func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
  387. if self.ivpcs == nil {
  388. err := self.fetchInfrastructure()
  389. if err != nil {
  390. return nil, err
  391. }
  392. }
  393. return self.ivpcs, nil
  394. }
  395. func (self *SRegion) GetEipById(eipId string) (SEipAddress, error) {
  396. var eip SEipAddress
  397. err := DoGet(self.ecsClient.Eips.Get, eipId, nil, &eip)
  398. eip.region = self
  399. return eip, err
  400. }
  401. // 返回参数分别为eip 列表、列表长度、error。
  402. // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html
  403. func (self *SRegion) GetEips() ([]SEipAddress, error) {
  404. querys := make(map[string]string)
  405. eips := make([]SEipAddress, 0)
  406. err := doListAllWithMarker(self.ecsClient.Eips.List, querys, &eips)
  407. for i := range eips {
  408. eips[i].region = self
  409. }
  410. return eips, err
  411. }
  412. func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
  413. _, err := self.getECSClient()
  414. if err != nil {
  415. return nil, err
  416. }
  417. eips, err := self.GetEips()
  418. if err != nil {
  419. return nil, err
  420. }
  421. ret := make([]cloudprovider.ICloudEIP, len(eips))
  422. for i := 0; i < len(eips); i += 1 {
  423. eips[i].region = self
  424. ret[i] = &eips[i]
  425. }
  426. return ret, nil
  427. }
  428. func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
  429. ivpcs, err := self.GetIVpcs()
  430. if err != nil {
  431. return nil, err
  432. }
  433. for i := 0; i < len(ivpcs); i += 1 {
  434. if ivpcs[i].GetGlobalId() == id {
  435. return ivpcs[i], nil
  436. }
  437. }
  438. return nil, cloudprovider.ErrNotFound
  439. }
  440. func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
  441. izones, err := self.GetIZones()
  442. if err != nil {
  443. return nil, err
  444. }
  445. for i := 0; i < len(izones); i += 1 {
  446. if izones[i].GetGlobalId() == id {
  447. return izones[i], nil
  448. }
  449. }
  450. return nil, cloudprovider.ErrNotFound
  451. }
  452. func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
  453. eip, err := self.GetEipById(eipId)
  454. return &eip, err
  455. }
  456. // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html
  457. func (self *SRegion) DeleteSecurityGroup(secgroupId string) error {
  458. return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil)
  459. }
  460. func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) {
  461. secgroup, err := self.GetSecurityGroup(secgroupId)
  462. if err != nil {
  463. return nil, err
  464. }
  465. return secgroup, nil
  466. }
  467. func (self *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
  468. return self.CreateSecurityGroup(opts)
  469. }
  470. func (self *SRegion) CreateSecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (*SSecurityGroup, error) {
  471. params := map[string]interface{}{
  472. "name": opts.Name,
  473. "description": opts.Desc,
  474. "enterprise_project_id": opts.ProjectId,
  475. }
  476. resp, err := self.post(SERVICE_VPC, "vpc/security-groups", map[string]interface{}{"security_group": params})
  477. if err != nil {
  478. return nil, err
  479. }
  480. ret := &SSecurityGroup{region: self}
  481. return ret, resp.Unmarshal(ret, "security_group")
  482. }
  483. // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html
  484. func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) {
  485. return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc)
  486. }
  487. func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) {
  488. params := map[string]interface{}{
  489. "vpc": map[string]string{
  490. "name": name,
  491. "cidr": cidr,
  492. "description": desc,
  493. },
  494. }
  495. vpc := &SVpc{region: self}
  496. return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc)
  497. }
  498. // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html
  499. // size: 1Mbit/s~2000Mbit/s
  500. // bgpType: 5_telcom,5_union,5_bgp,5_sbgp.
  501. // 东北-大连:5_telcom、5_union
  502. // 华南-广州:5_sbgp
  503. // 华东-上海二:5_sbgp
  504. // 华北-北京一:5_bgp、5_sbgp
  505. // 亚太-香港:5_bgp
  506. func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) {
  507. var ctype TInternetChargeType
  508. switch eip.ChargeType {
  509. case api.EIP_CHARGE_TYPE_BY_TRAFFIC:
  510. ctype = InternetChargeByTraffic
  511. case api.EIP_CHARGE_TYPE_BY_BANDWIDTH:
  512. ctype = InternetChargeByBandwidth
  513. }
  514. if len(eip.BGPType) == 0 {
  515. eip.BGPType = "5_bgp"
  516. }
  517. // 华为云EIP名字最大长度64
  518. if len(eip.Name) > 64 {
  519. eip.Name = eip.Name[:64]
  520. }
  521. ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId)
  522. ieip.region = self
  523. if err != nil {
  524. return nil, err
  525. }
  526. err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second)
  527. return ieip, err
  528. }
  529. func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
  530. snapshots, err := self.GetSnapshots("", "")
  531. if err != nil {
  532. log.Errorf("self.GetSnapshots fail %s", err)
  533. return nil, err
  534. }
  535. ret := make([]cloudprovider.ICloudSnapshot, len(snapshots))
  536. for i := 0; i < len(snapshots); i += 1 {
  537. snapshots[i].region = self
  538. ret[i] = &snapshots[i]
  539. }
  540. return ret, nil
  541. }
  542. func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
  543. snapshot, err := self.GetSnapshotById(snapshotId)
  544. return &snapshot, err
  545. }
  546. func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
  547. iHosts := make([]cloudprovider.ICloudHost, 0)
  548. izones, err := self.GetIZones()
  549. if err != nil {
  550. return nil, err
  551. }
  552. for i := 0; i < len(izones); i += 1 {
  553. iZoneHost, err := izones[i].GetIHosts()
  554. if err != nil {
  555. return nil, err
  556. }
  557. iHosts = append(iHosts, iZoneHost...)
  558. }
  559. return iHosts, nil
  560. }
  561. func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
  562. izones, err := self.GetIZones()
  563. if err != nil {
  564. return nil, err
  565. }
  566. for i := 0; i < len(izones); i += 1 {
  567. ihost, err := izones[i].GetIHostById(id)
  568. if err == nil {
  569. return ihost, nil
  570. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  571. return nil, err
  572. }
  573. }
  574. return nil, cloudprovider.ErrNotFound
  575. }
  576. func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
  577. iStores := make([]cloudprovider.ICloudStorage, 0)
  578. izones, err := self.GetIZones()
  579. if err != nil {
  580. return nil, err
  581. }
  582. for i := 0; i < len(izones); i += 1 {
  583. iZoneStores, err := izones[i].GetIStorages()
  584. if err != nil {
  585. return nil, err
  586. }
  587. iStores = append(iStores, iZoneStores...)
  588. }
  589. return iStores, nil
  590. }
  591. func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
  592. izones, err := self.GetIZones()
  593. if err != nil {
  594. return nil, err
  595. }
  596. for i := 0; i < len(izones); i += 1 {
  597. istore, err := izones[i].GetIStorageById(id)
  598. if err == nil {
  599. return istore, nil
  600. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  601. return nil, err
  602. }
  603. }
  604. return nil, cloudprovider.ErrNotFound
  605. }
  606. func (self *SRegion) GetProvider() string {
  607. return CLOUD_PROVIDER_HUAWEI
  608. }
  609. func (self *SRegion) GetCloudEnv() string {
  610. return ""
  611. }
  612. func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancerCreateOptions) (cloudprovider.ICloudLoadbalancer, error) {
  613. ret, err := self.CreateLoadBalancer(loadbalancer)
  614. if err != nil {
  615. return nil, err
  616. }
  617. return &ret, nil
  618. }
  619. // https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html
  620. func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancerCreateOptions) (SLoadbalancer, error) {
  621. ret := SLoadbalancer{}
  622. subnet, err := self.getNetwork(loadbalancer.NetworkIds[0])
  623. if err != nil {
  624. return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork")
  625. }
  626. params := jsonutils.NewDict()
  627. elbObj := jsonutils.NewDict()
  628. elbObj.Set("name", jsonutils.NewString(loadbalancer.Name))
  629. elbObj.Set("vip_subnet_id", jsonutils.NewString(subnet.NeutronSubnetID))
  630. if len(loadbalancer.Address) > 0 {
  631. elbObj.Set("vip_address", jsonutils.NewString(loadbalancer.Address))
  632. }
  633. elbObj.Set("tenant_id", jsonutils.NewString(self.client.projectId))
  634. params.Set("loadbalancer", elbObj)
  635. err = DoCreate(self.ecsClient.Elb.Create, params, &ret)
  636. if err != nil {
  637. return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.DoCreate")
  638. }
  639. ret.region = self
  640. // 创建公网类型ELB
  641. if len(loadbalancer.EipId) > 0 {
  642. err := self.AssociateEipWithPortId(loadbalancer.EipId, ret.VipPortID)
  643. if err != nil {
  644. return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId")
  645. }
  646. }
  647. return ret, nil
  648. }
  649. func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
  650. return nil, cloudprovider.ErrNotSupported
  651. }
  652. func (self *SRegion) CreateLoadBalancerAcl(listenerId string, acl *cloudprovider.SLoadbalancerAccessControlList) (SElbACL, error) {
  653. params := jsonutils.NewDict()
  654. aclObj := jsonutils.NewDict()
  655. aclObj.Set("listener_id", jsonutils.NewString(listenerId))
  656. if len(acl.Entrys) > 0 {
  657. whitelist := []string{}
  658. for i := range acl.Entrys {
  659. whitelist = append(whitelist, acl.Entrys[i].CIDR)
  660. }
  661. aclObj.Set("enable_whitelist", jsonutils.NewBool(true))
  662. aclObj.Set("whitelist", jsonutils.NewString(strings.Join(whitelist, ",")))
  663. } else {
  664. aclObj.Set("enable_whitelist", jsonutils.NewBool(false))
  665. }
  666. params.Set("whitelist", aclObj)
  667. ret := SElbACL{}
  668. err := DoCreate(self.ecsClient.ElbWhitelist.Create, params, &ret)
  669. if err != nil {
  670. return ret, err
  671. }
  672. ret.region = self
  673. return ret, nil
  674. }
  675. func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
  676. iBuckets, err := region.client.getIBuckets()
  677. if err != nil {
  678. return nil, errors.Wrap(err, "getIBuckets")
  679. }
  680. ret := make([]cloudprovider.ICloudBucket, 0)
  681. for i := range iBuckets {
  682. // huawei OBS is shared across projects
  683. if iBuckets[i].GetLocation() == region.GetId() {
  684. ret = append(ret, iBuckets[i])
  685. }
  686. }
  687. return ret, nil
  688. }
  689. func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) {
  690. if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) {
  691. return obs.StorageClassStandard, nil
  692. } else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) {
  693. return obs.StorageClassWarm, nil
  694. } else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) {
  695. return obs.StorageClassCold, nil
  696. } else {
  697. return obs.StorageClassStandard, errors.Error("unsupported storageClass")
  698. }
  699. }
  700. func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error {
  701. obsClient, err := region.getOBSClient()
  702. if err != nil {
  703. return errors.Wrap(err, "region.getOBSClient")
  704. }
  705. input := &obs.CreateBucketInput{}
  706. input.Bucket = name
  707. input.Location = region.GetId()
  708. if len(aclStr) > 0 {
  709. if strings.EqualFold(aclStr, string(obs.AclPrivate)) {
  710. input.ACL = obs.AclPrivate
  711. } else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) {
  712. input.ACL = obs.AclPublicRead
  713. } else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) {
  714. input.ACL = obs.AclPublicReadWrite
  715. } else {
  716. return errors.Error("unsupported acl")
  717. }
  718. }
  719. if len(storageClassStr) > 0 {
  720. input.StorageClass, err = str2StorageClass(storageClassStr)
  721. if err != nil {
  722. return err
  723. }
  724. }
  725. _, err = obsClient.CreateBucket(input)
  726. if err != nil {
  727. return errors.Wrap(err, "obsClient.CreateBucket")
  728. }
  729. region.client.invalidateIBuckets()
  730. return nil
  731. }
  732. func obsHttpCode(err error) int {
  733. switch httpErr := err.(type) {
  734. case obs.ObsError:
  735. return httpErr.StatusCode
  736. case *obs.ObsError:
  737. return httpErr.StatusCode
  738. }
  739. return -1
  740. }
  741. func (region *SRegion) DeleteIBucket(name string) error {
  742. obsClient, err := region.getOBSClient()
  743. if err != nil {
  744. return errors.Wrap(err, "region.getOBSClient")
  745. }
  746. _, err = obsClient.DeleteBucket(name)
  747. if err != nil {
  748. if obsHttpCode(err) == 404 {
  749. return nil
  750. }
  751. log.Debugf("%#v %s", err, err)
  752. return errors.Wrap(err, "DeleteBucket")
  753. }
  754. region.client.invalidateIBuckets()
  755. return nil
  756. }
  757. func (region *SRegion) HeadBucket(name string) (*obs.BaseModel, error) {
  758. obsClient, err := region.getOBSClient()
  759. if err != nil {
  760. return nil, errors.Wrap(err, "region.getOBSClient")
  761. }
  762. return obsClient.HeadBucket(name)
  763. }
  764. func (region *SRegion) IBucketExist(name string) (bool, error) {
  765. _, err := region.HeadBucket(name)
  766. if err != nil {
  767. if obsHttpCode(err) == 404 {
  768. return false, nil
  769. } else {
  770. return false, errors.Wrap(err, "HeadBucket")
  771. }
  772. }
  773. return true, nil
  774. }
  775. func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
  776. return cloudprovider.GetIBucketById(region, name)
  777. }
  778. func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
  779. return region.GetIBucketById(name)
  780. }
  781. func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
  782. if self.iskus != nil {
  783. return self.iskus, nil
  784. }
  785. ret := make([]cloudprovider.ICloudSku, 0)
  786. flavors, err := self.fetchInstanceTypes(zoneId)
  787. if err != nil {
  788. return nil, errors.Wrap(err, "fetchInstanceTypes")
  789. }
  790. for i := range flavors {
  791. ret = append(ret, &flavors[i])
  792. }
  793. self.iskus = ret
  794. return ret, nil
  795. }
  796. func (self *SRegion) GetICloudSku(skuId string) (cloudprovider.ICloudSku, error) {
  797. skus, err := self.GetSkus("")
  798. if err != nil {
  799. return nil, err
  800. }
  801. for i := range skus {
  802. if skus[i].GetId() == skuId {
  803. return skus[i], nil
  804. }
  805. }
  806. return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetICloudSku")
  807. }
  808. func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) {
  809. caches, err := self.GetElasticCaches()
  810. if err != nil {
  811. return nil, err
  812. }
  813. icaches := make([]cloudprovider.ICloudElasticcache, len(caches))
  814. for i := range caches {
  815. caches[i].region = self
  816. icaches[i] = &caches[i]
  817. }
  818. return icaches, nil
  819. }
  820. func (region *SRegion) GetCapabilities() []string {
  821. return region.client.GetCapabilities()
  822. }
  823. func (self *SRegion) GetDiskTypes() ([]SDiskType, error) {
  824. ret, err := self.ecsClient.Disks.GetDiskTypes()
  825. if err != nil {
  826. return nil, errors.Wrap(err, "GetDiskTypes")
  827. }
  828. dts := []SDiskType{}
  829. _ret := jsonutils.NewArray(ret.Data...)
  830. err = _ret.Unmarshal(&dts)
  831. if err != nil {
  832. return nil, errors.Wrap(err, "Unmarshal")
  833. }
  834. return dts, nil
  835. }
  836. func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) {
  837. dts, err := self.GetDiskTypes()
  838. if err != nil {
  839. return nil, errors.Wrap(err, "GetDiskTypes")
  840. }
  841. ret := []string{}
  842. for i := range dts {
  843. if dts[i].IsAvaliableInZone(zoneId) {
  844. ret = append(ret, dts[i].Name)
  845. }
  846. }
  847. return ret, nil
  848. }
  849. func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) {
  850. return self.GetSkus("")
  851. }
  852. func (self *SRegion) GetEndpoints() ([]jsonutils.JSONObject, error) {
  853. endpoints := make([]jsonutils.JSONObject, 0)
  854. err := doListAll(self.ecsClient.Endpoints.List, nil, &endpoints)
  855. if err != nil {
  856. return nil, err
  857. }
  858. return endpoints, nil
  859. }
  860. func (self *SRegion) GetServices() ([]jsonutils.JSONObject, error) {
  861. services := make([]jsonutils.JSONObject, 0)
  862. err := doListAll(self.ecsClient.Services.List, nil, &services)
  863. if err != nil {
  864. return nil, err
  865. }
  866. return services, nil
  867. }
  868. func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
  869. vms, err := region.GetInstances()
  870. if err != nil {
  871. return nil, errors.Wrap(err, "GetInstances")
  872. }
  873. ret := []cloudprovider.ICloudVM{}
  874. for i := range vms {
  875. ret = append(ret, &vms[i])
  876. }
  877. return ret, nil
  878. }