eip.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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 ksyun
  15. import (
  16. "fmt"
  17. "strings"
  18. "time"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
  23. api "yunion.io/x/cloudmux/pkg/apis/compute"
  24. "yunion.io/x/cloudmux/pkg/cloudprovider"
  25. "yunion.io/x/cloudmux/pkg/multicloud"
  26. )
  27. type SEipResp struct {
  28. RequestID string `json:"RequestId"`
  29. NextToken string `json:"NextToken"`
  30. AddressesSet []SEip `json:"AddressesSet"`
  31. TotalCount int `json:"TotalCount"`
  32. }
  33. type SEip struct {
  34. multicloud.SEipBase
  35. region *SRegion
  36. SKsyunTags
  37. PublicIP string `json:"PublicIp"`
  38. AllocationId string `json:"AllocationId"`
  39. State string `json:"State"`
  40. IPState string `json:"IpState"`
  41. LineId string `json:"LineId"`
  42. BandWidth int `json:"BandWidth"`
  43. InstanceType string `json:"InstanceType"`
  44. InstanceId string `json:"InstanceId"`
  45. ChargeType string `json:"ChargeType"`
  46. IPVersion string `json:"IpVersion"`
  47. ProjectId string `json:"ProjectId"`
  48. CreateTime string `json:"CreateTime"`
  49. Mode string `json:"Mode"`
  50. NetworkInterfaceId string `json:"NetworkInterfaceId,omitempty"`
  51. NetworkInterfaceType string `json:"NetworkInterfaceType,omitempty"`
  52. PrivateIPAddress string `json:"PrivateIpAddress,omitempty"`
  53. InternetGatewayId string `json:"InternetGatewayId,omitempty"`
  54. HostType string `json:"HostType,omitempty"`
  55. }
  56. func (region *SRegion) GetEips(eipIds []string) ([]SEip, error) {
  57. params := map[string]interface{}{
  58. "MaxResults": "1000",
  59. }
  60. for i, eipId := range eipIds {
  61. params[fmt.Sprintf("AllocationId.%d", i+1)] = eipId
  62. }
  63. res := []SEip{}
  64. for {
  65. resp, err := region.eipRequest("DescribeAddresses", params)
  66. if err != nil {
  67. return nil, errors.Wrap(err, "get eips")
  68. }
  69. part := SEipResp{}
  70. err = resp.Unmarshal(&part)
  71. if err != nil {
  72. return nil, errors.Wrap(err, "unmarshal eip")
  73. }
  74. res = append(res, part.AddressesSet...)
  75. if len(part.NextToken) == 0 {
  76. break
  77. }
  78. params["NextToken"] = part.NextToken
  79. }
  80. return res, nil
  81. }
  82. func (region *SRegion) GetEip(eipId string) (*SEip, error) {
  83. eips, err := region.GetEips([]string{eipId})
  84. if err != nil {
  85. return nil, errors.Wrap(err, "GetEips")
  86. }
  87. for _, eip := range eips {
  88. if eip.GetId() == eipId {
  89. return &eip, nil
  90. }
  91. }
  92. return nil, errors.Wrapf(errors.ErrNotFound, "eip id:%s", eipId)
  93. }
  94. func (eip *SEip) GetId() string {
  95. return eip.AllocationId
  96. }
  97. func (eip *SEip) GetName() string {
  98. return eip.AllocationId
  99. }
  100. func (eip *SEip) GetGlobalId() string {
  101. return eip.AllocationId
  102. }
  103. func (eip *SEip) GetTags() (map[string]string, error) {
  104. tags, err := eip.region.ListTags("eip", eip.AllocationId)
  105. if err != nil {
  106. return nil, err
  107. }
  108. return tags.GetTags(), nil
  109. }
  110. func (eip *SEip) SetTags(tags map[string]string, replace bool) error {
  111. return eip.region.SetResourceTags("eip", eip.AllocationId, tags, replace)
  112. }
  113. func (eip *SEip) GetStatus() string {
  114. switch eip.State {
  115. case "associate":
  116. return api.EIP_STATUS_READY
  117. case "disassociate":
  118. return api.EIP_STATUS_READY
  119. default:
  120. return api.EIP_STATUS_UNKNOWN
  121. }
  122. }
  123. func (eip *SEip) Refresh() error {
  124. extEip, err := eip.region.GetEip(eip.AllocationId)
  125. if err != nil {
  126. return errors.Wrap(err, "region.GetEip")
  127. }
  128. return jsonutils.Update(eip, &extEip)
  129. }
  130. func (eip *SEip) GetIpAddr() string {
  131. return eip.PublicIP
  132. }
  133. func (eip *SEip) GetMode() string {
  134. return api.EIP_MODE_STANDALONE_EIP
  135. }
  136. func (eip *SEip) GetAssociationType() string {
  137. switch eip.InstanceType {
  138. case "Ipfwd":
  139. return api.EIP_ASSOCIATE_TYPE_SERVER
  140. case "Slb":
  141. return api.EIP_ASSOCIATE_TYPE_LOADBALANCER
  142. default:
  143. return eip.InstanceType
  144. }
  145. }
  146. func (eip *SEip) GetAssociationExternalId() string {
  147. return eip.InstanceId
  148. }
  149. func (eip *SEip) GetBandwidth() int {
  150. return int(eip.BandWidth) // Mb
  151. }
  152. func (eip *SEip) GetINetworkId() string {
  153. return ""
  154. }
  155. func (eip *SEip) GetInternetChargeType() string {
  156. if eip.ChargeType == "Monthly" {
  157. return api.EIP_CHARGE_TYPE_BY_BANDWIDTH
  158. }
  159. return api.EIP_CHARGE_TYPE_BY_TRAFFIC
  160. }
  161. func (eip *SEip) GetBillingType() string {
  162. if eip.ChargeType == "Monthly" {
  163. return billing_api.BILLING_TYPE_PREPAID
  164. }
  165. return billing_api.BILLING_TYPE_POSTPAID
  166. }
  167. func (eip *SEip) GetCreatedAt() time.Time {
  168. createdAt, _ := time.Parse("2006-01-02 15:04:05", eip.CreateTime)
  169. return createdAt
  170. }
  171. func (eip *SEip) GetExpiredAt() time.Time {
  172. return time.Time{}
  173. }
  174. func (eip *SEip) Delete() error {
  175. return eip.region.DeallocateEIP(eip.AllocationId)
  176. }
  177. func (eip *SEip) Associate(conf *cloudprovider.AssociateConfig) error {
  178. return eip.region.AssociateEip(eip.AllocationId, conf.InstanceId)
  179. }
  180. func (eip *SEip) Dissociate() error {
  181. return eip.region.DissociateEip(eip.AllocationId)
  182. }
  183. func (eip *SEip) ChangeBandwidth(bw int) error {
  184. return cloudprovider.ErrNotImplemented
  185. }
  186. func (region *SRegion) DeallocateEIP(eipId string) error {
  187. params := map[string]interface{}{
  188. "AllocationId": eipId,
  189. }
  190. _, err := region.eipRequest("ReleaseAddress", params)
  191. return err
  192. }
  193. func (region *SRegion) AssociateEip(eipId string, instanceId string) error {
  194. params := map[string]interface{}{
  195. "AllocationId": eipId,
  196. "InstanceId": instanceId,
  197. "InstanceType": "Ipfwd",
  198. }
  199. vm, err := region.GetInstance(instanceId)
  200. if err != nil {
  201. return errors.Wrap(err, "GetInstance")
  202. }
  203. for _, nic := range vm.NetworkInterfaceSet {
  204. if len(nic.AllocationId) == 0 {
  205. params["NetworkInterfaceId"] = nic.NetworkInterfaceId
  206. break
  207. }
  208. }
  209. _, err = region.eipRequest("AssociateAddress", params)
  210. return err
  211. }
  212. func (region *SRegion) DissociateEip(eipId string) error {
  213. params := map[string]interface{}{
  214. "AllocationId": eipId,
  215. }
  216. _, err := region.eipRequest("DisassociateAddress", params)
  217. return err
  218. }
  219. func (eip *SEip) GetProjectId() string {
  220. return eip.ProjectId
  221. }
  222. func (region *SRegion) CreateEip(opts *cloudprovider.SEip) (*SEip, error) {
  223. lines, err := region.GetLines()
  224. if err != nil {
  225. return nil, errors.Wrap(err, "GetLines")
  226. }
  227. lineId := ""
  228. for i := range lines {
  229. if strings.Contains(lines[i].LineName, "BGP") {
  230. lineId = lines[i].LineId
  231. break
  232. }
  233. }
  234. if len(lineId) == 0 {
  235. return nil, errors.Wrap(errors.ErrNotFound, "No bgp lines found")
  236. }
  237. params := map[string]interface{}{
  238. "LineId": lineId,
  239. "BandWidth": fmt.Sprintf("%d", opts.BandwidthMbps),
  240. }
  241. chargeTypes := []string{}
  242. if opts.ChargeType == api.EIP_CHARGE_TYPE_BY_BANDWIDTH {
  243. chargeTypes = append(chargeTypes, "Monthly")
  244. params["PurchaseTime"] = "1"
  245. } else {
  246. chargeTypes = append(chargeTypes, "TrafficMonthly")
  247. chargeTypes = append(chargeTypes, "DailyPaidByTransfer")
  248. }
  249. ret := &SEip{region: region}
  250. var body jsonutils.JSONObject
  251. for _, chargeType := range chargeTypes {
  252. params["ChargeType"] = chargeType
  253. body, err = region.eipRequest("AllocateAddress", params)
  254. if err != nil {
  255. log.Debugf("not support charge type %s, error: %v", chargeType, err)
  256. if e, ok := err.(*sKsyunError); ok && e.ErrorMsg.Code == "PackageNotExists" {
  257. continue
  258. }
  259. return nil, errors.Wrap(err, "AllocateAddress")
  260. }
  261. err = body.Unmarshal(ret)
  262. if err != nil {
  263. return nil, errors.Wrap(err, "Unmarshal")
  264. }
  265. }
  266. if err != nil {
  267. return nil, errors.Wrap(err, "AllocateAddress")
  268. }
  269. if len(opts.Tags) > 0 {
  270. err = region.CreateTags("eip", ret.AllocationId, opts.Tags)
  271. if err != nil {
  272. log.Errorf("set tags %s to eip %s failed: %v", opts.Tags, ret.AllocationId, err)
  273. }
  274. }
  275. return ret, nil
  276. }
  277. type SLine struct {
  278. LineId string `json:"LineId"`
  279. LineName string `json:"LineName"`
  280. }
  281. func (region *SRegion) GetLines() ([]SLine, error) {
  282. params := map[string]interface{}{}
  283. body, err := region.eipRequest("GetLines", params)
  284. if err != nil {
  285. return nil, errors.Wrap(err, "GetLines")
  286. }
  287. ret := []SLine{}
  288. err = body.Unmarshal(&ret, "LineSet")
  289. if err != nil {
  290. return nil, errors.Wrap(err, "Unmarshal")
  291. }
  292. return ret, nil
  293. }