loadbalancer.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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 apsara
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  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 ListenerProtocol string
  28. const (
  29. ListenerProtocolTCP ListenerProtocol = "tcp"
  30. ListenerProtocolUDP ListenerProtocol = "udp"
  31. ListenerProtocolHTTP ListenerProtocol = "http"
  32. ListenerProtocolHTTPS ListenerProtocol = "https"
  33. )
  34. type ListenerPorts struct {
  35. ListenerPort []int
  36. }
  37. type ListenerPortsAndProtocol struct {
  38. ListenerPortAndProtocol []ListenerPortAndProtocol
  39. }
  40. type ListenerPortAndProtocol struct {
  41. Description string
  42. ListenerPort int
  43. ListenerProtocol ListenerProtocol
  44. }
  45. type BackendServers struct {
  46. BackendServer []SLoadbalancerDefaultBackend
  47. }
  48. type SLoadbalancer struct {
  49. multicloud.SLoadbalancerBase
  50. ApsaraTags
  51. region *SRegion
  52. LoadBalancerId string //负载均衡实例ID。
  53. LoadBalancerName string //负载均衡实例的名称。
  54. LoadBalancerStatus string //负载均衡实例状态:inactive: 此状态的实例监听不会再转发流量。active: 实例创建后,默认状态为active。 locked: 实例已经被锁定。
  55. Address string //负载均衡实例的服务地址。
  56. RegionId string //负载均衡实例的地域ID。
  57. RegionIdAlias string //负载均衡实例的地域名称。
  58. AddressType string //负载均衡实例的网络类型。
  59. VSwitchId string //私网负载均衡实例的交换机ID。
  60. VpcId string //私网负载均衡实例的专有网络ID。
  61. NetworkType string //私网负载均衡实例的网络类型:vpc:专有网络实例 classic:经典网络实例
  62. ListenerPorts ListenerPorts
  63. ListenerPortsAndProtocol ListenerPortsAndProtocol
  64. BackendServers BackendServers
  65. CreateTime time.Time //负载均衡实例的创建时间。
  66. MasterZoneId string //实例的主可用区ID。
  67. SlaveZoneId string //实例的备可用区ID。
  68. InternetChargeType TInternetChargeType //公网实例的计费方式。取值:paybybandwidth:按带宽计费 paybytraffic:按流量计费(默认值) 说明 当 PayType参数的值为PrePay时,只支持按带宽计费。
  69. PayType string //实例的计费类型,取值:PayOnDemand:按量付费 PrePay:预付费
  70. LoadBalancerSpec string //负载均衡实例的的性能规格
  71. Bandwidth int //按带宽计费的公网型实例的带宽峰值
  72. DepartmentInfo
  73. }
  74. func (lb *SLoadbalancer) GetName() string {
  75. return lb.LoadBalancerName
  76. }
  77. func (lb *SLoadbalancer) GetId() string {
  78. return lb.LoadBalancerId
  79. }
  80. func (lb *SLoadbalancer) GetGlobalId() string {
  81. return lb.LoadBalancerId
  82. }
  83. func (lb *SLoadbalancer) GetStatus() string {
  84. if lb.LoadBalancerStatus == "active" {
  85. return api.LB_STATUS_ENABLED
  86. }
  87. return api.LB_STATUS_DISABLED
  88. }
  89. func (lb *SLoadbalancer) GetTags() (map[string]string, error) {
  90. tags, err := lb.region.ListResourceTags("slb", "instance", []string{lb.GetId()})
  91. if err != nil {
  92. return nil, errors.Wrap(err, "lb.region.ListResourceTags")
  93. }
  94. if _, ok := tags[lb.GetId()]; !ok {
  95. return map[string]string{}, nil
  96. }
  97. return *tags[lb.GetId()], nil
  98. }
  99. func (lb *SLoadbalancer) GetAddress() string {
  100. return lb.Address
  101. }
  102. func (lb *SLoadbalancer) GetAddressType() string {
  103. return lb.AddressType
  104. }
  105. func (lb *SLoadbalancer) GetNetworkType() string {
  106. return lb.NetworkType
  107. }
  108. func (lb *SLoadbalancer) GetNetworkIds() []string {
  109. return []string{lb.VSwitchId}
  110. }
  111. func (lb *SLoadbalancer) GetZoneId() string {
  112. zone, err := lb.region.getZoneById(lb.MasterZoneId)
  113. if err != nil {
  114. log.Errorf("failed to find zone for lb %s error: %v", lb.LoadBalancerName, err)
  115. return ""
  116. }
  117. return zone.GetGlobalId()
  118. }
  119. func (self *SLoadbalancer) GetZone1Id() string {
  120. return ""
  121. }
  122. func (lb *SLoadbalancer) IsEmulated() bool {
  123. return false
  124. }
  125. func (lb *SLoadbalancer) GetVpcId() string {
  126. return lb.VpcId
  127. }
  128. func (lb *SLoadbalancer) Refresh() error {
  129. loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId)
  130. if err != nil {
  131. return err
  132. }
  133. return jsonutils.Update(lb, loadbalancer)
  134. }
  135. func (region *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) {
  136. params := map[string]string{}
  137. params["RegionId"] = region.RegionId
  138. if ids != nil && len(ids) > 0 {
  139. params["LoadBalancerId"] = strings.Join(ids, ",")
  140. }
  141. body, err := region.lbRequest("DescribeLoadBalancers", params)
  142. if err != nil {
  143. return nil, err
  144. }
  145. lbs := []SLoadbalancer{}
  146. return lbs, body.Unmarshal(&lbs, "LoadBalancers", "LoadBalancer")
  147. }
  148. func (region *SRegion) GetLoadbalancerDetail(loadbalancerId string) (*SLoadbalancer, error) {
  149. params := map[string]string{}
  150. params["RegionId"] = region.RegionId
  151. params["LoadBalancerId"] = loadbalancerId
  152. body, err := region.lbRequest("DescribeLoadBalancerAttribute", params)
  153. if err != nil {
  154. return nil, err
  155. }
  156. lb := SLoadbalancer{region: region}
  157. return &lb, body.Unmarshal(&lb)
  158. }
  159. func (lb *SLoadbalancer) Delete(ctx context.Context) error {
  160. params := map[string]string{}
  161. params["RegionId"] = lb.region.RegionId
  162. params["LoadBalancerId"] = lb.LoadBalancerId
  163. _, err := lb.region.lbRequest("DeleteLoadBalancer", params)
  164. return err
  165. }
  166. func (lb *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
  167. ibackendgroups := []cloudprovider.ICloudLoadbalancerBackendGroup{}
  168. {
  169. backendgroups, err := lb.region.GetLoadbalancerBackendgroups(lb.LoadBalancerId)
  170. if err != nil {
  171. return nil, err
  172. }
  173. for i := 0; i < len(backendgroups); i++ {
  174. backendgroups[i].lb = lb
  175. ibackendgroups = append(ibackendgroups, &backendgroups[i])
  176. }
  177. }
  178. {
  179. iDefaultBackendgroup := SLoadbalancerDefaultBackendGroup{lb: lb}
  180. ibackendgroups = append(ibackendgroups, &iDefaultBackendgroup)
  181. }
  182. {
  183. backendgroups, err := lb.region.GetLoadbalancerMasterSlaveBackendgroups(lb.LoadBalancerId)
  184. if err != nil {
  185. return nil, err
  186. }
  187. for i := 0; i < len(backendgroups); i++ {
  188. backendgroups[i].lb = lb
  189. ibackendgroups = append(ibackendgroups, &backendgroups[i])
  190. }
  191. }
  192. return ibackendgroups, nil
  193. }
  194. func (lb *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
  195. switch group.GroupType {
  196. case api.LB_BACKENDGROUP_TYPE_NORMAL:
  197. group, err := lb.region.CreateLoadbalancerBackendGroup(group.Name, lb.LoadBalancerId, group.Backends)
  198. if err != nil {
  199. return nil, err
  200. }
  201. group.lb = lb
  202. return group, nil
  203. case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE:
  204. group, err := lb.region.CreateLoadbalancerMasterSlaveBackendGroup(group.Name, lb.LoadBalancerId, group.Backends)
  205. if err != nil {
  206. return nil, err
  207. }
  208. group.lb = lb
  209. return group, nil
  210. default:
  211. return nil, fmt.Errorf("Unsupport backendgroup type %s", group.GroupType)
  212. }
  213. }
  214. func (lb *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListenerCreateOptions) (cloudprovider.ICloudLoadbalancerListener, error) {
  215. switch listener.ListenerType {
  216. case api.LB_LISTENER_TYPE_TCP:
  217. return lb.region.CreateLoadbalancerTCPListener(lb, listener)
  218. case api.LB_LISTENER_TYPE_UDP:
  219. return lb.region.CreateLoadbalancerUDPListener(lb, listener)
  220. case api.LB_LISTENER_TYPE_HTTP:
  221. return lb.region.CreateLoadbalancerHTTPListener(lb, listener)
  222. case api.LB_LISTENER_TYPE_HTTPS:
  223. return lb.region.CreateLoadbalancerHTTPSListener(lb, listener)
  224. }
  225. return nil, fmt.Errorf("unsupport listener type %s", listener.ListenerType)
  226. }
  227. func (lb *SLoadbalancer) GetLoadbalancerSpec() string {
  228. if len(lb.LoadBalancerSpec) == 0 {
  229. lb.Refresh()
  230. }
  231. return lb.LoadBalancerSpec
  232. }
  233. func (lb *SLoadbalancer) GetChargeType() string {
  234. switch lb.InternetChargeType {
  235. case "paybybandwidth":
  236. return api.LB_CHARGE_TYPE_BY_BANDWIDTH
  237. case "paybytraffic":
  238. return api.LB_CHARGE_TYPE_BY_TRAFFIC
  239. }
  240. return "unknown"
  241. }
  242. func (lb *SLoadbalancer) GetCreatedAt() time.Time {
  243. return lb.CreateTime
  244. }
  245. func (lb *SLoadbalancer) GetEgressMbps() int {
  246. if lb.Bandwidth < 1 {
  247. return 0
  248. }
  249. return lb.Bandwidth
  250. }
  251. func (lb *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
  252. groups, err := lb.GetILoadBalancerBackendGroups()
  253. if err != nil {
  254. return nil, err
  255. }
  256. for i := 0; i < len(groups); i++ {
  257. if groups[i].GetGlobalId() == groupId {
  258. return groups[i], nil
  259. }
  260. }
  261. return nil, cloudprovider.ErrNotFound
  262. }
  263. func (lb *SLoadbalancer) GetIEIPs() ([]cloudprovider.ICloudEIP, error) {
  264. if lb.AddressType == "internet" {
  265. eip := SEipAddress{
  266. region: lb.region,
  267. IpAddress: lb.Address,
  268. InstanceId: lb.GetGlobalId(),
  269. InstanceType: EIP_INTANNCE_TYPE_SLB,
  270. Status: EIP_STATUS_INUSE,
  271. AllocationId: lb.GetGlobalId(),
  272. AllocationTime: lb.CreateTime,
  273. Bandwidth: lb.Bandwidth,
  274. InternetChargeType: lb.InternetChargeType,
  275. }
  276. return []cloudprovider.ICloudEIP{&eip}, nil
  277. }
  278. eips, _, err := lb.region.GetEips("", lb.LoadBalancerId, 0, 1)
  279. if err != nil {
  280. return nil, errors.Wrapf(err, "lb.region.GetEips(%s)", lb.LoadBalancerId)
  281. }
  282. ret := []cloudprovider.ICloudEIP{}
  283. for i := range eips {
  284. eips[i].region = lb.region
  285. ret = append(ret, &eips[i])
  286. }
  287. return ret, nil
  288. }
  289. func (region *SRegion) loadbalancerOperation(loadbalancerId, status string) error {
  290. params := map[string]string{}
  291. params["RegionId"] = region.RegionId
  292. params["LoadBalancerId"] = loadbalancerId
  293. params["LoadBalancerStatus"] = status
  294. _, err := region.lbRequest("SetLoadBalancerStatus", params)
  295. return err
  296. }
  297. func (lb *SLoadbalancer) Start() error {
  298. if lb.LoadBalancerStatus != "active" {
  299. return lb.region.loadbalancerOperation(lb.LoadBalancerId, "active")
  300. }
  301. return nil
  302. }
  303. func (lb *SLoadbalancer) Stop() error {
  304. if lb.LoadBalancerStatus != "inactive" {
  305. return lb.region.loadbalancerOperation(lb.LoadBalancerId, "inactive")
  306. }
  307. return nil
  308. }
  309. func (lb *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) {
  310. listener, err := lb.GetILoadBalancerListeners()
  311. if err != nil {
  312. return nil, err
  313. }
  314. for i := 0; i < len(listener); i++ {
  315. if listener[i].GetGlobalId() == listenerId {
  316. return listener[i], nil
  317. }
  318. }
  319. return nil, cloudprovider.ErrNotFound
  320. }
  321. func (lb *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) {
  322. loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId)
  323. if err != nil {
  324. return nil, err
  325. }
  326. listeners := []cloudprovider.ICloudLoadbalancerListener{}
  327. for _, listenerInfo := range loadbalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol {
  328. switch listenerInfo.ListenerProtocol {
  329. case ListenerProtocolHTTP:
  330. listener, err := lb.region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
  331. if err != nil {
  332. return nil, err
  333. }
  334. listener.lb = lb
  335. listeners = append(listeners, listener)
  336. case ListenerProtocolHTTPS:
  337. listener, err := lb.region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
  338. if err != nil {
  339. return nil, err
  340. }
  341. listener.lb = lb
  342. listeners = append(listeners, listener)
  343. case ListenerProtocolTCP:
  344. listener, err := lb.region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
  345. if err != nil {
  346. return nil, err
  347. }
  348. listener.lb = lb
  349. listeners = append(listeners, listener)
  350. case ListenerProtocolUDP:
  351. listener, err := lb.region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
  352. if err != nil {
  353. return nil, err
  354. }
  355. listener.lb = lb
  356. listeners = append(listeners, listener)
  357. default:
  358. return nil, fmt.Errorf("failed to recognize %s type listener", listenerInfo.ListenerProtocol)
  359. }
  360. }
  361. return listeners, nil
  362. }
  363. func (lb *SLoadbalancer) SetTags(tags map[string]string, replace bool) error {
  364. return lb.region.SetResourceTags("slb", "instance", []string{lb.LoadBalancerId}, tags, replace)
  365. }