mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #1017 in YUNIONIO/onecloud from ~TANGBIN/onecloud:feature/tb-qcloud-loadbalance-sync to release/2.6.0
* commit '8fdc9ec93d7be882b988899617c403ae90af7f4d': add qcloud driver lb sync method && add comment bugfix & comment fix backend group sync bugfix make fmt add sync add sync getNetworkOfIPOnHost fix getNetworkOfIPOnHost fix add loadbalancer operation method && qcloud GetINetwork fix add loadbalancer operation method create init impement method fix impement method fix impement method fix qcloud loadbalance sync
This commit is contained in:
@@ -2133,7 +2133,7 @@ func getCloudNicNetwork(vnic cloudprovider.ICloudNic, host *SHost) (*SNetwork, e
|
||||
return nil, fmt.Errorf("Cannot find inetwork for vnics %s %s", vnic.GetMAC(), vnic.GetIP())
|
||||
} else {
|
||||
// find network by IP
|
||||
return host.getNetworkOfIPOnHost(vnic.GetIP())
|
||||
return host.getNetworkOfIPOnHost(ip)
|
||||
}
|
||||
}
|
||||
localNetObj, err := NetworkManager.FetchByExternalId(vnet.GetGlobalId())
|
||||
|
||||
@@ -1670,15 +1670,15 @@ func (self *SHost) SyncHostVMs(ctx context.Context, userCred mcclient.TokenCrede
|
||||
}
|
||||
|
||||
func (self *SHost) getNetworkOfIPOnHost(ipAddr string) (*SNetwork, error) {
|
||||
net, err := NetworkManager.GetNetworkOfIP(ipAddr, "", tristate.None)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
netInterfaces := self.GetNetInterfaces()
|
||||
for _, netInterface := range netInterfaces {
|
||||
network, err := netInterface.GetCandidateNetworkForIp(auth.AdminCredential(), ipAddr)
|
||||
if err == nil && network != nil {
|
||||
return network, nil
|
||||
}
|
||||
}
|
||||
hw := self.getHostwireOfId(net.WireId)
|
||||
if hw == nil {
|
||||
return nil, fmt.Errorf("IP %s not reachable on this host", ipAddr)
|
||||
}
|
||||
return net, nil
|
||||
|
||||
return nil, fmt.Errorf("IP %s not reachable on this host", ipAddr)
|
||||
}
|
||||
|
||||
func (self *SHost) GetNetinterfaceWithIdAndCredential(netId string, userCred mcclient.TokenCredential, reserved bool) (*SNetInterface, *SNetwork) {
|
||||
|
||||
@@ -181,6 +181,7 @@ var LB_HEALTH_CHECK_TYPES_UDP = validators.NewChoices(
|
||||
)
|
||||
|
||||
const (
|
||||
LB_HEALTH_CHECK_HTTP_CODE_1xx = "http_1xx"
|
||||
LB_HEALTH_CHECK_HTTP_CODE_2xx = "http_2xx"
|
||||
LB_HEALTH_CHECK_HTTP_CODE_3xx = "http_3xx"
|
||||
LB_HEALTH_CHECK_HTTP_CODE_4xx = "http_4xx"
|
||||
@@ -189,6 +190,7 @@ const (
|
||||
)
|
||||
|
||||
var LB_HEALTH_CHECK_HTTP_CODES = validators.NewChoices(
|
||||
LB_HEALTH_CHECK_HTTP_CODE_1xx,
|
||||
LB_HEALTH_CHECK_HTTP_CODE_2xx,
|
||||
LB_HEALTH_CHECK_HTTP_CODE_3xx,
|
||||
LB_HEALTH_CHECK_HTTP_CODE_4xx,
|
||||
|
||||
@@ -177,27 +177,54 @@ func (lbbg *SLoadbalancerBackendGroup) GetIRegion() (cloudprovider.ICloudRegion,
|
||||
return nil, fmt.Errorf("failed to find loadbalancer for backendgroup %s", lbbg.Name)
|
||||
}
|
||||
|
||||
func (lbbg *SLoadbalancerBackendGroup) GetBackends() ([]SLoadbalancerBackend, error) {
|
||||
backends := make([]SLoadbalancerBackend, 0)
|
||||
q := LoadbalancerBackendManager.Query()
|
||||
err := q.Equals("backend_group_id", lbbg.GetId()).All(&backends)
|
||||
return backends, err
|
||||
}
|
||||
|
||||
// 返回值 TotalRef
|
||||
func (lbbg *SLoadbalancerBackendGroup) RefCount() int {
|
||||
men := lbbg.getRefManagers()
|
||||
var count int
|
||||
for _, m := range men {
|
||||
count += lbbg.refCount(m)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func (lbbg *SLoadbalancerBackendGroup) refCount(men db.IModelManager) int {
|
||||
t := men.TableSpec().Instance()
|
||||
pdF := t.Field("pending_deleted")
|
||||
return t.Query().
|
||||
Equals("backend_group_id", lbbg.Id).
|
||||
Filter(sqlchemy.OR(sqlchemy.IsNull(pdF), sqlchemy.IsFalse(pdF))).
|
||||
Count()
|
||||
}
|
||||
|
||||
func (lbbg *SLoadbalancerBackendGroup) getRefManagers() []db.IModelManager {
|
||||
// 引用Backend Group的数据库
|
||||
return []db.IModelManager{
|
||||
LoadbalancerManager,
|
||||
LoadbalancerListenerManager,
|
||||
LoadbalancerListenerRuleManager,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (lbbg *SLoadbalancerBackendGroup) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (lbbg *SLoadbalancerBackendGroup) ValidateDeleteCondition(ctx context.Context) error {
|
||||
men := []db.IModelManager{
|
||||
LoadbalancerManager,
|
||||
LoadbalancerListenerManager,
|
||||
LoadbalancerListenerRuleManager,
|
||||
}
|
||||
lbbgId := lbbg.Id
|
||||
for _, man := range men {
|
||||
t := man.TableSpec().Instance()
|
||||
pdF := t.Field("pending_deleted")
|
||||
n := t.Query().
|
||||
Equals("backend_group_id", lbbgId).
|
||||
Filter(sqlchemy.OR(sqlchemy.IsNull(pdF), sqlchemy.IsFalse(pdF))).
|
||||
Count()
|
||||
men := lbbg.getRefManagers()
|
||||
for _, m := range men {
|
||||
n := lbbg.refCount(m)
|
||||
if n > 0 {
|
||||
return fmt.Errorf("backend group %s is still referred to by %d %s",
|
||||
lbbgId, n, man.KeywordPlural())
|
||||
lbbg.Id, n, m.KeywordPlural())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +389,11 @@ func (man *SLoadbalancerBackendGroupManager) SyncLoadbalancerBackendgroups(ctx c
|
||||
}
|
||||
|
||||
func (lbbg *SLoadbalancerBackendGroup) constructFieldsFromCloudBackendgroup(lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup) {
|
||||
lbbg.Name = extLoadbalancerBackendgroup.GetName()
|
||||
// 对于腾讯云,backend group 名字以本地为准
|
||||
if lbbg.GetProviderName() != CLOUD_PROVIDER_QCLOUD || len(lbbg.Name) == 0 {
|
||||
lbbg.Name = extLoadbalancerBackendgroup.GetName()
|
||||
}
|
||||
|
||||
lbbg.Type = extLoadbalancerBackendgroup.GetType()
|
||||
lbbg.Status = extLoadbalancerBackendgroup.GetStatus()
|
||||
}
|
||||
@@ -397,8 +428,10 @@ func (man *SLoadbalancerBackendGroupManager) newFromCloudLoadbalancerBackendgrou
|
||||
lbbg.LoadbalancerId = lb.Id
|
||||
lbbg.ExternalId = extLoadbalancerBackendgroup.GetGlobalId()
|
||||
|
||||
lbbg.constructFieldsFromCloudBackendgroup(lb, extLoadbalancerBackendgroup)
|
||||
lbbg.CloudregionId = lb.CloudregionId
|
||||
lbbg.ManagerId = lb.ManagerId
|
||||
|
||||
lbbg.constructFieldsFromCloudBackendgroup(lb, extLoadbalancerBackendgroup)
|
||||
lbbg.ProjectId = userCred.GetProjectId()
|
||||
if len(projectId) > 0 {
|
||||
lbbg.ProjectId = projectId
|
||||
|
||||
@@ -251,6 +251,7 @@ func (lbb *SLoadbalancerBackend) StartLoadBalancerBackendDeleteTask(ctx context.
|
||||
func (man *SLoadbalancerBackendManager) getLoadbalancerBackendsByLoadbalancerBackendgroup(loadbalancerBackendgroup *SLoadbalancerBackendGroup) ([]SLoadbalancerBackend, error) {
|
||||
loadbalancerBackends := []SLoadbalancerBackend{}
|
||||
q := man.Query().Equals("backend_group_id", loadbalancerBackendgroup.Id)
|
||||
q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("pending_deleted")), sqlchemy.IsFalse(q.Field("pending_deleted"))))
|
||||
if err := db.FetchModelObjects(man, q, &loadbalancerBackends); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -298,7 +299,7 @@ func (man *SLoadbalancerBackendManager) SyncLoadbalancerBackends(ctx context.Con
|
||||
syncResult.Delete()
|
||||
}
|
||||
} else {
|
||||
err = removed[i].Delete(ctx, userCred)
|
||||
err = removed[i].PendingDelete()
|
||||
if err != nil {
|
||||
syncResult.DeleteError(err)
|
||||
} else {
|
||||
@@ -367,6 +368,9 @@ func (man *SLoadbalancerBackendManager) newFromCloudLoadbalancerBackend(ctx cont
|
||||
lbb.BackendGroupId = loadbalancerBackendgroup.Id
|
||||
lbb.ExternalId = extLoadbalancerBackend.GetGlobalId()
|
||||
|
||||
lbb.CloudregionId = loadbalancerBackendgroup.CloudregionId
|
||||
lbb.ManagerId = loadbalancerBackendgroup.ManagerId
|
||||
|
||||
if err := lbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ type SLoadbalancerListenerRule struct {
|
||||
Domain string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
|
||||
Path string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
|
||||
|
||||
SLoadbalancerHealthCheck // 目前只有腾讯云HTTP、HTTPS类型的健康检查是和规则绑定的。
|
||||
SLoadbalancerHTTPRateLimiter
|
||||
}
|
||||
|
||||
@@ -116,9 +117,17 @@ func (man *SLoadbalancerListenerRuleManager) ValidateCreateData(ctx context.Cont
|
||||
return nil, fmt.Errorf("listener type must be http/https, got %s", listenerType)
|
||||
}
|
||||
{
|
||||
if backendGroup, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && backendGroup.LoadbalancerId != listener.LoadbalancerId {
|
||||
if lbbg, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != listener.LoadbalancerId {
|
||||
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
|
||||
backendGroup.Name, backendGroup.Id, backendGroup.LoadbalancerId, listener.LoadbalancerId)
|
||||
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, listener.LoadbalancerId)
|
||||
} else {
|
||||
// 腾讯云backend group只能1v1关联
|
||||
if listener.GetProviderName() == CLOUD_PROVIDER_QCLOUD {
|
||||
count := lbbg.RefCount()
|
||||
if count > 0 {
|
||||
return nil, fmt.Errorf("backendgroup already related with other listener/rule")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err := loadbalancerListenerRuleCheckUniqueness(ctx, listener, domainV.Value, pathV.Value)
|
||||
@@ -334,6 +343,18 @@ func (lbr *SLoadbalancerListenerRule) constructFieldsFromCloudListenerRule(extRu
|
||||
lbr.Domain = extRule.GetDomain()
|
||||
lbr.Path = extRule.GetPath()
|
||||
if groupId := extRule.GetBackendGroupId(); len(groupId) > 0 {
|
||||
// 腾讯云兼容代码。主要目的是在关联listener rule时回写一个fake的backend group external id
|
||||
if len(groupId) > 0 && len(lbr.BackendGroupId) > 0 {
|
||||
ilbbg, err := LoadbalancerBackendGroupManager.FetchById(lbr.BackendGroupId)
|
||||
lbbg := ilbbg.(*SLoadbalancerBackendGroup)
|
||||
if err == nil && (len(lbbg.ExternalId) == 0 || lbbg.ExternalId != groupId) {
|
||||
err = lbbg.SetExternalId(groupId)
|
||||
if err != nil {
|
||||
log.Errorf("Update loadbalancer BackendGroup(%s) external id failed: %s", lbbg.GetId(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if backendgroup, err := LoadbalancerBackendGroupManager.FetchByExternalId(groupId); err == nil {
|
||||
lbr.BackendGroupId = backendgroup.GetId()
|
||||
}
|
||||
|
||||
@@ -42,6 +42,23 @@ type SLoadbalancerHTTPRateLimiter struct {
|
||||
HTTPRequestRatePerSrc int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
}
|
||||
|
||||
type SLoadbalancerHealthCheck struct {
|
||||
HealthCheck string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
|
||||
HealthCheckDomain string `charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckURI string `charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckHttpCode string `charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
|
||||
HealthCheckRise int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckFall int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckTimeout int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckInterval int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
|
||||
HealthCheckReq string `list:"user" create:"optional" update:"user"`
|
||||
HealthCheckExp string `list:"user" create:"optional" update:"user"`
|
||||
}
|
||||
|
||||
type SLoadbalancerTCPListener struct{}
|
||||
type SLoadbalancerUDPListener struct{}
|
||||
|
||||
@@ -90,26 +107,12 @@ type SLoadbalancerListener struct {
|
||||
AclType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
AclId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
|
||||
HealthCheck string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
|
||||
HealthCheckDomain string `charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckURI string `charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckHttpCode string `charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
|
||||
HealthCheckRise int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckFall int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckTimeout int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
HealthCheckInterval int `nullable:"false" list:"user" create:"optional" update:"user"`
|
||||
|
||||
HealthCheckReq string `list:"user" create:"optional" update:"user"`
|
||||
HealthCheckExp string `list:"user" create:"optional" update:"user"`
|
||||
|
||||
SLoadbalancerTCPListener
|
||||
SLoadbalancerUDPListener
|
||||
SLoadbalancerHTTPListener
|
||||
SLoadbalancerHTTPSListener
|
||||
|
||||
SLoadbalancerHealthCheck
|
||||
SLoadbalancerHTTPRateLimiter
|
||||
}
|
||||
|
||||
@@ -218,9 +221,17 @@ func (man *SLoadbalancerListenerManager) ValidateCreateData(ctx context.Context,
|
||||
}
|
||||
}
|
||||
{
|
||||
if backendGroup, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && backendGroup.LoadbalancerId != lb.Id {
|
||||
if lbbg, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lb.Id {
|
||||
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
|
||||
backendGroup.Name, backendGroup.Id, backendGroup.LoadbalancerId, lb.Id)
|
||||
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lb.Id)
|
||||
} else {
|
||||
// 腾讯云backend group只能1v1关联
|
||||
if lb.GetProviderName() == CLOUD_PROVIDER_QCLOUD {
|
||||
count := lbbg.RefCount()
|
||||
if count > 0 {
|
||||
return nil, fmt.Errorf("backendgroup aready related with other listener/rule")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -763,6 +774,18 @@ func (lblis *SLoadbalancerListener) constructFieldsFromCloudListener(lb *SLoadba
|
||||
lblis.Gzip = extListener.GzipEnabled()
|
||||
}
|
||||
groupId := extListener.GetBackendGroupId()
|
||||
// 腾讯云兼容代码。主要目的是在关联listen时回写一个fake的backend group external id
|
||||
if len(groupId) > 0 && len(lblis.BackendGroupId) > 0 {
|
||||
ilbbg, err := LoadbalancerBackendGroupManager.FetchById(lblis.BackendGroupId)
|
||||
lbbg := ilbbg.(*SLoadbalancerBackendGroup)
|
||||
if err == nil && (len(lbbg.ExternalId) == 0 || lbbg.ExternalId != groupId) {
|
||||
err = lbbg.SetExternalId(groupId)
|
||||
if err != nil {
|
||||
log.Errorf("Update loadbalancer BackendGroup(%s) external id failed: %s", lbbg.GetId(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(groupId) == 0 {
|
||||
lblis.BackendGroupId = lb.BackendGroupId
|
||||
} else if group, err := LoadbalancerBackendGroupManager.FetchByExternalId(groupId); err == nil {
|
||||
|
||||
@@ -39,6 +39,7 @@ func init() {
|
||||
const (
|
||||
LB_CHARGE_TYPE_BY_TRAFFIC = "traffic"
|
||||
LB_CHARGE_TYPE_BY_BANDWIDTH = "bandwidth"
|
||||
LB_CHARGE_TYPE_BY_HOUR = "hour"
|
||||
)
|
||||
|
||||
// TODO build errors on pkg/httperrors/errors.go
|
||||
@@ -66,7 +67,8 @@ type SLoadbalancer struct {
|
||||
ChargeType string `list:"user" get:"user" create:"optional"`
|
||||
LoadbalancerSpec string `list:"user" get:"user" create:"optional"`
|
||||
|
||||
BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" update:"user"`
|
||||
BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" update:"user"`
|
||||
LBInfo jsonutils.JSONObject `charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional"`
|
||||
}
|
||||
|
||||
func (man *SLoadbalancerManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
|
||||
@@ -551,6 +553,10 @@ func (man *SLoadbalancerManager) newFromCloudLoadbalancer(ctx context.Context, u
|
||||
lb.ProjectId = provider.ProjectId
|
||||
}
|
||||
|
||||
if extLb.GetMetadata() != nil {
|
||||
lb.LBInfo = extLb.GetMetadata()
|
||||
}
|
||||
|
||||
if err := man.TableSpec().Insert(&lb); err != nil {
|
||||
log.Errorf("newFromCloudRegion fail %s", err)
|
||||
return nil, err
|
||||
@@ -581,6 +587,10 @@ func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred
|
||||
lb.LoadbalancerSpec = extLb.GetLoadbalancerSpec()
|
||||
lb.ChargeType = extLb.GetChargeType()
|
||||
|
||||
if extLb.GetMetadata() != nil {
|
||||
lb.LBInfo = extLb.GetMetadata()
|
||||
}
|
||||
|
||||
if projectSync && len(projectId) > 0 {
|
||||
lb.ProjectId = projectId
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package regiondrivers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
type SQcloudRegionDriver struct {
|
||||
@@ -16,3 +23,274 @@ func init() {
|
||||
func (self *SQcloudRegionDriver) GetProvider() string {
|
||||
return models.CLOUD_PROVIDER_QCLOUD
|
||||
}
|
||||
|
||||
func (self *SQcloudRegionDriver) RequestCreateLoadbalancerBackendGroup(ctx context.Context, userCred mcclient.TokenCredential, lbbg *models.SLoadbalancerBackendGroup, backends []cloudprovider.SLoadbalancerBackend, task taskman.ITask) error {
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
iRegion, err := lbbg.GetIRegion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 腾讯云本身没有后端服务器组,因此不需要在qcloud端执行创建操作
|
||||
if iRegion.GetProvider() == models.CLOUD_PROVIDER_QCLOUD {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
loadbalancer := lbbg.GetLoadbalancer()
|
||||
if loadbalancer == nil {
|
||||
return nil, fmt.Errorf("failed to find loadbalancer for backendgroup %s", lbbg.Name)
|
||||
}
|
||||
iLoadbalancer, err := iRegion.GetILoadBalancerById(loadbalancer.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
group := &cloudprovider.SLoadbalancerBackendGroup{
|
||||
Name: lbbg.Name,
|
||||
GroupType: lbbg.Type,
|
||||
Backends: backends,
|
||||
}
|
||||
iLoadbalancerBackendGroup, err := iLoadbalancer.CreateILoadBalancerBackendGroup(group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := lbbg.SetExternalId(iLoadbalancerBackendGroup.GetGlobalId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iBackends, err := iLoadbalancerBackendGroup.GetILoadbalancerBackends()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(iBackends) > 0 {
|
||||
provider := loadbalancer.GetCloudprovider()
|
||||
if provider == nil {
|
||||
return nil, fmt.Errorf("failed to find cloudprovider for lb %s", loadbalancer.Name)
|
||||
}
|
||||
models.LoadbalancerBackendManager.SyncLoadbalancerBackends(ctx, userCred, provider, lbbg, iBackends, &models.SSyncRange{})
|
||||
}
|
||||
return nil, nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SQcloudRegionDriver) RequestCreateLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, lbb *models.SLoadbalancerBackend, task taskman.ITask) error {
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
lbbg := lbb.GetLoadbalancerBackendGroup()
|
||||
if lbbg == nil {
|
||||
return nil, fmt.Errorf("failed to find lbbg for backend %s", lbb.Name)
|
||||
}
|
||||
|
||||
guest := lbb.GetGuest()
|
||||
if guest == nil {
|
||||
return nil, fmt.Errorf("failed to find guest for lbb %s", lbb.Name)
|
||||
}
|
||||
|
||||
// 兼容腾讯云,在fake的backend group 关联具体的转发策略之前。不需要同步后端服务器
|
||||
if lbbg.GetProviderName() == models.CLOUD_PROVIDER_QCLOUD && lbbg.RefCount() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
lb := lbbg.GetLoadbalancer()
|
||||
if lb == nil {
|
||||
return nil, fmt.Errorf("failed to find lb for backendgroup %s", lbbg.Name)
|
||||
}
|
||||
iRegion, err := lb.GetIRegion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iLoadbalancer, err := iRegion.GetILoadBalancerById(lb.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iLoadbalancerBackendGroup, err := iLoadbalancer.GetILoadBalancerBackendGroupById(lbbg.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iLoadbalancerBackend, err := iLoadbalancerBackendGroup.AddBackendServer(guest.ExternalId, lbb.Weight, lbb.Port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := lbb.SetExternalId(iLoadbalancerBackend.GetGlobalId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, iLoadbalancerBackend, "", false)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SQcloudRegionDriver) RequestDeleteLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, lbb *models.SLoadbalancerBackend, task taskman.ITask) error {
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
if jsonutils.QueryBoolean(task.GetParams(), "purge", false) {
|
||||
return nil, nil
|
||||
}
|
||||
lbbg := lbb.GetLoadbalancerBackendGroup()
|
||||
if lbbg == nil {
|
||||
return nil, fmt.Errorf("failed to find lbbg for backend %s", lbb.Name)
|
||||
}
|
||||
lb := lbbg.GetLoadbalancer()
|
||||
if lb == nil {
|
||||
return nil, fmt.Errorf("failed to find lb for backendgroup %s", lbbg.Name)
|
||||
}
|
||||
iRegion, err := lb.GetIRegion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ===========兼容腾讯云,未关联具体转发规则时,直接删除本地数据即可===============
|
||||
if iRegion.GetProvider() == models.CLOUD_PROVIDER_QCLOUD {
|
||||
count := lbbg.RefCount()
|
||||
if count == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
iLoadbalancer, err := iRegion.GetILoadBalancerById(lb.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iLoadbalancerBackendGroup, err := iLoadbalancer.GetILoadBalancerBackendGroupById(lbbg.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
guest := lbb.GetGuest()
|
||||
if guest == nil {
|
||||
return nil, fmt.Errorf("failed to find guest for lbb %s", lbb.Name)
|
||||
}
|
||||
return nil, iLoadbalancerBackendGroup.RemoveBackendServer(guest.ExternalId, lbb.Weight, lbb.Port)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SQcloudRegionDriver) RequestCreateLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *models.SLoadbalancerListener, task taskman.ITask) error {
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
params, err := lblis.GetLoadbalancerListenerParams()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loadbalancer := lblis.GetLoadbalancer()
|
||||
if loadbalancer == nil {
|
||||
return nil, fmt.Errorf("failed to find loadbalancer for lblis %s", lblis.Name)
|
||||
}
|
||||
iRegion, err := loadbalancer.GetIRegion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iLoadbalancer, err := iRegion.GetILoadBalancerById(loadbalancer.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iListener, err := iLoadbalancer.CreateILoadBalancerListener(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := lblis.SetExternalId(iListener.GetGlobalId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ====腾讯云添加后端服务器=====
|
||||
if iRegion.GetProvider() == models.CLOUD_PROVIDER_QCLOUD {
|
||||
group := lblis.GetLoadbalancerBackendGroup()
|
||||
if group != nil {
|
||||
backends, err := group.GetBackends()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find backends for backend group %s: %s", group.GetId(), err)
|
||||
}
|
||||
|
||||
extBgID := iListener.GetBackendGroupId()
|
||||
if len(extBgID) == 0 {
|
||||
return nil, fmt.Errorf("the backend group external id of loadbalancer listener %s is empty", lblis.GetId())
|
||||
}
|
||||
|
||||
ilbbg, err := iLoadbalancer.GetILoadBalancerBackendGroupById(extBgID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find backend group for loadbalancer listener %s: %s", lblis.GetId(), err)
|
||||
}
|
||||
|
||||
for _, backend := range backends {
|
||||
guest := backend.GetGuest()
|
||||
if guest == nil {
|
||||
return nil, fmt.Errorf("failed to find instance for loadbalancer backend %s", backend.GetId())
|
||||
}
|
||||
_, err := ilbbg.AddBackendServer(guest.GetExternalId(), backend.Weight, backend.Port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, "", false)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SQcloudRegionDriver) RequestCreateLoadbalancerListenerRule(ctx context.Context, userCred mcclient.TokenCredential, lbr *models.SLoadbalancerListenerRule, task taskman.ITask) error {
|
||||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||||
listener := lbr.GetLoadbalancerListener()
|
||||
if listener == nil {
|
||||
return nil, fmt.Errorf("failed to find listener for listnener rule %s", lbr.Name)
|
||||
}
|
||||
loadbalancer := listener.GetLoadbalancer()
|
||||
if loadbalancer == nil {
|
||||
return nil, fmt.Errorf("failed to find loadbalancer for listener %s", listener.Name)
|
||||
}
|
||||
iRegion, err := loadbalancer.GetIRegion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iLoadbalancer, err := iRegion.GetILoadBalancerById(loadbalancer.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iListener, err := iLoadbalancer.GetILoadBalancerListenerById(listener.ExternalId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule := &cloudprovider.SLoadbalancerListenerRule{
|
||||
Name: lbr.Name,
|
||||
Domain: lbr.Domain,
|
||||
Path: lbr.Path,
|
||||
}
|
||||
if len(lbr.BackendGroupId) > 0 {
|
||||
group := lbr.GetLoadbalancerBackendGroup()
|
||||
if group == nil {
|
||||
return nil, fmt.Errorf("failed to find backend group for listener rule %s", lbr.Name)
|
||||
}
|
||||
rule.BackendGroupID = group.ExternalId
|
||||
rule.BackendGroupType = group.Type
|
||||
}
|
||||
iListenerRule, err := iListener.CreateILoadBalancerListenerRule(rule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := lbr.SetExternalId(iListenerRule.GetGlobalId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// ====腾讯云添加后端服务器=====
|
||||
if listener.GetProviderName() == models.CLOUD_PROVIDER_QCLOUD && len(rule.BackendGroupID) > 0 {
|
||||
ilbbg, err := iLoadbalancer.GetILoadBalancerBackendGroupById(rule.BackendGroupID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find backend group for listener rule %s: %s", lbr.Name, err)
|
||||
}
|
||||
|
||||
group := lbr.GetLoadbalancerBackendGroup()
|
||||
backends, err := group.GetBackends()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find backends for backend group %s: %s", group.GetId(), err)
|
||||
}
|
||||
|
||||
for _, backend := range backends {
|
||||
guest := backend.GetGuest()
|
||||
if guest == nil {
|
||||
return nil, fmt.Errorf("failed to find instance for loadbalancer backend %s", backend.GetId())
|
||||
}
|
||||
_, err := ilbbg.AddBackendServer(guest.GetExternalId(), backend.Weight, backend.Port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, "", false)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -237,9 +237,9 @@ func (lb *SLoadbalancer) GetLoadbalancerSpec() string {
|
||||
func (lb *SLoadbalancer) GetChargeType() string {
|
||||
switch lb.InternetChargeType {
|
||||
case "paybybandwidth":
|
||||
return "bandwidth"
|
||||
return models.LB_CHARGE_TYPE_BY_BANDWIDTH
|
||||
case "paybytraffic":
|
||||
return "traffic"
|
||||
return models.LB_CHARGE_TYPE_BY_TRAFFIC
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
Executable
+118
@@ -0,0 +1,118 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type projectInfo struct {
|
||||
ProjectID string `json:"projectId"`
|
||||
OwnerUin int64 `json:"ownerUin"`
|
||||
Name string `json:"name"`
|
||||
CreatorUin int64 `json:"creatorUin"`
|
||||
CreateTime string `json:"createTime"`
|
||||
Info string `json:"info"`
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/400/13675
|
||||
type SCertificate struct {
|
||||
OwnerUin string `json:"ownerUin"`
|
||||
ProjectID string `json:"projectId"`
|
||||
From string `json:"from"`
|
||||
Type int `json:"type"`
|
||||
Cert string `json:"cert"`
|
||||
CERTType string `json:"certType"`
|
||||
ProductZhName string `json:"productZhName"`
|
||||
Domain string `json:"domain"`
|
||||
Alias string `json:"alias"`
|
||||
Status int `json:"status"`
|
||||
VulnerabilityStatus string `json:"vulnerability_status"`
|
||||
VerifyType string `json:"verifyType"`
|
||||
CERTBeginTime time.Time `json:"certBeginTime"`
|
||||
CERTEndTime time.Time `json:"certEndTime"`
|
||||
ValidityPeriod string `json:"validityPeriod"`
|
||||
InsertTime string `json:"insertTime"`
|
||||
ProjectInfo projectInfo `json:"projectInfo"`
|
||||
ID string `json:"id"` // 证书Id
|
||||
SubjectAltName []string `json:"subjectAltName"`
|
||||
TypeName string `json:"type_name"`
|
||||
StatusName string `json:"status_name"`
|
||||
IsVip bool `json:"is_vip"`
|
||||
IsDv bool `json:"is_dv"`
|
||||
IsWildcard bool `json:"is_wildcard"`
|
||||
IsVulnerability bool `json:"is_vulnerability"`
|
||||
}
|
||||
|
||||
func (self *SRegion) GetCertificates(id string, withCert bool, limit int, page int) ([]SCertificate, int, error) {
|
||||
params := map[string]string{}
|
||||
if withCert {
|
||||
params["withCert"] = "1"
|
||||
}
|
||||
|
||||
if len(id) > 0 {
|
||||
params["id"] = id
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
params["count"] = strconv.Itoa(limit)
|
||||
}
|
||||
|
||||
if page > 0 {
|
||||
params["page"] = strconv.Itoa(page)
|
||||
}
|
||||
|
||||
resp, err := self.wssRequest("CertGetList", params)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
certs := []SCertificate{}
|
||||
err = resp.Unmarshal(&certs, "list")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
total, err := resp.Float("totalNum")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return certs, int(total), nil
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/400/9078
|
||||
// 返回证书ID
|
||||
func (self *SRegion) CreateCertificate(cert, certType, key, desc string) (string, error) {
|
||||
|
||||
params := map[string]string{
|
||||
"cert": cert,
|
||||
"certType": certType,
|
||||
"alias": desc,
|
||||
}
|
||||
|
||||
if certType == "SVR" {
|
||||
params["key"] = key
|
||||
}
|
||||
|
||||
resp, err := self.wssRequest("CertUpload", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("id")
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteCertificate(id string) error {
|
||||
if len(id) == 0 {
|
||||
return fmt.Errorf("DelteCertificate certificate id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{"id": id}
|
||||
_, err := self.wssRequest("CertDelete", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -25,7 +25,7 @@ func (self *SInstanceNic) GetDriver() string {
|
||||
}
|
||||
|
||||
func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork {
|
||||
networkId := self.instance.VirtualPrivateCloud.VpcId
|
||||
networkId := self.instance.VirtualPrivateCloud.SubnetId
|
||||
wires, err := self.instance.host.GetIWires()
|
||||
if err != nil {
|
||||
return nil
|
||||
|
||||
Executable
+579
@@ -0,0 +1,579 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
const (
|
||||
LB_ADDR_TYPE_INTERNAL = "INTERNAL"
|
||||
LB_ADDR_TYPE_OPEN = "OPEN"
|
||||
)
|
||||
|
||||
type LB_TYPE int64
|
||||
|
||||
const (
|
||||
LB_TYPE_CLASSIC = LB_TYPE(0)
|
||||
LB_TYPE_APPLICATION = LB_TYPE(1)
|
||||
)
|
||||
|
||||
/*
|
||||
todo:
|
||||
1.统一LB 证书fingerprint算法.另外缺少一个回写指纹算法到数据库的方法。
|
||||
2.需要同步腾讯云LB 所在的project
|
||||
*/
|
||||
|
||||
// https://cloud.tencent.com/document/api/214/30694#LoadBalancer
|
||||
type SLoadbalancer struct {
|
||||
region *SRegion
|
||||
|
||||
Status int64 `json:"Status"` // 0:创建中,1:正常运行
|
||||
Domain string `json:"Domain"`
|
||||
VpcID string `json:"VpcId"`
|
||||
Log string `json:"Log"`
|
||||
ProjectID int64 `json:"ProjectId"`
|
||||
Snat bool `json:"Snat"`
|
||||
LoadBalancerID string `json:"LoadBalancerId"`
|
||||
LoadBalancerVips []string `json:"LoadBalancerVips"`
|
||||
LoadBalancerType string `json:"LoadBalancerType"` // 负载均衡实例的网络类型: OPEN:公网属性, INTERNAL:内网属性。
|
||||
LoadBalancerName string `json:"LoadBalancerName"`
|
||||
Forward LB_TYPE `json:"Forward"` // 应用型负载均衡标识,1:应用型负载均衡,0:传统型的负载均衡。
|
||||
StatusTime time.Time `json:"StatusTime"`
|
||||
OpenBGP int64 `json:"OpenBgp"` // 高防 LB 的标识,1:高防负载均衡 0:非高防负载均衡。
|
||||
CreateTime time.Time `json:"CreateTime"`
|
||||
Isolation int64 `json:"Isolation"` // 0:表示未被隔离,1:表示被隔离。
|
||||
SubnetId string `json:"SubnetId"`
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetLoadbalancerSpec() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetChargeType() string {
|
||||
return models.LB_CHARGE_TYPE_BY_HOUR
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30689
|
||||
func (self *SLoadbalancer) Delete() error {
|
||||
if self.Forward == LB_TYPE_APPLICATION {
|
||||
_, err := self.region.DeleteLoadbalancer(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
_, err := self.region.DeleteClassicLoadbalancer(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return cloudprovider.WaitDeleted(self, 5*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
// 腾讯云loadbalance不支持启用/禁用
|
||||
func (self *SLoadbalancer) Start() error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) Stop() error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// 腾讯云无后端服务器组
|
||||
// todo: 是否返回一个fake的后端服务器组
|
||||
func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
|
||||
groups, err := self.GetILoadBalancerBackendGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
if group.GetId() == groupId {
|
||||
return group, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func onecloudHealthCodeToQcloud(codes string) int {
|
||||
qcode := 0
|
||||
for i, code := range HTTP_CODES {
|
||||
if strings.Contains(code, codes) {
|
||||
// 按位或然后再赋值qcode
|
||||
qcode |= 1 << uint(i)
|
||||
}
|
||||
}
|
||||
|
||||
return qcode
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30693
|
||||
// todo: 1.限制比较多必须加参数校验 2.Onecloud 不支持双向证书可能存在兼容性问题
|
||||
// 应用型负载均衡 https监听默认开启SNI。传统型不支持设置SNI
|
||||
func (self *SLoadbalancer) CreateILoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) {
|
||||
sniSwitch := 0
|
||||
if listener.ListenerType == models.LB_LISTENER_TYPE_HTTPS {
|
||||
sniSwitch = 1
|
||||
}
|
||||
|
||||
hc := getHealthCheck(listener)
|
||||
cert := getCertificate(listener)
|
||||
|
||||
var listenId string
|
||||
var err error
|
||||
if self.Forward == LB_TYPE_APPLICATION {
|
||||
listenId, err = self.region.CreateLoadbalancerListener(self.GetId(),
|
||||
listener.Name,
|
||||
getProtocol(listener),
|
||||
listener.ListenerPort,
|
||||
getScheduler(listener),
|
||||
&listener.StickySessionCookieTimeout,
|
||||
&sniSwitch,
|
||||
hc,
|
||||
cert)
|
||||
} else {
|
||||
// 传统型内网属性负载均衡不支持指定scheduler
|
||||
var scheduler *string
|
||||
if self.LoadBalancerType == "OPEN" {
|
||||
scheduler = getScheduler(listener)
|
||||
}
|
||||
|
||||
listenId, err = self.region.CreateClassicLoadbalancerListener(self.GetId(),
|
||||
listener.Name,
|
||||
getClassicLBProtocol(listener),
|
||||
listener.ListenerPort,
|
||||
listener.BackendServerPort,
|
||||
scheduler,
|
||||
&listener.StickySessionCookieTimeout,
|
||||
&sniSwitch,
|
||||
hc,
|
||||
cert)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
return self.GetILoadBalancerListenerById(listenId)
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) {
|
||||
listeners, err := self.GetLoadbalancerListeners("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, listener := range listeners {
|
||||
if listener.GetId() == listenerId {
|
||||
return &listener, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetId() string {
|
||||
return self.LoadBalancerID
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetName() string {
|
||||
return self.LoadBalancerName
|
||||
}
|
||||
|
||||
// add region?
|
||||
func (self *SLoadbalancer) GetGlobalId() string {
|
||||
return self.LoadBalancerID
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetStatus() string {
|
||||
switch self.Status {
|
||||
case 0:
|
||||
return models.LB_STATUS_INIT
|
||||
case 1:
|
||||
return models.LB_STATUS_ENABLED
|
||||
default:
|
||||
return models.LB_STATUS_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) Refresh() error {
|
||||
lb, err := self.region.GetLoadbalancer(self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return jsonutils.Update(self, lb)
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetMetadata() *jsonutils.JSONDict {
|
||||
meta := jsonutils.NewDict()
|
||||
meta.Add(jsonutils.NewInt(int64(self.Forward)), "Forward")
|
||||
meta.Add(jsonutils.NewInt(self.OpenBGP), "OpenBGP")
|
||||
meta.Add(jsonutils.NewString(self.Domain), "Domain")
|
||||
meta.Add(jsonutils.NewInt(self.ProjectID), "ProjectID")
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
// 腾讯云当前不支持一个LB绑定多个ip,每个LB只支持绑定一个ip
|
||||
func (self *SLoadbalancer) GetAddress() string {
|
||||
return self.LoadBalancerVips[0]
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetAddressType() string {
|
||||
switch self.LoadBalancerType {
|
||||
case LB_ADDR_TYPE_INTERNAL:
|
||||
return models.LB_ADDR_TYPE_INTRANET
|
||||
case LB_ADDR_TYPE_OPEN:
|
||||
return models.LB_ADDR_TYPE_INTERNET
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetNetworkType() string {
|
||||
return models.LB_NETWORK_TYPE_VPC
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetNetworkId() string {
|
||||
return self.SubnetId
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetVpcId() string {
|
||||
return self.VpcID
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetZoneId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetLoadbalancerListeners(protocal string) ([]SLBListener, error) {
|
||||
listeners, err := self.region.GetLoadbalancerListeners(self.GetId(), self.Forward, protocal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range listeners {
|
||||
listeners[i].lb = self
|
||||
}
|
||||
|
||||
return listeners, nil
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) {
|
||||
listeners, err := self.GetLoadbalancerListeners("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ilisteners := make([]cloudprovider.ICloudLoadbalancerListener, len(listeners))
|
||||
for i := range listeners {
|
||||
l := listeners[i]
|
||||
ilisteners[i] = &l
|
||||
}
|
||||
|
||||
return ilisteners, nil
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
|
||||
listeners, err := self.GetLoadbalancerListeners("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bgs := []cloudprovider.ICloudLoadbalancerBackendGroup{}
|
||||
for i := range listeners {
|
||||
listener := listeners[i]
|
||||
t := listener.GetListenerType()
|
||||
if t == models.LB_LISTENER_TYPE_HTTP || t == models.LB_LISTENER_TYPE_HTTPS {
|
||||
rules := listener.Rules
|
||||
for i := range rules {
|
||||
rule := rules[i]
|
||||
rule.listener = &listener
|
||||
bg := rule.GetBackendGroup()
|
||||
bgs = append(bgs, bg)
|
||||
}
|
||||
} else {
|
||||
bg := listener.GetBackendGroup()
|
||||
bgs = append(bgs, bg)
|
||||
}
|
||||
}
|
||||
|
||||
ibgs := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(bgs))
|
||||
for i := range bgs {
|
||||
ibgs[i] = bgs[i]
|
||||
}
|
||||
|
||||
return ibgs, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) {
|
||||
params := map[string]string{}
|
||||
for i, id := range ids {
|
||||
params[fmt.Sprintf("LoadBalancerIds.%d", i)] = id
|
||||
}
|
||||
|
||||
offset := 0
|
||||
limit := 100
|
||||
lbs := make([]SLoadbalancer, 0)
|
||||
for {
|
||||
params["Limit"] = strconv.Itoa(limit)
|
||||
params["Offset"] = strconv.Itoa(offset)
|
||||
|
||||
resp, err := self.clbRequest("DescribeLoadBalancers", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parts := make([]SLoadbalancer, 0)
|
||||
err = resp.Unmarshal(&parts, "LoadBalancerSet")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_total, err := resp.Float("TotalCount")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
total := int(_total)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lbs = append(lbs, parts...)
|
||||
offset += len(parts)
|
||||
if offset >= total {
|
||||
for i := range lbs {
|
||||
lbs[i].region = self
|
||||
}
|
||||
|
||||
return lbs, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) {
|
||||
if len(id) == 0 {
|
||||
return nil, fmt.Errorf("GetLoadbalancer id should not empty")
|
||||
}
|
||||
|
||||
lbs, err := self.GetLoadbalancers([]string{id})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch len(lbs) {
|
||||
case 0:
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
case 1:
|
||||
return &lbs[0], nil
|
||||
default:
|
||||
return nil, fmt.Errorf("GetLoadbalancer %s found %d", id, len(lbs))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
返回requstid 用于异步任务查询
|
||||
https://cloud.tencent.com/document/product/214/30689
|
||||
*/
|
||||
func (self *SRegion) DeleteLoadbalancer(lbid string) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{"LoadBalancerIds.0": lbid}
|
||||
resp, err := self.clbRequest("DeleteLoadBalancer", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
|
||||
/*
|
||||
返回requstid 用于异步任务查询
|
||||
https://cloud.tencent.com/document/product/214/30689
|
||||
*/
|
||||
func (self *SRegion) DeleteClassicLoadbalancer(lbid string) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{"loadBalancerIds.n": lbid}
|
||||
resp, err := self.lbRequest("DeleteLoadBalancers", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("requestId")
|
||||
}
|
||||
|
||||
/*
|
||||
https://cloud.tencent.com/document/product/214/30693
|
||||
SNI 特性是什么??
|
||||
*/
|
||||
func (self *SRegion) CreateLoadbalancerListener(lbid, name, protocol string, port int, scheduler *string, sessionExpireTime, sniSwitch *int, healthCheck *healthCheck, cert *certificate) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{
|
||||
"LoadBalancerId": lbid,
|
||||
"Ports.0": strconv.Itoa(port),
|
||||
"Protocol": protocol,
|
||||
}
|
||||
|
||||
if len(name) > 0 {
|
||||
params["ListenerNames.0"] = name
|
||||
}
|
||||
|
||||
if sniSwitch != nil {
|
||||
params["SniSwitch"] = strconv.Itoa(*sniSwitch)
|
||||
}
|
||||
|
||||
if sessionExpireTime != nil {
|
||||
params["SessionExpireTime"] = strconv.Itoa(*sessionExpireTime)
|
||||
}
|
||||
|
||||
if scheduler != nil && len(*scheduler) > 0 {
|
||||
params["Scheduler"] = *scheduler
|
||||
}
|
||||
|
||||
params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "HealthCheck.")
|
||||
params = certificateParams(LB_TYPE_APPLICATION, params, cert, "Certificate.")
|
||||
|
||||
resp, err := self.clbRequest("CreateListener", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
listeners, err := resp.GetArray("ListenerIds")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(listeners) == 0 {
|
||||
return "", fmt.Errorf("CreateLoadbalancerListener no listener id returned: %s", resp.String())
|
||||
} else if len(listeners) == 1 {
|
||||
return listeners[0].GetString()
|
||||
} else {
|
||||
return "", fmt.Errorf("CreateLoadbalancerListener mutliple listener id returned: %s", resp.String())
|
||||
}
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/214/1255
|
||||
// 不支持sniSwitch
|
||||
// todo: 待测试
|
||||
func (self *SRegion) CreateClassicLoadbalancerListener(lbid, name string, protocol, port, backendServerPort int, scheduler *string, sessionExpireTime, sniSwitch *int, healthCheck *healthCheck, cert *certificate) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
// 负载均衡实例监听器协议类型 1:HTTP,2:TCP,3:UDP,4:HTTPS。
|
||||
// todo: 待测试 。 这里没有判断是否为公网负载均衡,可能存在问题.内网传统型负载均衡监听协议只支持TCP、UDP,并且不能指定调度算法
|
||||
params := map[string]string{
|
||||
"loadBalancerId": lbid,
|
||||
"listeners.0.loadBalancerPort": strconv.Itoa(port),
|
||||
"listeners.0.instancePort": strconv.Itoa(backendServerPort),
|
||||
"listeners.0.protocol": strconv.Itoa(protocol),
|
||||
}
|
||||
|
||||
if len(name) > 0 {
|
||||
params["listeners.0.listenerName"] = name
|
||||
}
|
||||
|
||||
if sessionExpireTime != nil {
|
||||
params["listeners.0.sessionExpire"] = strconv.Itoa(*sessionExpireTime)
|
||||
}
|
||||
|
||||
if scheduler != nil && len(*scheduler) > 0 && (protocol == 2 || protocol == 3) {
|
||||
params["listeners.0.scheduler"] = strings.ToLower(*scheduler)
|
||||
}
|
||||
|
||||
if scheduler != nil && len(*scheduler) > 0 && (protocol == 1 || protocol == 4) {
|
||||
params["listeners.0.httpHash"] = strings.ToLower(*scheduler)
|
||||
}
|
||||
|
||||
params = healthCheckParams(LB_TYPE_CLASSIC, params, healthCheck, "listeners.0.")
|
||||
params = certificateParams(LB_TYPE_CLASSIC, params, cert, "listeners.0.")
|
||||
|
||||
resp, err := self.lbRequest("CreateLoadBalancerListeners", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
listeners, err := resp.GetArray("listenerIds")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(listeners) == 0 {
|
||||
return "", fmt.Errorf("CreateLoadbalancerListener no listener id returned: %s", resp.String())
|
||||
} else if len(listeners) == 1 {
|
||||
return listeners[0].GetString()
|
||||
} else {
|
||||
return "", fmt.Errorf("CreateLoadbalancerListener mutliple listener id returned: %s", resp.String())
|
||||
}
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30683
|
||||
// 任务的当前状态。 0:成功,1:失败,2:进行中
|
||||
func (self *SRegion) GetLBTaskStatus(requestId string) (string, error) {
|
||||
if len(requestId) == 0 {
|
||||
return "", fmt.Errorf("WaitTaskSuccess requestId should not be emtpy")
|
||||
}
|
||||
|
||||
params := map[string]string{"TaskId": requestId}
|
||||
resp, err := self.clbRequest("DescribeTaskStatus", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
status, err := resp.Get("Status")
|
||||
if err != nil {
|
||||
log.Debugf("WaitTaskSuccess failed %s: %s", err, resp.String())
|
||||
return "", err
|
||||
}
|
||||
|
||||
_status, err := status.Float()
|
||||
return fmt.Sprintf("%1.f", _status), err
|
||||
}
|
||||
|
||||
func (self *SRegion) WaitLBTaskSuccess(requestId string, interval time.Duration, timeout time.Duration) error {
|
||||
startTime := time.Now()
|
||||
for time.Now().Sub(startTime) < timeout {
|
||||
status, err := self.GetLBTaskStatus(requestId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status == "0" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if status == "1" {
|
||||
return fmt.Errorf("Task %s failed.", requestId)
|
||||
}
|
||||
|
||||
time.Sleep(interval)
|
||||
}
|
||||
|
||||
return cloudprovider.ErrTimeout
|
||||
}
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
// 腾讯云没有LB ACL
|
||||
type SLBACL struct{}
|
||||
|
||||
func (self *SLBACL) GetId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBACL) GetName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBACL) GetGlobalId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBACL) GetStatus() string {
|
||||
return models.LB_BOOL_OFF
|
||||
}
|
||||
|
||||
func (self *SLBACL) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBACL) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SLBACL) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBACL) GetAclEntries() *jsonutils.JSONArray {
|
||||
return nil
|
||||
}
|
||||
Executable
+171
@@ -0,0 +1,171 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
type SLBBackend struct {
|
||||
group *SLBBackendGroup
|
||||
|
||||
PublicIPAddresses []string `json:"PublicIpAddresses"`
|
||||
Weight int `json:"Weight"`
|
||||
InstanceID string `json:"InstanceId"`
|
||||
InstanceName string `json:"InstanceName"`
|
||||
PrivateIPAddresses []string `json:"PrivateIpAddresses"`
|
||||
RegisteredTime string `json:"RegisteredTime"`
|
||||
Type string `json:"Type"`
|
||||
Port int `json:"Port"`
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
type SListenerBackend struct {
|
||||
Rules []rule `json:"Rules"`
|
||||
Targets []SLBBackend `json:"Targets"`
|
||||
Protocol string `json:"Protocol"`
|
||||
ListenerID string `json:"ListenerId"`
|
||||
Port int64 `json:"Port"`
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
URL string `json:"Url"`
|
||||
Domain string `json:"Domain"`
|
||||
LocationID string `json:"LocationId"`
|
||||
Targets []SLBBackend `json:"Targets"`
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
|
||||
// backend InstanceID + protocol +Port + ip + rip全局唯一
|
||||
func (self *SLBBackend) GetId() string {
|
||||
return fmt.Sprintf("%s/%s-%d", self.group.GetId(), self.InstanceID, self.Port)
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetName() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetStatus() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBBackend) Refresh() error {
|
||||
backends, err := self.group.GetBackends()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, backend := range backends {
|
||||
if backend.GetId() == self.GetId() {
|
||||
return jsonutils.Update(self, backend)
|
||||
}
|
||||
}
|
||||
|
||||
return cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SLBBackend) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetWeight() int {
|
||||
return self.Weight
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetPort() int {
|
||||
return self.Port
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetBackendType() string {
|
||||
return models.LB_BACKEND_GUEST
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetBackendRole() string {
|
||||
return models.LB_BACKEND_ROLE_DEFAULT
|
||||
}
|
||||
|
||||
func (self *SLBBackend) GetBackendId() string {
|
||||
return self.InstanceID
|
||||
}
|
||||
|
||||
// 传统型: https://cloud.tencent.com/document/product/214/31790
|
||||
func (self *SRegion) getClassicBackends(lbId, listenerId string) ([]SLBBackend, error) {
|
||||
params := map[string]string{"LoadBalancerId": lbId}
|
||||
|
||||
resp, err := self.clbRequest("DescribeClassicalLBTargets", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
backends := []SLBBackend{}
|
||||
err = resp.Unmarshal(&backends, "Targets")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return backends, nil
|
||||
}
|
||||
|
||||
// 应用型: https://cloud.tencent.com/document/product/214/30684
|
||||
func (self *SRegion) getBackends(lbId, listenerId, ruleId string) ([]SLBBackend, error) {
|
||||
params := map[string]string{"LoadBalancerId": lbId}
|
||||
|
||||
if len(listenerId) > 0 {
|
||||
params["ListenerIds.0"] = listenerId
|
||||
}
|
||||
|
||||
resp, err := self.clbRequest("DescribeTargets", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lbackends := []SListenerBackend{}
|
||||
err = resp.Unmarshal(&lbackends, "Listeners")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, entry := range lbackends {
|
||||
if (entry.Protocol == "HTTP" || entry.Protocol == "HTTPS") && len(ruleId) == 0 {
|
||||
return nil, fmt.Errorf("GetBackends for http/https listener %s must specific rule id", listenerId)
|
||||
}
|
||||
|
||||
if len(ruleId) > 0 {
|
||||
for _, r := range entry.Rules {
|
||||
if r.LocationID == ruleId {
|
||||
return r.Targets, nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return entry.Targets, nil
|
||||
}
|
||||
}
|
||||
|
||||
// todo: 这里是返回空列表还是404?
|
||||
return []SLBBackend{}, nil
|
||||
}
|
||||
|
||||
// 注意http、https监听器必须指定ruleId
|
||||
func (self *SRegion) GetLBBackends(t LB_TYPE, lbId, listenerId, ruleId string) ([]SLBBackend, error) {
|
||||
if len(lbId) == 0 {
|
||||
return nil, fmt.Errorf("GetLBBackends loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
if t == LB_TYPE_APPLICATION {
|
||||
return self.getBackends(lbId, listenerId, ruleId)
|
||||
} else if t == LB_TYPE_CLASSIC {
|
||||
return self.getClassicBackends(lbId, listenerId)
|
||||
} else {
|
||||
return nil, fmt.Errorf("GetLBBackends unsupported loadbalancer type %d", t)
|
||||
}
|
||||
}
|
||||
Executable
+223
@@ -0,0 +1,223 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"strings"
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
type SLBBackendGroup struct {
|
||||
lb *SLoadbalancer // 必须不能为nil
|
||||
listener *SLBListener // 必须不能为nil
|
||||
rule *SLBListenerRule // tcp、udp、tcp_ssl监听rule 为nil
|
||||
}
|
||||
|
||||
// 返回requestid
|
||||
func (self *SLBBackendGroup) appLBBackendServer(action string, serverId string, weight int, port int) (string, error) {
|
||||
if len(serverId) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer backend instance id should not be empty.")
|
||||
}
|
||||
|
||||
params := map[string]string{
|
||||
"LoadBalancerId": self.lb.GetId(),
|
||||
"ListenerId": self.listener.GetId(),
|
||||
"Targets.0.InstanceId": serverId,
|
||||
"Targets.0.Port": strconv.Itoa(port),
|
||||
"Targets.0.Weight": strconv.Itoa(weight),
|
||||
}
|
||||
|
||||
if self.rule != nil {
|
||||
params["LocationId"] = self.rule.GetId()
|
||||
}
|
||||
|
||||
resp, err := self.lb.region.clbRequest(action, params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
|
||||
// 返回requestid
|
||||
func (self *SLBBackendGroup) classicLBBackendServer(action string, serverId string, weight int, port int) (string, error) {
|
||||
// 传统型负载均衡忽略了port参数
|
||||
params := map[string]string{
|
||||
"LoadBalancerId": self.lb.GetId(),
|
||||
"Targets.0.InstanceId": serverId,
|
||||
"Targets.0.Weight": strconv.Itoa(weight),
|
||||
}
|
||||
|
||||
resp, err := self.lb.region.clbRequest(action, params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30676
|
||||
// https://cloud.tencent.com/document/product/214/31789
|
||||
func (self *SLBBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) {
|
||||
var requestId string
|
||||
var err error
|
||||
if self.lb.Forward == LB_TYPE_APPLICATION {
|
||||
requestId, err = self.appLBBackendServer("RegisterTargets", serverId, weight, port)
|
||||
} else {
|
||||
requestId, err = self.classicLBBackendServer("RegisterTargetsWithClassicalLB", serverId, weight, port)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = self.Refresh()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
backends, err := self.GetBackends()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, backend := range backends {
|
||||
if strings.HasSuffix(backend.GetId(), fmt.Sprintf("%s-%d", serverId, port)) {
|
||||
return &backend, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30687
|
||||
// https://cloud.tencent.com/document/product/214/31794
|
||||
func (self *SLBBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error {
|
||||
var requestId string
|
||||
var err error
|
||||
if self.lb.Forward == LB_TYPE_APPLICATION {
|
||||
requestId, err = self.appLBBackendServer("DeregisterTargets", serverId, weight, port)
|
||||
} else {
|
||||
requestId, err = self.classicLBBackendServer("DeregisterTargetsFromClassicalLB", serverId, weight, port)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not registered") {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
// 腾讯云无后端服务器组。
|
||||
func (self *SLBBackendGroup) Delete() error {
|
||||
return fmt.Errorf("Please remove related listener/rule frist")
|
||||
}
|
||||
|
||||
// 腾讯云无后端服务器组
|
||||
func (self *SLBBackendGroup) Sync(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func backendGroupIdGen(lbid string, secondId string) string {
|
||||
if len(secondId) > 0 {
|
||||
return fmt.Sprintf("%s/%s", lbid, secondId)
|
||||
} else {
|
||||
return lbid
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetId() string {
|
||||
t := self.listener.GetListenerType()
|
||||
if t == models.LB_LISTENER_TYPE_HTTP || t == models.LB_LISTENER_TYPE_HTTPS {
|
||||
// http https 后端服务器只与规则绑定
|
||||
return backendGroupIdGen(self.lb.GetId(), self.rule.GetId())
|
||||
} else if self.lb.Forward == LB_TYPE_APPLICATION {
|
||||
return backendGroupIdGen(self.lb.GetId(), self.listener.GetId())
|
||||
} else {
|
||||
// 传统型lb 所有监听共用一个后端服务器组
|
||||
return backendGroupIdGen(self.lb.GetId(), "")
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetName() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetGlobalId() string {
|
||||
return self.GetId()
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetStatus() string {
|
||||
return models.LB_STATUS_ENABLED
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// note: model没有更新这个字段?
|
||||
func (self *SLBBackendGroup) IsEmulated() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) IsDefault() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetType() string {
|
||||
return models.LB_BACKENDGROUP_TYPE_NORMAL
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) {
|
||||
backends, err := self.GetBackends()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends))
|
||||
for i := range backends {
|
||||
ibackends[i] = &backends[i]
|
||||
}
|
||||
|
||||
return ibackends, nil
|
||||
}
|
||||
|
||||
func (self *SLBBackendGroup) GetBackends() ([]SLBBackend, error) {
|
||||
backends := []SLBBackend{}
|
||||
var err error
|
||||
if self.rule != nil {
|
||||
// http、https监听
|
||||
backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.listener.GetId(), self.rule.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// tcp,udp,tcp_ssl监听
|
||||
backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.listener.GetId(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for i := range backends {
|
||||
backends[i].group = self
|
||||
}
|
||||
|
||||
return backends, nil
|
||||
}
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
)
|
||||
|
||||
type SLBCertificate struct {
|
||||
region *SRegion
|
||||
|
||||
SCertificate
|
||||
}
|
||||
|
||||
// 证书不能修改
|
||||
func (self *SLBCertificate) Sync(name, privateKey, publickKey string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) Delete() error {
|
||||
return self.region.DeleteCertificate(self.GetId())
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetId() string {
|
||||
return self.ID
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetName() string {
|
||||
return self.Alias
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetGlobalId() string {
|
||||
return self.ID
|
||||
}
|
||||
|
||||
// todo: 貌似目前onecloud没有记录状态
|
||||
func (self *SLBCertificate) GetStatus() string {
|
||||
return strconv.Itoa(self.Status)
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) Refresh() error {
|
||||
certs, total, err := self.region.GetCertificates(self.GetId(), true, 0, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if total != 1 {
|
||||
return fmt.Errorf("Expecting 1 certificate, got %d", total)
|
||||
}
|
||||
|
||||
cert := SLBCertificate{region: self.region, SCertificate: certs[0]}
|
||||
return jsonutils.Update(self, cert)
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetCommonName() string {
|
||||
return self.Domain
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetSubjectAlternativeNames() string {
|
||||
return strings.Join(self.SubjectAltName, ",")
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetFingerprint() string {
|
||||
_fp := sha1.Sum([]byte(self.Cert))
|
||||
fp := fmt.Sprintf("sha1:% x", _fp)
|
||||
return strings.Replace(fp, " ", ":", -1)
|
||||
}
|
||||
|
||||
func (self *SLBCertificate) GetExpireTime() time.Time {
|
||||
return self.CERTEndTime
|
||||
}
|
||||
Executable
+782
@@ -0,0 +1,782 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
var HTTP_CODES = []string{
|
||||
models.LB_HEALTH_CHECK_HTTP_CODE_1xx,
|
||||
models.LB_HEALTH_CHECK_HTTP_CODE_2xx,
|
||||
models.LB_HEALTH_CHECK_HTTP_CODE_3xx,
|
||||
models.LB_HEALTH_CHECK_HTTP_CODE_4xx,
|
||||
models.LB_HEALTH_CHECK_HTTP_CODE_5xx,
|
||||
}
|
||||
|
||||
type certificate struct {
|
||||
SSLMode string `json:"SSLMode"`
|
||||
CERTCAID string `json:"CertCaId"`
|
||||
CERTID string `json:"CertId"`
|
||||
}
|
||||
|
||||
/*
|
||||
健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。
|
||||
1 表示探测后返回值 1xx 表示健康,2 表示返回 2xx 表示健康,4 表示返回 3xx 表示健康,8 表示返回 4xx 表示健康,16 表示返回 5xx 表示健康。
|
||||
若希望多种码都表示健康,则将相应的值相加。
|
||||
*/
|
||||
type healthCheck struct {
|
||||
HTTPCheckDomain string `json:"HttpCheckDomain"`
|
||||
HealthSwitch int `json:"HealthSwitch"`
|
||||
HTTPCheckPath string `json:"HttpCheckPath"`
|
||||
HTTPCheckMethod string `json:"HttpCheckMethod"`
|
||||
UnHealthNum int `json:"UnHealthNum"`
|
||||
IntervalTime int `json:"IntervalTime"`
|
||||
HTTPCode int `json:"HttpCode"` // 健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。
|
||||
HealthNum int `json:"HealthNum"`
|
||||
TimeOut int `json:"TimeOut"`
|
||||
}
|
||||
|
||||
type SLBListener struct {
|
||||
lb *SLoadbalancer
|
||||
|
||||
Protocol string `json:"Protocol"` // 监听器协议类型,取值 TCP | UDP | HTTP | HTTPS | TCP_SSL
|
||||
Certificate certificate `json:"Certificate"`
|
||||
SniSwitch int64 `json:"SniSwitch"` // 是否开启SNI特性(本参数仅对于HTTPS监听器有意义)
|
||||
HealthCheck healthCheck `json:"HealthCheck"` // 仅适用于TCP/UDP/TCP_SSL监听器
|
||||
ListenerID string `json:"ListenerId"`
|
||||
ListenerName string `json:"ListenerName"`
|
||||
Rules []SLBListenerRule `json:"Rules"` // 监听器下的全部转发规则(本参数仅对于HTTP/HTTPS监听器有意义)
|
||||
Scheduler string `json:"Scheduler"`
|
||||
SessionExpireTime int `json:"SessionExpireTime"` // 会话保持时间,单位:秒。可选值:30~3600,默认 0,表示不开启。此参数仅适用于TCP/UDP监听器。
|
||||
Port int `json:"Port"`
|
||||
ClassicListener bool // 这个字段是在qcloud返回字段基础上,额外增加的字段。用于区分listener 是否是classic。
|
||||
}
|
||||
|
||||
// 腾讯云后端端口不是与listener绑定的
|
||||
func (self *SLBListener) GetBackendServerPort() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30691
|
||||
func (self *SLBListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
|
||||
requestId, err := self.lb.region.CreateLoadbalancerListenerRule(self.lb.GetId(),
|
||||
self.GetId(),
|
||||
rule.Domain,
|
||||
rule.Path,
|
||||
&self.Scheduler,
|
||||
&self.SessionExpireTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = self.Refresh()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, r := range self.Rules {
|
||||
if r.GetPath() == rule.Path {
|
||||
return &r, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
|
||||
rules, err := self.GetILoadbalancerListenerRules()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, rule := range rules {
|
||||
if rule.GetId() == ruleId {
|
||||
return rule, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SLBListener) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBListener) Stop() error {
|
||||
return cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30677
|
||||
func (self *SLBListener) Sync(listener *cloudprovider.SLoadbalancerListener) error {
|
||||
hc := getHealthCheck(listener)
|
||||
cert := getCertificate(listener)
|
||||
requestId, err := self.lb.region.UpdateLoadbalancerListener(
|
||||
self.lb.Forward,
|
||||
self.lb.GetId(),
|
||||
self.GetId(),
|
||||
&listener.Name,
|
||||
getScheduler(listener),
|
||||
&listener.StickySessionCookieTimeout,
|
||||
hc,
|
||||
cert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
func (self *SLBListener) Delete() error {
|
||||
requestId, err := self.lb.region.DeleteLoadbalancerListener(self.lb.Forward, self.lb.GetId(), self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/214/30694#ClassicalListener
|
||||
type SLBClassicListener struct {
|
||||
InstancePort int64 `json:"InstancePort"`
|
||||
CERTCAID string `json:"CertCaId"`
|
||||
Status int64 `json:"Status"`
|
||||
CERTID string `json:"CertId"`
|
||||
Protocol string `json:"Protocol"`
|
||||
TimeOut int `json:"TimeOut"`
|
||||
HTTPHash string `json:"HttpHash"` // 公网固定IP型的 HTTP、HTTPS 协议监听器的轮询方法。wrr 表示按权重轮询,ip_hash 表示根据访问的源 IP 进行一致性哈希方式来分发
|
||||
UnhealthNum int `json:"UnhealthNum"`
|
||||
IntervalTime int `json:"IntervalTime"`
|
||||
ListenerID string `json:"ListenerId"`
|
||||
ListenerPort int `json:"ListenerPort"`
|
||||
HTTPCheckPath string `json:"HttpCheckPath"`
|
||||
HealthNum int `json:"HealthNum"`
|
||||
ListenerName string `json:"ListenerName"`
|
||||
HealthSwitch int `json:"HealthSwitch"`
|
||||
SSLMode string `json:"SSLMode"`
|
||||
SessionExpire int `json:"SessionExpire"`
|
||||
HTTPCode int `json:"HttpCode"`
|
||||
}
|
||||
|
||||
func (self *SLBClassicListener) ToLBListener() SLBListener {
|
||||
// 转换之后丢弃了 InstancePort、Status、HttpHash
|
||||
return SLBListener{
|
||||
Protocol: self.Protocol,
|
||||
Certificate: certificate{
|
||||
SSLMode: self.SSLMode,
|
||||
CERTCAID: self.CERTCAID,
|
||||
CERTID: self.CERTID,
|
||||
},
|
||||
HealthCheck: healthCheck{
|
||||
HTTPCheckDomain: "",
|
||||
HealthSwitch: self.HealthSwitch,
|
||||
HTTPCheckPath: self.HTTPCheckPath,
|
||||
HTTPCheckMethod: "",
|
||||
UnHealthNum: self.UnhealthNum,
|
||||
IntervalTime: self.IntervalTime,
|
||||
HTTPCode: self.HTTPCode,
|
||||
HealthNum: self.HealthNum,
|
||||
TimeOut: self.TimeOut,
|
||||
},
|
||||
ListenerID: self.ListenerID,
|
||||
ListenerName: self.ListenerName,
|
||||
Rules: nil,
|
||||
Scheduler: self.HTTPHash,
|
||||
SessionExpireTime: self.SessionExpire,
|
||||
Port: self.ListenerPort,
|
||||
ClassicListener: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetId() string {
|
||||
return self.ListenerID
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetName() string {
|
||||
return self.ListenerName
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetGlobalId() string {
|
||||
return self.ListenerID
|
||||
}
|
||||
|
||||
// 腾讯云负载均衡没有启用禁用操作
|
||||
func (self *SLBListener) GetStatus() string {
|
||||
return models.LB_STATUS_ENABLED
|
||||
}
|
||||
|
||||
func (self *SLBListener) Refresh() error {
|
||||
listeners, err := self.lb.region.GetLoadbalancerListeners(self.lb.GetId(), self.lb.Forward, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, listener := range listeners {
|
||||
if listener.GetId() == self.GetId() {
|
||||
listener.lb = self.lb
|
||||
err := jsonutils.Update(self, listener)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SLBListener) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetListenerType() string {
|
||||
switch self.Protocol {
|
||||
case "TCP":
|
||||
return models.LB_LISTENER_TYPE_TCP
|
||||
case "UDP":
|
||||
return models.LB_LISTENER_TYPE_UDP
|
||||
case "HTTP":
|
||||
return models.LB_LISTENER_TYPE_HTTP
|
||||
case "HTTPS":
|
||||
return models.LB_LISTENER_TYPE_HTTPS
|
||||
case "TCP_SSL":
|
||||
return models.LB_LISTENER_TYPE_TCP
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetListenerPort() int {
|
||||
return self.Port
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetScheduler() string {
|
||||
switch strings.ToLower(self.Scheduler) {
|
||||
case "wrr":
|
||||
return models.LB_SCHEDULER_WRR
|
||||
case "ip_hash":
|
||||
return models.LB_SCHEDULER_SCH
|
||||
case "least_conn":
|
||||
return models.LB_SCHEDULER_WLC
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetAclStatus() string {
|
||||
return models.LB_BOOL_OFF
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetAclType() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetAclId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheck() string {
|
||||
if self.HealthCheck.HealthSwitch == 0 {
|
||||
return models.LB_BOOL_OFF
|
||||
} else {
|
||||
return models.LB_BOOL_ON
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckType() string {
|
||||
if len(self.HealthCheck.HTTPCheckMethod) > 0 {
|
||||
return models.LB_HEALTH_CHECK_HTTP
|
||||
} else {
|
||||
return models.LB_HEALTH_CHECK_TCP
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckTimeout() int {
|
||||
return self.HealthCheck.TimeOut
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckInterval() int {
|
||||
return self.HealthCheck.IntervalTime
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckRise() int {
|
||||
return self.HealthCheck.HealthNum
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckFail() int {
|
||||
return self.HealthCheck.UnHealthNum
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckReq() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckExp() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetBackendGroup() *SLBBackendGroup {
|
||||
t := self.GetListenerType()
|
||||
// http、https类型的监听不能直接绑定服务器
|
||||
if t == models.LB_LISTENER_TYPE_HTTP || t == models.LB_LISTENER_TYPE_HTTPS {
|
||||
return nil
|
||||
} else {
|
||||
return &SLBBackendGroup{lb: self.lb, listener: self}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetBackendGroupId() string {
|
||||
bg := self.GetBackendGroup()
|
||||
if bg == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return bg.GetId()
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckDomain() string {
|
||||
return self.HealthCheck.HTTPCheckDomain
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckURI() string {
|
||||
return self.HealthCheck.HTTPCheckPath
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetHealthCheckCode() string {
|
||||
codes := []string{}
|
||||
for i := uint8(0); i < 5; i++ {
|
||||
n := 1 << i
|
||||
if (self.HealthCheck.HTTPCode & n) == n {
|
||||
codes = append(codes, HTTP_CODES[i])
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(codes, ",")
|
||||
}
|
||||
|
||||
// 仅http、https类型监听包含rules
|
||||
func (self *SLBListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) {
|
||||
rules := self.Rules
|
||||
iRules := []cloudprovider.ICloudLoadbalancerListenerRule{}
|
||||
for i := 0; i < len(rules); i++ {
|
||||
rules[i].listener = self
|
||||
iRules = append(iRules, &rules[i])
|
||||
}
|
||||
return iRules, nil
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetStickySession() string {
|
||||
if self.SessionExpireTime == 0 {
|
||||
return models.LB_BOOL_OFF
|
||||
} else {
|
||||
return models.LB_BOOL_ON
|
||||
}
|
||||
}
|
||||
|
||||
// 支持基于 cookie 插入的会话保持能力 https://cloud.tencent.com/document/product/214/6154
|
||||
func (self *SLBListener) GetStickySessionType() string {
|
||||
return models.LB_STICKY_SESSION_TYPE_INSERT
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/2736
|
||||
// 经测试应用型负载均衡返回都是 tgw_l7_route。
|
||||
func (self *SLBListener) GetStickySessionCookie() string {
|
||||
if self.GetListenerType() == models.LB_LISTENER_TYPE_HTTPS {
|
||||
return "tgw_l7_route"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetStickySessionCookieTimeout() int {
|
||||
return self.SessionExpireTime
|
||||
}
|
||||
|
||||
/*
|
||||
7层负载均衡系统提供 X-Forwarded-For 的方式获取访问者真实 IP,LB 侧默认开启
|
||||
|
||||
https://cloud.tencent.com/document/product/214/6151
|
||||
七层转发获取来访真实IP的方法 https://cloud.tencent.com/document/product/214/3728
|
||||
*/
|
||||
func (self *SLBListener) XForwardedForEnabled() bool {
|
||||
switch self.GetListenerType() {
|
||||
case models.LB_LISTENER_TYPE_HTTP, models.LB_LISTENER_TYPE_HTTPS:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP/HTTPS协议默认支持用户开启gzip压缩功能
|
||||
// 负载均衡开启Gzip配置及检测方法说明 https://cloud.tencent.com/document/product/214/5404
|
||||
func (self *SLBListener) GzipEnabled() bool {
|
||||
switch self.GetListenerType() {
|
||||
case models.LB_LISTENER_TYPE_HTTP, models.LB_LISTENER_TYPE_HTTPS:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SLBListener) GetCertificateId() string {
|
||||
return self.Certificate.CERTID
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/5412#2.-https.E6.94.AF.E6.8C.81.E5.93.AA.E4.BA.9B.E7.89.88.E6.9C.AC.E7.9A.84ssl.2Ftls.E5.AE.89.E5.85.A8.E5.8D.8F.E8.AE.AE.EF.BC.9F
|
||||
func (self *SLBListener) GetTLSCipherPolicy() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 负载均衡能力说明 https://cloud.tencent.com/document/product/214/6534
|
||||
func (self *SLBListener) HTTP2Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SRegion) GetLoadbalancerListeners(lbid string, t LB_TYPE, protocol string) ([]SLBListener, error) {
|
||||
params := map[string]string{"LoadBalancerId": lbid}
|
||||
if len(protocol) > 0 {
|
||||
params["Protocol"] = protocol
|
||||
}
|
||||
|
||||
listeners := []SLBListener{}
|
||||
if t == LB_TYPE_CLASSIC {
|
||||
resp, err := self.clbRequest("DescribeClassicalLBListeners", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clisteners := []SLBClassicListener{}
|
||||
err = resp.Unmarshal(&clisteners, "Listeners")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, l := range clisteners {
|
||||
listeners = append(listeners, l.ToLBListener())
|
||||
}
|
||||
|
||||
return listeners, nil
|
||||
}
|
||||
|
||||
resp, err := self.clbRequest("DescribeListeners", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = resp.Unmarshal(&listeners, "Listeners")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return listeners, nil
|
||||
}
|
||||
|
||||
// 返回requestID
|
||||
func (self *SRegion) CreateLoadbalancerListenerRule(lbid string, listenerId string, domain string, url string, scheduler *string, sessionExpireTime *int) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{
|
||||
"LoadBalancerId": lbid,
|
||||
"ListenerId": listenerId,
|
||||
"Rules.0.Domain": domain,
|
||||
"Rules.0.Url": url,
|
||||
}
|
||||
|
||||
if scheduler != nil && len(*scheduler) > 0 {
|
||||
params["Rules.0.Scheduler"] = *scheduler
|
||||
}
|
||||
|
||||
if sessionExpireTime != nil {
|
||||
params["Rules.0.SessionExpireTime"] = strconv.Itoa(*sessionExpireTime)
|
||||
}
|
||||
|
||||
resp, err := self.clbRequest("CreateRule", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
|
||||
// 返回requestID
|
||||
func (self *SRegion) deleteLoadbalancerListener(lbid string, listenerId string) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{
|
||||
"LoadBalancerId": lbid,
|
||||
"ListenerId": listenerId,
|
||||
}
|
||||
|
||||
resp, err := self.clbRequest("DeleteListener", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
|
||||
// 返回requestID
|
||||
func (self *SRegion) deleteClassicLoadbalancerListener(lbid string, listenerId string) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("classic loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{
|
||||
"loadBalancerId": lbid,
|
||||
"listenerIds.0": listenerId,
|
||||
}
|
||||
|
||||
resp, err := self.lbRequest("DeleteLoadBalancerListeners", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_requestId, err := resp.Float("requestId")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%.f", _requestId), nil
|
||||
}
|
||||
|
||||
// 返回requestID
|
||||
func (self *SRegion) DeleteLoadbalancerListener(t LB_TYPE, lbid string, listenerId string) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
if t == LB_TYPE_APPLICATION {
|
||||
return self.deleteLoadbalancerListener(lbid, listenerId)
|
||||
} else {
|
||||
return self.deleteClassicLoadbalancerListener(lbid, listenerId)
|
||||
}
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/product/214/30681
|
||||
func (self *SRegion) updateLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) {
|
||||
params := map[string]string{
|
||||
"LoadBalancerId": lbid,
|
||||
"ListenerId": listenerId,
|
||||
}
|
||||
|
||||
if listenerName != nil && len(*listenerName) > 0 {
|
||||
params["ListenerName"] = *listenerName
|
||||
}
|
||||
|
||||
if scheduler != nil && len(*scheduler) > 0 {
|
||||
params["Scheduler"] = *scheduler
|
||||
}
|
||||
|
||||
if sessionExpireTime != nil {
|
||||
params["SessionExpireTime"] = strconv.Itoa(*sessionExpireTime)
|
||||
}
|
||||
|
||||
params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "HealthCheck.")
|
||||
params = certificateParams(LB_TYPE_APPLICATION, params, cert, "Certificate.")
|
||||
|
||||
resp, err := self.clbRequest("ModifyListener", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/214/3601
|
||||
func (self *SRegion) updateClassicLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) {
|
||||
params := map[string]string{
|
||||
"loadBalancerId": lbid,
|
||||
"listenerId": listenerId,
|
||||
}
|
||||
|
||||
if listenerName != nil && len(*listenerName) > 0 {
|
||||
params["listenerName"] = *listenerName
|
||||
}
|
||||
|
||||
if scheduler != nil && len(*scheduler) > 0 {
|
||||
params["scheduler"] = strings.ToLower(*scheduler)
|
||||
}
|
||||
|
||||
if sessionExpireTime != nil {
|
||||
params["sessionExpire"] = strconv.Itoa(*sessionExpireTime)
|
||||
}
|
||||
|
||||
params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "listeners.0.")
|
||||
params = certificateParams(LB_TYPE_APPLICATION, params, cert, "listeners.0.")
|
||||
|
||||
resp, err := self.lbRequest("ModifyLoadBalancerListener", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
|
||||
func (self *SRegion) UpdateLoadbalancerListener(t LB_TYPE, lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
if len(listenerId) == 0 {
|
||||
return "", fmt.Errorf("loadbalancer listener id should not be empty")
|
||||
}
|
||||
|
||||
if t == LB_TYPE_APPLICATION {
|
||||
return self.updateLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert)
|
||||
} else {
|
||||
return self.updateClassicLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert)
|
||||
}
|
||||
}
|
||||
|
||||
func getHealthCheck(listener *cloudprovider.SLoadbalancerListener) *healthCheck {
|
||||
var hc *healthCheck
|
||||
if listener.HealthCheck == models.LB_BOOL_ON {
|
||||
hc = &healthCheck{
|
||||
HealthSwitch: 1,
|
||||
UnHealthNum: listener.HealthCheckFail,
|
||||
IntervalTime: listener.HealthCheckInterval,
|
||||
HealthNum: listener.HealthCheckRise,
|
||||
TimeOut: listener.HealthCheckTimeout,
|
||||
}
|
||||
|
||||
httpCode := onecloudHealthCodeToQcloud(listener.HealthCheckHttpCode)
|
||||
if httpCode > 0 {
|
||||
hc.HTTPCode = httpCode
|
||||
hc.HTTPCheckMethod = "HEAD" // todo: add column HttpCheckMethod in model
|
||||
hc.HTTPCheckDomain = listener.HealthCheckDomain
|
||||
hc.HTTPCheckPath = listener.HealthCheckURI
|
||||
}
|
||||
}
|
||||
|
||||
return hc
|
||||
}
|
||||
|
||||
func getCertificate(listener *cloudprovider.SLoadbalancerListener) *certificate {
|
||||
var cert *certificate
|
||||
if len(listener.CertificateID) > 0 {
|
||||
cert = &certificate{
|
||||
SSLMode: "UNIDIRECTIONAL",
|
||||
CERTCAID: listener.CertificateID,
|
||||
CERTID: "",
|
||||
}
|
||||
}
|
||||
|
||||
return cert
|
||||
}
|
||||
|
||||
func getProtocol(listener *cloudprovider.SLoadbalancerListener) string {
|
||||
switch listener.ListenerType {
|
||||
case models.LB_LISTENER_TYPE_HTTPS:
|
||||
return "HTTPS"
|
||||
case models.LB_LISTENER_TYPE_HTTP:
|
||||
return "HTTP"
|
||||
case models.LB_LISTENER_TYPE_TCP:
|
||||
return "TCP"
|
||||
case models.LB_LISTENER_TYPE_UDP:
|
||||
return "UDP"
|
||||
case "tcp_ssl":
|
||||
return "TCP_SSL"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func getClassicLBProtocol(listener *cloudprovider.SLoadbalancerListener) int {
|
||||
switch listener.ListenerType {
|
||||
case models.LB_LISTENER_TYPE_HTTP:
|
||||
return 1
|
||||
case models.LB_LISTENER_TYPE_HTTPS:
|
||||
return 4
|
||||
case models.LB_LISTENER_TYPE_TCP:
|
||||
return 2
|
||||
case models.LB_LISTENER_TYPE_UDP:
|
||||
return 3
|
||||
default:
|
||||
return 0 // 非法值
|
||||
}
|
||||
}
|
||||
|
||||
func getScheduler(listener *cloudprovider.SLoadbalancerListener) *string {
|
||||
var sch string
|
||||
switch listener.Scheduler {
|
||||
case models.LB_SCHEDULER_WRR:
|
||||
sch = "WRR"
|
||||
case models.LB_SCHEDULER_WLC:
|
||||
sch = "LEAST_CONN"
|
||||
case models.LB_SCHEDULER_SCH:
|
||||
sch = "IP_HASH"
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
return &sch
|
||||
}
|
||||
|
||||
func healthCheckParams(t LB_TYPE, params map[string]string, hc *healthCheck, paramPrefix string) map[string]string {
|
||||
if hc == nil {
|
||||
return params
|
||||
}
|
||||
|
||||
if t == LB_TYPE_APPLICATION {
|
||||
params[paramPrefix+"HealthSwitch"] = strconv.Itoa(hc.HealthSwitch)
|
||||
params[paramPrefix+"TimeOut"] = strconv.Itoa(hc.TimeOut)
|
||||
params[paramPrefix+"IntervalTime"] = strconv.Itoa(hc.IntervalTime)
|
||||
params[paramPrefix+"HealthNum"] = strconv.Itoa(hc.HealthNum)
|
||||
params[paramPrefix+"UnHealthNum"] = strconv.Itoa(hc.UnHealthNum)
|
||||
if hc.HTTPCode > 0 {
|
||||
params[paramPrefix+"HttpCode"] = strconv.Itoa(hc.HTTPCode)
|
||||
params[paramPrefix+"HttpCheckPath"] = hc.HTTPCheckPath
|
||||
params[paramPrefix+"HttpCheckDomain"] = hc.HTTPCheckDomain
|
||||
params[paramPrefix+"HttpCheckMethod"] = hc.HTTPCheckMethod
|
||||
}
|
||||
} else {
|
||||
params[paramPrefix+"healthSwitch"] = strconv.Itoa(hc.HealthSwitch)
|
||||
params[paramPrefix+"timeOut"] = strconv.Itoa(hc.TimeOut)
|
||||
params[paramPrefix+"intervalTime"] = strconv.Itoa(hc.IntervalTime)
|
||||
params[paramPrefix+"healthNum"] = strconv.Itoa(hc.HealthNum)
|
||||
params[paramPrefix+"unHealthNum"] = strconv.Itoa(hc.UnHealthNum)
|
||||
if hc.HTTPCode > 0 {
|
||||
params[paramPrefix+"httpCode"] = strconv.Itoa(hc.HTTPCode)
|
||||
params[paramPrefix+"httpCheckPath"] = hc.HTTPCheckPath
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func certificateParams(t LB_TYPE, params map[string]string, cert *certificate, paramPrefix string) map[string]string {
|
||||
if cert == nil {
|
||||
return params
|
||||
}
|
||||
|
||||
if t == LB_TYPE_APPLICATION {
|
||||
params[paramPrefix+"SSLMode"] = cert.SSLMode
|
||||
params[paramPrefix+"CertId"] = cert.CERTID
|
||||
if len(cert.CERTCAID) > 0 {
|
||||
params[paramPrefix+"CertCaId"] = cert.CERTCAID
|
||||
}
|
||||
} else {
|
||||
params[paramPrefix+"SSLMode"] = strings.ToLower(cert.SSLMode)
|
||||
params[paramPrefix+"certId"] = cert.CERTID
|
||||
if len(cert.CERTCAID) > 0 {
|
||||
params[paramPrefix+"certCaId"] = cert.CERTCAID
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
Executable
+138
@@ -0,0 +1,138 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
type SLBListenerRule struct {
|
||||
listener *SLBListener
|
||||
|
||||
Domain string `json:"Domain"`
|
||||
Certificate certificate `json:"Certificate"`
|
||||
URL string `json:"Url"`
|
||||
HealthCheck healthCheck `json:"HealthCheck"`
|
||||
LocationID string `json:"LocationId"`
|
||||
Scheduler string `json:"Scheduler"`
|
||||
SessionExpireTime int64 `json:"SessionExpireTime"`
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/214/30688
|
||||
func (self *SLBListenerRule) Delete() error {
|
||||
_, err := self.listener.lb.region.DeleteLBListenerRule(self.listener.lb.GetId(), self.listener.GetId(), self.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cloudprovider.WaitDeleted(self, 5*time.Second, 60*time.Second)
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetId() string {
|
||||
return self.LocationID
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetName() string {
|
||||
return self.LocationID
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetGlobalId() string {
|
||||
return self.LocationID
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetStatus() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) Refresh() error {
|
||||
err := self.listener.Refresh()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rule := range self.listener.Rules {
|
||||
if rule.GetId() == self.GetId() {
|
||||
rule.listener = self.listener
|
||||
return jsonutils.Update(self, rule)
|
||||
}
|
||||
}
|
||||
|
||||
return cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetDomain() string {
|
||||
return self.Domain
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetPath() string {
|
||||
return self.URL
|
||||
}
|
||||
|
||||
func (self *SLBListenerRule) GetBackendGroup() *SLBBackendGroup {
|
||||
t := self.listener.GetListenerType()
|
||||
if t == models.LB_LISTENER_TYPE_HTTP || t == models.LB_LISTENER_TYPE_HTTPS {
|
||||
return &SLBBackendGroup{
|
||||
lb: self.listener.lb,
|
||||
listener: self.listener,
|
||||
rule: self,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 只有http、https协议监听规则有backendgroupid
|
||||
func (self *SLBListenerRule) GetBackendGroupId() string {
|
||||
bg := self.GetBackendGroup()
|
||||
if bg == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return bg.GetId()
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/214/30688
|
||||
// 返回requestId及error
|
||||
func (self *SRegion) DeleteLBListenerRule(lbid, listenerId, ruleId string) (string, error) {
|
||||
if len(ruleId) == 0 {
|
||||
return "", fmt.Errorf("DeleteLBListenerRule rule id should not be empty")
|
||||
}
|
||||
return self.DeleteLBListenerRules(lbid, listenerId, []string{ruleId})
|
||||
}
|
||||
|
||||
func (self *SRegion) DeleteLBListenerRules(lbid, listenerId string, ruleIds []string) (string, error) {
|
||||
if len(lbid) == 0 {
|
||||
return "", fmt.Errorf("DeleteLBListenerRules loadbalancer id should not be empty")
|
||||
}
|
||||
|
||||
if len(listenerId) == 0 {
|
||||
return "", fmt.Errorf("DeleteLBListenerRules listener id should not be empty")
|
||||
}
|
||||
|
||||
if len(ruleIds) == 0 {
|
||||
return "", fmt.Errorf("DeleteLBListenerRules rule id should not be empty")
|
||||
}
|
||||
|
||||
params := map[string]string{"LoadBalancerId": lbid, "ListenerId": listenerId}
|
||||
for i, ruleId := range ruleIds {
|
||||
params[fmt.Sprintf("LocationIds.%d", i)] = ruleId
|
||||
}
|
||||
|
||||
resp, err := self.clbRequest("DeleteRule", params)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.GetString("RequestId")
|
||||
}
|
||||
+181
-14
@@ -1,11 +1,13 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
|
||||
@@ -23,6 +25,7 @@ const (
|
||||
QCLOUD_DEFAULT_REGION = "ap-beijing"
|
||||
|
||||
QCLOUD_API_VERSION = "2017-03-12"
|
||||
QCLOUD_CLB_API_VERSION = "2018-03-17"
|
||||
QCLOUD_BILLING_API_VERSION = "2018-07-09"
|
||||
)
|
||||
|
||||
@@ -48,40 +51,153 @@ func NewQcloudClient(providerId string, providerName string, secretID string, se
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
func jsonRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := "cvm.tencentcloudapi.com"
|
||||
if region, ok := params["Region"]; ok && strings.HasSuffix(region, "-fsi") {
|
||||
domain = "cvm." + region + ".tencentcloudapi.com"
|
||||
// 默认接口请求频率限制:20次/秒
|
||||
// 部分接口支持金融区地域。由于金融区和非金融区是隔离不互通的,因此当公共参数 Region 为金融区地域(例如 ap-shanghai-fsi)时,需要同时指定带金融区地域的域名,最好和 Region 的地域保持一致,例如:clb.ap-shanghai-fsi.tencentcloudapi.com
|
||||
// https://cloud.tencent.com/document/product/416/6479
|
||||
func apiDomain(product string, params map[string]string) string {
|
||||
region, ok := params["Region"]
|
||||
if ok && strings.HasSuffix(region, "-fsi") {
|
||||
return product + "." + region + ".tencentcloudapi.com"
|
||||
} else {
|
||||
return product + ".tencentcloudapi.com"
|
||||
}
|
||||
}
|
||||
|
||||
func jsonRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := apiDomain("cvm", params)
|
||||
return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params)
|
||||
}
|
||||
|
||||
func vpcRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := "vpc.tencentcloudapi.com"
|
||||
if region, ok := params["Region"]; ok && strings.HasSuffix(region, "-fsi") {
|
||||
domain = "vpc." + region + ".tencentcloudapi.com"
|
||||
}
|
||||
domain := apiDomain("vpc", params)
|
||||
return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params)
|
||||
}
|
||||
|
||||
func cbsRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := "cbs.tencentcloudapi.com"
|
||||
if region, ok := params["Region"]; ok && strings.HasSuffix(region, "-fsi") {
|
||||
domain = "cbs." + region + ".tencentcloudapi.com"
|
||||
}
|
||||
domain := apiDomain("cbs", params)
|
||||
return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params)
|
||||
}
|
||||
|
||||
// loadbalancer服务 api 3.0
|
||||
func clbRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := apiDomain("clb", params)
|
||||
return _jsonRequest(client, domain, QCLOUD_CLB_API_VERSION, apiName, params)
|
||||
}
|
||||
|
||||
// loadbalancer服务 api 2017
|
||||
func lbRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := "lb.api.qcloud.com"
|
||||
return _phpJsonRequest(client, &lbJsonResponse{}, domain, "/v2/index.php", "", apiName, params)
|
||||
}
|
||||
|
||||
// ssl 证书服务
|
||||
func wssRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := "wss.api.qcloud.com"
|
||||
return _phpJsonRequest(client, &wssJsonResponse{}, domain, "/v2/index.php", "", apiName, params)
|
||||
}
|
||||
|
||||
func billingRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
domain := "billing.tencentcloudapi.com"
|
||||
return _jsonRequest(client, domain, QCLOUD_BILLING_API_VERSION, apiName, params)
|
||||
}
|
||||
|
||||
// ============phpJsonRequest============
|
||||
type qcloudResponse interface {
|
||||
tchttp.Response
|
||||
GetResponse() *interface{}
|
||||
}
|
||||
|
||||
type phpJsonRequest struct {
|
||||
tchttp.BaseRequest
|
||||
Path string
|
||||
}
|
||||
|
||||
func (r *phpJsonRequest) GetUrl() string {
|
||||
url := r.BaseRequest.GetUrl()
|
||||
if url == "" {
|
||||
return url
|
||||
}
|
||||
|
||||
index := strings.Index(url, "?")
|
||||
if index == -1 {
|
||||
// POST request
|
||||
return strings.TrimSuffix(url, "/") + r.Path
|
||||
}
|
||||
|
||||
p1, p2 := url[:index], url[index:]
|
||||
p1 = strings.TrimSuffix(p1, "/")
|
||||
return p1 + r.Path + p2
|
||||
}
|
||||
|
||||
func (r *phpJsonRequest) GetPath() string {
|
||||
return r.Path
|
||||
}
|
||||
|
||||
// SSL证书专用response
|
||||
type wssJsonResponse struct {
|
||||
Code int `json:"code"`
|
||||
CodeDesc string `json:"codeDesc"`
|
||||
Message string `json:"message"`
|
||||
Response *interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (r *wssJsonResponse) ParseErrorFromHTTPResponse(body []byte) (err error) {
|
||||
resp := &wssJsonResponse{}
|
||||
err = json.Unmarshal(body, resp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.Code != 0 {
|
||||
return errors.NewTencentCloudSDKError(resp.CodeDesc, resp.Message, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *wssJsonResponse) GetResponse() *interface{} {
|
||||
return r.Response
|
||||
}
|
||||
|
||||
// 2017版负载均衡API专用response
|
||||
type lbJsonResponse struct {
|
||||
Response map[string]interface{}
|
||||
}
|
||||
|
||||
func (r *lbJsonResponse) ParseErrorFromHTTPResponse(body []byte) (err error) {
|
||||
resp := &wssJsonResponse{}
|
||||
err = json.Unmarshal(body, resp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.Code != 0 {
|
||||
return errors.NewTencentCloudSDKError(resp.CodeDesc, resp.Message, "")
|
||||
}
|
||||
|
||||
// hook 由于目前只能从这个方法中拿到原始的body.这里将原始body hook 到 Response
|
||||
err = json.Unmarshal(body, &r.Response)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *lbJsonResponse) GetResponse() *interface{} {
|
||||
return func(resp interface{}) *interface{} {
|
||||
return &resp
|
||||
}(r.Response)
|
||||
}
|
||||
|
||||
// 3.0版本通用response
|
||||
type QcloudResponse struct {
|
||||
*tchttp.BaseResponse
|
||||
Response *interface{} `json:"Response"`
|
||||
}
|
||||
|
||||
func (r *QcloudResponse) GetResponse() *interface{} {
|
||||
return r.Response
|
||||
}
|
||||
|
||||
func _jsonRequest(client *common.Client, domain string, version string, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
req := &tchttp.BaseRequest{}
|
||||
if region, ok := params["Region"]; ok {
|
||||
@@ -98,9 +214,36 @@ func _jsonRequest(client *common.Client, domain string, version string, apiName
|
||||
}
|
||||
req.GetParams()[k] = v
|
||||
}
|
||||
|
||||
resp := &QcloudResponse{
|
||||
BaseResponse: &tchttp.BaseResponse{},
|
||||
}
|
||||
return _baseJsonRequest(client, req, resp)
|
||||
}
|
||||
|
||||
// 老版本腾讯云api。 适用于类似 https://cvm.api.qcloud.com/v2/index.php 这样的带/v2/index.php路径的接口
|
||||
// todo: 添加自定义response参数
|
||||
func _phpJsonRequest(client *common.Client, resp qcloudResponse, domain string, path string, version string, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
req := &phpJsonRequest{Path: path}
|
||||
if region, ok := params["Region"]; ok {
|
||||
client = client.Init(region)
|
||||
}
|
||||
client.WithProfile(profile.NewClientProfile())
|
||||
service := strings.Split(domain, ".")[0]
|
||||
req.Init().WithApiInfo(service, version, apiName)
|
||||
req.SetDomain(domain)
|
||||
|
||||
for k, v := range params {
|
||||
if strings.HasSuffix(k, "Ids.0") && len(v) == 0 {
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
req.GetParams()[k] = v
|
||||
}
|
||||
|
||||
return _baseJsonRequest(client, req, resp)
|
||||
}
|
||||
|
||||
func _baseJsonRequest(client *common.Client, req tchttp.Request, resp qcloudResponse) (jsonutils.JSONObject, error) {
|
||||
for i := 1; i <= 3; i++ {
|
||||
err := client.Send(req, resp)
|
||||
if err == nil {
|
||||
@@ -118,10 +261,10 @@ func _jsonRequest(client *common.Client, domain string, version string, apiName
|
||||
time.Sleep(time.Second * time.Duration(i*10))
|
||||
continue
|
||||
}
|
||||
log.Errorf("request url: %s\nparams: %s\nresponse: %s\nerror: %v", req.GetDomain(), jsonutils.Marshal(req.GetParams()).PrettyString(), resp.Response, err)
|
||||
log.Errorf("request url: %s\nparams: %s\nresponse: %s\nerror: %v", req.GetDomain(), jsonutils.Marshal(req.GetParams()).PrettyString(), resp.GetResponse(), err)
|
||||
return nil, err
|
||||
}
|
||||
return jsonutils.Marshal(resp.Response), nil
|
||||
return jsonutils.Marshal(resp.GetResponse()), nil
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) GetRegions() []SRegion {
|
||||
@@ -153,6 +296,30 @@ func (client *SQcloudClient) cbsRequest(apiName string, params map[string]string
|
||||
return cbsRequest(cli, apiName, params)
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) clbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
cli, err := client.getDefaultClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return clbRequest(cli, apiName, params)
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
cli, err := client.getDefaultClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lbRequest(cli, apiName, params)
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) wssRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
cli, err := client.getDefaultClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wssRequest(cli, apiName, params)
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) billingRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
cli, err := client.getDefaultClient()
|
||||
if err != nil {
|
||||
|
||||
+182
-40
@@ -2,6 +2,7 @@ package qcloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/nelsonken/cos-go-sdk-v5/cos"
|
||||
|
||||
@@ -33,6 +34,173 @@ type SRegion struct {
|
||||
fetchLocation bool
|
||||
}
|
||||
|
||||
func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
|
||||
lbs, err := self.GetLoadbalancers(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ilbs := make([]cloudprovider.ICloudLoadbalancer, len(lbs))
|
||||
for i := range lbs {
|
||||
lbs[i].region = self
|
||||
ilbs[i] = &lbs[i]
|
||||
}
|
||||
|
||||
return ilbs, nil
|
||||
}
|
||||
|
||||
// 腾讯云不支持acl
|
||||
func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return []cloudprovider.ICloudLoadbalancerAcl{}, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
lbs, err := self.GetLoadbalancers(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
icerts := []cloudprovider.ICloudLoadbalancerCertificate{}
|
||||
for _, lb := range lbs {
|
||||
listeners, err := lb.GetLoadbalancerListeners("HTTPS")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certIds := []string{}
|
||||
for _, listener := range listeners {
|
||||
if len(listener.Certificate.CERTID) > 0 && !utils.IsInStringArray(listener.Certificate.CERTID, certIds) {
|
||||
certIds = append(certIds, listener.Certificate.CERTID)
|
||||
}
|
||||
|
||||
if len(listener.Certificate.CERTCAID) > 0 && !utils.IsInStringArray(listener.Certificate.CERTCAID, certIds) {
|
||||
certIds = append(certIds, listener.Certificate.CERTCAID)
|
||||
}
|
||||
|
||||
for _, rule := range listener.Rules {
|
||||
if len(rule.Certificate.CERTID) > 0 && !utils.IsInStringArray(rule.Certificate.CERTID, certIds) {
|
||||
certIds = append(certIds, rule.Certificate.CERTID)
|
||||
}
|
||||
|
||||
if len(rule.Certificate.CERTCAID) > 0 && !utils.IsInStringArray(rule.Certificate.CERTCAID, certIds) {
|
||||
certIds = append(certIds, rule.Certificate.CERTCAID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, cid := range certIds {
|
||||
icert, err := self.GetILoadBalancerCertificateById(cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
icerts = append(icerts, icert)
|
||||
}
|
||||
}
|
||||
|
||||
return icerts, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
certs, _, err := self.GetCertificates(certId, true, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
icerts := []cloudprovider.ICloudLoadbalancerCertificate{}
|
||||
for i := 0; i < len(certs); i++ {
|
||||
cert := SLBCertificate{region: self, SCertificate: certs[i]}
|
||||
icerts = append(icerts, &cert)
|
||||
}
|
||||
|
||||
if len(certs) == 1 {
|
||||
return icerts[0], nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("GetILoadBalancerCertificateById %d certificate found, expect 1", len(certs))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
|
||||
lbs, err := self.GetLoadbalancers([]string{loadbalancerId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(lbs) == 1 {
|
||||
lbs[0].region = self
|
||||
return &lbs[0], nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("GetILoadBalancerById %d loadbalancer found", len(lbs))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// https://cloud.tencent.com/document/api/214/30692
|
||||
// todo: 1. 支持跨地域绑定负载均衡 及 https://cloud.tencent.com/document/product/214/12014
|
||||
// todo: 2. 支持指定Project。 ProjectId可以通过 DescribeProject 接口获取。不填则属于默认项目。
|
||||
func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
|
||||
LoadBalancerType := "INTERNAL"
|
||||
if loadbalancer.AddressType == "public" {
|
||||
LoadBalancerType = "OPEN"
|
||||
}
|
||||
params := map[string]string{
|
||||
"LoadBalancerType": LoadBalancerType,
|
||||
"LoadBalancerName": loadbalancer.Name,
|
||||
"VpcId": loadbalancer.VpcID,
|
||||
"SubnetId": loadbalancer.NetworkID,
|
||||
}
|
||||
|
||||
resp, err := self.clbRequest("CreateLoadBalancer", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requestId, err := resp.GetString("RequestId")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lbs, err := resp.GetArray("LoadBalancerIds")
|
||||
if err != nil || len(lbs) != 1 {
|
||||
log.Debugf("CreateILoadBalancer %s", resp.String())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = self.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return self.GetLoadbalancer(lbs[0].String())
|
||||
}
|
||||
|
||||
func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
// todo:目前onecloud端只能指定服务器端证书。需要兼容客户端证书?
|
||||
func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
certId, err := self.CreateCertificate(cert.Certificate, "SVR", cert.PrivateKey, cert.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certs, _, err := self.GetCertificates(certId, false, 10, 0)
|
||||
if len(certs) != 1 || err != nil {
|
||||
log.Debugf("CreateILoadBalancerCertificate failed. %d certificate matched", len(certs))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SLBCertificate{region: self, SCertificate: certs[0]}, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetId() string {
|
||||
return self.Region
|
||||
}
|
||||
@@ -439,6 +607,20 @@ func (self *SRegion) cbsRequest(apiName string, params map[string]string) (jsonu
|
||||
return self.client.cbsRequest(apiName, params)
|
||||
}
|
||||
|
||||
func (self *SRegion) clbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
params["Region"] = self.Region
|
||||
return self.client.clbRequest(apiName, params)
|
||||
}
|
||||
|
||||
func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
params["Region"] = self.Region
|
||||
return self.client.lbRequest(apiName, params)
|
||||
}
|
||||
|
||||
func (self *SRegion) wssRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
|
||||
return self.client.wssRequest(apiName, params)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetNetworks(ids []string, vpcId string, offset int, limit int) ([]SNetwork, int, error) {
|
||||
if limit > 50 || limit <= 0 {
|
||||
limit = 50
|
||||
@@ -591,43 +773,3 @@ func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) {
|
||||
}
|
||||
return instance.InstanceState, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user