yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/loadbalancer_backendgroup.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 qcloud 16 17 import ( 18 "context" 19 "fmt" 20 "strconv" 21 "strings" 22 "time" 23 24 "yunion.io/x/pkg/errors" 25 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 ) 30 31 type SLBBackendGroup struct { 32 multicloud.SResourceBase 33 QcloudTags 34 lb *SLoadbalancer // 必须不能为nil 35 listener *SLBListener // 可能为nil 36 rule *SLBListenerRule // tcp、udp、tcp_ssl监听rule 为nil 37 } 38 39 func (self *SLBBackendGroup) GetLoadbalancerId() string { 40 return self.lb.GetId() 41 } 42 43 func (self *SLBBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { 44 return self.lb 45 } 46 47 func (self *SLBBackendGroup) GetProtocolType() string { 48 return "" 49 } 50 51 func (self *SLBBackendGroup) GetScheduler() string { 52 return "" 53 } 54 55 func (self *SLBBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { 56 return nil, nil 57 } 58 59 func (self *SLBBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { 60 return nil, nil 61 } 62 63 func (self *SLBBackendGroup) GetListenerId() string { 64 if self.listener != nil { 65 return self.listener.GetId() 66 } 67 68 return "" 69 } 70 71 // 返回requestid 72 func (self *SLBBackendGroup) appLBBackendServer(action string, serverId string, weight int, port int) (string, error) { 73 if len(serverId) == 0 { 74 return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") 75 } 76 77 params := map[string]string{ 78 "LoadBalancerId": self.lb.GetId(), 79 "ListenerId": self.GetListenerId(), 80 "Targets.0.InstanceId": serverId, 81 "Targets.0.Port": strconv.Itoa(port), 82 "Targets.0.Weight": strconv.Itoa(weight), 83 } 84 85 if self.rule != nil { 86 params["LocationId"] = self.rule.GetId() 87 } 88 89 resp, err := self.lb.region.clbRequest(action, params) 90 if err != nil { 91 return "", err 92 } 93 94 return resp.GetString("RequestId") 95 } 96 97 // deprecated 98 func (self *SLBBackendGroup) appLBSeventhBackendServer(action string, serverId string, weight int, port int) (string, error) { 99 if len(serverId) == 0 { 100 return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") 101 } 102 103 params := map[string]string{ 104 "loadBalancerId": self.lb.GetId(), 105 "listenerId": self.GetListenerId(), 106 "backends.0.InstanceId": serverId, 107 "backends.0.Port": strconv.Itoa(port), 108 "backends.0.Weight": strconv.Itoa(weight), 109 } 110 111 if self.rule != nil { 112 params["LocationId"] = self.rule.GetId() 113 } 114 115 resp, err := self.lb.region.clbRequest(action, params) 116 if err != nil { 117 return "", err 118 } 119 120 return resp.GetString("RequestId") 121 } 122 123 // https://cloud.tencent.com/document/product/214/30677 124 func (self *SLBBackendGroup) updateBackendServerWeight(action string, serverId string, weight int, port int) (string, error) { 125 if len(serverId) == 0 { 126 return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") 127 } 128 129 params := map[string]string{ 130 "LoadBalancerId": self.lb.GetId(), 131 "ListenerId": self.GetListenerId(), 132 "Targets.0.InstanceId": serverId, 133 "Targets.0.Port": strconv.Itoa(port), 134 "Targets.0.Weight": strconv.Itoa(weight), 135 } 136 137 if self.rule != nil { 138 params["LocationId"] = self.rule.GetId() 139 } 140 141 resp, err := self.lb.region.clbRequest(action, params) 142 if err != nil { 143 return "", err 144 } 145 146 return resp.GetString("RequestId") 147 } 148 149 // https://cloud.tencent.com/document/product/214/30678 150 func (self *SLBBackendGroup) updateBackendServerPort(action string, serverId string, oldPort int, newPort int) (string, error) { 151 if len(serverId) == 0 { 152 return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") 153 } 154 155 params := map[string]string{ 156 "LoadBalancerId": self.lb.GetId(), 157 "ListenerId": self.GetListenerId(), 158 "Targets.0.InstanceId": serverId, 159 "Targets.0.Port": strconv.Itoa(oldPort), 160 "NewPort": strconv.Itoa(newPort), 161 } 162 163 if self.rule != nil { 164 params["LocationId"] = self.rule.GetId() 165 } 166 167 resp, err := self.lb.region.clbRequest(action, params) 168 if err != nil { 169 return "", err 170 } 171 172 return resp.GetString("RequestId") 173 } 174 175 // 返回requestid 176 // https://cloud.tencent.com/document/api/214/1264 177 func (self *SLBBackendGroup) classicLBBackendServer(action string, serverId string, weight int, port int) (string, error) { 178 // 传统型负载均衡忽略了port参数 179 params := map[string]string{ 180 "LoadBalancerId": self.lb.GetId(), 181 "Targets.0.InstanceId": serverId, 182 "Targets.0.Weight": strconv.Itoa(weight), 183 } 184 185 resp, err := self.lb.region.clbRequest(action, params) 186 if err != nil { 187 return "", err 188 } 189 190 return resp.GetString("RequestId") 191 } 192 193 // https://cloud.tencent.com/document/product/214/30676 194 // https://cloud.tencent.com/document/product/214/31789 195 func (self *SLBBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { 196 var requestId string 197 var err error 198 if self.lb.Forward == LB_TYPE_APPLICATION { 199 requestId, err = self.appLBBackendServer("RegisterTargets", serverId, weight, port) 200 } else { 201 requestId, err = self.classicLBBackendServer("RegisterTargetsWithClassicalLB", serverId, weight, port) 202 } 203 204 if err != nil { 205 return nil, err 206 } 207 208 err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) 209 if err != nil { 210 return nil, err 211 } 212 213 err = self.Refresh() 214 if err != nil { 215 return nil, err 216 } 217 218 backends, err := self.GetBackends() 219 if err != nil { 220 return nil, err 221 } 222 223 for _, backend := range backends { 224 if strings.HasSuffix(backend.GetId(), fmt.Sprintf("%s-%d", serverId, port)) { 225 return &backend, nil 226 } 227 } 228 229 return nil, cloudprovider.ErrNotFound 230 } 231 232 // https://cloud.tencent.com/document/product/214/30687 233 // https://cloud.tencent.com/document/product/214/31794 234 func (self *SLBBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { 235 _, err := self.lb.region.GetInstance(serverId) 236 if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { 237 return nil 238 } 239 240 var requestId string 241 if self.lb.Forward == LB_TYPE_APPLICATION { 242 requestId, err = self.appLBBackendServer("DeregisterTargets", serverId, weight, port) 243 } else { 244 requestId, err = self.classicLBBackendServer("DeregisterTargetsFromClassicalLB", serverId, weight, port) 245 } 246 247 if err != nil { 248 if strings.Contains(err.Error(), "not registered") { 249 return nil 250 } 251 return err 252 } 253 254 return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) 255 } 256 257 func (self *SLBBackendGroup) UpdateBackendServer(serverId string, oldWeight, oldPort, weight, newPort int) error { 258 var requestId string 259 var err error 260 // if self.lb.Forward == LB_TYPE_APPLICATION { 261 // // https://cloud.tencent.com/document/product/214/30678 262 // // https://cloud.tencent.com/document/product/214/30677 263 // if self.listener.Protocol == api.LB_LISTENER_TYPE_HTTPS || self.listener.Protocol == api.LB_LISTENER_TYPE_HTTP { 264 // requestId, err = self.appLBSeventhBackendServer("ModifyForwardSeventhBackends", serverId, weight, port) 265 // } else { 266 // requestId, err = self.appLBBackendServer("ModifyForwardFourthBackendsWeight", serverId, weight, port) 267 // } 268 // } else { 269 // requestId, err = self.classicLBBackendServer("ModifyLoadBalancerBackends", serverId, weight, port) 270 // } 271 if oldWeight != weight { 272 requestId, err = self.updateBackendServerWeight("ModifyTargetWeight", serverId, weight, oldPort) 273 if err != nil { 274 if strings.Contains(err.Error(), "not registered") { 275 return nil 276 } 277 return errors.Wrap(err, "LBBackendGroup.updateBackendServerWeight") 278 } 279 280 err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) 281 if err != nil { 282 return errors.Wrap(err, "LBBackendGroup.updateBackendServerWeight.WaitLBTaskSuccess") 283 } 284 } 285 286 if oldPort != newPort { 287 requestId, err = self.updateBackendServerPort("ModifyTargetPort", serverId, oldPort, newPort) 288 if err != nil { 289 if strings.Contains(err.Error(), "not registered") { 290 return nil 291 } 292 return errors.Wrap(err, "LBBackendGroup.updateBackendServerPort") 293 } 294 295 err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) 296 if err != nil { 297 return errors.Wrap(err, "LBBackendGroup.updateBackendServerPort.WaitLBTaskSuccess") 298 } 299 } 300 301 return nil 302 } 303 304 // 腾讯云无后端服务器组。 305 func (self *SLBBackendGroup) Delete(ctx context.Context) error { 306 return fmt.Errorf("Please remove related listener/rule frist") 307 } 308 309 // 腾讯云无后端服务器组 310 func (self *SLBBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { 311 return nil 312 } 313 314 func backendGroupIdGen(lbid string, secondId string) string { 315 if len(secondId) > 0 { 316 return fmt.Sprintf("%s", secondId) 317 } else { 318 return lbid 319 } 320 } 321 322 func (self *SLBBackendGroup) GetId() string { 323 t := "" 324 if self.listener != nil { 325 t = self.listener.GetListenerType() 326 } 327 328 if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { 329 // http https 后端服务器只与规则绑定 330 return backendGroupIdGen(self.lb.GetId(), self.rule.GetId()) 331 } else if self.lb.Forward == LB_TYPE_APPLICATION { 332 return backendGroupIdGen(self.lb.GetId(), self.GetListenerId()) 333 } else { 334 // 传统型lb 所有监听共用一个后端服务器组 335 return backendGroupIdGen(self.lb.GetId(), "") 336 } 337 } 338 339 func (self *SLBBackendGroup) GetName() string { 340 return self.GetId() 341 } 342 343 func (self *SLBBackendGroup) GetGlobalId() string { 344 return self.GetId() 345 } 346 347 func (self *SLBBackendGroup) GetStatus() string { 348 return api.LB_STATUS_ENABLED 349 } 350 351 func (self *SLBBackendGroup) Refresh() error { 352 return nil 353 } 354 355 // note: model没有更新这个字段? 356 func (self *SLBBackendGroup) IsEmulated() bool { 357 return true 358 } 359 360 func (self *SLBBackendGroup) IsDefault() bool { 361 return false 362 } 363 364 func (self *SLBBackendGroup) GetType() string { 365 return api.LB_BACKENDGROUP_TYPE_NORMAL 366 } 367 368 func (self *SLBBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { 369 backends, err := self.GetBackends() 370 if err != nil { 371 return nil, err 372 } 373 374 ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends)) 375 for i := range backends { 376 backends[i].group = self 377 ibackends[i] = &backends[i] 378 } 379 380 return ibackends, nil 381 } 382 383 func (self *SLBBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { 384 backends, err := self.GetILoadbalancerBackends() 385 if err != nil { 386 return nil, err 387 } 388 for i := 0; i < len(backends); i++ { 389 if backends[i].GetGlobalId() == backendId { 390 return backends[i], nil 391 } 392 } 393 return nil, cloudprovider.ErrNotFound 394 } 395 396 func (self *SLBBackendGroup) GetBackends() ([]SLBBackend, error) { 397 backends := []SLBBackend{} 398 var err error 399 if self.rule != nil { 400 // http、https监听 401 backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.GetListenerId(), self.rule.GetId()) 402 if err != nil { 403 return nil, err 404 } 405 } else { 406 // tcp,udp,tcp_ssl监听 407 backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.GetListenerId(), "") 408 if err != nil { 409 return nil, err 410 } 411 } 412 413 for i := range backends { 414 backends[i].group = self 415 } 416 417 return backends, nil 418 } 419 420 func (self *SLBBackendGroup) GetProjectId() string { 421 return self.lb.GetProjectId() 422 }