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