aws elb support

This commit is contained in:
TangBin
2019-07-28 11:25:54 +08:00
committed by tangbin
parent 976c8cb4d0
commit e4ef23515f
187 changed files with 56297 additions and 5473 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ require (
github.com/anacrolix/torrent v0.0.0-20181129073333-cc531b8c4a80
github.com/aokoli/goutils v1.0.1
github.com/apache/thrift v0.0.0-20180514124809-e59b73d3c2bf // indirect
github.com/aws/aws-sdk-go v1.15.73
github.com/aws/aws-sdk-go v1.21.4
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/bitly/go-simplejson v0.5.0
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
+4 -4
View File
@@ -65,8 +65,8 @@ github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg=
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
github.com/apache/thrift v0.0.0-20180514124809-e59b73d3c2bf h1:AmV4ypk1GFDRKjzX6eO47pRAoSO5FTjyVqRYhZmHhms=
github.com/apache/thrift v0.0.0-20180514124809-e59b73d3c2bf/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/aws/aws-sdk-go v1.15.73 h1:Xzo/nSFgDfRNHRkXc03nT9389YFFaxqsy9clPwAoff0=
github.com/aws/aws-sdk-go v1.15.73/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/aws/aws-sdk-go v1.21.4 h1:1xB+x6Dzev8ETmeHEiSfUVbIzmC/0EyFfXMkJpzKPCE=
github.com/aws/aws-sdk-go v1.21.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
@@ -223,8 +223,8 @@ github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
+2 -2
View File
@@ -40,8 +40,8 @@ const (
EIP_CHARGE_TYPE_DEFAULT = EIP_CHARGE_TYPE_BY_TRAFFIC
// EIP associate resource type
EIP_ASSOCIATE_TYPE_VM = "SERVER"
EIP_ASSOCIATE_TYPE_ELB = "ELB"
EIP_ASSOCIATE_TYPE_VM = "server"
EIP_ASSOCIATE_TYPE_ELB = "elb"
)
var (
+30 -7
View File
@@ -88,6 +88,9 @@ const (
LB_ALIYUN_SPEC_S2_MEDIUM = "slb.s2.medium"
LB_ALIYUN_SPEC_S3_MEDIUM = "slb.s3.medium"
LB_ALIYUN_SPEC_S3_LARGE = "slb.s3.large"
LB_AWS_SPEC_APPLICATION = "application"
LB_AWS_SPEC_NETWORK = "network"
)
const (
@@ -105,6 +108,11 @@ var LB_ALIYUN_SPECS = choices.NewChoices(
LB_ALIYUN_SPEC_S3_LARGE,
)
var LB_AWS_SPECS = choices.NewChoices(
LB_AWS_SPEC_APPLICATION,
LB_AWS_SPEC_NETWORK,
)
// Load Balancer network type (vpc or classic) determines viable backend
// servers (they should be from the same network type as the load balancer).
//
@@ -134,10 +142,11 @@ var LB_NETWORK_TYPES = choices.NewChoices(
// TODO https_direct sni
const (
LB_LISTENER_TYPE_TCP = "tcp"
LB_LISTENER_TYPE_UDP = "udp"
LB_LISTENER_TYPE_HTTP = "http"
LB_LISTENER_TYPE_HTTPS = "https"
LB_LISTENER_TYPE_TCP = "tcp"
LB_LISTENER_TYPE_UDP = "udp"
LB_LISTENER_TYPE_TCP_UDP = "tcp_udp"
LB_LISTENER_TYPE_HTTP = "http"
LB_LISTENER_TYPE_HTTPS = "https"
)
var LB_LISTENER_TYPES = choices.NewChoices(
@@ -147,6 +156,19 @@ var LB_LISTENER_TYPES = choices.NewChoices(
LB_LISTENER_TYPE_HTTPS,
)
// aws_network_lb_listener
var AWS_NETWORK_LB_LISTENER_TYPES = choices.NewChoices(
LB_LISTENER_TYPE_TCP,
LB_LISTENER_TYPE_UDP,
// LB_LISTENER_TYPE_TCP_UDP
)
// aws_application_lb_listener
var AWS_APPLICATION_LB_LISTENER_TYPES = choices.NewChoices(
LB_LISTENER_TYPE_HTTP,
LB_LISTENER_TYPE_HTTPS,
)
// huawei backend group protocal choices
var HUAWEI_LBBG_PROTOCOL_TYPES = choices.NewChoices(
LB_LISTENER_TYPE_TCP,
@@ -212,9 +234,10 @@ var LB_STICKY_SESSION_TYPES = choices.NewChoices(
// TODO maybe https check when field need comes ;)
const (
LB_HEALTH_CHECK_TCP = "tcp"
LB_HEALTH_CHECK_UDP = "udp"
LB_HEALTH_CHECK_HTTP = "http"
LB_HEALTH_CHECK_TCP = "tcp"
LB_HEALTH_CHECK_UDP = "udp"
LB_HEALTH_CHECK_HTTP = "http"
LB_HEALTH_CHECK_HTTPS = "https"
)
var LB_HEALTH_CHECK_TYPES = choices.NewChoices(
+4
View File
@@ -22,6 +22,10 @@ import (
type SFakeOnPremiseRegion struct {
}
func (region *SFakeOnPremiseRegion) GetILoadBalancerBackendGroups() ([]ICloudLoadbalancerBackendGroup, error) {
return nil, ErrNotSupported
}
func (region *SFakeOnPremiseRegion) GetId() string {
return "default"
}
+1 -1
View File
@@ -20,7 +20,7 @@ type SLoadbalancer struct {
Name string
ZoneID string
VpcID string
NetworkID string
NetworkIDs []string
EipID string // eip id
Address string
AddressType string
@@ -26,6 +26,9 @@ type SLoadbalancerBackendGroup struct {
Scheduler string
StickySession *SLoadbalancerStickySession
HealthCheck *SLoadbalancerHealthCheck
// aws
ListenPort int // 后端端口
VpcId string // vpc id
}
type SLoadbalancerHealthCheck struct {
@@ -35,6 +35,7 @@ type SLoadbalancerListener struct {
HealthCheckExp string
HealthCheck string
HealthCheckType string
HealthCheckTimeout int
HealthCheckDomain string
HealthCheckHttpCode string
@@ -62,4 +63,6 @@ type SLoadbalancerListenerRule struct {
Path string
BackendGroupID string
BackendGroupType string
Condition string // for aws only
}
+4 -1
View File
@@ -97,6 +97,7 @@ type ICloudRegion interface {
GetILoadBalancers() ([]ICloudLoadbalancer, error)
GetILoadBalancerAcls() ([]ICloudLoadbalancerAcl, error)
GetILoadBalancerCertificates() ([]ICloudLoadbalancerCertificate, error)
GetILoadBalancerBackendGroups() ([]ICloudLoadbalancerBackendGroup, error) // for aws only
GetILoadBalancerById(loadbalancerId string) (ICloudLoadbalancer, error)
GetILoadBalancerAclById(aclId string) (ICloudLoadbalancerAcl, error)
@@ -458,7 +459,7 @@ type ICloudLoadbalancer interface {
GetAddress() string
GetAddressType() string
GetNetworkType() string
GetNetworkId() string
GetNetworkIds() []string
GetVpcId() string
GetZoneId() string
GetLoadbalancerSpec() string
@@ -538,6 +539,7 @@ type ICloudLoadbalancerListenerRule interface {
GetDomain() string
GetPath() string
GetCondition() string
GetBackendGroupId() string
Delete() error
@@ -548,6 +550,7 @@ type ICloudLoadbalancerBackendGroup interface {
IsDefault() bool
GetType() string
GetLoadbalancerId() string
GetILoadbalancerBackends() ([]ICloudLoadbalancerBackend, error)
GetILoadbalancerBackendById(backendId string) (ICloudLoadbalancerBackend, error)
GetProtocolType() string // huawei only .后端云服务器组的后端协议。
+59 -9
View File
@@ -17,7 +17,7 @@ func syncRegionLoadbalancerCertificates(ctx context.Context, userCred mcclient.T
certificates, err := remoteRegion.GetILoadBalancerCertificates()
if err != nil {
msg := fmt.Sprintf("GetILoadBalancerCertificates for region %s failed %s", remoteRegion.GetName(), err)
log.Errorf(msg)
log.Errorln(msg)
return
}
result := CachedLoadbalancerCertificateManager.SyncLoadbalancerCertificates(ctx, userCred, provider, localRegion, certificates, syncRange)
@@ -35,7 +35,7 @@ func syncRegionLoadbalancerAcls(ctx context.Context, userCred mcclient.TokenCred
acls, err := remoteRegion.GetILoadBalancerAcls()
if err != nil {
msg := fmt.Sprintf("GetILoadBalancerAcls for region %s failed %s", remoteRegion.GetName(), err)
log.Errorf(msg)
log.Errorln(msg)
return
}
result := CachedLoadbalancerAclManager.SyncLoadbalancerAcls(ctx, userCred, provider, localRegion, acls, syncRange)
@@ -53,7 +53,7 @@ func syncRegionLoadbalancers(ctx context.Context, userCred mcclient.TokenCredent
lbs, err := remoteRegion.GetILoadBalancers()
if err != nil {
msg := fmt.Sprintf("GetILoadBalancers for region %s failed %s", remoteRegion.GetName(), err)
log.Errorf(msg)
log.Errorln(msg)
return
}
localLbs, remoteLbs, result := LoadbalancerManager.SyncLoadbalancers(ctx, userCred, provider, localRegion, lbs, syncRange)
@@ -66,6 +66,9 @@ func syncRegionLoadbalancers(ctx context.Context, userCred mcclient.TokenCredent
return
}
db.OpsLog.LogEvent(provider, db.ACT_SYNC_LB_COMPLETE, msg, userCred)
// 同步未关联负载均衡的后端服务器组
syncAwsLoadbalancerBackendgroups(ctx, userCred, syncResults, provider, localRegion, remoteRegion, syncRange)
for i := 0; i < len(localLbs); i++ {
func() {
lockman.LockObject(ctx, &localLbs[i])
@@ -74,6 +77,8 @@ func syncRegionLoadbalancers(ctx context.Context, userCred mcclient.TokenCredent
syncLoadbalancerEip(ctx, userCred, provider, &localLbs[i], remoteLbs[i])
switch provider.Provider {
case compute.CLOUD_PROVIDER_AWS:
break
case compute.CLOUD_PROVIDER_HUAWEI:
syncHuaweiLoadbalancerBackendgroups(ctx, userCred, syncResults, provider, &localLbs[i], remoteLbs[i], syncRange)
default:
@@ -104,7 +109,7 @@ func syncLoadbalancerListeners(ctx context.Context, userCred mcclient.TokenCrede
remoteListeners, err := remoteLoadbalancer.GetILoadBalancerListeners()
if err != nil {
msg := fmt.Sprintf("GetILoadBalancerListeners for loadbalancer %s failed %s", localLoadbalancer.Name, err)
log.Errorf(msg)
log.Errorln(msg)
return
}
localListeners, remoteListeners, result := LoadbalancerListenerManager.SyncLoadbalancerListeners(ctx, userCred, provider, localLoadbalancer, remoteListeners, syncRange)
@@ -131,7 +136,7 @@ func syncLoadbalancerListenerRules(ctx context.Context, userCred mcclient.TokenC
remoteRules, err := remoteListener.GetILoadbalancerListenerRules()
if err != nil {
msg := fmt.Sprintf("GetILoadbalancerListenerRules for listener %s failed %s", localListener.Name, err)
log.Errorf(msg)
log.Errorln(msg)
return
}
result := LoadbalancerListenerRuleManager.SyncLoadbalancerListenerRules(ctx, userCred, provider, localListener, remoteRules, syncRange)
@@ -149,7 +154,7 @@ func syncLoadbalancerBackendgroups(ctx context.Context, userCred mcclient.TokenC
remoteBackendgroups, err := remoteLoadbalancer.GetILoadBalancerBackendGroups()
if err != nil {
msg := fmt.Sprintf("GetILoadBalancerBackendGroups for loadbalancer %s failed %s", localLoadbalancer.Name, err)
log.Errorf(msg)
log.Errorln(msg)
return
}
localLbbgs, remoteLbbgs, result := LoadbalancerBackendGroupManager.SyncLoadbalancerBackendgroups(ctx, userCred, provider, localLoadbalancer, remoteBackendgroups, syncRange)
@@ -175,7 +180,7 @@ func syncLoadbalancerBackends(ctx context.Context, userCred mcclient.TokenCreden
remoteLbbs, err := remoteLbbg.GetILoadbalancerBackends()
if err != nil {
msg := fmt.Sprintf("GetILoadbalancerBackends for lbbg %s failed %s", localLbbg.Name, err)
log.Errorf(msg)
log.Errorln(msg)
return
}
result := LoadbalancerBackendManager.SyncLoadbalancerBackends(ctx, userCred, provider, localLbbg, remoteLbbs, syncRange)
@@ -194,7 +199,7 @@ func syncHuaweiLoadbalancerBackendgroups(ctx context.Context, userCred mcclient.
remoteBackendgroups, err := remoteLoadbalancer.GetILoadBalancerBackendGroups()
if err != nil {
msg := fmt.Sprintf("GetILoadBalancerBackendGroups for loadbalancer %s failed %s", localLoadbalancer.Name, err)
log.Errorf(msg)
log.Errorln(msg)
return
}
localLbbgs, remoteLbbgs, result := HuaweiCachedLbbgManager.SyncLoadbalancerBackendgroups(ctx, userCred, provider, localLoadbalancer, remoteBackendgroups, syncRange)
@@ -220,7 +225,7 @@ func syncHuaweiLoadbalancerBackends(ctx context.Context, userCred mcclient.Token
remoteLbbs, err := remoteLbbg.GetILoadbalancerBackends()
if err != nil {
msg := fmt.Sprintf("GetILoadbalancerBackends for lbbg %s failed %s", localLbbg.Name, err)
log.Errorf(msg)
log.Errorln(msg)
return
}
result := HuaweiCachedLbManager.SyncLoadbalancerBackends(ctx, userCred, provider, localLbbg, remoteLbbs, syncRange)
@@ -233,3 +238,48 @@ func syncHuaweiLoadbalancerBackends(ctx context.Context, userCred mcclient.Token
return
}
}
/*aws elb sync*/
func syncAwsLoadbalancerBackendgroups(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *SSyncRange) {
remoteBackendgroups, err := remoteRegion.GetILoadBalancerBackendGroups()
if err != nil {
msg := fmt.Sprintf("GetILoadBalancerBackendGroups for region %s failed %s", localRegion.Name, err)
log.Errorln(msg)
return
}
localLbbgs, remoteLbbgs, result := AwsCachedLbbgManager.SyncLoadbalancerBackendgroups(ctx, userCred, provider, localRegion, remoteBackendgroups, syncRange)
syncResults.Add(LoadbalancerBackendGroupManager, result)
msg := result.Result()
log.Infof("SyncLoadbalancerBackendgroups for region %s result: %s", localRegion.Name, msg)
if result.IsError() {
return
}
for i := 0; i < len(localLbbgs); i++ {
func() {
lockman.LockObject(ctx, &localLbbgs[i])
defer lockman.ReleaseObject(ctx, &localLbbgs[i])
syncAwsLoadbalancerBackends(ctx, userCred, syncResults, provider, &localLbbgs[i], remoteLbbgs[i], syncRange)
}()
}
}
func syncAwsLoadbalancerBackends(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localLbbg *SAwsCachedLbbg, remoteLbbg cloudprovider.ICloudLoadbalancerBackendGroup, syncRange *SSyncRange) {
remoteLbbs, err := remoteLbbg.GetILoadbalancerBackends()
if err != nil {
msg := fmt.Sprintf("GetILoadbalancerBackends for lbbg %s failed %s", localLbbg.Name, err)
log.Errorln(msg)
return
}
result := AwsCachedLbManager.SyncLoadbalancerBackends(ctx, userCred, provider, localLbbg, remoteLbbs, syncRange)
syncResults.Add(LoadbalancerBackendManager, result)
msg := result.Result()
log.Infof("SyncLoadbalancerBackends for LoadbalancerBackendgroup %s result: %s", localLbbg.Name, msg)
if result.IsError() {
return
}
}
+1
View File
@@ -40,6 +40,7 @@ func InitDB() error {
SecurityGroupManager,
NetworkManager,
LoadbalancerCertificateManager,
LoadbalancerAclManager,
LoadbalancerManager,
LoadbalancerListenerManager,
LoadbalancerListenerRuleManager,
+35 -4
View File
@@ -134,10 +134,13 @@ func init() {
type SLoadbalancerAcl struct {
db.SSharableVirtualResourceBase
// db.SExternalizedResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SCloudregionResourceBase
AclEntries *SLoadbalancerAclEntries `list:"user" update:"user" create:"required"`
Fingerprint string `name:"fingerprint" width:"64" charset:"ascii" nullable:"false" index:"true" list:"user"`
Fingerprint string `name:"fingerprint" width:"64" charset:"ascii" nullable:"false" index:"true" list:"user" update:"user" create:"required"`
}
func loadbalancerAclsValidateAclEntries(data *jsonutils.JSONDict, update bool) (*jsonutils.JSONDict, error) {
@@ -157,7 +160,7 @@ func loadbalancerAclsValidateAclEntries(data *jsonutils.JSONDict, update bool) (
func (man *SLoadbalancerAclManager) FetchByFingerPrint(fingerprint string) (*SLoadbalancerAcl, error) {
ret := &SLoadbalancerAcl{}
q := man.TableSpec().Query()
q := man.Query().IsFalse("pending_deletetd")
q = q.Equals("fingerprint", fingerprint).Asc("created_at").Limit(1)
err := q.First(ret)
if err != nil {
@@ -168,7 +171,7 @@ func (man *SLoadbalancerAclManager) FetchByFingerPrint(fingerprint string) (*SLo
}
func (man *SLoadbalancerAclManager) CountByFingerPrint(fingerprint string) int {
q := man.TableSpec().Query()
q := man.Query().IsFalse("pending_deletetd")
return q.Equals("fingerprint", fingerprint).Asc("created_at").Count()
}
@@ -385,3 +388,31 @@ func (manager *SLoadbalancerAclManager) GetResourceCount() ([]db.SProjectResourc
virts := manager.Query().IsFalse("pending_deleted")
return db.CalculateProjectResourceCount(virts)
}
func (manager *SLoadbalancerAclManager) InitializeData() error {
// sync acl to acl cache
acls := []SLoadbalancerAcl{}
cachedAcls := CachedLoadbalancerAclManager.Query("acl_id").SubQuery()
q := manager.Query().IsNotEmpty("external_id").IsNotEmpty("cloudregion_id").NotIn("id", cachedAcls)
if err := q.All(&acls); err != nil {
return err
}
for i := range acls {
acl := acls[i]
aclObj := jsonutils.Marshal(acl)
cachedAcl := &SCachedLoadbalancerAcl{}
err := aclObj.Unmarshal(cachedAcl)
if err != nil {
return err
}
cachedAcl.Id = ""
cachedAcl.AclId = acl.Id
err = CachedLoadbalancerAclManager.TableSpec().Insert(cachedAcl)
if err != nil {
return err
}
}
return nil
}
@@ -0,0 +1,253 @@
package models
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/util/compare"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SAwsCachedLbManager struct {
SLoadbalancerLogSkipper
db.SVirtualResourceBaseManager
}
var AwsCachedLbManager *SAwsCachedLbManager
func init() {
AwsCachedLbManager = &SAwsCachedLbManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SAwsCachedLb{},
"awscachedlbbs_tbl",
"awscachedlbb",
"awscachedlbbs",
),
}
AwsCachedLbManager.SetVirtualObject(AwsCachedLbManager)
}
type SAwsCachedLb struct {
db.SVirtualResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SCloudregionResourceBase
BackendServerId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 后端服务器 实例ID
BackendId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 本地loadbalancebackend id
CachedBackendGroupId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
}
func (lbb *SAwsCachedLb) GetCustomizeColumns(context.Context, mcclient.TokenCredential, jsonutils.JSONObject) *jsonutils.JSONDict {
return nil
}
func (man *SAwsCachedLbManager) GetBackendsByLocalBackendId(backendId string) ([]SAwsCachedLb, error) {
loadbalancerBackends := []SAwsCachedLb{}
q := man.Query().Equals("backend_id", backendId)
if err := db.FetchModelObjects(man, q, &loadbalancerBackends); err != nil {
return nil, err
}
return loadbalancerBackends, nil
}
func (man *SAwsCachedLbManager) CreateAwsCachedLb(ctx context.Context, userCred mcclient.TokenCredential, lbb *SLoadbalancerBackend, cachedLbbg *SAwsCachedLbbg, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) (*SAwsCachedLb, error) {
cachedlbb := &SAwsCachedLb{}
cachedlbb.SetModelManager(man, cachedlbb)
cachedlbb.CloudregionId = cachedLbbg.CloudregionId
cachedlbb.ManagerId = cachedLbbg.ManagerId
cachedlbb.CachedBackendGroupId = cachedLbbg.GetId()
cachedlbb.BackendId = lbb.GetId()
cachedlbb.ExternalId = extLoadbalancerBackend.GetGlobalId()
newName, err := db.GenerateName(man, syncOwnerId, extLoadbalancerBackend.GetName())
if err != nil {
return nil, err
}
cachedlbb.Name = newName
if err := cachedlbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend); err != nil {
return nil, err
}
err = man.TableSpec().Insert(lbb)
if err != nil {
return nil, err
}
SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, cachedLbbg.ManagerId)
db.OpsLog.LogEvent(cachedlbb, db.ACT_CREATE, lbb.GetShortDesc(ctx), userCred)
return cachedlbb, nil
}
func (lbb *SAwsCachedLb) GetCachedBackendGroup() (*SAwsCachedLbbg, error) {
lbbg, err := db.FetchById(AwsCachedLbbgManager, lbb.CachedBackendGroupId)
if err != nil {
return nil, err
}
return lbbg.(*SAwsCachedLbbg), nil
}
func (man *SAwsCachedLbManager) getLoadbalancerBackendsByLoadbalancerBackendgroup(loadbalancerBackendgroup *SAwsCachedLbbg) ([]SAwsCachedLb, error) {
loadbalancerBackends := []SAwsCachedLb{}
q := man.Query().Equals("cached_backend_group_id", loadbalancerBackendgroup.Id)
if err := db.FetchModelObjects(man, q, &loadbalancerBackends); err != nil {
return nil, err
}
return loadbalancerBackends, nil
}
func (man *SAwsCachedLbManager) SyncLoadbalancerBackends(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, loadbalancerBackendgroup *SAwsCachedLbbg, lbbs []cloudprovider.ICloudLoadbalancerBackend, syncRange *SSyncRange) compare.SyncResult {
syncOwnerId := provider.GetOwnerId()
lockman.LockClass(ctx, man, db.GetLockClassKey(man, syncOwnerId))
defer lockman.ReleaseClass(ctx, man, db.GetLockClassKey(man, syncOwnerId))
syncResult := compare.SyncResult{}
dbLbbs, err := man.getLoadbalancerBackendsByLoadbalancerBackendgroup(loadbalancerBackendgroup)
if err != nil {
syncResult.Error(err)
return syncResult
}
removed := []SAwsCachedLb{}
commondb := []SAwsCachedLb{}
commonext := []cloudprovider.ICloudLoadbalancerBackend{}
added := []cloudprovider.ICloudLoadbalancerBackend{}
err = compare.CompareSets(dbLbbs, lbbs, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return syncResult
}
for i := 0; i < len(removed); i++ {
err = removed[i].syncRemoveCloudLoadbalancerBackend(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
} else {
syncResult.Delete()
}
}
for i := 0; i < len(commondb); i++ {
err = commondb[i].SyncWithCloudLoadbalancerBackend(ctx, userCred, commonext[i], syncOwnerId)
if err != nil {
syncResult.UpdateError(err)
} else {
syncMetadata(ctx, userCred, &commondb[i], commonext[i])
syncResult.Update()
}
}
for i := 0; i < len(added); i++ {
local, err := man.newFromCloudLoadbalancerBackend(ctx, userCred, loadbalancerBackendgroup, added[i], syncOwnerId)
if err != nil {
syncResult.AddError(err)
} else {
syncMetadata(ctx, userCred, local, added[i])
syncResult.Add()
}
}
return syncResult
}
func (lbb *SAwsCachedLb) syncRemoveCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, lbb)
defer lockman.ReleaseObject(ctx, lbb)
err := lbb.ValidateDeleteCondition(ctx)
if err != nil { // cannot delete
err = lbb.SetStatus(userCred, api.LB_STATUS_UNKNOWN, "sync to delete")
} else {
lbb.SetModelManager(AwsCachedLbManager, lbb)
err := db.DeleteModel(ctx, userCred, lbb)
if err != nil {
return err
}
}
return err
}
func (lbb *SAwsCachedLb) constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend) error {
lbb.Status = extLoadbalancerBackend.GetStatus()
instance, err := db.FetchByExternalId(GuestManager, extLoadbalancerBackend.GetBackendId())
if err != nil {
return err
}
guest := instance.(*SGuest)
lbb.BackendServerId = guest.Id
return nil
}
func (lbb *SAwsCachedLb) SyncWithCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) error {
lbb.SetModelManager(AwsCachedLbManager, lbb)
diff, err := db.UpdateWithLock(ctx, lbb, func() error {
return lbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend)
})
if err != nil {
return err
}
db.OpsLog.LogSyncUpdate(lbb, diff, userCred)
SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, lbb.ManagerId)
return nil
}
func (man *SAwsCachedLbManager) newFromCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, loadbalancerBackendgroup *SAwsCachedLbbg, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) (*SAwsCachedLb, error) {
localBackendGroup, err := loadbalancerBackendgroup.GetLocalBackendGroup(ctx, userCred)
if err != nil {
return nil, err
} else if localBackendGroup == nil {
return nil, fmt.Errorf("newFromCloudLoadbalancerBackend localBackendGroup is nil")
}
locallbb, err := newLocalBackendFromCloudLoadbalancerBackend(ctx, userCred, localBackendGroup, extLoadbalancerBackend, syncOwnerId)
if err != nil {
return nil, err
}
lbb := &SAwsCachedLb{}
lbb.SetModelManager(man, lbb)
lbb.CloudregionId = loadbalancerBackendgroup.CloudregionId
lbb.ManagerId = loadbalancerBackendgroup.ManagerId
lbb.CachedBackendGroupId = loadbalancerBackendgroup.Id
lbb.BackendId = locallbb.GetId()
lbb.ExternalId = extLoadbalancerBackend.GetGlobalId()
newName, err := db.GenerateName(man, syncOwnerId, extLoadbalancerBackend.GetName())
if err != nil {
return nil, err
}
lbb.Name = newName
if err := lbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend); err != nil {
return nil, err
}
err = man.TableSpec().Insert(lbb)
if err != nil {
return nil, err
}
SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, loadbalancerBackendgroup.ManagerId)
db.OpsLog.LogEvent(lbb, db.ACT_CREATE, lbb.GetShortDesc(ctx), userCred)
return lbb, nil
}
@@ -0,0 +1,377 @@
package models
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SAwsCachedLbbgManager struct {
SLoadbalancerLogSkipper
db.SVirtualResourceBaseManager
}
var AwsCachedLbbgManager *SAwsCachedLbbgManager
func init() {
AwsCachedLbbgManager = &SAwsCachedLbbgManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SAwsCachedLbbg{},
"awscachedlbbgs_tbl",
"awscachedlbbg",
"awscachedlbbgs",
),
}
AwsCachedLbbgManager.SetVirtualObject(AwsCachedLbbgManager)
}
type SAwsCachedLbbg struct {
db.SVirtualResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SCloudregionResourceBase
LoadbalancerId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
BackendGroupId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
TargetType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` // 后端服务器类型
ProtocolType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` // 监听协议类型
Port int `nullable:"false" list:"user" create:"required"` // 监听端口
HealthCheckProtocol string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` // 健康检查协议类型
HealthCheckInterval int `nullable:"false" list:"user" create:"required"` // 健康检查时间间隔
}
func (lbb *SAwsCachedLbbg) GetCustomizeColumns(context.Context, mcclient.TokenCredential, jsonutils.JSONObject) *jsonutils.JSONDict {
return nil
}
func (lbbg *SAwsCachedLbbg) GetLocalBackendGroup(ctx context.Context, userCred mcclient.TokenCredential) (*SLoadbalancerBackendGroup, error) {
if len(lbbg.BackendGroupId) == 0 {
return nil, fmt.Errorf("GetLocalBackendGroup no related local backendgroup")
}
locallbbg, err := db.FetchById(LoadbalancerBackendGroupManager, lbbg.BackendGroupId)
if err != nil {
return nil, err
}
return locallbbg.(*SLoadbalancerBackendGroup), err
}
func (lbbg *SAwsCachedLbbg) GetLoadbalancer() *SLoadbalancer {
lb, err := LoadbalancerManager.FetchById(lbbg.LoadbalancerId)
if err != nil {
log.Errorf("failed to find loadbalancer for backendgroup %s", lbbg.Name)
return nil
}
return lb.(*SLoadbalancer)
}
func (lbbg *SAwsCachedLbbg) GetCachedBackends() ([]SAwsCachedLb, error) {
ret := []SAwsCachedLb{}
err := AwsCachedLbbgManager.Query().Equals("cached_backend_group_id", lbbg.GetId()).IsFalse("pending_deleted").All(&ret)
if err != nil {
log.Errorf("failed to get cached backends for backendgroup %s", lbbg.Name)
return nil, err
}
return ret, nil
}
func (lbbg *SAwsCachedLbbg) GetICloudLoadbalancerBackendGroup() (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
if len(lbbg.ExternalId) == 0 {
return nil, fmt.Errorf("backendgroup %s has no external id", lbbg.GetId())
}
lb := lbbg.GetLoadbalancer()
if lb == nil {
return nil, fmt.Errorf("backendgroup %s releated loadbalancer not found", lbbg.GetId())
}
iregion, err := lb.GetIRegion()
if err != nil {
return nil, err
}
ilb, err := iregion.GetILoadBalancerById(lb.GetExternalId())
if err != nil {
return nil, err
}
ilbbg, err := ilb.GetILoadBalancerBackendGroupById(lbbg.ExternalId)
if err != nil {
return nil, err
}
return ilbbg, nil
}
func (man *SAwsCachedLbbgManager) GetUsableCachedBackendGroups(loadbalancerId, backendGroupId, protocolType, healthCheckProtocol string, healthCheckInterval int) ([]SAwsCachedLbbg, error) {
ret := []SAwsCachedLbbg{}
q := man.Query().Equals("protocol_type", protocolType).IsNotEmpty("external_id").Equals("health_check_protocol", healthCheckProtocol)
q = q.Filter(sqlchemy.OR(sqlchemy.Equals(q.Field("loadbalancer_id"), loadbalancerId), sqlchemy.IsNullOrEmpty(q.Field("loadbalancer_id"))))
if !utils.IsInStringArray(protocolType, []string{api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS}) {
// healthCheckInterval 10/30
q = q.Equals("health_check_interval", healthCheckInterval)
}
q = q.Filter(sqlchemy.OR(sqlchemy.Equals(q.Field("backend_group_id"), backendGroupId), sqlchemy.IsNullOrEmpty(q.Field("backend_group_id"))))
q = q.IsFalse("pending_deleted")
err := q.All(&ret)
if err != nil {
return ret, err
}
return ret, nil
}
func (man *SAwsCachedLbbgManager) GetUsableCachedBackendGroup(loadbalancerId, backendGroupId, protocolType, healthCheckProtocol string, healthCheckInterval int) (*SAwsCachedLbbg, error) {
ret, err := man.GetUsableCachedBackendGroups(loadbalancerId, backendGroupId, protocolType, healthCheckProtocol, healthCheckInterval)
if err != nil {
return nil, err
}
if len(ret) > 0 {
cachedLbbg := &ret[0]
cachedLbbg.SetModelManager(AwsCachedLbbgManager, cachedLbbg)
if cachedLbbg.LoadbalancerId == "" {
_, err := db.Update(cachedLbbg, func() error {
cachedLbbg.LoadbalancerId = loadbalancerId
return nil
})
if err != nil {
return nil, err
}
}
return cachedLbbg, nil
}
return nil, nil
}
func (man *SAwsCachedLbbgManager) GetCachedBackendGroups(backendGroupId string) ([]SAwsCachedLbbg, error) {
ret := []SAwsCachedLbbg{}
err := man.Query().IsFalse("pending_deleted").Equals("backend_group_id", backendGroupId).All(&ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (man *SAwsCachedLbbgManager) getLoadbalancerBackendgroupsByRegion(regionId string) ([]SAwsCachedLbbg, error) {
lbbgs := []SAwsCachedLbbg{}
q := man.Query().Equals("cloudregion_id", regionId).IsFalse("pending_deleted")
if err := db.FetchModelObjects(man, q, &lbbgs); err != nil {
log.Errorf("failed to get lbbgs for region: %s error: %v", regionId, err)
return nil, err
}
return lbbgs, nil
}
func (man *SAwsCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, region *SCloudregion, lbbgs []cloudprovider.ICloudLoadbalancerBackendGroup, syncRange *SSyncRange) ([]SAwsCachedLbbg, []cloudprovider.ICloudLoadbalancerBackendGroup, compare.SyncResult) {
syncOwnerId := provider.GetOwnerId()
lockman.LockClass(ctx, man, db.GetLockClassKey(man, syncOwnerId))
defer lockman.ReleaseClass(ctx, man, db.GetLockClassKey(man, syncOwnerId))
localLbgs := []SAwsCachedLbbg{}
remoteLbbgs := []cloudprovider.ICloudLoadbalancerBackendGroup{}
syncResult := compare.SyncResult{}
dbLbbgs, err := man.getLoadbalancerBackendgroupsByRegion(region.GetId())
if err != nil {
syncResult.Error(err)
return nil, nil, syncResult
}
removed := []SAwsCachedLbbg{}
commondb := []SAwsCachedLbbg{}
commonext := []cloudprovider.ICloudLoadbalancerBackendGroup{}
added := []cloudprovider.ICloudLoadbalancerBackendGroup{}
err = compare.CompareSets(dbLbbgs, lbbgs, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return nil, nil, syncResult
}
for i := 0; i < len(removed); i++ {
err = removed[i].syncRemoveCloudLoadbalancerBackendgroup(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
} else {
syncResult.Delete()
}
}
for i := 0; i < len(commondb); i++ {
var elb *SLoadbalancer
elbIds := commonext[i].GetLoadbalancerId()
if err != nil {
syncResult.UpdateError(err)
continue
}
elbId := commonext[i].GetLoadbalancerId()
if len(elbIds) > 0 {
ielb, err := db.FetchByExternalId(LoadbalancerManager, elbId)
if err == nil {
elb = ielb.(*SLoadbalancer)
}
}
if elb == nil {
elb = &SLoadbalancer{}
elb.Id = ""
elb.CloudregionId = region.GetId()
elb.ManagerId = provider.GetId()
}
err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, elb, commonext[i], provider.GetOwnerId())
if err != nil {
syncResult.UpdateError(err)
} else {
syncMetadata(ctx, userCred, &commondb[i], commonext[i])
localLbgs = append(localLbgs, commondb[i])
remoteLbbgs = append(remoteLbbgs, commonext[i])
syncResult.Update()
}
}
for i := 0; i < len(added); i++ {
var elb *SLoadbalancer
elbId := added[i].GetLoadbalancerId()
if err != nil {
syncResult.AddError(err)
continue
}
if len(elbId) > 0 {
ielb, err := db.FetchByExternalId(LoadbalancerManager, elbId)
if err == nil {
elb = ielb.(*SLoadbalancer)
}
}
if elb == nil {
elb = &SLoadbalancer{}
elb.Id = ""
elb.CloudregionId = region.GetId()
elb.ManagerId = provider.GetId()
}
new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, elb, added[i], syncOwnerId)
if err != nil {
syncResult.AddError(err)
} else {
syncMetadata(ctx, userCred, new, added[i])
localLbgs = append(localLbgs, *new)
remoteLbbgs = append(remoteLbbgs, added[i])
syncResult.Add()
}
}
return localLbgs, remoteLbbgs, syncResult
}
func (lbbg *SAwsCachedLbbg) syncRemoveCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, lbbg)
defer lockman.ReleaseObject(ctx, lbbg)
err := lbbg.ValidateDeleteCondition(ctx)
if err != nil { // cannot delete
err = lbbg.SetStatus(userCred, api.LB_STATUS_UNKNOWN, "sync to delete")
} else {
lbbg.SetModelManager(AwsCachedLbbgManager, lbbg)
err := db.DeleteModel(ctx, userCred, lbbg)
if err != nil {
return err
}
}
return err
}
func (lbbg *SAwsCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) error {
lbbg.SetModelManager(AwsCachedLbbgManager, lbbg)
diff, err := db.UpdateWithLock(ctx, lbbg, func() error {
lbbg.Status = extLoadbalancerBackendgroup.GetStatus()
metadata := extLoadbalancerBackendgroup.GetMetadata()
if port, _ := metadata.Int("port"); port > 0 {
lbbg.Port = int(port)
}
if protocol, _ := metadata.GetString("health_check_protocol"); len(protocol) > 0 {
lbbg.HealthCheckProtocol = protocol
}
if interval, _ := metadata.Int("health_check_interval"); interval > 0 {
lbbg.HealthCheckInterval = int(interval)
}
return nil
})
if err != nil {
return err
}
db.OpsLog.LogSyncUpdate(lbbg, diff, userCred)
SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId)
return err
}
func (man *SAwsCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) (*SAwsCachedLbbg, error) {
LocalLbbg, err := newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId)
if err != nil {
return nil, err
}
lbbg := &SAwsCachedLbbg{}
lbbg.SetModelManager(man, lbbg)
lbbg.ManagerId = lb.ManagerId
lbbg.CloudregionId = lb.CloudregionId
lbbg.LoadbalancerId = lb.Id
lbbg.BackendGroupId = LocalLbbg.GetId()
lbbg.ExternalId = extLoadbalancerBackendgroup.GetGlobalId()
lbbg.ProtocolType = extLoadbalancerBackendgroup.GetProtocolType()
metadata := extLoadbalancerBackendgroup.GetMetadata()
if t, _ := metadata.GetString("target_type"); len(t) > 0 {
lbbg.TargetType = t
}
if p, _ := metadata.Int("port"); p > 0 {
lbbg.Port = int(p)
}
if protocol, _ := metadata.GetString("health_check_protocol"); len(protocol) > 0 {
lbbg.HealthCheckProtocol = protocol
}
if interval, _ := metadata.Int("health_check_interval"); interval > 0 {
lbbg.HealthCheckInterval = int(interval)
}
newName, err := db.GenerateName(man, syncOwnerId, LocalLbbg.GetName())
if err != nil {
return nil, err
}
lbbg.Name = newName
lbbg.Status = extLoadbalancerBackendgroup.GetStatus()
err = man.TableSpec().Insert(lbbg)
if err != nil {
return nil, err
}
SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId)
db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred)
return lbbg, nil
}
+72 -24
View File
@@ -62,14 +62,6 @@ type SLoadbalancerBackendGroup struct {
Type string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"normal" create:"optional"`
LoadbalancerId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
//
//// 目前只有华为云用到。
//ProtocolType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"`
//Scheduler string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
//SLoadbalancerTCPListener
//SLoadbalancerUDPListener
//SLoadbalancerHTTPListener
//SLoadbalancerHealthCheck
}
func (man *SLoadbalancerBackendGroupManager) pendingDeleteSubs(ctx context.Context, userCred mcclient.TokenCredential, q *sqlchemy.SQuery) {
@@ -291,7 +283,6 @@ func (man *SLoadbalancerBackendGroupManager) FilterZeroRefBackendGroup(q *sqlche
for _, m := range lbbgRefManagers() {
_ids := m.Query("backend_group_id").In("backend_group_id", ids).SubQuery()
_ids.DebugQuery()
q = q.NotIn("id", _ids)
}
@@ -325,9 +316,9 @@ func (lbbg *SLoadbalancerBackendGroup) GetCustomizeColumns(ctx context.Context,
if err != nil {
log.Errorf("loadbalancer backend group %s(%s): fetch loadbalancer (%s) error: %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, err)
return extra
} else {
extra.Set("loadbalancer", jsonutils.NewString(lb.GetName()))
}
extra.Set("loadbalancer", jsonutils.NewString(lb.GetName()))
}
regionInfo := lbbg.SCloudregionResourceBase.GetCustomizeColumns(ctx, userCred, query)
if regionInfo != nil {
@@ -372,6 +363,15 @@ func (lbbg *SLoadbalancerBackendGroup) StartHuaweiLoadBalancerBackendGroupCreate
return nil
}
func (lbbg *SLoadbalancerBackendGroup) StartAwsLoadBalancerBackendGroupCreateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "AwsLoadbalancerLoadbalancerBackendGroupCreateTask", lbbg, userCred, params, parentTaskId, "", nil)
if err != nil {
return err
}
task.ScheduleRun(nil)
return nil
}
func (lbbg *SLoadbalancerBackendGroup) LBPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) {
if lb := lbbg.GetLoadbalancer(); lb != nil && lb.BackendGroupId == lbbg.Id {
if _, err := db.UpdateWithLock(ctx, lb, func() error {
@@ -435,10 +435,10 @@ func (lbbg *SLoadbalancerBackendGroup) GetListener() *SLoadbalancerListener {
return ret
}
func (lbbg *SLoadbalancerBackendGroup) GetBackendGroupParams() (cloudprovider.SLoadbalancerBackendGroup, error) {
func (lbbg *SLoadbalancerBackendGroup) GetBackendGroupParams() (*cloudprovider.SLoadbalancerBackendGroup, error) {
backends, err := lbbg.GetBackendsParams()
if err != nil {
return cloudprovider.SLoadbalancerBackendGroup{}, err
return &cloudprovider.SLoadbalancerBackendGroup{}, err
}
listener := lbbg.GetListener()
@@ -447,24 +447,23 @@ func (lbbg *SLoadbalancerBackendGroup) GetBackendGroupParams() (cloudprovider.SL
listenerId = listener.ExternalId
}
loadbalancer := lbbg.GetLoadbalancer()
loadbalancerId := ""
if loadbalancer != nil {
loadbalancerId = loadbalancer.ExternalId
ret := &cloudprovider.SLoadbalancerBackendGroup{
Name: lbbg.Name,
GroupType: lbbg.Type,
Backends: backends,
ListenerID: listenerId,
}
ret := cloudprovider.SLoadbalancerBackendGroup{
Name: lbbg.Name,
GroupType: lbbg.Type,
Backends: backends,
LoadbalancerID: loadbalancerId,
ListenerID: listenerId,
loadbalancer := lbbg.GetLoadbalancer()
if loadbalancer != nil {
ret.VpcId = loadbalancer.VpcId
ret.LoadbalancerID = loadbalancer.ExternalId
}
return ret, nil
}
func (lbbg *SLoadbalancerBackendGroup) GetHuaweiBackendGroupParams(lblis *SLoadbalancerListener, lbr *SLoadbalancerListenerRule) (cloudprovider.SLoadbalancerBackendGroup, error) {
func (lbbg *SLoadbalancerBackendGroup) GetHuaweiBackendGroupParams(lblis *SLoadbalancerListener, lbr *SLoadbalancerListenerRule) (*cloudprovider.SLoadbalancerBackendGroup, error) {
ret, err := lbbg.GetBackendGroupParams()
if err != nil {
return ret, err
@@ -510,6 +509,45 @@ func (lbbg *SLoadbalancerBackendGroup) GetHuaweiBackendGroupParams(lblis *SLoadb
return ret, nil
}
func (lbbg *SLoadbalancerBackendGroup) GetAwsBackendGroupParams(lblis *SLoadbalancerListener, lbr *SLoadbalancerListenerRule) (*cloudprovider.SLoadbalancerBackendGroup, error) {
ret, err := lbbg.GetBackendGroupParams()
if err != nil {
return ret, err
}
healthCheck := &cloudprovider.SLoadbalancerHealthCheck{
HealthCheckType: lblis.HealthCheckType,
HealthCheckReq: lblis.HealthCheckReq,
HealthCheckExp: lblis.HealthCheckExp,
HealthCheck: lblis.HealthCheck,
HealthCheckTimeout: lblis.HealthCheckTimeout,
HealthCheckDomain: lblis.HealthCheckDomain,
HealthCheckHttpCode: lblis.HealthCheckHttpCode,
HealthCheckURI: lblis.HealthCheckURI,
HealthCheckInterval: lblis.HealthCheckInterval,
HealthCheckRise: lblis.HealthCheckRise,
HealthCheckFail: lblis.HealthCheckFall,
}
ret.ListenerID = lblis.GetExternalId()
lb := lblis.GetLoadbalancer()
if lb != nil {
vpc := lb.GetVpc()
if vpc != nil {
ret.VpcId = vpc.GetExternalId()
} else {
return nil, fmt.Errorf("loadbalancer %s related vpc not found", lb.GetId())
}
}
ret.ListenType = lblis.ListenerType
ret.ListenPort = lblis.ListenerPort
ret.Scheduler = lblis.Scheduler
ret.HealthCheck = healthCheck
return ret, nil
}
func (lbbg *SLoadbalancerBackendGroup) GetBackendsParams() ([]cloudprovider.SLoadbalancerBackend, error) {
backends, err := lbbg.GetBackends()
if err != nil {
@@ -569,6 +607,16 @@ func (lbbg *SLoadbalancerBackendGroup) GetICloudLoadbalancerBackendGroup() (clou
return ilbbg, nil
}
func (man *SLoadbalancerBackendGroupManager) getLoadbalancerBackendgroupsByRegion(regonId string) ([]SLoadbalancerBackendGroup, error) {
lbbgs := []SLoadbalancerBackendGroup{}
q := man.Query().Equals("cloudregion_id", regonId).IsFalse("pending_deleted")
if err := db.FetchModelObjects(man, q, &lbbgs); err != nil {
log.Errorf("failed to get lbbgs for region: %s error: %v", regonId, err)
return nil, err
}
return lbbgs, nil
}
func (man *SLoadbalancerBackendGroupManager) getLoadbalancerBackendgroupsByLoadbalancer(lb *SLoadbalancer) ([]SLoadbalancerBackendGroup, error) {
lbbgs := []SLoadbalancerBackendGroup{}
q := man.Query().Equals("loadbalancer_id", lb.Id).IsFalse("pending_deleted")
+11 -88
View File
@@ -35,7 +35,6 @@ import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rand"
)
type SLoadbalancerBackendManager struct {
@@ -147,86 +146,19 @@ func (man *SLoadbalancerBackendManager) ValidateBackendVpc(lb *SLoadbalancer, gu
func (man *SLoadbalancerBackendManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
backendGroupV := validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", ownerId)
if err := backendGroupV.Validate(data); err != nil {
return nil, err
}
backendTypeV := validators.NewStringChoicesValidator("backend_type", api.LB_BACKEND_TYPES)
keyV := map[string]validators.IValidator{
"backend_group": backendGroupV,
"backend_type": backendTypeV,
"weight": validators.NewRangeValidator("weight", 1, 256).Default(1),
"port": validators.NewPortValidator("port"),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
}
for _, v := range keyV {
if err := v.Validate(data); err != nil {
return nil, err
}
if err := backendTypeV.Validate(data); err != nil {
return nil, err
}
backendType := backendTypeV.Value
backendGroup := backendGroupV.Model.(*SLoadbalancerBackendGroup)
lb := backendGroup.GetLoadbalancer()
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
backendType := backendTypeV.Value
var (
basename string
backendModel db.IModel
)
switch backendType {
case api.LB_BACKEND_GUEST:
backendV := validators.NewModelIdOrNameValidator("backend", "server", ownerId)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
guest := backendV.Model.(*SGuest)
err = man.ValidateBackendVpc(lb, guest, backendGroup)
if err != nil {
return nil, err
}
basename = guest.Name
backendModel = backendV.Model
case api.LB_BACKEND_HOST:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify host as backend")
}
backendV := validators.NewModelIdOrNameValidator("backend", "host", userCred)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
host := backendV.Model.(*SHost)
{
if len(host.AccessIp) == 0 {
return nil, fmt.Errorf("host %s has no access ip", host.GetId())
}
data.Set("address", jsonutils.NewString(host.AccessIp))
}
basename = host.Name
backendModel = backendV.Model
case api.LB_BACKEND_IP:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify ip address as backend")
}
backendV := validators.NewIPv4AddrValidator("backend")
err := backendV.Validate(data)
if err != nil {
return nil, err
}
ip := backendV.IP.String()
data.Set("address", jsonutils.NewString(ip))
basename = ip
default:
return nil, fmt.Errorf("internal error: unexpected backend type %s", backendType)
}
name, _ := data.GetString("name")
if name == "" {
// name it
//
// NOTE it's okay for name to be not unique.
//
// - Mix in loadbalancer name if needed
// - Use name from input query
name = fmt.Sprintf("%s-%s-%s-%s", backendGroup.Name, backendType, basename, rand.String(4))
}
data.Set("name", jsonutils.NewString(name))
var backendModel db.IModel
if _, err := man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data); err != nil {
return nil, err
}
@@ -234,6 +166,8 @@ func (man *SLoadbalancerBackendManager) ValidateCreateData(ctx context.Context,
if region == nil {
return nil, httperrors.NewResourceNotFoundError("failed to find region for loadbalancer %s", lb.Name)
}
ctx = context.WithValue(ctx, "ownerId", ownerId)
return region.GetDriver().ValidateCreateLoadbalancerBackendData(ctx, userCred, data, backendType, lb, backendGroup, backendModel)
}
@@ -286,17 +220,6 @@ func (man *SLoadbalancerBackendManager) GetGuestAddress(guest *SGuest) (string,
}
func (lbb *SLoadbalancerBackend) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
keyV := map[string]validators.IValidator{
"weight": validators.NewRangeValidator("weight", 1, 256),
"port": validators.NewPortValidator("port"),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES),
}
for _, v := range keyV {
v.Optional(true)
if err := v.Validate(data); err != nil {
return nil, err
}
}
_, err := lbb.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
if err != nil {
return nil, err
@@ -50,6 +50,8 @@ func init() {
"cachedloadbalanceracls",
),
}
CachedLoadbalancerAclManager.SetVirtualObject(CachedLoadbalancerAclManager)
}
type SCachedLoadbalancerAcl struct {
@@ -541,3 +543,8 @@ func (man *SCachedLoadbalancerAclManager) newFromCloudLoadbalancerAcl(ctx contex
return &acl, nil
}
func (manager *SCachedLoadbalancerAclManager) InitializeData() error {
// todo: sync old data from acls
return nil
}
@@ -35,6 +35,8 @@ func init() {
"cachedloadbalancercertificates",
),
}
CachedLoadbalancerCertificateManager.SetVirtualObject(CachedLoadbalancerCertificateManager)
}
type SCachedLoadbalancerCertificate struct {
@@ -241,11 +243,18 @@ func (man *SCachedLoadbalancerCertificateManager) newFromCloudLoadbalancerCertif
lbcert.PrivateKey = extCertificate.GetPrivateKey()
// check local cert
localcert, err := LoadbalancerCertificateManager.GetOrCreateCertificate(lbcert.Name, lbcert.Certificate, lbcert.PrivateKey)
if err != nil {
log.Debugf("newFromCloudLoadbalancerCertificate GetOrCreateCertificate %s", err)
// todo: check fingerprint not empty & aws 证书不区分region,需要去除重复数据?
c := SCachedLoadbalancerCertificate{}
err = CachedLoadbalancerCertificateManager.Query().IsFalse("pending_deleted").Equals("fingerprint", lbcert.Fingerprint).First(&c)
if err != nil && len(c.CertificateId) == 0 {
localcert, err := LoadbalancerCertificateManager.CreateCertificate(lbcert.Name, lbcert.Certificate, lbcert.PrivateKey, lbcert.Fingerprint)
if err != nil {
log.Debugf("newFromCloudLoadbalancerCertificate CreateCertificate %s", err)
}
lbcert.Certificate = localcert.Id
} else {
lbcert.CertificateId = localcert.Id
lbcert.CertificateId = c.CertificateId
}
err = man.TableSpec().Insert(&lbcert)
+40 -12
View File
@@ -59,7 +59,10 @@ func init() {
// - ca info: self-signed, public ca
type SLoadbalancerCertificate struct {
db.SVirtualResourceBase
// db.SExternalizedResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SCloudregionResourceBase
Certificate string `create:"required" list:"user" update:"user"`
PrivateKey string `create:"required" list:"admin" update:"user"`
@@ -217,6 +220,8 @@ func (man *SLoadbalancerCertificateManager) ValidateCreateData(ctx context.Conte
return nil, err
}
data.Remove("cloudregion_id")
data.Remove("manager_id")
return data, nil
}
@@ -254,22 +259,45 @@ func (man *SLoadbalancerCertificateManager) InitializeData() error {
return err
}
}
// sync certificate to certificate cache
lbcerts = []SLoadbalancerCertificate{}
cachedCerts := CachedLoadbalancerCertificateManager.Query("certificate_id").SubQuery()
q2 := man.Query().IsNotEmpty("external_id").IsNotEmpty("cloudregion_id").NotIn("id", cachedCerts)
if err := q2.All(&lbcerts); err != nil {
return err
}
for i := range lbcerts {
cert := lbcerts[i]
certObj := jsonutils.Marshal(cert)
cachedCert := &SCachedLoadbalancerCertificate{}
err := certObj.Unmarshal(cachedCert)
if err != nil {
return err
}
cachedCert.Id = ""
cachedCert.CertificateId = cert.Id
err = CachedLoadbalancerCertificateManager.TableSpec().Insert(cachedCert)
if err != nil {
return err
}
}
return nil
}
func (man *SLoadbalancerCertificateManager) GetOrCreateCertificate(name string, publicKey string, privateKey string) (*SLoadbalancerCertificate, error) {
func (man *SLoadbalancerCertificateManager) CreateCertificate(name string, publicKey string, privateKey, fingerprint string) (*SLoadbalancerCertificate, error) {
if len(fingerprint) == 0 {
return nil, fmt.Errorf("CreateCertificate fingerprint can not be empty")
}
data := jsonutils.NewDict()
data.Set("certificate", jsonutils.NewString(publicKey))
data.Set("private_key", jsonutils.NewString(privateKey))
data, err := man.validateCertKey(nil, data)
if err != nil {
return nil, err
}
data.Set("Name", jsonutils.NewString(name))
fp, _ := data.GetString("fingerprint")
count := man.TableSpec().Query().Equals("fingerprint", fp).Asc("created_at").Count()
data.Set("name", jsonutils.NewString(name))
data.Set("fingerprint", jsonutils.NewString(fingerprint))
count := man.Query().Equals("fingerprint", fingerprint).Asc("created_at").Count()
if count == 0 {
cert := &SLoadbalancerCertificate{}
err := data.Unmarshal(cert)
@@ -284,7 +312,7 @@ func (man *SLoadbalancerCertificateManager) GetOrCreateCertificate(name string,
}
ret := &SLoadbalancerCertificate{}
err = man.TableSpec().Query().Equals("fingerprint", fp).Asc("created_at").First(ret)
err := man.Query().Equals("Name", name).Equals("fingerprint", fingerprint).Asc("created_at").IsFalse("pending_deleted").First(ret)
if err != nil {
return nil, err
}
@@ -76,7 +76,7 @@ func (lbbg *SHuaweiCachedLbbg) GetLoadbalancer() *SLoadbalancer {
func (lbbg *SHuaweiCachedLbbg) GetCachedBackends() ([]SHuaweiCachedLb, error) {
ret := []SHuaweiCachedLb{}
err := HuaweiCachedLbManager.TableSpec().Query().Equals("cached_backend_group_id", lbbg.GetId()).All(&ret)
err := HuaweiCachedLbManager.Query().Equals("cached_backend_group_id", lbbg.GetId()).IsFalse("pending_deleted").All(&ret)
if err != nil {
log.Errorf("failed to get cached backends for backendgroup %s", lbbg.Name)
return nil, err
+317 -64
View File
@@ -16,6 +16,7 @@ package models
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -61,14 +62,298 @@ type SLoadbalancerListenerRule struct {
ListenerId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
BackendGroupId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user"`
Domain string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
Path string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
Domain string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
Path string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"`
Condition string `charset:"ascii" nullable:"false" list:"user" create:"optional"`
SLoadbalancerHealthCheck // 目前只有腾讯云HTTP、HTTPS类型的健康检查是和规则绑定的。
SLoadbalancerHTTPRateLimiter
}
func loadbalancerListenerRuleCheckUniqueness(ctx context.Context, lbls *SLoadbalancerListener, domain, path string) error {
func ValidateListenerRuleConditions(condition string) error {
// total limit 5
// host-header limit 1
// path-pattern limit 1
// source-ip limit 1
// http-request-method limit 1
// http-header no limit
// query-string no limit
limitations := &map[string]int{
"rules": 5,
"http-header": 5,
"query-string": 5,
"path-pattern": 1,
"http-request-method": 1,
"host-header": 1,
"source-ip": 1,
}
obj, err := jsonutils.ParseString(condition)
if err != nil {
return httperrors.NewInputParameterError("invalid conditions format,required json")
}
conditionArray, ok := obj.(*jsonutils.JSONArray)
if !ok {
return httperrors.NewInputParameterError("invalid conditions fromat,required json array")
}
if conditionArray.Length() > 5 {
return httperrors.NewInputParameterError("condition values limit (5 per rule). %d given.", conditionArray.Length())
}
cs := conditionArray.Value()
for i := range cs {
err := validateListenerRuleCondition(cs[i], limitations)
if err != nil {
return err
}
}
return nil
}
func validateListenerRuleCondition(condition jsonutils.JSONObject, limitations *map[string]int) error {
conditionDict, ok := condition.(*jsonutils.JSONDict)
if !ok {
return fmt.Errorf("invalid condition fromat,required dict. %#v", condition)
}
dict := conditionDict.Value()
field, ok := dict["field"]
if !ok {
return fmt.Errorf("parseCondition invalid condition, missing field: %#v", condition)
}
f, _ := field.GetString()
switch f {
case "http-header":
return parseHttpHeaderCondition(conditionDict, limitations)
case "path-pattern":
return parsePathPatternCondition(conditionDict, limitations)
case "http-request-method":
return parseRequestModthdCondition(conditionDict, limitations)
case "host-header":
return parseHostHeaderCondition(conditionDict, limitations)
case "query-string":
return parseQueryStringCondition(conditionDict, limitations)
case "source-ip":
return parseSourceIpCondition(conditionDict, limitations)
default:
return fmt.Errorf("parseCondition invalid condition key %#v", field)
}
}
func parseHttpHeaderCondition(conditon *jsonutils.JSONDict, limitations *map[string]int) error {
(*limitations)["http-header"] = (*limitations)["http-header"] - 1
if (*limitations)["http-header"] < 0 {
return fmt.Errorf("http-header exceeded limiation.")
}
values, err := conditon.GetMap("httpHeaderConfig")
if err != nil {
return err
}
name, ok := values["HttpHeaderName"]
if !ok {
return fmt.Errorf("parseHttpHeaderCondition missing filed HttpHeaderName")
}
_, ok = name.(*jsonutils.JSONString)
if !ok {
return fmt.Errorf("parseHttpHeaderCondition missing invalid data %#v", name)
}
vs, ok := values["values"]
if !ok {
return fmt.Errorf("parseHttpHeaderCondition missing filed values")
}
err = parseConditionStringArrayValues(vs, limitations)
if err != nil {
return err
}
return nil
}
func parsePathPatternCondition(condition *jsonutils.JSONDict, limitations *map[string]int) error {
(*limitations)["path-pattern"] = (*limitations)["path-pattern"] - 1
if (*limitations)["path-pattern"] < 0 {
return fmt.Errorf("path-pattern exceeded limiation.")
}
values, err := condition.GetMap("pathPatternConfig")
if err != nil {
return err
}
vs, ok := values["values"]
if !ok {
return fmt.Errorf("parsePathPatternCondition missing filed values")
}
err = parseConditionStringArrayValues(vs, limitations)
if err != nil {
return err
}
return nil
}
func parseRequestModthdCondition(condition *jsonutils.JSONDict, limitations *map[string]int) error {
(*limitations)["http-request-method"] = (*limitations)["http-request-method"] - 1
if (*limitations)["http-request-method"] < 0 {
return fmt.Errorf("http-request-method exceeded limiation.")
}
values, err := condition.GetMap("httpRequestMethodConfig")
if err != nil {
return err
}
vs, ok := values["values"]
if !ok {
return fmt.Errorf("parseRequestModthdCondition missing filed values")
}
err = parseConditionStringArrayValues(vs, limitations)
if err != nil {
return err
}
return nil
}
func parseHostHeaderCondition(condition *jsonutils.JSONDict, limitations *map[string]int) error {
(*limitations)["host-header"] = (*limitations)["host-header"] - 1
if (*limitations)["host-header"] < 0 {
return fmt.Errorf("host-header exceeded limiation.")
}
values, err := condition.GetMap("hostHeaderConfig")
if err != nil {
return err
}
vs, ok := values["values"]
if !ok {
return fmt.Errorf("parseHostHeaderCondition missing filed values")
}
err = parseConditionStringArrayValues(vs, limitations)
if err != nil {
return err
}
return nil
}
func parseQueryStringCondition(condition *jsonutils.JSONDict, limitations *map[string]int) error {
(*limitations)["query-string"] = (*limitations)["query-string"] - 1
if (*limitations)["query-string"] < 0 {
return fmt.Errorf("query-string exceeded limiation.")
}
values, err := condition.GetMap("queryStringConfig")
if err != nil {
return err
}
vs, ok := values["values"]
if !ok {
return fmt.Errorf("parseQueryStringCondition missing filed values")
}
err = parseConditionDictArrayValues(vs, limitations)
if err != nil {
return err
}
return nil
}
func parseSourceIpCondition(condition *jsonutils.JSONDict, limitations *map[string]int) error {
(*limitations)["source-ip"] = (*limitations)["source-ip"] - 1
if (*limitations)["source-ip"] < 0 {
return fmt.Errorf("source-ip exceeded limiation.")
}
values, err := condition.GetMap("sourceIpConfig")
if err != nil {
return err
}
vs, ok := values["values"]
if !ok {
return fmt.Errorf("parseSourceIpCondition missing filed values")
}
err = parseConditionStringArrayValues(vs, limitations)
if err != nil {
return err
}
return nil
}
func parseConditionStringArrayValues(values jsonutils.JSONObject, limitations *map[string]int) error {
objs, ok := values.(*jsonutils.JSONArray)
if !ok {
return fmt.Errorf("parseConditionStringArrayValues invalid values format, required array: %#v", values)
}
vs := objs.Value()
for i := range vs {
(*limitations)["rules"] = (*limitations)["rules"] - 1
if (*limitations)["rules"] < 0 {
return fmt.Errorf("rules exceeded limiation.")
}
v, ok := vs[i].(*jsonutils.JSONString)
if !ok {
return fmt.Errorf("parseConditionStringArrayValues invalid value, required string: %#v", v)
}
}
return nil
}
func parseConditionDictArrayValues(values jsonutils.JSONObject, limitations *map[string]int) error {
objs, ok := values.(*jsonutils.JSONArray)
if !ok {
return fmt.Errorf("parseConditionDictArrayValues invalid values format, required array: %#v", values)
}
vs := objs.Value()
for i := range vs {
(*limitations)["rules"] = (*limitations)["rules"] - 1
if (*limitations)["rules"] < 0 {
return fmt.Errorf("rules exceeded limiation.")
}
v, ok := vs[i].(*jsonutils.JSONDict)
if !ok {
return fmt.Errorf("parseConditionDictArrayValues invalid value, required dict: %#v", v)
}
_, err := v.GetString("key")
if err != nil {
return err
}
_, err = v.GetString("value")
if err != nil {
return err
}
}
return nil
}
func LoadbalancerListenerRuleCheckUniqueness(ctx context.Context, lbls *SLoadbalancerListener, domain, path string) error {
q := LoadbalancerListenerRuleManager.Query().
IsFalse("pending_deleted").
Equals("listener_id", lbls.Id).
@@ -108,63 +393,30 @@ func (man *SLoadbalancerListenerRuleManager) ListItemFilter(ctx context.Context,
}
func (man *SLoadbalancerListenerRuleManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
if _, err := man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data); err != nil {
return nil, err
}
listenerV := validators.NewModelIdOrNameValidator("listener", "loadbalancerlistener", ownerId)
backendGroupV := validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", ownerId)
domainV := validators.NewDomainNameValidator("domain")
pathV := validators.NewURLPathValidator("path")
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"listener": listenerV,
"backend_group": backendGroupV,
"domain": domainV.AllowEmpty(true).Default(""),
"path": pathV.Default(""),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
}
for _, v := range keyV {
if err := v.Validate(data); err != nil {
return nil, err
}
}
listener := listenerV.Model.(*SLoadbalancerListener)
data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId))
data.Set("manager_id", jsonutils.NewString(listener.ManagerId))
listenerType := listener.ListenerType
if listenerType != api.LB_LISTENER_TYPE_HTTP && listenerType != api.LB_LISTENER_TYPE_HTTPS {
return nil, httperrors.NewInputParameterError("listener type must be http/https, got %s", listenerType)
}
{
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",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, listener.LoadbalancerId)
} else {
// 腾讯云backend group只能1v1关联
if listener.GetProviderName() == api.CLOUD_PROVIDER_QCLOUD {
count, err := lbbg.RefCount()
if err != nil {
return nil, httperrors.NewInternalServerError("get lbbg RefCount fail %s", err)
}
if count > 0 {
return nil, httperrors.NewResourceBusyError("backendgroup already related with other listener/rule")
}
}
}
}
err := loadbalancerListenerRuleCheckUniqueness(ctx, listener, domainV.Value, pathV.Value)
if err != nil {
return nil, err
}
if _, err := man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data); err != nil {
return nil, err
}
region := listener.GetRegion()
if region == nil {
return nil, httperrors.NewResourceNotFoundError("failed to find region for loadbalancer listener %s", listener.Name)
}
return region.GetDriver().ValidateCreateLoadbalancerListenerRuleData(ctx, userCred, data, backendGroupV.Model)
return region.GetDriver().ValidateCreateLoadbalancerListenerRuleData(ctx, userCred, ownerId, data, backendGroupV.Model)
}
func (lbr *SLoadbalancerListenerRule) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
@@ -215,30 +467,21 @@ func (lbr *SLoadbalancerListenerRule) AllowPerformStatus(ctx context.Context, us
func (lbr *SLoadbalancerListenerRule) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
backendGroupV := validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", lbr.GetOwnerId())
keyV := map[string]validators.IValidator{
"backend_group": backendGroupV,
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate"),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src"),
if err := backendGroupV.Optional(true).Validate(data); err != nil {
return nil, err
}
for _, v := range keyV {
v.Optional(true)
if err := v.Validate(data); err != nil {
return nil, err
}
if _, err := lbr.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data); err != nil {
return nil, err
}
if backendGroup, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && backendGroup.Id != lbr.BackendGroupId {
listenerM, err := LoadbalancerListenerManager.FetchById(lbr.ListenerId)
if err != nil {
return nil, httperrors.NewInputParameterError("loadbalancerlistenerrule %s(%s): fetching listener %s failed",
lbr.Name, lbr.Id, lbr.ListenerId)
}
listener := listenerM.(*SLoadbalancerListener)
if backendGroup.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)
}
region := lbr.GetRegion()
if region == nil {
return nil, httperrors.NewResourceNotFoundError("failed to find region for loadbalancer listener rule %s", lbr.Name)
}
return lbr.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data)
ctx = context.WithValue(ctx, "lbr", lbr)
return region.GetDriver().ValidateUpdateLoadbalancerListenerRuleData(ctx, userCred, data, backendGroupV.Model)
}
func (lbr *SLoadbalancerListenerRule) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
@@ -367,6 +610,7 @@ func (lbr *SLoadbalancerListenerRule) constructFieldsFromCloudListenerRule(userC
lbr.Domain = extRule.GetDomain()
lbr.Path = extRule.GetPath()
lbr.Status = extRule.GetStatus()
lbr.Condition = extRule.GetCondition()
if groupId := extRule.GetBackendGroupId(); len(groupId) > 0 {
// 腾讯云兼容代码。主要目的是在关联listener rule时回写一个fake的backend group external id
if lbr.GetProviderName() == api.CLOUD_PROVIDER_QCLOUD && len(groupId) > 0 && len(lbr.BackendGroupId) > 0 {
@@ -387,6 +631,15 @@ func (lbr *SLoadbalancerListenerRule) constructFieldsFromCloudListenerRule(userC
}
lbr.BackendGroupId = group.(*SHuaweiCachedLbbg).BackendGroupId
} else if lbr.GetProviderName() == api.CLOUD_PROVIDER_AWS {
if len(groupId) > 0 {
group, err := db.FetchByExternalId(AwsCachedLbbgManager, groupId)
if err != nil {
log.Errorf("Fetch aws loadbalancer backendgroup by external id %s failed: %s", groupId, err)
}
lbr.BackendGroupId = group.(*SAwsCachedLbbg).BackendGroupId
}
} else if backendgroup, err := db.FetchByExternalId(LoadbalancerBackendGroupManager, groupId); err == nil {
lbr.BackendGroupId = backendgroup.GetId()
}
+73 -195
View File
@@ -17,7 +17,6 @@ package models
import (
"context"
"fmt"
"regexp"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -143,7 +142,7 @@ type SLoadbalancerListener struct {
SLoadbalancerHTTPRateLimiter
}
func (man *SLoadbalancerListenerManager) checkListenerUniqueness(ctx context.Context, lb *SLoadbalancer, listenerType string, listenerPort int64) error {
func (man *SLoadbalancerListenerManager) CheckListenerUniqueness(ctx context.Context, lb *SLoadbalancer, listenerType string, listenerPort int64) error {
q := man.Query().
IsFalse("pending_deleted").
Equals("loadbalancer_id", lb.Id).
@@ -165,6 +164,24 @@ func (man *SLoadbalancerListenerManager) checkListenerUniqueness(ctx context.Con
return nil
}
func (man *SLoadbalancerListenerManager) CheckAwsListenerUniqueness(ctx context.Context, lb *SLoadbalancer, lblis *SLoadbalancerListener, listenerType string, listenerPort int64) error {
q := man.Query().
IsFalse("pending_deleted").
Equals("loadbalancer_id", lb.Id).
Equals("listener_port", listenerPort)
if lblis != nil {
q = q.NotEquals("id", lblis.GetId())
}
var listener SLoadbalancerListener
q.First(&listener)
if len(listener.Id) > 0 {
return httperrors.NewConflictError("%s listener port %d is already taken by listener %s(%s)",
listenerType, listenerPort, listener.Name, listener.Id)
}
return nil
}
func (man *SLoadbalancerListenerManager) pendingDeleteSubs(ctx context.Context, userCred mcclient.TokenCredential, q *sqlchemy.SQuery) {
subs := []SLoadbalancerListener{}
db.FetchModelObjects(man, q, &subs)
@@ -195,132 +212,26 @@ func (man *SLoadbalancerListenerManager) ListItemFilter(ctx context.Context, q *
func (man *SLoadbalancerListenerManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
lbV := validators.NewModelIdOrNameValidator("loadbalancer", "loadbalancer", ownerId)
listenerTypeV := validators.NewStringChoicesValidator("listener_type", api.LB_LISTENER_TYPES)
listenerPortV := validators.NewPortValidator("listener_port")
if err := lbV.Validate(data); err != nil {
return nil, err
}
backendGroupV := validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", ownerId)
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
aclV := validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"loadbalancer": lbV,
"listener_type": listenerTypeV,
"listener_port": listenerPortV,
"backend_group": backendGroupV.Optional(true),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
"acl_status": aclStatusV.Default(api.LB_BOOL_OFF),
"acl_type": aclTypeV.Optional(true),
"acl": aclV.Optional(true),
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"egress_mbps": validators.NewRangeValidator("egress_mbps", api.LB_MbpsMin, api.LB_MbpsMax).Optional(true),
"client_request_timeout": validators.NewRangeValidator("client_request_timeout", 0, 600).Default(10),
"client_idle_timeout": validators.NewRangeValidator("client_idle_timeout", 0, 600).Default(90),
"backend_connect_timeout": validators.NewRangeValidator("backend_connect_timeout", 0, 180).Default(5),
"backend_idle_timeout": validators.NewRangeValidator("backend_idle_timeout", 0, 600).Default(90),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES).Default(api.LB_BOOL_OFF),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES).Default(api.LB_STICKY_SESSION_TYPE_INSERT),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)).Optional(true),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout").Optional(true),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for").Default(true),
"gzip": validators.NewBoolValidator("gzip").Default(false),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
if err := backendGroupV.Validate(data); err != nil {
return nil, err
}
for _, v := range keyV {
if err := v.Validate(data); err != nil {
return nil, err
}
}
lb := lbV.Model.(*SLoadbalancer)
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
listenerPort := listenerPortV.Value
listenerType := listenerTypeV.Value
{
err := man.checkListenerUniqueness(ctx, lb, listenerType, listenerPort)
if err != nil {
// duplicate?
return nil, err
}
}
{
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",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lb.Id)
} else {
// 腾讯云backend group只能1v1关联
if lb.GetProviderName() == api.CLOUD_PROVIDER_QCLOUD {
if lbbg != nil {
count, err := lbbg.RefCount()
if err != nil {
return nil, httperrors.NewInternalServerError("get lbbg RefCount fail %s", err)
}
if count > 0 {
return nil, httperrors.NewResourceBusyError("backendgroup aready related with other listener/rule")
}
}
}
}
}
{
if listenerType == api.LB_LISTENER_TYPE_HTTPS {
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
httpsV := map[string]validators.IValidator{
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2").Default(true),
}
for _, v := range httpsV {
if err := v.Validate(data); err != nil {
return nil, err
}
}
}
}
{
// health check default depends on input parameters
checkTypeV := man.CheckTypeV(listenerType)
keyVHealth := map[string]validators.IValidator{
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES).Default(api.LB_BOOL_ON),
"health_check_type": checkTypeV,
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true).Default(""),
"health_check_path": validators.NewURLPathValidator("health_check_path").Default(""),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(",").Default(api.LB_HEALTH_CHECK_HTTP_CODE_DEFAULT),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 1000).Default(3),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 1000).Default(3),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 1, 300).Default(5),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 1, 1000).Default(5),
}
for _, v := range keyVHealth {
if err := v.Validate(data); err != nil {
return nil, err
}
}
}
if _, err := man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data); err != nil {
return nil, err
}
lb := lbV.Model.(*SLoadbalancer)
region := lb.GetRegion()
if region == nil {
return nil, httperrors.NewResourceNotFoundError("failed to find region for loadbalancer %s", lb.Name)
}
if err := man.validateAcl(aclStatusV, aclTypeV, aclV, data, lb.GetProviderName()); err != nil {
return nil, err
}
return region.GetDriver().ValidateCreateLoadbalancerListenerData(ctx, userCred, data, backendGroupV.Model)
return region.GetDriver().ValidateCreateLoadbalancerListenerData(ctx, userCred, ownerId, data, lb, backendGroupV.Model)
}
func (man *SLoadbalancerListenerManager) CheckTypeV(listenerType string) validators.IValidator {
@@ -336,7 +247,7 @@ func (man *SLoadbalancerListenerManager) CheckTypeV(listenerType string) validat
return nil
}
func (man *SLoadbalancerListenerManager) validateAcl(aclStatusV *validators.ValidatorStringChoices, aclTypeV *validators.ValidatorStringChoices, aclV *validators.ValidatorModelIdOrName, data *jsonutils.JSONDict, providerName string) error {
func (man *SLoadbalancerListenerManager) ValidateAcl(aclStatusV *validators.ValidatorStringChoices, aclTypeV *validators.ValidatorStringChoices, aclV *validators.ValidatorModelIdOrName, data *jsonutils.JSONDict, providerName string) error {
if aclStatusV.Value == api.LB_BOOL_ON {
if aclV.Model == nil {
return httperrors.NewMissingParameterError("acl")
@@ -408,83 +319,10 @@ func (lblis *SLoadbalancerListener) StartLoadBalancerListenerSyncstatusTask(ctx
func (lblis *SLoadbalancerListener) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
ownerId := lblis.GetOwnerId()
backendGroupV := validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", ownerId)
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclStatusV.Default(lblis.AclStatus)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
if api.LB_ACL_TYPES.Has(lblis.AclType) {
aclTypeV.Default(lblis.AclType)
}
var aclV *validators.ValidatorModelIdOrName
if _acl, _ := data.GetString("acl"); len(_acl) > 0 {
aclV = validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
} else {
aclV = validators.NewModelIdOrNameValidator("acl", "cachedloadbalanceracl", ownerId)
if len(lblis.AclId) > 0 {
aclV.Default(lblis.AclId)
}
}
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
keyV := map[string]validators.IValidator{
"backend_group": backendGroupV,
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES),
"acl_status": aclStatusV,
"acl_type": aclTypeV,
"acl": aclV,
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"egress_mbps": validators.NewRangeValidator("egress_mbps", api.LB_MbpsMin, api.LB_MbpsMax),
"client_request_timeout": validators.NewRangeValidator("client_request_timeout", 0, 600),
"client_idle_timeout": validators.NewRangeValidator("client_idle_timeout", 0, 600),
"backend_connect_timeout": validators.NewRangeValidator("backend_connect_timeout", 0, 180),
"backend_idle_timeout": validators.NewRangeValidator("backend_idle_timeout", 0, 600),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout"),
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES),
"health_check_type": LoadbalancerListenerManager.CheckTypeV(lblis.ListenerType),
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true),
"health_check_path": validators.NewURLPathValidator("health_check_path"),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(","),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 1000),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 1000),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 1, 300),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 1, 1000),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for"),
"gzip": validators.NewBoolValidator("gzip"),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate"),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src"),
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2"),
}
for _, v := range keyV {
v.Optional(true)
if err := v.Validate(data); err != nil {
return nil, err
}
}
if err := LoadbalancerListenerManager.validateAcl(aclStatusV, aclTypeV, aclV, data, lblis.GetProviderName()); err != nil {
if err := backendGroupV.Validate(data); err != nil {
return nil, err
}
{
if backendGroup, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && backendGroup.LoadbalancerId != lblis.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
backendGroup.Name, backendGroup.Id, backendGroup.LoadbalancerId, lblis.LoadbalancerId)
}
}
if _, err := lblis.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data); err != nil {
return nil, err
}
@@ -659,6 +497,7 @@ func (lblis *SLoadbalancerListener) GetLoadbalancerListenerParams() (*cloudprovi
HealthCheckExp: lblis.HealthCheckExp,
HealthCheck: lblis.HealthCheck,
HealthCheckType: lblis.HealthCheckType,
HealthCheckTimeout: lblis.HealthCheckTimeout,
HealthCheckDomain: lblis.HealthCheckDomain,
HealthCheckHttpCode: lblis.HealthCheckHttpCode,
@@ -731,16 +570,46 @@ func (lblis *SLoadbalancerListener) GetHuaweiLoadbalancerListenerParams() (*clou
return listener, nil
}
func (lblis *SLoadbalancerListener) GetAwsLoadbalancerListenerParams() (*cloudprovider.SLoadbalancerListener, error) {
listener, err := lblis.GetLoadbalancerListenerParams()
if err != nil {
return nil, err
}
lb := lblis.GetLoadbalancer()
if lb != nil {
listener.LoadbalancerID = lb.ExternalId
}
if backendgroup := lblis.GetLoadbalancerBackendGroup(); backendgroup != nil {
cachedLbbg, err := AwsCachedLbbgManager.GetUsableCachedBackendGroup(lb.GetId(), lblis.BackendGroupId, listener.ListenerType, listener.HealthCheckType, listener.HealthCheckInterval)
if err != nil {
return nil, err
}
if cachedLbbg == nil {
return nil, fmt.Errorf("backendgroup %s related cached loadbalancer backendgroup not found", backendgroup.GetId())
}
listener.BackendGroupID = cachedLbbg.ExternalId
listener.BackendGroupType = backendgroup.Type
}
return listener, nil
}
func (lblis *SLoadbalancerListener) GetLoadbalancerCertificate() *SCachedLoadbalancerCertificate {
if len(lblis.CertificateId) == 0 {
return nil
}
certificate, err := CachedLoadbalancerCertificateManager.FetchById(lblis.CertificateId)
ret := &SCachedLoadbalancerCertificate{}
err := CachedLoadbalancerCertificateManager.Query().Equals("certificate_id", lblis.CertificateId).Equals("cloudregion_id", lblis.CloudregionId).IsFalse("pending_deleted").First(ret)
if err != nil {
return nil
}
return certificate.(*SCachedLoadbalancerCertificate)
return ret
}
func (lblis *SLoadbalancerListener) GetLoadbalancerAcl() *SCachedLoadbalancerAcl {
@@ -947,6 +816,15 @@ func (lblis *SLoadbalancerListener) constructFieldsFromCloudListener(userCred mc
lblis.BackendGroupId = group.(*SHuaweiCachedLbbg).BackendGroupId
}
} else if lblis.GetProviderName() == api.CLOUD_PROVIDER_AWS {
if len(groupId) > 0 {
group, err := db.FetchByExternalId(AwsCachedLbbgManager, groupId)
if err != nil {
log.Errorf("Fetch aws loadbalancer backendgroup by external id %s failed: %s", groupId, err)
}
lblis.BackendGroupId = group.(*SAwsCachedLbbg).BackendGroupId
}
} else if group, err := db.FetchByExternalId(LoadbalancerBackendGroupManager, groupId); err == nil {
lblis.BackendGroupId = group.GetId()
}
+11 -8
View File
@@ -136,7 +136,7 @@ func (m *SLoadbalancernetworkManager) DeleteLoadbalancerNetwork(ctx context.Cont
if err != nil {
return err
}
if req.reserve && regutils.MatchIP4Addr(ln.IpAddr) {
if req.reserve && len(ln.IpAddr) > 0 && regutils.MatchIP4Addr(ln.IpAddr) {
note := fmt.Sprintf("reserved from loadbalancer delete: %s",
req.loadbalancer.Id)
reservedIpMan := db.GetModelManager("reservedip").(*SReservedipManager)
@@ -151,18 +151,21 @@ func (m *SLoadbalancernetworkManager) DeleteLoadbalancerNetwork(ctx context.Cont
}
func (m *SLoadbalancernetworkManager) syncLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential, req *SLoadbalancerNetworkRequestData) error {
_network, err := NetworkManager.FetchById(req.NetworkId)
_network, err := db.FetchByExternalId(NetworkManager, req.NetworkId)
if err != nil {
return err
}
network := _network.(*SNetwork)
ip, err := netutils.NewIPV4Addr(req.Address)
if err != nil {
return err
}
if !network.IsAddressInRange(ip) {
return fmt.Errorf("address %s is not in the range of network %s(%s)", req.Address, network.Id, network.Name)
if len(req.Address) > 0 {
ip, err := netutils.NewIPV4Addr(req.Address)
if err != nil {
return err
}
if !network.IsAddressInRange(ip) {
return fmt.Errorf("address %s is not in the range of network %s(%s)", req.Address, network.Id, network.Name)
}
}
q := m.Query().Equals("loadbalancer_id", req.Loadbalancer.Id).Equals("network_id", req.NetworkId)
lns := []SLoadbalancerNetwork{}
if err := db.FetchModelObjects(m, q, &lns); err != nil {
+74 -168
View File
@@ -17,11 +17,12 @@ package models
import (
"context"
"fmt"
"net"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -72,10 +73,10 @@ type SLoadbalancer struct {
SZoneResourceBase
SLoadbalancerRateLimiter
Address string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"`
Address string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"optional"`
AddressType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"`
NetworkType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"`
NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
NetworkId string `width:"147" charset:"ascii" nullable:"false" list:"user" create:"optional"`
VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
ClusterId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
@@ -115,158 +116,38 @@ func (man *SLoadbalancerManager) ListItemFilter(ctx context.Context, q *sqlchemy
}
func (man *SLoadbalancerManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId)
addressType, _ := data.GetString("address_type")
zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId)
managerIdV := validators.NewModelIdOrNameValidator("manager", "cloudprovider", ownerId)
if addressType == api.LB_ADDR_TYPE_INTERNET {
networkV.Optional(true)
} else {
zoneV.Optional(true)
managerIdV.Optional(true)
}
addressV := validators.NewIPv4AddrValidator("address")
chargeTypeV := validators.NewStringChoicesValidator("charge_type", api.LB_CHARGE_TYPES)
chargeTypeV.Default(api.LB_CHARGE_TYPE_BY_TRAFFIC)
addressTypeV := validators.NewStringChoicesValidator("address_type", api.LB_ADDR_TYPES)
clusterV := validators.NewModelIdOrNameValidator("cluster", "loadbalancercluster", ownerId)
{
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"charge_type": chargeTypeV,
"address": addressV.Optional(true),
"address_type": addressTypeV.Default(api.LB_ADDR_TYPE_INTRANET),
"network": networkV,
"zone": zoneV,
"manager": managerIdV,
"cluster": clusterV.Optional(true),
}
for _, v := range keyV {
if err := v.Validate(data); err != nil {
return nil, err
}
}
}
var (
region *SCloudregion
zone *SZone
)
var wire *SWire
network := networkV.Model.(*SNetwork)
if network != nil {
wire = network.GetWire()
if wire == nil {
return nil, fmt.Errorf("getting wire failed")
}
vpc := wire.getVpc()
if vpc == nil {
var region *SCloudregion
if id, _ := data.GetString("vpc"); len(id) > 0 {
vpc, err := db.FetchById(VpcManager, id)
if err != nil {
return nil, fmt.Errorf("getting vpc failed")
}
data.Set("vpc_id", jsonutils.NewString(vpc.Id))
if len(vpc.ManagerId) > 0 {
if managerIdV.Model != nil && managerIdV.Model.GetId() != vpc.ManagerId {
return nil, httperrors.NewInputParameterError("Loadbalancer's manager (%s(%s)) does not match vpc's(%s(%s)) (%s)", managerIdV.Model.GetName(), managerIdV.Model.GetId(), vpc.GetName(), vpc.GetId(), vpc.ManagerId)
}
data.Set("manager_id", jsonutils.NewString(vpc.ManagerId))
}
}
if addressTypeV.Value == api.LB_ADDR_TYPE_INTRANET {
if chargeTypeV.Value == api.LB_CHARGE_TYPE_BY_BANDWIDTH {
return nil, httperrors.NewUnsupportOperationError("intranet loadbalancer not support bandwidth charge type")
}
if ipAddr := addressV.IP; ipAddr != nil {
ipS := ipAddr.String()
ip, err := netutils.NewIPV4Addr(ipS)
if err != nil {
return nil, err
}
if !network.IsAddressInRange(ip) {
return nil, httperrors.NewInputParameterError("address %s is not in the range of network %s(%s)",
ipS, network.Name, network.Id)
}
used, err := network.isAddressUsed(ipS)
if err != nil {
return nil, httperrors.NewInternalServerError("isAddressUsed fail %s", err)
}
if used {
return nil, httperrors.NewInputParameterError("address %s is already occupied", ipS)
}
}
freeCnt, err := network.getFreeAddressCount()
region, _ = vpc.(*SVpc).GetRegion()
} else if id, _ := data.GetString("zone"); len(id) > 0 {
zone, err := db.FetchById(ZoneManager, id)
if err != nil {
return nil, httperrors.NewInternalServerError("getFreeAddressCount fail %s", err)
}
if freeCnt <= 0 {
return nil, httperrors.NewNotAcceptableError("network %s(%s) has no free addresses",
network.Name, network.Id)
return nil, fmt.Errorf("getting zone failed")
}
zone := wire.GetZone()
if zone == nil {
if provider := managerIdV.Model.(*SCloudprovider); provider.Provider != api.CLOUD_PROVIDER_HUAWEI {
return nil, fmt.Errorf("getting zone failed")
}
} else {
data.Set("zone_id", jsonutils.NewString(zone.GetId()))
region = zone.(*SZone).GetRegion()
} else if id, _ := data.GetString("network"); len(id) > 0 {
network, err := db.FetchById(NetworkManager, strings.Split(id, ",")[0])
if err != nil {
return nil, fmt.Errorf("getting network failed")
}
region = network.(*SNetwork).getRegion()
}
region = wire.getRegion()
if region == nil {
return nil, fmt.Errorf("getting region failed")
}
data.Set("cloudregion_id", jsonutils.NewString(region.GetId()))
// TODO validate network is of classic type
data.Set("network_type", jsonutils.NewString(api.LB_NETWORK_TYPE_CLASSIC))
data.Set("address_type", jsonutils.NewString(api.LB_ADDR_TYPE_INTRANET))
} else {
zone = zoneV.Model.(*SZone)
region = zone.GetRegion()
if region == nil {
return nil, fmt.Errorf("getting region failed")
}
if chargeTypeV.Value == api.LB_CHARGE_TYPE_BY_BANDWIDTH {
egressMbpsV := validators.NewNonNegativeValidator("egress_mpbs")
if err := egressMbpsV.Validate(data); err != nil {
return nil, err
}
}
if region == nil {
return nil, fmt.Errorf("getting region failed")
}
// 公网 lb 实例和vpc、network无关联
data.Set("zone_id", jsonutils.NewString(zone.GetId()))
data.Set("cloudregion_id", jsonutils.NewString(region.GetId()))
data.Set("network_type", jsonutils.NewString(api.LB_NETWORK_TYPE_VPC))
data.Set("address_type", jsonutils.NewString(api.LB_ADDR_TYPE_INTERNET))
}
if zone == nil {
return nil, httperrors.NewInputParameterError("zone info missing")
}
if managerIdV.Model == nil {
if clusterV.Model == nil {
clusters := LoadbalancerClusterManager.findByZoneId(zone.Id)
if len(clusters) == 0 {
return nil, httperrors.NewInputParameterError("zone %s(%s) has no lbcluster", zone.Name, zone.Id)
}
if len(clusters) > 1 {
log.Warningf("found %d lbclusters, randomly select 1", len(clusters))
}
data.Set("cluster_id", jsonutils.NewString(clusters[0].Id))
} else {
cluster := clusterV.Model.(*SLoadbalancerCluster)
if cluster.ZoneId != zone.Id {
return nil, httperrors.NewInputParameterError("cluster zone %s does not match network zone %s ",
cluster.ZoneId, zone.Id)
}
}
} else {
data.Remove("cluster_id")
}
if _, err := man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data); err != nil {
return nil, err
}
ctx = context.WithValue(ctx, "ownerId", ownerId)
return region.GetDriver().ValidateCreateLoadbalancerData(ctx, userCred, data)
}
@@ -367,12 +248,23 @@ func (lb *SLoadbalancer) GetVpc() *SVpc {
return vpc.(*SVpc)
}
func (lb *SLoadbalancer) GetNetwork() *SNetwork {
network, err := NetworkManager.FetchById(lb.NetworkId)
func (lb *SLoadbalancer) GetNetworks() ([]SNetwork, error) {
networks := []SNetwork{}
networkIds := strings.Split(lb.NetworkId, ",")
err := NetworkManager.Query().In("id", networkIds).IsFalse("pending_deleted").All(&networks)
if err != nil {
return nil
return nil, err
}
return network.(*SNetwork)
if len(networks) == 0 {
return nil, fmt.Errorf("loadbalancer has no releated network found")
}
if len(networks) != len(networkIds) {
return nil, fmt.Errorf("expected %d networks, %d found", len(networkIds), len(networks))
}
return networks, nil
}
func (lb *SLoadbalancer) GetIRegion() (cloudprovider.ICloudRegion, error) {
@@ -413,7 +305,7 @@ func (lb *SLoadbalancer) GetCreateLoadbalancerParams(iRegion cloudprovider.IClou
if lb.ChargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH {
params.EgressMbps = lb.EgressMbps
}
if lb.AddressType == api.LB_ADDR_TYPE_INTRANET || lb.GetProviderName() == api.CLOUD_PROVIDER_HUAWEI {
if lb.AddressType == api.LB_ADDR_TYPE_INTRANET || lb.GetProviderName() == api.CLOUD_PROVIDER_HUAWEI || lb.GetProviderName() == api.CLOUD_PROVIDER_AWS {
vpc := lb.GetVpc()
if vpc == nil {
return nil, fmt.Errorf("failed to find vpc for lb %s", lb.Name)
@@ -423,15 +315,19 @@ func (lb *SLoadbalancer) GetCreateLoadbalancerParams(iRegion cloudprovider.IClou
return nil, err
}
params.VpcID = iVpc.GetId()
network := lb.GetNetwork()
if network == nil {
return nil, fmt.Errorf("failed to find network for lb %s", lb.Name)
}
iNetwork, err := network.GetINetwork()
networks, err := lb.GetNetworks()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to find network for lb %s: %s", lb.Name, err)
}
params.NetworkID = iNetwork.GetId()
for i := range networks {
iNetwork, err := networks[i].GetINetwork()
if err != nil {
return nil, err
}
params.NetworkIDs = append(params.NetworkIDs, iNetwork.GetId())
}
}
return params, nil
}
@@ -682,11 +578,15 @@ func (man *SLoadbalancerManager) newFromCloudLoadbalancer(ctx context.Context, u
lb.ChargeType = extLb.GetChargeType()
lb.EgressMbps = extLb.GetEgressMbps()
lb.ExternalId = extLb.GetGlobalId()
if networkId := extLb.GetNetworkId(); len(networkId) > 0 {
networkIds := extLb.GetNetworkIds()
lbNetworkIds := []string{}
for _, networkId := range networkIds {
if network, err := db.FetchByExternalId(NetworkManager, networkId); err == nil && network != nil {
lb.NetworkId = network.GetId()
lbNetworkIds = append(lbNetworkIds, network.GetId())
}
}
lb.NetworkId = strings.Join(lbNetworkIds, ",")
if vpcId := extLb.GetVpcId(); len(vpcId) > 0 {
if vpc, err := db.FetchByExternalId(VpcManager, vpcId); err == nil && vpc != nil {
lb.VpcId = vpc.GetId()
@@ -711,7 +611,7 @@ func (man *SLoadbalancerManager) newFromCloudLoadbalancer(ctx context.Context, u
db.OpsLog.LogEvent(&lb, db.ACT_CREATE, lb.GetShortDesc(ctx), userCred)
lb.syncLoadbalancerNetwork(ctx, userCred)
lb.syncLoadbalancerNetwork(ctx, userCred, networkIds)
return &lb, nil
}
@@ -728,16 +628,23 @@ func (lb *SLoadbalancer) syncRemoveCloudLoadbalancer(ctx context.Context, userCr
}
}
func (lb *SLoadbalancer) syncLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential) {
func (lb *SLoadbalancer) syncLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential, networkIds []string) {
if len(lb.NetworkId) > 0 {
lbNetReq := &SLoadbalancerNetworkRequestData{
Loadbalancer: lb,
NetworkId: lb.NetworkId,
Address: lb.Address,
ip := ""
if net.ParseIP(lb.Address) != nil {
ip = lb.Address
}
err := LoadbalancernetworkManager.syncLoadbalancerNetwork(ctx, userCred, lbNetReq)
if err != nil {
log.Errorf("failed to create loadbalancer network: %v", err)
for i := range networkIds {
lbNetReq := &SLoadbalancerNetworkRequestData{
Loadbalancer: lb,
NetworkId: networkIds[i],
Address: ip,
}
err := LoadbalancernetworkManager.syncLoadbalancerNetwork(ctx, userCred, lbNetReq)
if err != nil {
log.Errorf("failed to create loadbalancer network: %v", err)
}
}
}
}
@@ -863,8 +770,7 @@ func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred
db.OpsLog.LogSyncUpdate(lb, diff, userCred)
SyncCloudProject(userCred, lb, syncOwnerId, extLb, lb.ManagerId)
lb.syncLoadbalancerNetwork(ctx, userCred)
lb.syncLoadbalancerNetwork(ctx, userCred, extLb.GetNetworkIds())
return err
}
+61
View File
@@ -18,6 +18,7 @@ import (
"context"
"database/sql"
"fmt"
"net"
"strconv"
"strings"
"time"
@@ -190,6 +191,66 @@ func (self *SNetwork) GetTotalNicCount() (int, error) {
return total, nil
}
/*验证elb network可用,并返回关联的region, zone,vpc, wire*/
func (self *SNetwork) ValidateElbNetwork(ipAddr net.IP) (*SCloudregion, *SZone, *SVpc, *SWire, error) {
// 验证IP Address可用
if ipAddr != nil {
ipS := ipAddr.String()
ip, err := netutils.NewIPV4Addr(ipS)
if err != nil {
return nil, nil, nil, nil, err
}
if !self.IsAddressInRange(ip) {
return nil, nil, nil, nil, httperrors.NewInputParameterError("address %s is not in the range of network %s(%s)",
ipS, self.Name, self.Id)
}
used, err := self.isAddressUsed(ipS)
if err != nil {
return nil, nil, nil, nil, httperrors.NewInternalServerError("isAddressUsed fail %s", err)
}
if used {
return nil, nil, nil, nil, httperrors.NewInputParameterError("address %s is already occupied", ipS)
}
}
// 验证网络存在剩余地址空间
freeCnt, err := self.getFreeAddressCount()
if err != nil {
return nil, nil, nil, nil, httperrors.NewInternalServerError("getFreeAddressCount fail %s", err)
}
if freeCnt <= 0 {
return nil, nil, nil, nil, httperrors.NewNotAcceptableError("network %s(%s) has no free addresses",
self.Name, self.Id)
}
// 验证网络可用
wire := self.GetWire()
if wire == nil {
return nil, nil, nil, nil, fmt.Errorf("getting wire failed")
}
vpc := wire.getVpc()
if vpc == nil {
return nil, nil, nil, nil, fmt.Errorf("getting vpc failed")
}
var zone *SZone
if len(wire.ZoneId) > 0 {
zone = wire.GetZone()
if zone == nil {
return nil, nil, nil, nil, fmt.Errorf("getting zone failed")
}
}
region := wire.getRegion()
if region == nil {
return nil, nil, nil, nil, fmt.Errorf("getting region failed")
}
return region, zone, vpc, wire, nil
}
func (self *SNetwork) GetGuestnicsCount() (int, error) {
return GuestnetworkManager.Query().Equals("network_id", self.Id).IsFalse("virtual").CountWithError()
}
+3 -2
View File
@@ -61,7 +61,7 @@ type IRegionDriver interface {
RequestDeleteLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, lbb *SLoadbalancerBackend, task taskman.ITask) error
RequestSyncLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, lbb *SLoadbalancerBackend, task taskman.ITask) error
ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error)
ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, lb *SLoadbalancer, backendGroup db.IModel) (*jsonutils.JSONDict, error)
ValidateUpdateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lblist *SLoadbalancerListener, backendGroup db.IModel) (*jsonutils.JSONDict, error)
RequestCreateLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *SLoadbalancerListener, task taskman.ITask) error
RequestDeleteLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *SLoadbalancerListener, task taskman.ITask) error
@@ -70,7 +70,8 @@ type IRegionDriver interface {
RequestSyncstatusLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *SLoadbalancerListener, task taskman.ITask) error
RequestSyncLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *SLoadbalancerListener, task taskman.ITask) error
ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error)
ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error)
ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error)
RequestCreateLoadbalancerListenerRule(ctx context.Context, userCred mcclient.TokenCredential, lbr *SLoadbalancerListenerRule, task taskman.ITask) error
RequestDeleteLoadbalancerListenerRule(ctx context.Context, userCred mcclient.TokenCredential, lbr *SLoadbalancerListenerRule, task taskman.ITask) error
+4
View File
@@ -615,6 +615,10 @@ func chooseCandidateNetworksByNetworkType(nets []SNetwork, isExit bool, serverTy
}
func (self *SWire) GetZone() *SZone {
if self.ZoneId == "" {
return nil
}
return ZoneManager.FetchZoneById(self.ZoneId)
}
+455 -66
View File
@@ -21,6 +21,8 @@ import (
"sort"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/util/choices"
"yunion.io/x/onecloud/pkg/util/rand"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/apis/compute"
@@ -46,28 +48,109 @@ func (self *SAliyunRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_ALIYUN
}
func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
func (self *SAliyunRegionDriver) validateCreateLBCommonData(ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*validators.ValidatorModelIdOrName, *jsonutils.JSONDict, error) {
zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId)
managerIdV := validators.NewModelIdOrNameValidator("manager", "cloudprovider", ownerId)
chargeTypeV := validators.NewStringChoicesValidator("charge_type", choices.NewChoices(api.LB_CHARGE_TYPE_BY_BANDWIDTH, api.LB_CHARGE_TYPE_BY_TRAFFIC))
chargeTypeV.Default(api.LB_CHARGE_TYPE_BY_TRAFFIC)
addressTypeV := validators.NewStringChoicesValidator("address_type", api.LB_ADDR_TYPES)
loadbalancerSpecV := validators.NewStringChoicesValidator("loadbalancer_spec", api.LB_ALIYUN_SPECS)
loadbalancerSpecV.Default(api.LB_ALIYUN_SPEC_SHAREABLE)
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"charge_type": chargeTypeV,
"address_type": addressTypeV.Default(api.LB_ADDR_TYPE_INTRANET),
"zone": zoneV,
"manager": managerIdV,
"loadbalancer_spec": loadbalancerSpecV,
}
if err := RunValidators(keyV, data); err != nil {
return nil, nil, err
}
if chargeTypeV.Value == api.LB_CHARGE_TYPE_BY_BANDWIDTH {
egressMbps := validators.NewRangeValidator("egress_mbps", 1, 5000)
if err := egressMbps.Validate(data); err != nil {
return nil, nil, err
}
}
region := zoneV.Model.(*models.SZone).GetRegion()
if region == nil {
return nil, nil, fmt.Errorf("getting region failed")
}
data.Set("network_type", jsonutils.NewString(api.LB_NETWORK_TYPE_VPC))
data.Set("cloudregion_id", jsonutils.NewString(region.GetId()))
return managerIdV, data, nil
}
func (self *SAliyunRegionDriver) validateCreateIntranetLBData(ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
managerIdV, data, err := self.validateCreateLBCommonData(ownerId, data)
if err != nil {
return nil, err
}
networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId)
if err := networkV.Validate(data); err != nil {
return nil, err
}
network := networkV.Model.(*models.SNetwork)
region, zone, vpc, _, err := network.ValidateElbNetwork(nil)
if err != nil {
return nil, err
}
chargeType, _ := data.GetString("charge_type")
if chargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH {
return nil, httperrors.NewUnsupportOperationError("intranet loadbalancer not support bandwidth charge type")
}
managerId, _ := data.GetString("manager_id")
if managerId != vpc.ManagerId {
return nil, httperrors.NewInputParameterError("Loadbalancer's manager (%s(%s)) does not match vpc's(%s(%s)) (%s)", managerIdV.Model.GetName(), managerIdV.Model.GetId(), vpc.GetName(), vpc.GetId(), vpc.ManagerId)
}
data.Set("vpc_id", jsonutils.NewString(vpc.Id))
data.Set("cloudregion_id", jsonutils.NewString(region.GetId()))
data.Set("zone_id", jsonutils.NewString(zone.GetId()))
data.Set("address_type", jsonutils.NewString(api.LB_ADDR_TYPE_INTRANET))
return data, nil
}
func (self *SAliyunRegionDriver) validateCreateInternetLBData(ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
_, data, err := self.validateCreateLBCommonData(ownerId, data)
if err != nil {
return nil, err
}
// 公网 lb 实例和vpc、network无关联
data.Set("vpc_id", jsonutils.NewString(""))
data.Set("address", jsonutils.NewString(""))
data.Set("network_id", jsonutils.NewString(""))
loadbalancerSpecV := validators.NewStringChoicesValidator("loadbalancer_spec", api.LB_ALIYUN_SPECS)
loadbalancerSpecV.Default(api.LB_ALIYUN_SPEC_SHAREABLE)
if err := loadbalancerSpecV.Validate(data); err != nil {
data.Set("address_type", jsonutils.NewString(api.LB_ADDR_TYPE_INTERNET))
return data, nil
}
func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
addressTypeV := validators.NewStringChoicesValidator("address_type", api.LB_ADDR_TYPES)
if err := addressTypeV.Validate(data); err != nil {
return nil, err
}
chargeType, _ := data.GetString("charge_type")
if len(chargeType) == 0 {
chargeType = api.LB_CHARGE_TYPE_BY_TRAFFIC
data.Set("charge_type", jsonutils.NewString(chargeType))
var validator func(ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
if addressTypeV.Value == api.LB_ADDR_TYPE_INTRANET {
validator = self.validateCreateIntranetLBData
} else {
validator = self.validateCreateInternetLBData
}
if !utils.IsInStringArray(chargeType, []string{api.LB_CHARGE_TYPE_BY_BANDWIDTH, api.LB_CHARGE_TYPE_BY_TRAFFIC}) {
return nil, httperrors.NewInputParameterError("Unsupport charge type %s, only support traffic or bandwidth")
}
if chargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH {
egressMbps := validators.NewRangeValidator("egress_mbps", 1, 5000)
if err := egressMbps.Validate(data); err != nil {
return nil, err
}
if _, err := validator(ownerId, data); err != nil {
return nil, err
}
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerData(ctx, userCred, data)
}
@@ -107,12 +190,81 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerBackendGroupData(ctx
}
func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendType string, lb *models.SLoadbalancer, backendGroup *models.SLoadbalancerBackendGroup, backend db.IModel) (*jsonutils.JSONDict, error) {
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
man := models.LoadbalancerBackendManager
backendTypeV := validators.NewStringChoicesValidator("backend_type", api.LB_BACKEND_TYPES)
keyV := map[string]validators.IValidator{
"backend_type": backendTypeV,
"weight": validators.NewRangeValidator("weight", 0, 100).Default(1),
"port": validators.NewPortValidator("port"),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
var basename string
switch backendType {
case api.LB_BACKEND_GUEST:
backendV := validators.NewModelIdOrNameValidator("backend", "server", ownerId)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
guest := backendV.Model.(*models.SGuest)
err = man.ValidateBackendVpc(lb, guest, backendGroup)
if err != nil {
return nil, err
}
basename = guest.Name
backend = backendV.Model
case api.LB_BACKEND_HOST:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify host as backend")
}
backendV := validators.NewModelIdOrNameValidator("backend", "host", userCred)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
host := backendV.Model.(*models.SHost)
{
if len(host.AccessIp) == 0 {
return nil, fmt.Errorf("host %s has no access ip", host.GetId())
}
data.Set("address", jsonutils.NewString(host.AccessIp))
}
basename = host.Name
backend = backendV.Model
case api.LB_BACKEND_IP:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify ip address as backend")
}
backendV := validators.NewIPv4AddrValidator("backend")
err := backendV.Validate(data)
if err != nil {
return nil, err
}
ip := backendV.IP.String()
data.Set("address", jsonutils.NewString(ip))
basename = ip
default:
return nil, fmt.Errorf("internal error: unexpected backend type %s", backendType)
}
name, _ := data.GetString("name")
if name == "" {
name = fmt.Sprintf("%s-%s-%s-%s", backendGroup.Name, backendType, basename, rand.String(4))
}
if backendType != api.LB_BACKEND_GUEST {
return nil, httperrors.NewUnsupportOperationError("internal error: unexpected backend type %s", backendType)
}
if !utils.IsInStringArray(backendGroup.Type, []string{api.LB_BACKENDGROUP_TYPE_DEFAULT, api.LB_BACKENDGROUP_TYPE_NORMAL}) {
return nil, httperrors.NewUnsupportOperationError("backendgroup %s not support this operation", backendGroup.Name)
}
guest := backend.(*models.SGuest)
host := guest.GetHost()
if host == nil {
@@ -121,33 +273,44 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerBackendData(ctx conte
if lb == nil {
return nil, fmt.Errorf("error loadbalancer of backend group %s", backendGroup.GetId())
}
hostRegion := host.GetRegion()
lbRegion := lb.GetRegion()
if hostRegion.Id != lbRegion.Id {
return nil, httperrors.NewInputParameterError("region of host %q (%s) != region of loadbalancer %q (%s))",
host.Name, host.ZoneId, lb.Name, lb.ZoneId)
}
address, err := models.LoadbalancerBackendManager.GetGuestAddress(guest)
if err != nil {
return nil, err
}
data.Set("address", jsonutils.NewString(address))
weight, _ := data.Int("weight")
if weight < 0 || weight > 100 {
return nil, httperrors.NewInputParameterError("Aliyun instance weight must be in the range of 0 ~ 100")
}
data.Set("name", jsonutils.NewString(name))
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return data, nil
}
func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lbbg *models.SLoadbalancerBackendGroup) (*jsonutils.JSONDict, error) {
keyV := map[string]validators.IValidator{
"weight": validators.NewRangeValidator("weight", 1, 100).Optional(true),
"port": validators.NewPortValidator("port").Optional(true),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Optional(true),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
switch lbbg.Type {
case api.LB_BACKENDGROUP_TYPE_DEFAULT:
if data.Contains("port") {
return nil, httperrors.NewInputParameterError("%s backend group not support change port", lbbg.Type)
}
case api.LB_BACKENDGROUP_TYPE_NORMAL:
weightV := validators.NewRangeValidator("weight", 1, 100).Optional(true)
return data, weightV.Validate(data)
return data, nil
case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE:
if data.Contains("port") || data.Contains("weight") {
return data, httperrors.NewInputParameterError("%s backend group not support change port or weight", lbbg.Type)
@@ -155,10 +318,52 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx conte
default:
return nil, httperrors.NewInputParameterError("Unknown backend group type %s", lbbg.Type)
}
return data, nil
}
func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
domainV := validators.NewDomainNameValidator("domain")
pathV := validators.NewURLPathValidator("path")
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"domain": domainV.AllowEmpty(true).Default(""),
"path": pathV.Default(""),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
listenerId, err := data.GetString("listener_id")
if err != nil {
return nil, err
}
ilistener, err := db.FetchById(models.LoadbalancerListenerManager, listenerId)
if err != nil {
return nil, err
}
listener := ilistener.(*models.SLoadbalancerListener)
listenerType := listener.ListenerType
if listenerType != api.LB_LISTENER_TYPE_HTTP && listenerType != api.LB_LISTENER_TYPE_HTTPS {
return nil, httperrors.NewInputParameterError("listener type must be http/https, got %s", listenerType)
}
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != listener.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, listener.LoadbalancerId)
}
err = models.LoadbalancerListenerRuleCheckUniqueness(ctx, listener, domainV.Value, pathV.Value)
if err != nil {
return nil, err
}
backendgroup, ok := backendGroup.(*models.SLoadbalancerBackendGroup)
if !ok {
return nil, httperrors.NewMissingParameterError("backend_group")
@@ -166,30 +371,89 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx
if backendgroup.Type != api.LB_BACKENDGROUP_TYPE_NORMAL {
return nil, httperrors.NewInputParameterError("backend group type must be normal")
}
data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId))
data.Set("manager_id", jsonutils.NewString(listener.ManagerId))
return data, nil
}
func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
backendgroup, ok := backendGroup.(*models.SLoadbalancerBackendGroup)
if !ok {
return nil, httperrors.NewMissingParameterError("backend_group")
func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
lbr := ctx.Value("lbr").(*models.SLoadbalancerListenerRule)
keyV := map[string]validators.IValidator{
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate"),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src"),
}
listenerType, _ := data.GetString("listener_type")
if utils.IsInStringArray(listenerType, []string{api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS}) && !utils.IsInStringArray(backendgroup.Type, []string{api.LB_BACKENDGROUP_TYPE_DEFAULT, api.LB_BACKENDGROUP_TYPE_NORMAL}) {
return nil, httperrors.NewUnsupportOperationError("http or https listener only supportd default or normal backendgroup")
for _, v := range keyV {
v.Optional(true)
if err := v.Validate(data); err != nil {
return nil, err
}
}
if backendGroup, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && backendGroup.Id != lbr.BackendGroupId {
listenerM, err := models.LoadbalancerListenerManager.FetchById(lbr.ListenerId)
if err != nil {
return nil, httperrors.NewInputParameterError("loadbalancerlistenerrule %s(%s): fetching listener %s failed",
lbr.Name, lbr.Id, lbr.ListenerId)
}
listener := listenerM.(*models.SLoadbalancerListener)
if backendGroup.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)
}
}
return data, nil
}
func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, lb *models.SLoadbalancer, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
listenerTypeV := validators.NewStringChoicesValidator("listener_type", api.LB_LISTENER_TYPES)
listenerPortV := validators.NewPortValidator("listener_port")
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
aclV := validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"listener_type": listenerTypeV,
"listener_port": listenerPortV,
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
"acl_status": aclStatusV.Default(api.LB_BOOL_OFF),
"acl_type": aclTypeV.Optional(true),
"acl": aclV.Optional(true),
"client_request_timeout": validators.NewRangeValidator("client_request_timeout", 0, 600).Default(10),
"client_idle_timeout": validators.NewRangeValidator("client_idle_timeout", 0, 600).Default(90),
"backend_connect_timeout": validators.NewRangeValidator("backend_connect_timeout", 0, 180).Default(5),
"backend_idle_timeout": validators.NewRangeValidator("backend_idle_timeout", 0, 600).Default(90),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES).Default(api.LB_BOOL_OFF),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES).Default(api.LB_STICKY_SESSION_TYPE_INSERT),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)).Optional(true),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout").Optional(true),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for").Default(true),
"gzip": validators.NewBoolValidator("gzip").Default(false),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
}
lb := backendgroup.GetLoadbalancer()
if tlsCipherPolicy, _ := data.GetString("tls_cipher_policy"); len(tlsCipherPolicy) > 0 && len(lb.LoadbalancerSpec) == 0 {
data.Set("tls_cipher_policy", jsonutils.NewString(""))
}
if healthCheckDomain, _ := data.GetString("health_check_domain"); len(healthCheckDomain) > 80 {
return nil, httperrors.NewInputParameterError("health_check_domain must be in the range of 1 ~ 80")
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
egressMbps := 5000
// listener uniqueness
listenerType := listenerTypeV.Value
err := models.LoadbalancerListenerManager.CheckListenerUniqueness(ctx, lb, listenerType, listenerPortV.Value)
if err != nil {
return nil, err
}
// 检查带宽限制
maxEgressMbps := 5000
if lb.ChargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH {
egressMbps = lb.EgressMbps
maxEgressMbps = lb.EgressMbps
}
listeners, err := lb.GetLoadbalancerListeners()
@@ -198,37 +462,99 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerData(ctx cont
}
for _, listener := range listeners {
if listener.EgressMbps > 0 {
egressMbps -= listener.EgressMbps
maxEgressMbps -= listener.EgressMbps
}
}
keyV := map[string]validators.IValidator{
"egress_mbps": validators.NewRangeValidator("egress_mbps", 0, int64(egressMbps)).Optional(true),
egressMbpsV := validators.NewRangeValidator("egress_mbps", 0, int64(maxEgressMbps)).Optional(true)
if err := egressMbpsV.Validate(data); err != nil {
return nil, err
}
// backendgroup check
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lb.Id {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lb.Id)
}
// https additional certificate check
if listenerType == api.LB_LISTENER_TYPE_HTTPS {
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
httpsV := map[string]validators.IValidator{
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2").Default(true),
}
if err := RunValidators(httpsV, data); err != nil {
return nil, err
}
}
// health check default depends on input parameters
checkTypeV := models.LoadbalancerListenerManager.CheckTypeV(listenerType)
keyVHealth := map[string]validators.IValidator{
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES).Default(api.LB_BOOL_ON),
"health_check_type": checkTypeV,
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true).Default(""),
"health_check_path": validators.NewURLPathValidator("health_check_path").Default(""),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(",").Default(api.LB_HEALTH_CHECK_HTTP_CODE_DEFAULT),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 2, 10).Default(3),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 2, 10).Default(3),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 1, 300).Default(5),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 1, 50).Default(2),
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_ALIYUN_COMMON_SCHEDULER_TYPES),
}
strickySession, _ := data.GetString("sticky_session")
if err := RunValidators(keyVHealth, data); err != nil {
return nil, err
}
// acl check
if err := models.LoadbalancerListenerManager.ValidateAcl(aclStatusV, aclTypeV, aclV, data, api.CLOUD_PROVIDER_ALIYUN); err != nil {
return nil, err
}
backendgroup, ok := backendGroup.(*models.SLoadbalancerBackendGroup)
if !ok {
return nil, httperrors.NewMissingParameterError("backend_group")
}
// http&https listenerType limitation check
if utils.IsInStringArray(listenerType, []string{api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS}) && !utils.IsInStringArray(backendgroup.Type, []string{api.LB_BACKENDGROUP_TYPE_DEFAULT, api.LB_BACKENDGROUP_TYPE_NORMAL}) {
return nil, httperrors.NewUnsupportOperationError("http or https listener only supportd default or normal backendgroup")
}
if tlsCipherPolicy, _ := data.GetString("tls_cipher_policy"); len(tlsCipherPolicy) > 0 && len(lb.LoadbalancerSpec) == 0 {
data.Set("tls_cipher_policy", jsonutils.NewString(""))
}
if healthCheckDomain, _ := data.GetString("health_check_domain"); len(healthCheckDomain) > 80 {
return nil, httperrors.NewInputParameterError("health_check_domain must be in the range of 1 ~ 80")
}
// 阿里云协议限制
V := map[string]validators.IValidator{}
V["scheduler"] = validators.NewStringChoicesValidator("scheduler", api.LB_ALIYUN_COMMON_SCHEDULER_TYPES)
switch listenerType {
case api.LB_LISTENER_TYPE_UDP:
keyV["health_check_interval"] = validators.NewRangeValidator("health_check_interval", 1, 50).Default(5)
keyV["scheduler"] = validators.NewStringChoicesValidator("scheduler", api.LB_ALIYUN_UDP_SCHEDULER_TYPES)
V["health_check_interval"] = validators.NewRangeValidator("health_check_interval", 1, 50).Default(5)
V["scheduler"] = validators.NewStringChoicesValidator("scheduler", api.LB_ALIYUN_UDP_SCHEDULER_TYPES)
for _, _key := range []string{"health_check_req", "health_check_exp"} {
if key, _ := data.GetString(_key); len(key) > 500 {
return nil, httperrors.NewInputParameterError("%s length must less 500 letters", key)
}
}
case api.LB_LISTENER_TYPE_HTTP:
if strickySession == api.LB_BOOL_ON {
V["client_idle_timeout"] = validators.NewRangeValidator("client_idle_timeout", 1, 60).Default(15)
V["client_request_timeout"] = validators.NewRangeValidator("client_request_timeout", 1, 180).Default(60)
if strickySession, _ := data.GetString("sticky_session"); strickySession == api.LB_BOOL_ON {
strickySessionType, _ := data.GetString("sticky_session_type")
switch strickySessionType {
case api.LB_STICKY_SESSION_TYPE_INSERT:
keyV["sticky_session_cookie_timeout"] = validators.NewRangeValidator("sticky_session_cookie_timeout", 1, 86400).Default(1000)
V["sticky_session_cookie_timeout"] = validators.NewRangeValidator("sticky_session_cookie_timeout", 1, 86400).Default(1000)
case api.LB_STICKY_SESSION_TYPE_SERVER:
cookie, _ := data.GetString("sticky_session_cookie")
if len(cookie) < 1 || len(cookie) > 200 {
@@ -243,17 +569,20 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerData(ctx cont
return nil, httperrors.NewInputParameterError("Unknown sticky_session_type, only support %s or %s", api.LB_STICKY_SESSION_TYPE_INSERT, api.LB_STICKY_SESSION_TYPE_SERVER)
}
}
keyV["client_idle_timeout"] = validators.NewRangeValidator("client_idle_timeout", 1, 60).Default(15)
keyV["client_request_timeout"] = validators.NewRangeValidator("client_request_timeout", 1, 180).Default(60)
case api.LB_LISTENER_TYPE_HTTPS:
keyV["client_idle_timeout"] = validators.NewRangeValidator("client_idle_timeout", 1, 60).Default(15)
keyV["client_request_timeout"] = validators.NewRangeValidator("client_request_timeout", 1, 180).Default(60)
V["client_idle_timeout"] = validators.NewRangeValidator("client_idle_timeout", 1, 60).Default(15)
V["client_request_timeout"] = validators.NewRangeValidator("client_request_timeout", 1, 180).Default(60)
}
if backendgroup.Type == api.LB_BACKENDGROUP_TYPE_DEFAULT {
keyV["backend_server_port"] = validators.NewPortValidator("backend_server_port")
V["backend_server_port"] = validators.NewPortValidator("backend_server_port")
}
if err := RunValidators(V, data); err != nil {
return nil, err
}
// check scheduler limiations
if scheduler, _ := data.GetString("scheduler"); utils.IsInStringArray(scheduler, []string{api.LB_SCHEDULER_SCH, api.LB_SCHEDULER_TCH, api.LB_SCHEDULER_QCH}) {
if len(lb.LoadbalancerSpec) == 0 {
return nil, httperrors.NewInputParameterError("The specified Scheduler %s is invalid for performance sharing loadbalancer", scheduler)
@@ -281,15 +610,77 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerData(ctx cont
}
}
for _, v := range keyV {
if err := v.Validate(data); err != nil {
return nil, err
}
}
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerData(ctx, userCred, data, backendGroup)
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerData(ctx, userCred, ownerId, data, lb, backendGroup)
}
func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lblis *models.SLoadbalancerListener, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
ownerId := lblis.GetOwnerId()
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclStatusV.Default(lblis.AclStatus)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
if api.LB_ACL_TYPES.Has(lblis.AclType) {
aclTypeV.Default(lblis.AclType)
}
var aclV *validators.ValidatorModelIdOrName
if _acl, _ := data.GetString("acl"); len(_acl) > 0 {
aclV = validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
} else {
aclV = validators.NewModelIdOrNameValidator("acl", "cachedloadbalanceracl", ownerId)
if len(lblis.AclId) > 0 {
aclV.Default(lblis.AclId)
}
}
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
keyV := map[string]validators.IValidator{
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES),
"acl_status": aclStatusV,
"acl_type": aclTypeV,
"acl": aclV,
"client_idle_timeout": validators.NewRangeValidator("client_idle_timeout", 0, 600),
"backend_connect_timeout": validators.NewRangeValidator("backend_connect_timeout", 0, 180),
"backend_idle_timeout": validators.NewRangeValidator("backend_idle_timeout", 0, 600),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)),
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES),
"health_check_type": models.LoadbalancerListenerManager.CheckTypeV(lblis.ListenerType),
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true),
"health_check_path": validators.NewURLPathValidator("health_check_path"),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(","),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for"),
"gzip": validators.NewBoolValidator("gzip"),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate"),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src"),
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2"),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
if err := models.LoadbalancerListenerManager.ValidateAcl(aclStatusV, aclTypeV, aclV, data, lblis.GetProviderName()); err != nil {
return nil, err
}
{
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lblis.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lblis.LoadbalancerId)
}
}
listenerType, _ := data.GetString("listener_type")
lb := lblis.GetLoadbalancer()
@@ -312,7 +703,7 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont
}
}
keyV := map[string]validators.IValidator{
V := map[string]validators.IValidator{
"egress_mbps": validators.NewRangeValidator("egress_mbps", 0, int64(egressMbps)).Optional(true),
"client_request_timeout": validators.NewRangeValidator("client_request_timeout", 1, 180).Optional(true),
@@ -326,7 +717,7 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_ALIYUN_COMMON_SCHEDULER_TYPES).Optional(true),
}
if lblis.ListenerType == api.LB_LISTENER_TYPE_UDP {
keyV["scheduler"] = validators.NewStringChoicesValidator("scheduler", api.LB_ALIYUN_UDP_SCHEDULER_TYPES).Optional(true)
V["scheduler"] = validators.NewStringChoicesValidator("scheduler", api.LB_ALIYUN_UDP_SCHEDULER_TYPES).Optional(true)
}
if scheduler, _ := data.GetString("scheduler"); utils.IsInStringArray(scheduler, []string{api.LB_SCHEDULER_SCH, api.LB_SCHEDULER_TCH, api.LB_SCHEDULER_QCH}) {
@@ -389,7 +780,7 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont
if backendgroup.Type == api.LB_BACKENDGROUP_TYPE_DEFAULT {
if lblis.BackendServerPort == 0 {
keyV["backend_server_port"] = validators.NewPortValidator("backend_server_port")
V["backend_server_port"] = validators.NewPortValidator("backend_server_port")
}
}
@@ -401,14 +792,12 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont
if !utils.IsInStringArray(listenerType, []string{api.LB_LISTENER_TYPE_UDP, api.LB_LISTENER_TYPE_TCP}) {
if lblis.ClientIdleTimeout == 0 {
keyV["client_idle_timeout"] = validators.NewRangeValidator("client_idle_timeout", 1, 60)
V["client_idle_timeout"] = validators.NewRangeValidator("client_idle_timeout", 1, 60)
}
}
for _, v := range keyV {
if err := v.Validate(data); err != nil {
return nil, err
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
return self.SManagedVirtualizationRegionDriver.ValidateUpdateLoadbalancerListenerData(ctx, userCred, data, lblis, backendGroup)
}
File diff suppressed because it is too large Load Diff
+338 -26
View File
@@ -17,6 +17,7 @@ package regiondrivers
import (
"context"
"fmt"
"regexp"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -27,6 +28,7 @@ import (
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rand"
)
type SHuaWeiRegionDriver struct {
@@ -43,8 +45,37 @@ func (self *SHuaWeiRegionDriver) GetProvider() string {
}
func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
addressType, _ := data.GetString("address_type")
if addressType == api.LB_ADDR_TYPE_INTERNET {
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId)
managerIdV := validators.NewModelIdOrNameValidator("manager", "cloudprovider", ownerId)
addressTypeV := validators.NewStringChoicesValidator("address_type", api.LB_ADDR_TYPES)
networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId)
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"address_type": addressTypeV.Default(api.LB_ADDR_TYPE_INTRANET),
"network": networkV,
"zone": zoneV,
"manager": managerIdV,
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
// 检查网络可用
network := networkV.Model.(*models.SNetwork)
_, _, vpc, _, err := network.ValidateElbNetwork(nil)
if err != nil {
return nil, err
}
if managerIdV.Model.GetId() != vpc.ManagerId {
return nil, httperrors.NewInputParameterError("Loadbalancer's manager (%s(%s)) does not match vpc's(%s(%s)) (%s)", managerIdV.Model.GetName(), managerIdV.Model.GetId(), vpc.GetName(), vpc.GetId(), vpc.ManagerId)
}
// 公网ELB需要指定EIP
if addressTypeV.Value == api.LB_ADDR_TYPE_INTERNET {
eipV := validators.NewModelIdOrNameValidator("eip", "eip", nil)
if err := eipV.Validate(data); err != nil {
return nil, err
@@ -62,6 +93,13 @@ func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerData(ctx context.Cont
data.Set("eip_id", jsonutils.NewString(eip.ExternalId))
}
region := zoneV.Model.(*models.SZone).GetRegion()
if region == nil {
return nil, fmt.Errorf("getting region failed")
}
data.Set("network_type", jsonutils.NewString(api.LB_NETWORK_TYPE_VPC))
data.Set("cloudregion_id", jsonutils.NewString(region.GetId()))
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerData(ctx, userCred, data)
}
@@ -151,20 +189,213 @@ func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerAclData(ctx context.C
// }
func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendType string, lb *models.SLoadbalancer, backendGroup *models.SLoadbalancerBackendGroup, backend db.IModel) (*jsonutils.JSONDict, error) {
// requiredbackend,backend_group,port,weight
// be3a5b845e604decb9005e6643f688af/ports?network_id=28bf47f5-5999-45dd-9546-9f964b2fac80&tenant_id=be3a5b845e604decb9005e6643f688af&limit=2000 ,验证binding:vif_details primary_interface: true
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
man := models.LoadbalancerBackendManager
backendTypeV := validators.NewStringChoicesValidator("backend_type", api.LB_BACKEND_TYPES)
keyV := map[string]validators.IValidator{
"backend_type": backendTypeV,
"weight": validators.NewRangeValidator("weight", 0, 100).Default(10),
"port": validators.NewPortValidator("port"),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
var basename string
switch backendType {
case api.LB_BACKEND_GUEST:
backendV := validators.NewModelIdOrNameValidator("backend", "server", ownerId)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
guest := backendV.Model.(*models.SGuest)
err = man.ValidateBackendVpc(lb, guest, backendGroup)
if err != nil {
return nil, err
}
basename = guest.Name
backend = backendV.Model
case api.LB_BACKEND_HOST:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify host as backend")
}
backendV := validators.NewModelIdOrNameValidator("backend", "host", userCred)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
host := backendV.Model.(*models.SHost)
{
if len(host.AccessIp) == 0 {
return nil, fmt.Errorf("host %s has no access ip", host.GetId())
}
data.Set("address", jsonutils.NewString(host.AccessIp))
}
basename = host.Name
backend = backendV.Model
case api.LB_BACKEND_IP:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify ip address as backend")
}
backendV := validators.NewIPv4AddrValidator("backend")
err := backendV.Validate(data)
if err != nil {
return nil, err
}
ip := backendV.IP.String()
data.Set("address", jsonutils.NewString(ip))
basename = ip
default:
return nil, fmt.Errorf("internal error: unexpected backend type %s", backendType)
}
name, _ := data.GetString("name")
if name == "" {
name = fmt.Sprintf("%s-%s-%s-%s", backendGroup.Name, backendType, basename, rand.String(4))
}
data.Set("name", jsonutils.NewString(name))
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return data, nil
}
// func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
// // required: protocol,protocol_port,loadbalancer_id
// // others: name, description,connection_limit?,http2_enable,default_pool_id,
//
// return nil, nil
// }
func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, lb *models.SLoadbalancer, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
listenerTypeV := validators.NewStringChoicesValidator("listener_type", api.LB_LISTENER_TYPES)
listenerPortV := validators.NewPortValidator("listener_port")
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
aclV := validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
data, err := self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerRuleData(ctx, userCred, data, backendGroup)
"listener_type": listenerTypeV,
"listener_port": listenerPortV,
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
"acl_status": aclStatusV.Default(api.LB_BOOL_OFF),
"acl_type": aclTypeV.Optional(true),
"acl": aclV.Optional(true),
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES).Default(api.LB_BOOL_OFF),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES).Default(api.LB_STICKY_SESSION_TYPE_INSERT),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)).Optional(true),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout").Optional(true),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for").Default(true),
"gzip": validators.NewBoolValidator("gzip").Default(false),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
// listener uniqueness
listenerType := listenerTypeV.Value
err := models.LoadbalancerListenerManager.CheckListenerUniqueness(ctx, lb, listenerType, listenerPortV.Value)
if err != nil {
return nil, err
}
// backendgroup check
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lb.Id {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lb.Id)
}
// https additional certificate check
if listenerType == api.LB_LISTENER_TYPE_HTTPS {
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
httpsV := map[string]validators.IValidator{
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2").Default(true),
}
if err := RunValidators(httpsV, data); err != nil {
return nil, err
}
}
// health check default depends on input parameters
checkTypeV := models.LoadbalancerListenerManager.CheckTypeV(listenerType)
keyVHealth := map[string]validators.IValidator{
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES).Default(api.LB_BOOL_ON),
"health_check_type": checkTypeV,
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true).Default(""),
"health_check_path": validators.NewURLPathValidator("health_check_path").Default(""),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(",").Default(api.LB_HEALTH_CHECK_HTTP_CODE_DEFAULT),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 10).Default(3),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 10).Default(3),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 1, 50).Default(10),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 1, 50).Default(5),
}
if err := RunValidators(keyVHealth, data); err != nil {
return nil, err
}
// acl check
if err := models.LoadbalancerListenerManager.ValidateAcl(aclStatusV, aclTypeV, aclV, data, api.CLOUD_PROVIDER_HUAWEI); err != nil {
return nil, err
}
data.Set("acl_status", jsonutils.NewString(api.LB_BOOL_OFF))
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerData(ctx, userCred, ownerId, data, lb, backendGroup)
}
func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
domainV := validators.NewDomainNameValidator("domain")
pathV := validators.NewURLPathValidator("path")
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"domain": domainV.AllowEmpty(true).Default(""),
"path": pathV.Default(""),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
listenerId, err := data.GetString("listener_id")
if err != nil {
return nil, err
}
ilistener, err := db.FetchById(models.LoadbalancerListenerManager, listenerId)
if err != nil {
return nil, err
}
listener := ilistener.(*models.SLoadbalancerListener)
listenerType := listener.ListenerType
if listenerType != api.LB_LISTENER_TYPE_HTTP && listenerType != api.LB_LISTENER_TYPE_HTTPS {
return nil, httperrors.NewInputParameterError("listener type must be http/https, got %s", listenerType)
}
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != listener.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, listener.LoadbalancerId)
}
err = models.LoadbalancerListenerRuleCheckUniqueness(ctx, listener, domainV.Value, pathV.Value)
if err != nil {
return nil, err
}
_, err = self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerRuleData(ctx, userCred, ownerId, data, backendGroup)
if err != nil {
return data, err
}
@@ -175,6 +406,25 @@ func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx
return data, fmt.Errorf("'domain' or 'path' should not be empty.")
}
data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId))
data.Set("manager_id", jsonutils.NewString(listener.ManagerId))
return data, nil
}
func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
lbr := ctx.Value("lbr").(*models.SLoadbalancerListenerRule)
if backendGroup, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && backendGroup.Id != lbr.BackendGroupId {
listenerM, err := models.LoadbalancerListenerManager.FetchById(lbr.ListenerId)
if err != nil {
return nil, httperrors.NewInputParameterError("loadbalancerlistenerrule %s(%s): fetching listener %s failed",
lbr.Name, lbr.Id, lbr.ListenerId)
}
listener := listenerM.(*models.SLoadbalancerListener)
if backendGroup.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)
}
}
return data, nil
}
@@ -198,6 +448,16 @@ func (self *SHuaWeiRegionDriver) ValidateDeleteLoadbalancerBackendGroupCondition
}
func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lbbg *models.SLoadbalancerBackendGroup) (*jsonutils.JSONDict, error) {
keyV := map[string]validators.IValidator{
"weight": validators.NewRangeValidator("weight", 0, 100).Optional(true),
"port": validators.NewPortValidator("port").Optional(true),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Optional(true),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
// 只能更新权重。不能更新端口
port, err := data.Int("port")
if err == nil && port != 0 {
@@ -213,16 +473,65 @@ func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx conte
// }
func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lblis *models.SLoadbalancerListener, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
/*
default_pool_id有如下限制
不能更新为其他监听器的default_pool
不能更新为其他监听器的关联的转发策略所使用的pool
default_pool_id对应的后端云服务器组的protocol和监听器的protocol有如下关系
监听器的protocol为TCP时后端云服务器组的protocol必须为TCP
监听器的protocol为UDP时后端云服务器组的protocol必须为UDP
监听器的protocol为HTTP或TERMINATED_HTTPS时后端云服务器组的protocol必须为HTTP
*/
return data, nil
ownerId := lblis.GetOwnerId()
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclStatusV.Default(lblis.AclStatus)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
if api.LB_ACL_TYPES.Has(lblis.AclType) {
aclTypeV.Default(lblis.AclType)
}
var aclV *validators.ValidatorModelIdOrName
if _acl, _ := data.GetString("acl"); len(_acl) > 0 {
aclV = validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
} else {
aclV = validators.NewModelIdOrNameValidator("acl", "cachedloadbalanceracl", ownerId)
if len(lblis.AclId) > 0 {
aclV.Default(lblis.AclId)
}
}
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
keyV := map[string]validators.IValidator{
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES),
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout"),
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES),
"health_check_type": models.LoadbalancerListenerManager.CheckTypeV(lblis.ListenerType),
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true).Default(""),
"health_check_path": validators.NewURLPathValidator("health_check_path").Default(""),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(",").Default(api.LB_HEALTH_CHECK_HTTP_CODE_DEFAULT),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 10).Default(3),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 10).Default(3),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 1, 50).Default(10),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 1, 50).Default(5),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for"),
"gzip": validators.NewBoolValidator("gzip"),
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2"),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
{
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lblis.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lblis.LoadbalancerId)
}
}
return self.SManagedVirtualizationRegionDriver.ValidateUpdateLoadbalancerListenerData(ctx, userCred, data, lblis, backendGroup)
}
func (self *SHuaWeiRegionDriver) createLoadbalancerBackendGroup(ctx context.Context, userCred mcclient.TokenCredential, lblis *models.SLoadbalancerListener, lbr *models.SLoadbalancerListenerRule, lbbg *models.SLoadbalancerBackendGroup, backends []cloudprovider.SLoadbalancerBackend) (jsonutils.JSONObject, error) {
@@ -269,7 +578,7 @@ func (self *SHuaWeiRegionDriver) createLoadbalancerBackendGroup(ctx context.Cont
return nil, err
}
iLoadbalancerBackendGroup, err := iLoadbalancer.CreateILoadBalancerBackendGroup(&group)
iLoadbalancerBackendGroup, err := iLoadbalancer.CreateILoadBalancerBackendGroup(group)
if err != nil {
return nil, err
}
@@ -318,11 +627,14 @@ func (self *SHuaWeiRegionDriver) createLoadbalancerBackendGroup(ctx context.Cont
}
func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerBackendGroup(ctx context.Context, userCred mcclient.TokenCredential, lbbg *models.SLoadbalancerBackendGroup, backends []cloudprovider.SLoadbalancerBackend, task taskman.ITask) error {
// 未指定后端协议类型的情况下,跳过创建步骤
// 未指定listenerId或ruleId情况下,跳过远端创建步骤
listenerId, _ := task.GetParams().GetString("listenerId")
ruleId, _ := task.GetParams().GetString("ruleId")
if len(listenerId) == 0 && len(ruleId) == 0 {
return fmt.Errorf("CreateLoadbalancerBackendGroup listener/rule id should not be emtpy")
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
return nil, nil
})
return nil
}
var rule *models.SLoadbalancerListenerRule
@@ -458,7 +770,7 @@ func (self *SHuaWeiRegionDriver) RequestSyncLoadbalancerBackendGroup(ctx context
return nil, err
}
if err := ilbbg.Sync(&group); err != nil {
if err := ilbbg.Sync(group); err != nil {
return nil, err
}
+356 -4
View File
@@ -17,18 +17,20 @@ package regiondrivers
import (
"context"
"fmt"
"yunion.io/x/onecloud/pkg/httperrors"
"regexp"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/util/rand"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
@@ -41,11 +43,44 @@ func init() {
models.RegisterRegionDriver(&driver)
}
func RunValidators(validators map[string]validators.IValidator, data *jsonutils.JSONDict) error {
for _, v := range validators {
if err := v.Validate(data); err != nil {
return err
}
}
return nil
}
func (self *SKVMRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_ONECLOUD
}
func (self *SKVMRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId)
addressV := validators.NewIPv4AddrValidator("address")
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"address": addressV.Optional(true),
"network": networkV,
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
network := networkV.Model.(*models.SNetwork)
region, zone, vpc, _, err := network.ValidateElbNetwork(addressV.IP)
if err != nil {
return nil, err
}
data.Set("cloudregion_id", jsonutils.NewString(region.GetId()))
data.Set("zone_id", jsonutils.NewString(zone.GetId()))
data.Set("vpc_id", jsonutils.NewString(vpc.GetId()))
data.Set("network_type", jsonutils.NewString(api.LB_NETWORK_TYPE_CLASSIC))
data.Set("address_type", jsonutils.NewString(api.LB_ADDR_TYPE_INTRANET))
return data, nil
}
@@ -75,6 +110,74 @@ func (self *SKVMRegionDriver) ValidateCreateLoadbalancerBackendGroupData(ctx con
}
func (self *SKVMRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendType string, lb *models.SLoadbalancer, backendGroup *models.SLoadbalancerBackendGroup, backend db.IModel) (*jsonutils.JSONDict, error) {
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
man := models.LoadbalancerBackendManager
backendTypeV := validators.NewStringChoicesValidator("backend_type", api.LB_BACKEND_TYPES)
keyV := map[string]validators.IValidator{
"backend_type": backendTypeV,
"weight": validators.NewRangeValidator("weight", 1, 256).Default(1),
"port": validators.NewPortValidator("port"),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
var basename string
switch backendType {
case api.LB_BACKEND_GUEST:
backendV := validators.NewModelIdOrNameValidator("backend", "server", ownerId)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
guest := backendV.Model.(*models.SGuest)
err = man.ValidateBackendVpc(lb, guest, backendGroup)
if err != nil {
return nil, err
}
basename = guest.Name
backend = backendV.Model
case api.LB_BACKEND_HOST:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify host as backend")
}
backendV := validators.NewModelIdOrNameValidator("backend", "host", userCred)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
host := backendV.Model.(*models.SHost)
{
if len(host.AccessIp) == 0 {
return nil, fmt.Errorf("host %s has no access ip", host.GetId())
}
data.Set("address", jsonutils.NewString(host.AccessIp))
}
basename = host.Name
backend = backendV.Model
case api.LB_BACKEND_IP:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify ip address as backend")
}
backendV := validators.NewIPv4AddrValidator("backend")
err := backendV.Validate(data)
if err != nil {
return nil, err
}
ip := backendV.IP.String()
data.Set("address", jsonutils.NewString(ip))
basename = ip
default:
return nil, fmt.Errorf("internal error: unexpected backend type %s", backendType)
}
name, _ := data.GetString("name")
if name == "" {
name = fmt.Sprintf("%s-%s-%s-%s", backendGroup.Name, backendType, basename, rand.String(4))
}
switch backendType {
case api.LB_BACKEND_GUEST:
guest := backend.(*models.SGuest)
@@ -104,22 +207,271 @@ func (self *SKVMRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context.
data.Set("address", jsonutils.NewString(address))
}
}
data.Set("name", jsonutils.NewString(name))
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return data, nil
}
func (self *SKVMRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lbbg *models.SLoadbalancerBackendGroup) (*jsonutils.JSONDict, error) {
keyV := map[string]validators.IValidator{
"weight": validators.NewRangeValidator("weight", 1, 256).Optional(true),
"port": validators.NewPortValidator("port").Optional(true),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Optional(true),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
return data, nil
}
func (self *SKVMRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
func (self *SKVMRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
listenerV := validators.NewModelIdOrNameValidator("listener", "loadbalancerlistener", ownerId)
domainV := validators.NewDomainNameValidator("domain")
pathV := validators.NewURLPathValidator("path")
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"listener": listenerV,
"domain": domainV.AllowEmpty(true).Default(""),
"path": pathV.Default(""),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
listener := listenerV.Model.(*models.SLoadbalancerListener)
listenerType := listener.ListenerType
if listenerType != api.LB_LISTENER_TYPE_HTTP && listenerType != api.LB_LISTENER_TYPE_HTTPS {
return nil, httperrors.NewInputParameterError("listener type must be http/https, got %s", listenerType)
}
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != listener.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, listener.LoadbalancerId)
}
err := models.LoadbalancerListenerRuleCheckUniqueness(ctx, listener, domainV.Value, pathV.Value)
if err != nil {
return nil, err
}
data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId))
data.Set("manager_id", jsonutils.NewString(listener.ManagerId))
return data, nil
}
func (self *SKVMRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
func (self *SKVMRegionDriver) ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
lbr := ctx.Value("lbr").(*models.SLoadbalancerListenerRule)
keyV := map[string]validators.IValidator{
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate"),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src"),
}
for _, v := range keyV {
v.Optional(true)
if err := v.Validate(data); err != nil {
return nil, err
}
}
if backendGroup, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && backendGroup.Id != lbr.BackendGroupId {
listenerM, err := models.LoadbalancerListenerManager.FetchById(lbr.ListenerId)
if err != nil {
return nil, httperrors.NewInputParameterError("loadbalancerlistenerrule %s(%s): fetching listener %s failed",
lbr.Name, lbr.Id, lbr.ListenerId)
}
listener := listenerM.(*models.SLoadbalancerListener)
if backendGroup.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)
}
}
return data, nil
}
func (self *SKVMRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, lb *models.SLoadbalancer, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
listenerTypeV := validators.NewStringChoicesValidator("listener_type", api.LB_LISTENER_TYPES)
listenerPortV := validators.NewPortValidator("listener_port")
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
aclV := validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"listener_type": listenerTypeV,
"listener_port": listenerPortV,
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
"acl_status": aclStatusV.Default(api.LB_BOOL_OFF),
"acl_type": aclTypeV.Optional(true),
"acl": aclV.Optional(true),
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"egress_mbps": validators.NewRangeValidator("egress_mbps", api.LB_MbpsMin, api.LB_MbpsMax).Optional(true),
"client_request_timeout": validators.NewRangeValidator("client_request_timeout", 0, 600).Default(10),
"client_idle_timeout": validators.NewRangeValidator("client_idle_timeout", 0, 600).Default(90),
"backend_connect_timeout": validators.NewRangeValidator("backend_connect_timeout", 0, 180).Default(5),
"backend_idle_timeout": validators.NewRangeValidator("backend_idle_timeout", 0, 600).Default(90),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES).Default(api.LB_BOOL_OFF),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES).Default(api.LB_STICKY_SESSION_TYPE_INSERT),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)).Optional(true),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout").Optional(true),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for").Default(true),
"gzip": validators.NewBoolValidator("gzip").Default(false),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
// listener uniqueness
listenerType := listenerTypeV.Value
err := models.LoadbalancerListenerManager.CheckListenerUniqueness(ctx, lb, listenerType, listenerPortV.Value)
if err != nil {
return nil, err
}
// backendgroup check
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lb.Id {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lb.Id)
}
// https additional certificate check
if listenerType == api.LB_LISTENER_TYPE_HTTPS {
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
httpsV := map[string]validators.IValidator{
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2").Default(true),
}
if err := RunValidators(httpsV, data); err != nil {
return nil, err
}
}
// health check default depends on input parameters
checkTypeV := models.LoadbalancerListenerManager.CheckTypeV(listenerType)
keyVHealth := map[string]validators.IValidator{
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES).Default(api.LB_BOOL_ON),
"health_check_type": checkTypeV,
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true).Default(""),
"health_check_path": validators.NewURLPathValidator("health_check_path").Default(""),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(",").Default(api.LB_HEALTH_CHECK_HTTP_CODE_DEFAULT),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 1000).Default(3),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 1000).Default(3),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 1, 300).Default(5),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 1, 1000).Default(5),
}
if err := RunValidators(keyVHealth, data); err != nil {
return nil, err
}
// acl check
if err := models.LoadbalancerListenerManager.ValidateAcl(aclStatusV, aclTypeV, aclV, data, api.CLOUD_PROVIDER_ONECLOUD); err != nil {
return nil, err
}
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return data, nil
}
func (self *SKVMRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lblis *models.SLoadbalancerListener, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
ownerId := lblis.GetOwnerId()
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclStatusV.Default(lblis.AclStatus)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
if api.LB_ACL_TYPES.Has(lblis.AclType) {
aclTypeV.Default(lblis.AclType)
}
var aclV *validators.ValidatorModelIdOrName
if _acl, _ := data.GetString("acl"); len(_acl) > 0 {
aclV = validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
} else {
aclV = validators.NewModelIdOrNameValidator("acl", "cachedloadbalanceracl", ownerId)
if len(lblis.AclId) > 0 {
aclV.Default(lblis.AclId)
}
}
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
keyV := map[string]validators.IValidator{
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES),
"acl_status": aclStatusV,
"acl_type": aclTypeV,
"acl": aclV,
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"egress_mbps": validators.NewRangeValidator("egress_mbps", api.LB_MbpsMin, api.LB_MbpsMax),
"client_request_timeout": validators.NewRangeValidator("client_request_timeout", 0, 600),
"client_idle_timeout": validators.NewRangeValidator("client_idle_timeout", 0, 600),
"backend_connect_timeout": validators.NewRangeValidator("backend_connect_timeout", 0, 180),
"backend_idle_timeout": validators.NewRangeValidator("backend_idle_timeout", 0, 600),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout"),
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES),
"health_check_type": models.LoadbalancerListenerManager.CheckTypeV(lblis.ListenerType),
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true),
"health_check_path": validators.NewURLPathValidator("health_check_path"),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(","),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 1000),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 1000),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 1, 300),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 1, 1000),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for"),
"gzip": validators.NewBoolValidator("gzip"),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate"),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src"),
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2"),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
if err := models.LoadbalancerListenerManager.ValidateAcl(aclStatusV, aclTypeV, aclV, data, lblis.GetProviderName()); err != nil {
return nil, err
}
{
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lblis.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lblis.LoadbalancerId)
}
}
return data, nil
}
+25 -11
View File
@@ -101,23 +101,19 @@ func (self *SManagedVirtualizationRegionDriver) ValidateCreateLoadbalancerBacken
return data, nil
}
func (self *SManagedVirtualizationRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
func (self *SManagedVirtualizationRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
return data, nil
}
func (self *SManagedVirtualizationRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
func (self *SManagedVirtualizationRegionDriver) ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
return data, nil
}
func (self *SManagedVirtualizationRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, lb *models.SLoadbalancer, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
_, err := self.ValidateManagerId(ctx, userCred, data)
if err != nil {
return nil, err
}
loadbalancerId, _ := data.GetString("loadbalancer_id")
_, err = models.LoadbalancerManager.FetchById(loadbalancerId)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("failed to find loadbalancer %s", loadbalancerId)
}
return nil, httperrors.NewGeneralError(err)
}
if aclStatus, _ := data.GetString("acl_status"); aclStatus == api.LB_BOOL_ON {
aclId, _ := data.GetString("acl_id")
@@ -507,7 +503,25 @@ func (self *SManagedVirtualizationRegionDriver) RequestDeleteLoadbalancerBackend
}
return nil, err
}
return nil, iLoadbalancerBackendGroup.Delete()
err = iLoadbalancerBackendGroup.Delete()
if err != nil {
return nil, err
}
cachedLbbgs, err := models.AwsCachedLbbgManager.GetCachedBackendGroups(lbbg.GetId())
if err != nil {
return nil, err
}
for i := range cachedLbbgs {
err = cachedLbbgs[i].Delete(ctx, userCred)
if err != nil {
return nil, err
}
}
return nil, nil
})
return nil
}
+349 -2
View File
@@ -17,10 +17,11 @@ package regiondrivers
import (
"context"
"fmt"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"regexp"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/util/rand"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -44,6 +45,142 @@ func (self *SQcloudRegionDriver) GetProvider() string {
return api.CLOUD_PROVIDER_QCLOUD
}
func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId)
vpcV := validators.NewModelIdOrNameValidator("vpc", "vpc", ownerId)
managerIdV := validators.NewModelIdOrNameValidator("manager", "cloudprovider", ownerId)
addressTypeV := validators.NewStringChoicesValidator("address_type", api.LB_ADDR_TYPES)
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"address_type": addressTypeV.Default(api.LB_ADDR_TYPE_INTRANET),
"vpc": vpcV,
"zone": zoneV,
"manager": managerIdV,
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
// 内网ELB需要增加network
if addressTypeV.Value == api.LB_ADDR_TYPE_INTRANET {
networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId)
if err := networkV.Validate(data); err != nil {
return nil, err
}
network := networkV.Model.(*models.SNetwork)
_, _, vpc, _, err := network.ValidateElbNetwork(nil)
if err != nil {
return nil, err
}
if managerIdV.Model.GetId() != vpc.ManagerId {
return nil, httperrors.NewInputParameterError("Loadbalancer's manager (%s(%s)) does not match vpc's(%s(%s)) (%s)", managerIdV.Model.GetName(), managerIdV.Model.GetId(), vpc.GetName(), vpc.GetId(), vpc.ManagerId)
}
}
region := zoneV.Model.(*models.SZone).GetRegion()
if region == nil {
return nil, fmt.Errorf("getting region failed")
}
data.Set("network_type", jsonutils.NewString(api.LB_NETWORK_TYPE_VPC))
data.Set("cloudregion_id", jsonutils.NewString(region.GetId()))
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerData(ctx, userCred, data)
}
func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, lb *models.SLoadbalancer, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
listenerTypeV := validators.NewStringChoicesValidator("listener_type", api.LB_LISTENER_TYPES)
listenerPortV := validators.NewPortValidator("listener_port")
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"listener_type": listenerTypeV,
"listener_port": listenerPortV,
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES).Default(api.LB_BOOL_OFF),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES).Default(api.LB_STICKY_SESSION_TYPE_INSERT),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)).Optional(true),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout").Optional(true),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for").Default(true),
"gzip": validators.NewBoolValidator("gzip").Default(false),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
// listener uniqueness
listenerType := listenerTypeV.Value
err := models.LoadbalancerListenerManager.CheckListenerUniqueness(ctx, lb, listenerType, listenerPortV.Value)
if err != nil {
return nil, err
}
// backendgroup check
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lb.Id {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lb.Id)
} else {
if lbbg != nil {
count, err := lbbg.RefCount()
if err != nil {
return nil, httperrors.NewInternalServerError("get lbbg RefCount fail %s", err)
}
if count > 0 {
return nil, httperrors.NewResourceBusyError("backendgroup aready related with other listener/rule")
}
}
}
// https additional certificate check
if listenerType == api.LB_LISTENER_TYPE_HTTPS {
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
httpsV := map[string]validators.IValidator{
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2").Default(true),
}
if err := RunValidators(httpsV, data); err != nil {
return nil, err
}
}
// health check default depends on input parameters
checkTypeV := models.LoadbalancerListenerManager.CheckTypeV(listenerType)
keyVHealth := map[string]validators.IValidator{
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES).Default(api.LB_BOOL_ON),
"health_check_type": checkTypeV,
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true).Default(""),
"health_check_path": validators.NewURLPathValidator("health_check_path").Default(""),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(",").Default(api.LB_HEALTH_CHECK_HTTP_CODE_DEFAULT),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 10).Default(3),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 10).Default(3),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 2, 60).Default(2),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 5, 300).Default(5),
}
if err := RunValidators(keyVHealth, data); err != nil {
return nil, err
}
data.Set("acl_status", jsonutils.NewString(api.LB_BOOL_OFF))
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerData(ctx, userCred, ownerId, data, lb, backendGroup)
}
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()
@@ -393,6 +530,216 @@ func (self *SQcloudRegionDriver) ValidateCreateVpcData(ctx context.Context, user
return data, nil
}
func (self *SQcloudRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lblis *models.SLoadbalancerListener, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
ownerId := lblis.GetOwnerId()
aclStatusV := validators.NewStringChoicesValidator("acl_status", api.LB_BOOL_VALUES)
aclStatusV.Default(lblis.AclStatus)
aclTypeV := validators.NewStringChoicesValidator("acl_type", api.LB_ACL_TYPES)
if api.LB_ACL_TYPES.Has(lblis.AclType) {
aclTypeV.Default(lblis.AclType)
}
var aclV *validators.ValidatorModelIdOrName
if _acl, _ := data.GetString("acl"); len(_acl) > 0 {
aclV = validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerId)
} else {
aclV = validators.NewModelIdOrNameValidator("acl", "cachedloadbalanceracl", ownerId)
if len(lblis.AclId) > 0 {
aclV.Default(lblis.AclId)
}
}
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", api.LB_TLS_CIPHER_POLICIES).Default(api.LB_TLS_CIPHER_POLICY_1_2)
keyV := map[string]validators.IValidator{
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES),
"scheduler": validators.NewStringChoicesValidator("scheduler", api.LB_SCHEDULER_TYPES),
"sticky_session": validators.NewStringChoicesValidator("sticky_session", api.LB_BOOL_VALUES),
"sticky_session_type": validators.NewStringChoicesValidator("sticky_session_type", api.LB_STICKY_SESSION_TYPES),
"sticky_session_cookie": validators.NewRegexpValidator("sticky_session_cookie", regexp.MustCompile(`\w+`)),
"sticky_session_cookie_timeout": validators.NewNonNegativeValidator("sticky_session_cookie_timeout"),
"health_check": validators.NewStringChoicesValidator("health_check", api.LB_BOOL_VALUES),
"health_check_type": models.LoadbalancerListenerManager.CheckTypeV(lblis.ListenerType),
"health_check_domain": validators.NewDomainNameValidator("health_check_domain").AllowEmpty(true).Default(""),
"health_check_path": validators.NewURLPathValidator("health_check_path").Default(""),
"health_check_http_code": validators.NewStringMultiChoicesValidator("health_check_http_code", api.LB_HEALTH_CHECK_HTTP_CODES).Sep(",").Default(api.LB_HEALTH_CHECK_HTTP_CODE_DEFAULT),
"health_check_rise": validators.NewRangeValidator("health_check_rise", 1, 10).Default(3),
"health_check_fall": validators.NewRangeValidator("health_check_fall", 1, 10).Default(3),
"health_check_timeout": validators.NewRangeValidator("health_check_timeout", 2, 60).Default(2),
"health_check_interval": validators.NewRangeValidator("health_check_interval", 5, 300).Default(5),
"x_forwarded_for": validators.NewBoolValidator("x_forwarded_for"),
"gzip": validators.NewBoolValidator("gzip"),
"certificate": certV,
"tls_cipher_policy": tlsCipherPolicyV,
"enable_http2": validators.NewBoolValidator("enable_http2"),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
{
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != lblis.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, lblis.LoadbalancerId)
}
}
return self.SManagedVirtualizationRegionDriver.ValidateUpdateLoadbalancerListenerData(ctx, userCred, data, lblis, backendGroup)
}
func (self *SQcloudRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, lbbg *models.SLoadbalancerBackendGroup) (*jsonutils.JSONDict, error) {
keyV := map[string]validators.IValidator{
"weight": validators.NewRangeValidator("weight", 1, 256).Optional(true),
"port": validators.NewPortValidator("port").Optional(true),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Optional(true),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
return data, nil
}
func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
domainV := validators.NewDomainNameValidator("domain")
pathV := validators.NewURLPathValidator("path")
keyV := map[string]validators.IValidator{
"status": validators.NewStringChoicesValidator("status", api.LB_STATUS_SPEC).Default(api.LB_STATUS_ENABLED),
"domain": domainV.AllowEmpty(true).Default(""),
"path": pathV.Default(""),
"http_request_rate": validators.NewNonNegativeValidator("http_request_rate").Default(0),
"http_request_rate_per_src": validators.NewNonNegativeValidator("http_request_rate_per_src").Default(0),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
listenerId, err := data.GetString("listener_id")
if err != nil {
return nil, err
}
ilistener, err := db.FetchById(models.LoadbalancerListenerManager, listenerId)
if err != nil {
return nil, err
}
listener := ilistener.(*models.SLoadbalancerListener)
listenerType := listener.ListenerType
if listenerType != api.LB_LISTENER_TYPE_HTTP && listenerType != api.LB_LISTENER_TYPE_HTTPS {
return nil, httperrors.NewInputParameterError("listener type must be http/https, got %s", listenerType)
}
if lbbg, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && lbbg.LoadbalancerId != listener.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, listener.LoadbalancerId)
}
err = models.LoadbalancerListenerRuleCheckUniqueness(ctx, listener, domainV.Value, pathV.Value)
if err != nil {
return nil, err
}
data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId))
data.Set("manager_id", jsonutils.NewString(listener.ManagerId))
return data, nil
}
func (self *SQcloudRegionDriver) ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendGroup db.IModel) (*jsonutils.JSONDict, error) {
lbr := ctx.Value("lbr").(*models.SLoadbalancerListenerRule)
if backendGroup, ok := backendGroup.(*models.SLoadbalancerBackendGroup); ok && backendGroup.Id != lbr.BackendGroupId {
listenerM, err := models.LoadbalancerListenerManager.FetchById(lbr.ListenerId)
if err != nil {
return nil, httperrors.NewInputParameterError("loadbalancerlistenerrule %s(%s): fetching listener %s failed",
lbr.Name, lbr.Id, lbr.ListenerId)
}
listener := listenerM.(*models.SLoadbalancerListener)
if backendGroup.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)
}
}
return data, nil
}
func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, backendType string, lb *models.SLoadbalancer, backendGroup *models.SLoadbalancerBackendGroup, backend db.IModel) (*jsonutils.JSONDict, error) {
ownerId := ctx.Value("ownerId").(mcclient.IIdentityProvider)
man := models.LoadbalancerBackendManager
backendTypeV := validators.NewStringChoicesValidator("backend_type", api.LB_BACKEND_TYPES)
keyV := map[string]validators.IValidator{
"backend_type": backendTypeV,
"weight": validators.NewRangeValidator("weight", 0, 100).Default(10),
"port": validators.NewPortValidator("port"),
"send_proxy": validators.NewStringChoicesValidator("send_proxy", api.LB_SENDPROXY_CHOICES).Default(api.LB_SENDPROXY_OFF),
}
if err := RunValidators(keyV, data); err != nil {
return nil, err
}
var basename string
switch backendType {
case api.LB_BACKEND_GUEST:
backendV := validators.NewModelIdOrNameValidator("backend", "server", ownerId)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
guest := backendV.Model.(*models.SGuest)
err = man.ValidateBackendVpc(lb, guest, backendGroup)
if err != nil {
return nil, err
}
basename = guest.Name
backend = backendV.Model
case api.LB_BACKEND_HOST:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify host as backend")
}
backendV := validators.NewModelIdOrNameValidator("backend", "host", userCred)
err := backendV.Validate(data)
if err != nil {
return nil, err
}
host := backendV.Model.(*models.SHost)
{
if len(host.AccessIp) == 0 {
return nil, fmt.Errorf("host %s has no access ip", host.GetId())
}
data.Set("address", jsonutils.NewString(host.AccessIp))
}
basename = host.Name
backend = backendV.Model
case api.LB_BACKEND_IP:
if !db.IsAdminAllowCreate(userCred, man) {
return nil, fmt.Errorf("only sysadmin can specify ip address as backend")
}
backendV := validators.NewIPv4AddrValidator("backend")
err := backendV.Validate(data)
if err != nil {
return nil, err
}
ip := backendV.IP.String()
data.Set("address", jsonutils.NewString(ip))
basename = ip
default:
return nil, fmt.Errorf("internal error: unexpected backend type %s", backendType)
}
name, _ := data.GetString("name")
if name == "" {
name = fmt.Sprintf("%s-%s-%s-%s", backendGroup.Name, backendType, basename, rand.String(4))
}
data.Set("name", jsonutils.NewString(name))
data.Set("manager_id", jsonutils.NewString(lb.ManagerId))
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return data, nil
}
+2
View File
@@ -108,6 +108,8 @@ func InitHandlers(app *appsrv.Application) {
models.CachedLoadbalancerCertificateManager,
models.HuaweiCachedLbManager,
models.HuaweiCachedLbbgManager,
models.AwsCachedLbManager,
models.AwsCachedLbbgManager,
models.RouteTableManager,
models.SchedpolicyManager,
@@ -19,7 +19,6 @@ import (
"fmt"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
@@ -37,9 +36,14 @@ type HuaweiLoadbalancerLoadbalancerBackendGroupCreateTask struct {
LoadbalancerLoadbalancerBackendGroupCreateTask
}
type AwsLoadbalancerLoadbalancerBackendGroupCreateTask struct {
LoadbalancerLoadbalancerBackendGroupCreateTask
}
func init() {
taskman.RegisterTask(LoadbalancerLoadbalancerBackendGroupCreateTask{})
taskman.RegisterTask(HuaweiLoadbalancerLoadbalancerBackendGroupCreateTask{})
taskman.RegisterTask(AwsLoadbalancerLoadbalancerBackendGroupCreateTask{})
}
func (self *LoadbalancerLoadbalancerBackendGroupCreateTask) taskFail(ctx context.Context, lbacl *models.SLoadbalancerBackendGroup, reason string) {
@@ -60,12 +64,6 @@ func (self *LoadbalancerLoadbalancerBackendGroupCreateTask) OnInit(ctx context.C
backends := []cloudprovider.SLoadbalancerBackend{}
self.GetParams().Unmarshal(&backends, "backends")
self.SetStage("OnLoadbalancerBackendGroupCreateComplete", nil)
// 为统一前端交互,华为后端服务器组。不能通过此任务创建,需要绕道HuaweiLoadbalancerLoadbalancerBackendGroupCreateTask。
if lbbg.GetProviderName() == api.CLOUD_PROVIDER_HUAWEI {
lbbg.SetStatus(self.GetUserCred(), api.LB_STATUS_ENABLED, "")
self.SetStageComplete(ctx, nil)
return
}
if err := region.GetDriver().RequestCreateLoadbalancerBackendGroup(ctx, self.GetUserCred(), lbbg, backends, self); err != nil {
self.taskFail(ctx, lbbg, err.Error())
@@ -97,6 +95,41 @@ func (self *HuaweiLoadbalancerLoadbalancerBackendGroupCreateTask) OnInit(ctx con
return
}
// 必须指定listenerId或ruleId
listenerId, _ := self.GetParams().GetString("listenerId")
ruleId, _ := self.GetParams().GetString("ruleId")
if len(listenerId) == 0 && len(ruleId) == 0 {
self.taskFail(ctx, lbbg, fmt.Sprintf("CreateLoadbalancerBackendGroup listener/rule id should not be emtpy"))
return
}
self.SetStage("OnLoadbalancerBackendGroupCreateComplete", nil)
if err := region.GetDriver().RequestCreateLoadbalancerBackendGroup(ctx, self.GetUserCred(), lbbg, backends, self); err != nil {
self.taskFail(ctx, lbbg, err.Error())
}
}
func (self *AwsLoadbalancerLoadbalancerBackendGroupCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
lbbg := obj.(*models.SLoadbalancerBackendGroup)
region := lbbg.GetRegion()
if region == nil {
self.taskFail(ctx, lbbg, fmt.Sprintf("failed to find region for lb backendgroup %s", lbbg.Name))
return
}
backends, err := lbbg.GetBackendsParams()
if err != nil {
self.taskFail(ctx, lbbg, err.Error())
return
}
// 必须指定listenerId
listenerId, _ := self.GetParams().GetString("listener_id")
if len(listenerId) == 0 {
self.taskFail(ctx, lbbg, fmt.Sprintf("CreateLoadbalancerBackendGroup listener id should not be emtpy"))
return
}
self.SetStage("OnLoadbalancerBackendGroupCreateComplete", nil)
if err := region.GetDriver().RequestCreateLoadbalancerBackendGroup(ctx, self.GetUserCred(), lbbg, backends, self); err != nil {
self.taskFail(ctx, lbbg, err.Error())
@@ -35,6 +35,66 @@ func init() {
taskman.RegisterTask(LoadbalancerListenerCreateTask{})
}
func getOnLoadbalancerListenerCreateCompleteFunc(provider string) func(ctx context.Context, lblis *models.SLoadbalancerListener, data jsonutils.JSONObject, self *LoadbalancerListenerCreateTask) {
switch provider {
case api.CLOUD_PROVIDER_HUAWEI:
return onHuaweiLoadbalancerListenerCreateComplete
default:
return onLoadbalancerListenerCreateComplete
}
}
func onLoadbalancerListenerCreateComplete(ctx context.Context, lblis *models.SLoadbalancerListener, data jsonutils.JSONObject, task *LoadbalancerListenerCreateTask) {
task.OnPrepareLoadbalancerBackendgroup(ctx, lblis, data)
return
}
func onHuaweiLoadbalancerListenerCreateComplete(ctx context.Context, lblis *models.SLoadbalancerListener, data jsonutils.JSONObject, self *LoadbalancerListenerCreateTask) {
lbbg := lblis.GetLoadbalancerBackendGroup()
if lbbg == nil {
self.taskFail(ctx, lblis, "huawei loadbalancer listener releated backend group not found")
return
}
groupParams, err := lbbg.GetHuaweiBackendGroupParams(lblis, nil)
if err != nil {
self.taskFail(ctx, lblis, err.Error())
return
}
params := jsonutils.NewDict()
params.Set("listenerId", jsonutils.NewString(lblis.GetId()))
group, _ := models.HuaweiCachedLbbgManager.GetUsableCachedBackendGroup(lbbg.GetId(), lblis.ListenerType)
if group != nil {
// 服务器组存在
ilbbg, err := group.GetICloudLoadbalancerBackendGroup()
if err != nil {
self.taskFail(ctx, lblis, err.Error())
return
}
// 服务器组已经存在,直接同步即可
if err := ilbbg.Sync(groupParams); err != nil {
self.taskFail(ctx, lblis, err.Error())
return
} else {
if _, err := db.UpdateWithLock(ctx, group, func() error {
group.AssociatedId = lblis.GetId()
group.AssociatedType = api.LB_ASSOCIATE_TYPE_LISTENER
return nil
}); err != nil {
self.taskFail(ctx, lblis, err.Error())
return
}
self.OnPrepareLoadbalancerBackendgroup(ctx, lblis, data)
}
} else {
// 服务器组不存在
self.SetStage("OnPrepareLoadbalancerBackendgroup", nil)
lbbg.StartHuaweiLoadBalancerBackendGroupCreateTask(ctx, self.GetUserCred(), params, self.GetTaskId())
}
}
func (self *LoadbalancerListenerCreateTask) taskFail(ctx context.Context, lblis *models.SLoadbalancerListener, reason string) {
lblis.SetStatus(self.GetUserCred(), api.LB_CREATE_FAILED, reason)
db.OpsLog.LogEvent(lblis, db.ACT_ALLOCATE_FAIL, reason, self.UserCred)
@@ -70,55 +130,8 @@ func (self *LoadbalancerListenerCreateTask) OnPrepareLoadbalancerBackendgroupFai
}
func (self *LoadbalancerListenerCreateTask) OnLoadbalancerListenerCreateComplete(ctx context.Context, lblis *models.SLoadbalancerListener, data jsonutils.JSONObject) {
lbbg := lblis.GetLoadbalancerBackendGroup()
// 目前只有华为才需要在创建监听器时创建服务器组,其他云直接绕过此步骤
if lblis.GetProviderName() != api.CLOUD_PROVIDER_HUAWEI {
self.OnPrepareLoadbalancerBackendgroup(ctx, lblis, data)
return
}
if lblis.GetProviderName() == api.CLOUD_PROVIDER_HUAWEI && lbbg == nil {
self.taskFail(ctx, lblis, "huawei loadbalancer listener releated backend group not found")
return
}
groupParams, err := lbbg.GetHuaweiBackendGroupParams(lblis, nil)
if err != nil {
self.taskFail(ctx, lblis, err.Error())
return
}
params := jsonutils.NewDict()
params.Set("listenerId", jsonutils.NewString(lblis.GetId()))
group, _ := models.HuaweiCachedLbbgManager.GetUsableCachedBackendGroup(lbbg.GetId(), lblis.ListenerType)
if group != nil {
// 服务器组存在
ilbbg, err := group.GetICloudLoadbalancerBackendGroup()
if err != nil {
self.taskFail(ctx, lblis, err.Error())
return
}
// 服务器组已经存在,直接同步即可
if err := ilbbg.Sync(&groupParams); err != nil {
self.taskFail(ctx, lblis, err.Error())
return
} else {
if _, err := db.UpdateWithLock(ctx, group, func() error {
group.AssociatedId = lblis.GetId()
group.AssociatedType = api.LB_ASSOCIATE_TYPE_LISTENER
return nil
}); err != nil {
self.taskFail(ctx, lblis, err.Error())
return
}
self.OnPrepareLoadbalancerBackendgroup(ctx, lblis, data)
}
} else {
// 服务器组不存在
self.SetStage("OnPrepareLoadbalancerBackendgroup", nil)
lbbg.StartHuaweiLoadBalancerBackendGroupCreateTask(ctx, self.GetUserCred(), params, self.GetTaskId())
}
call := getOnLoadbalancerListenerCreateCompleteFunc(lblis.GetProviderName())
call(ctx, lblis, data, self)
}
func (self *LoadbalancerListenerCreateTask) OnLoadbalancerListenerCreateCompleteFailed(ctx context.Context, lblis *models.SLoadbalancerListener, reason jsonutils.JSONObject) {
@@ -134,32 +147,3 @@ func (self *LoadbalancerListenerCreateTask) OnLoadbalancerListenerStartCompleteF
lblis.SetStatus(self.GetUserCred(), api.LB_STATUS_DISABLED, reason.String())
self.SetStageFailed(ctx, reason.String())
}
//func updateHuaweiLbbg(lblis *models.SLoadbalancerListener, lbbg *models.SLoadbalancerBackendGroup, withExtParams bool) error {
// _, err := lbbg.GetModelManager().TableSpec().Update(lbbg, func() error {
// if withExtParams {
// lbbg.StickySession = lblis.StickySession
// lbbg.StickySessionCookie = lblis.StickySessionCookie
// lbbg.StickySessionType = lblis.StickySessionType
// lbbg.StickySessionCookieTimeout = lblis.StickySessionCookieTimeout
//
// lbbg.HealthCheckType = lblis.HealthCheckType
// lbbg.HealthCheckReq = lblis.HealthCheckReq
// lbbg.HealthCheckExp = lblis.HealthCheckExp
// lbbg.HealthCheck = lblis.HealthCheck
// lbbg.HealthCheckTimeout = lblis.HealthCheckTimeout
// lbbg.HealthCheckDomain = lblis.HealthCheckDomain
// lbbg.HealthCheckHttpCode = lblis.HealthCheckHttpCode
// lbbg.HealthCheckURI = lblis.HealthCheckURI
// lbbg.HealthCheckInterval = lblis.HealthCheckInterval
// lbbg.HealthCheckRise = lblis.HealthCheckRise
// lbbg.HealthCheckFall = lblis.HealthCheckFall
// }
//
// lbbg.Scheduler = lblis.Scheduler
// lbbg.ProtocolType = lblis.ListenerType
// return nil
// })
//
// return err
//}
@@ -35,6 +35,117 @@ func init() {
taskman.RegisterTask(LoadbalancerListenerRuleCreateTask{})
}
func getOnPrepareLoadbalancerBackendgroupFunc(provider string) func(ctx context.Context, region *models.SCloudregion, lbr *models.SLoadbalancerListenerRule, data jsonutils.JSONObject, self *LoadbalancerListenerRuleCreateTask) {
switch provider {
case api.CLOUD_PROVIDER_HUAWEI:
return onHuaiweiPrepareLoadbalancerBackendgroup
case api.CLOUD_PROVIDER_AWS:
return onAwsPrepareLoadbalancerBackendgroup
default:
return onPrepareLoadbalancerBackendgroup
}
}
func onPrepareLoadbalancerBackendgroup(ctx context.Context, region *models.SCloudregion, lbr *models.SLoadbalancerListenerRule, data jsonutils.JSONObject, self *LoadbalancerListenerRuleCreateTask) {
self.OnCreateLoadbalancerListenerRule(ctx, lbr, data)
return
}
func onHuaiweiPrepareLoadbalancerBackendgroup(ctx context.Context, region *models.SCloudregion, lbr *models.SLoadbalancerListenerRule, data jsonutils.JSONObject, self *LoadbalancerListenerRuleCreateTask) {
lbbg := lbr.GetLoadbalancerBackendGroup()
if lbbg == nil {
self.taskFail(ctx, lbr, "huawei loadbalancer listener rule releated backend group not found")
return
}
lblis := lbr.GetLoadbalancerListener()
if lblis == nil {
self.taskFail(ctx, lbr, "huawei loadbalancer listener rule releated listener not found")
return
}
params := jsonutils.NewDict()
params.Set("ruleId", jsonutils.NewString(lbr.GetId()))
group, _ := models.HuaweiCachedLbbgManager.GetUsableCachedBackendGroup(lbbg.GetId(), lblis.ListenerType)
if group != nil {
ilbbg, err := group.GetICloudLoadbalancerBackendGroup()
if err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
groupParams, err := lbbg.GetHuaweiBackendGroupParams(lblis, lbr)
if err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
groupParams.ListenerID = ""
// 服务器组已经存在,直接同步即可
if err := ilbbg.Sync(groupParams); err != nil {
self.taskFail(ctx, lbr, err.Error())
return
} else {
group.SetModelManager(models.HuaweiCachedLbbgManager, group)
if _, err := db.UpdateWithLock(ctx, group, func() error {
group.AssociatedId = lbr.GetId()
group.AssociatedType = api.LB_ASSOCIATE_TYPE_RULE
return nil
}); err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
self.OnCreateLoadbalancerListenerRule(ctx, lbr, data)
}
} else {
// 服务器组不存在
self.SetStage("OnCreateLoadbalancerListenerRule", nil)
lbbg.StartHuaweiLoadBalancerBackendGroupCreateTask(ctx, self.GetUserCred(), params, self.GetTaskId())
}
}
func onAwsPrepareLoadbalancerBackendgroup(ctx context.Context, region *models.SCloudregion, lbr *models.SLoadbalancerListenerRule, data jsonutils.JSONObject, self *LoadbalancerListenerRuleCreateTask) {
lbbg := lbr.GetLoadbalancerBackendGroup()
if lbbg == nil {
self.taskFail(ctx, lbr, "aws loadbalancer listener rule releated backend group not found")
return
}
lblis := lbr.GetLoadbalancerListener()
if lblis == nil {
self.taskFail(ctx, lbr, "aws loadbalancer listener rule releated listener not found")
return
}
params, err := lbbg.GetAwsBackendGroupParams(lblis, lbr)
if err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
group, _ := models.AwsCachedLbbgManager.GetUsableCachedBackendGroup(lblis.LoadbalancerId, lblis.BackendGroupId, lblis.ListenerType, lblis.HealthCheckType, lblis.HealthCheckInterval)
if group != nil {
ilbbg, err := group.GetICloudLoadbalancerBackendGroup()
if err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
// 服务器组已经存在,直接同步即可
if err := ilbbg.Sync(params); err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
self.OnCreateLoadbalancerListenerRule(ctx, lbr, data)
} else {
paramsObj := jsonutils.Marshal(params).(*jsonutils.JSONDict)
// 服务器组不存在
self.SetStage("OnCreateLoadbalancerListenerRule", nil)
lbbg.StartAwsLoadBalancerBackendGroupCreateTask(ctx, self.GetUserCred(), paramsObj, self.GetTaskId())
}
}
func (self *LoadbalancerListenerRuleCreateTask) taskFail(ctx context.Context, lbr *models.SLoadbalancerListenerRule, reason string) {
lbr.SetStatus(self.GetUserCred(), api.LB_CREATE_FAILED, reason)
db.OpsLog.LogEvent(lbr, db.ACT_ALLOCATE_FAIL, reason, self.UserCred)
@@ -59,63 +170,8 @@ func (self *LoadbalancerListenerRuleCreateTask) OnInit(ctx context.Context, obj
}
func (self *LoadbalancerListenerRuleCreateTask) OnPrepareLoadbalancerBackendgroup(ctx context.Context, region *models.SCloudregion, lbr *models.SLoadbalancerListenerRule, data jsonutils.JSONObject) {
lbbg := lbr.GetLoadbalancerBackendGroup()
// 目前只有华为才需要在创建监听器规则时创建服务器组,其他云直接绕过此步骤
if lbr.GetProviderName() != api.CLOUD_PROVIDER_HUAWEI {
self.OnCreateLoadbalancerListenerRule(ctx, lbr, data)
return
}
lblis := lbr.GetLoadbalancerListener()
if lblis == nil {
self.taskFail(ctx, lbr, "huawei loadbalancer listener rule releated listener not found")
return
}
params := jsonutils.NewDict()
params.Set("ruleId", jsonutils.NewString(lbr.GetId()))
if lbr.GetProviderName() == api.CLOUD_PROVIDER_HUAWEI && lbbg == nil {
self.taskFail(ctx, lbr, "huawei loadbalancer listener rule releated backend group not found")
return
}
group, _ := models.HuaweiCachedLbbgManager.GetUsableCachedBackendGroup(lbbg.GetId(), lblis.ListenerType)
if group != nil {
ilbbg, err := group.GetICloudLoadbalancerBackendGroup()
if err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
groupParams, err := lbbg.GetHuaweiBackendGroupParams(lblis, lbr)
if err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
groupParams.ListenerID = ""
// 服务器组已经存在,直接同步即可
if err := ilbbg.Sync(&groupParams); err != nil {
self.taskFail(ctx, lbr, err.Error())
return
} else {
group.SetModelManager(models.HuaweiCachedLbbgManager, group)
if _, err := db.UpdateWithLock(ctx, group, func() error {
group.AssociatedId = lbr.GetId()
group.AssociatedType = api.LB_ASSOCIATE_TYPE_RULE
return nil
}); err != nil {
self.taskFail(ctx, lbr, err.Error())
return
}
self.OnCreateLoadbalancerListenerRule(ctx, lbr, data)
}
} else {
// 服务器组不存在
self.SetStage("OnCreateLoadbalancerListenerRule", nil)
lbbg.StartHuaweiLoadBalancerBackendGroupCreateTask(ctx, self.GetUserCred(), params, self.GetTaskId())
}
call := getOnPrepareLoadbalancerBackendgroupFunc(lbr.GetProviderName())
call(ctx, region, lbr, data, self)
}
func (self *LoadbalancerListenerRuleCreateTask) OnCreateLoadbalancerListenerRule(ctx context.Context, lbr *models.SLoadbalancerListenerRule, data jsonutils.JSONObject) {
@@ -52,14 +52,15 @@ func (self *LoadbalancerListenerSyncTask) OnInit(ctx context.Context, obj db.ISt
return
}
if lblis.GetProviderName() != api.CLOUD_PROVIDER_HUAWEI {
// todo: 这个if应该可以删除
if lblis.GetProviderName() != api.CLOUD_PROVIDER_HUAWEI || lblis.GetProviderName() != api.CLOUD_PROVIDER_AWS {
self.OnLoadbalancerBackendgroupSyncComplete(ctx, lblis, data)
return
}
lbbg := lblis.GetLoadbalancerBackendGroup()
if lbbg == nil {
self.taskFail(ctx, lblis, fmt.Sprintf("failed to find region for lblis %s", lblis.Name))
self.taskFail(ctx, lblis, fmt.Sprintf("failed to find lbbg for lblis %s", lblis.Name))
return
}
+2 -2
View File
@@ -118,8 +118,8 @@ func (lb *SLoadbalancer) GetNetworkType() string {
return lb.NetworkType
}
func (lb *SLoadbalancer) GetNetworkId() string {
return lb.VSwitchId
func (lb *SLoadbalancer) GetNetworkIds() []string {
return []string{lb.VSwitchId}
}
func (lb *SLoadbalancer) GetZoneId() string {
@@ -56,6 +56,10 @@ type SLoadbalancerBackendGroup struct {
AssociatedObjects AssociatedObjects
}
func (backendgroup *SLoadbalancerBackendGroup) GetLoadbalancerId() string {
return backendgroup.lb.GetId()
}
func (backendgroup *SLoadbalancerBackendGroup) GetProtocolType() string {
return ""
}
@@ -27,6 +27,10 @@ type SLoadbalancerDefaultBackendGroup struct {
lb *SLoadbalancer
}
func (backendgroup *SLoadbalancerDefaultBackendGroup) GetLoadbalancerId() string {
return backendgroup.lb.GetId()
}
func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProtocolType() string {
return ""
}
@@ -79,6 +79,10 @@ func (lbr *SLoadbalancerListenerRule) Refresh() error {
return jsonutils.Update(lbr, rule)
}
func (lbr *SLoadbalancerListenerRule) GetCondition() string {
return ""
}
func (lbr *SLoadbalancerListenerRule) GetDomain() string {
return lbr.Domain
}
@@ -30,6 +30,10 @@ type SLoadbalancerMasterSlaveBackendGroup struct {
MasterSlaveServerGroupName string
}
func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetLoadbalancerId() string {
return backendgroup.lb.GetId()
}
func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProtocolType() string {
return ""
}
+6 -2
View File
@@ -61,6 +61,10 @@ type SRegion struct {
fetchLocation bool
}
func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetClient() *SAliyunClient {
return self.client
}
@@ -849,8 +853,8 @@ func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbala
params["VpcId"] = loadbalancer.VpcID
}
if len(loadbalancer.NetworkID) > 0 {
params["VSwitchId"] = loadbalancer.NetworkID
if len(loadbalancer.NetworkIDs) > 0 {
params["VSwitchId"] = loadbalancer.NetworkIDs[0]
}
if len(loadbalancer.Address) > 0 {
+7 -7
View File
@@ -187,7 +187,7 @@ func (self *SAwsClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, e
return self.iregions[i], nil
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SAwsClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
@@ -195,11 +195,11 @@ func (self *SAwsClient) GetIHostById(id string) (cloudprovider.ICloudHost, error
ihost, err := self.iregions[i].GetIHostById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
} else if err != ErrorNotFound() {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SAwsClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
@@ -207,11 +207,11 @@ func (self *SAwsClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error)
ihost, err := self.iregions[i].GetIVpcById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
} else if err != ErrorNotFound() {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SAwsClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
@@ -219,11 +219,11 @@ func (self *SAwsClient) GetIStorageById(id string) (cloudprovider.ICloudStorage,
ihost, err := self.iregions[i].GetIStorageById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
} else if err != ErrorNotFound() {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
type SAccountBalance struct {
+5 -5
View File
@@ -188,7 +188,7 @@ func (self *SDisk) GetMountpoint() string {
}
func (self *SDisk) Delete(ctx context.Context) error {
if _, err := self.storage.zone.region.GetDisk(self.DiskId); err == cloudprovider.ErrNotFound {
if _, err := self.storage.zone.region.GetDisk(self.DiskId); err == ErrorNotFound() {
log.Errorf("Failed to find disk %s when delete", self.DiskId)
return nil
}
@@ -256,7 +256,7 @@ func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) {
if snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil {
return nil, err
} else if total != 1 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
} else {
return &snapshots[0], nil
}
@@ -359,18 +359,18 @@ func (self *SRegion) GetDisks(instanceId string, zoneId string, storageType stri
func (self *SRegion) GetDisk(diskId string) (*SDisk, error) {
if len(diskId) == 0 {
// return nil, fmt.Errorf("GetDisk diskId should not be empty.")
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
disks, total, err := self.GetDisks("", "", "", []string{diskId}, 0, 1)
if err != nil {
if strings.Contains(err.Error(), "InvalidVolume.NotFound") {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
} else {
return nil, err
}
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
return &disks[0], nil
}
+2 -2
View File
@@ -221,7 +221,7 @@ func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
return &eips[0], nil
}
@@ -233,7 +233,7 @@ func (self *SRegion) GetEipByIpAddress(eipAddress string) (*SEipAddress, error)
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
return &eips[0], nil
}
+2 -2
View File
@@ -74,7 +74,7 @@ func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
if len(gid) == 0 {
log.Errorf("GetIVMById guest id is empty")
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
ivms, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{gid}, 0, 1)
@@ -82,7 +82,7 @@ func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
return nil, err
}
if len(ivms) == 0 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
if len(ivms) > 1 {
return nil, cloudprovider.ErrDuplicateId
+2 -2
View File
@@ -272,7 +272,7 @@ func (self *SRegion) GetImage(imageId string) (*SImage, error) {
return nil, err
}
if len(images) == 0 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
return &images[0], nil
}
@@ -287,7 +287,7 @@ func (self *SRegion) GetImageByName(name string, owners []TImageOwnerType) (*SIm
return nil, err
}
if len(images) == 0 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
log.Debugf("%d image found match name %s", len(images), name)
+2 -2
View File
@@ -505,7 +505,7 @@ func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit
res, err := self.ec2Client.DescribeInstances(params)
if err != nil {
if strings.Contains(err.Error(), "InvalidInstanceID.NotFound") {
return nil, 0, cloudprovider.ErrNotFound
return nil, 0, ErrorNotFound()
} else {
return nil, 0, err
}
@@ -642,7 +642,7 @@ func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
return nil, err
}
if len(instances) == 0 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
return &instances[0], nil
}
+432
View File
@@ -0,0 +1,432 @@
package aws
import (
"fmt"
"sort"
"strconv"
"strings"
"github.com/aws/aws-sdk-go/service/elbv2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
/*
https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/Welcome.html
*/
type SElb struct {
region *SRegion
Type string `json:"Type"`
Scheme string `json:"Scheme"`
IPAddressType string `json:"IpAddressType"`
VpcID string `json:"VpcId"`
AvailabilityZones []AvailabilityZone `json:"AvailabilityZones"`
CreatedTime string `json:"CreatedTime"`
CanonicalHostedZoneID string `json:"CanonicalHostedZoneId"`
DNSName string `json:"DNSName"`
SecurityGroups []string `json:"SecurityGroups"`
LoadBalancerName string `json:"LoadBalancerName"`
State State `json:"State"`
LoadBalancerArn string `json:"LoadBalancerArn"`
}
type AvailabilityZone struct {
LoadBalancerAddresses []LoadBalancerAddress `json:"LoadBalancerAddresses"`
ZoneName string `json:"ZoneName"`
SubnetID string `json:"SubnetId"`
}
type LoadBalancerAddress struct {
IPAddress string `json:"IpAddress"`
AllocationID string `json:"AllocationId"`
}
type State struct {
Code string `json:"Code"`
}
func (self *SElb) GetId() string {
return self.LoadBalancerArn
}
func (self *SElb) GetName() string {
return self.LoadBalancerName
}
func (self *SElb) GetGlobalId() string {
return self.GetId()
}
func (self *SElb) GetStatus() string {
switch self.State.Code {
case "provisioning":
return api.LB_STATUS_INIT
case "active":
return api.LB_STATUS_ENABLED
case "failed":
return api.LB_STATUS_START_FAILED
default:
return api.LB_STATUS_UNKNOWN
}
}
func (self *SElb) Refresh() error {
ielb, err := self.region.GetILoadBalancerById(self.GetId())
if err != nil {
return err
}
err = jsonutils.Update(self, ielb)
if err != nil {
return err
}
return nil
}
func (self *SElb) IsEmulated() bool {
return false
}
func (self *SElb) GetMetadata() *jsonutils.JSONDict {
metadata := jsonutils.NewDict()
metadata.Add(jsonutils.NewString(self.Type), "loadbalance_type")
attrs, err := self.region.getElbAttributesById(self.GetId())
if err != nil {
log.Errorf("SElb GetMetadata %s", err)
return metadata
}
for k, v := range attrs {
metadata.Add(jsonutils.NewString(v), k)
}
return metadata
}
func (self *SElb) GetProjectId() string {
return ""
}
func (self *SElb) GetAddress() string {
return self.DNSName
}
func (self *SElb) GetAddressType() string {
switch self.Scheme {
case "internal":
return api.LB_ADDR_TYPE_INTRANET
case "internet-facing":
return api.LB_ADDR_TYPE_INTERNET
default:
return api.LB_ADDR_TYPE_INTRANET
}
}
func (self *SElb) GetNetworkType() string {
return api.LB_NETWORK_TYPE_VPC
}
func (self *SElb) GetNetworkIds() []string {
ret := []string{}
for i := range self.AvailabilityZones {
ret = append(ret, self.AvailabilityZones[i].SubnetID)
}
return ret
}
func (self *SElb) GetVpcId() string {
return self.VpcID
}
func (self *SElb) GetZoneId() string {
zones := []string{}
for i := range self.AvailabilityZones {
zones = append(zones, self.AvailabilityZones[i].ZoneName)
}
sort.Strings(zones)
return zones[0]
}
func (self *SElb) GetLoadbalancerSpec() string {
return self.Type
}
func (self *SElb) GetChargeType() string {
return api.LB_CHARGE_TYPE_BY_TRAFFIC
}
func (self *SElb) GetEgressMbps() int {
return 0
}
func (self *SElb) Delete() error {
return self.region.DeleteElb(self.GetId())
}
func (self *SElb) Start() error {
return nil
}
func (self *SElb) Stop() error {
return cloudprovider.ErrNotSupported
}
func (self *SElb) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) {
listeners, err := self.region.GetElbListeners(self.GetId())
if err != nil {
return nil, err
}
ret := make([]cloudprovider.ICloudLoadbalancerListener, len(listeners))
for i := range listeners {
listeners[i].lb = self
ret[i] = &listeners[i]
}
return ret, nil
}
func (self *SElb) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
backendgroups, err := self.region.GetElbBackendgroups(self.GetId(), nil)
if err != nil {
return nil, err
}
ibackendgroups := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(backendgroups))
for i := range backendgroups {
backendgroups[i].lb = self
ibackendgroups[i] = &backendgroups[i]
}
return ibackendgroups, nil
}
func (self *SElb) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
backendgroup, err := self.region.CreateElbBackendgroup(group)
if err != nil {
return nil, err
}
backendgroup.lb = self
return backendgroup, nil
}
func (self *SElb) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return self.region.GetElbBackendgroup(groupId)
}
func (self *SElb) CreateILoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) {
ret, err := self.region.CreateElbListener(listener)
if err != nil {
return nil, err
}
ret.lb = self
return ret, nil
}
func (self *SElb) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) {
if listenerId == "" {
return nil, ErrorNotFound()
}
return self.region.GetElbListener(listenerId)
}
func (self *SElb) GetIEIP() (cloudprovider.ICloudEIP, error) {
return nil, nil
}
func (self *SRegion) DeleteElb(elbId string) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
params := &elbv2.DeleteLoadBalancerInput{}
params.SetLoadBalancerArn(elbId)
_, err = client.DeleteLoadBalancer(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) GetElbBackendgroups(elbId string, backendgroupIds []string) ([]SElbBackendGroup, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeTargetGroupsInput{}
if len(elbId) > 0 {
params.SetLoadBalancerArn(elbId)
}
if len(backendgroupIds) > 0 {
v := make([]*string, len(backendgroupIds))
for i := range backendgroupIds {
v[i] = &backendgroupIds[i]
}
params.SetTargetGroupArns(v)
}
ret, err := client.DescribeTargetGroups(params)
if err != nil {
return nil, err
}
backendgroups := []SElbBackendGroup{}
err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups)
if err != nil {
return nil, err
}
for i := range backendgroups {
backendgroups[i].region = self
}
return backendgroups, nil
}
func (self *SRegion) GetElbBackendgroup(backendgroupId string) (*SElbBackendGroup, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeTargetGroupsInput{}
params.SetTargetGroupArns([]*string{&backendgroupId})
ret, err := client.DescribeTargetGroups(params)
if err != nil {
return nil, err
}
backendgroups := []SElbBackendGroup{}
err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups)
if err != nil {
return nil, err
}
if len(backendgroups) == 1 {
backendgroups[0].region = self
return &backendgroups[0], nil
}
return nil, ErrorNotFound()
}
func ToAwsHealthCode(s string) string {
ret := []string{}
segs := strings.Split(s, ",")
for _, seg := range segs {
if seg == api.LB_HEALTH_CHECK_HTTP_CODE_4xx && !utils.IsInStringArray("400-499", ret) {
ret = append(ret, "400-499")
} else if seg == api.LB_HEALTH_CHECK_HTTP_CODE_3xx && !utils.IsInStringArray("300-399", ret) {
ret = append(ret, "300-399")
} else if seg == api.LB_HEALTH_CHECK_HTTP_CODE_2xx && !utils.IsInStringArray("200-299", ret) {
ret = append(ret, "200-299")
}
}
return strings.Join(ret, ",")
}
func ToOnecloudHealthCode(s string) string {
ret := []string{}
segs := strings.Split(s, ",")
for _, seg := range segs {
codes := strings.Split(seg, "-")
for _, code := range codes {
c, _ := strconv.Atoi(code)
if c >= 400 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_4xx, ret) {
ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_4xx)
} else if c >= 300 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_3xx, ret) {
ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_3xx)
} else if c >= 200 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_2xx, ret) {
ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_2xx)
}
}
if len(codes) == 2 {
min, _ := strconv.Atoi(codes[0])
max, _ := strconv.Atoi(codes[1])
if min >= 200 && max >= 400 {
if !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_3xx, ret) {
ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_3xx)
}
}
}
}
return strings.Join(ret, ",")
}
// 目前只支持target type instance
func (self *SRegion) CreateElbBackendgroup(group *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) {
params := &elbv2.CreateTargetGroupInput{}
params.SetProtocol(strings.ToUpper(group.ListenType))
params.SetPort(int64(group.ListenPort))
params.SetVpcId(group.VpcId)
params.SetName(group.Name)
params.SetTargetType("instance")
if group.HealthCheck != nil {
params.SetHealthCheckIntervalSeconds(int64(group.HealthCheck.HealthCheckInterval))
params.SetHealthCheckPort("traffic-port")
params.SetHealthCheckProtocol(strings.ToUpper(group.HealthCheck.HealthCheckType))
params.SetHealthCheckTimeoutSeconds(int64(group.HealthCheck.HealthCheckTimeout))
params.SetHealthyThresholdCount(int64(group.HealthCheck.HealthCheckRise))
params.SetUnhealthyThresholdCount(int64(group.HealthCheck.HealthCheckFail))
if len(group.HealthCheck.HealthCheckURI) > 0 {
params.SetHealthCheckPath(group.HealthCheck.HealthCheckURI)
}
if utils.IsInStringArray(group.ListenType, []string{api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS}) {
codes := ToAwsHealthCode(group.HealthCheck.HealthCheckHttpCode)
if len(codes) > 0 {
matcher := &elbv2.Matcher{}
matcher.SetHttpCode(codes)
params.SetMatcher(matcher)
}
}
}
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
ret, err := client.CreateTargetGroup(params)
if err != nil {
return nil, err
}
backendgroups := []SElbBackendGroup{}
err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups)
if err != nil {
return nil, err
}
if len(backendgroups) == 1 {
backendgroups[0].region = self
return &backendgroups[0], nil
}
return nil, fmt.Errorf("CreateElbBackendgroup error: %#v", backendgroups)
}
+97
View File
@@ -0,0 +1,97 @@
package aws
import (
"fmt"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SElbBackend struct {
region *SRegion
group *SElbBackendGroup
Target Target `json:"Target"`
TargetHealth TargetHealth `json:"TargetHealth"`
}
type Target struct {
ID string `json:"Id"`
Port int `json:"Port"`
}
type TargetHealth struct {
State string `json:"State"`
Reason string `json:"Reason"`
Description string `json:"Description"`
}
func (self *SElbBackend) GetId() string {
return fmt.Sprintf("%s::%s::%d", self.group.GetId(), self.Target.ID, self.Target.Port)
}
func (self *SElbBackend) GetName() string {
return self.GetId()
}
func (self *SElbBackend) GetGlobalId() string {
return self.GetId()
}
func (self *SElbBackend) GetStatus() string {
return api.LB_STATUS_ENABLED
}
func (self *SElbBackend) Refresh() error {
return nil
}
func (self *SElbBackend) IsEmulated() bool {
return false
}
func (self *SElbBackend) GetMetadata() *jsonutils.JSONDict {
return jsonutils.NewDict()
}
func (self *SElbBackend) GetProjectId() string {
return ""
}
func (self *SElbBackend) GetWeight() int {
return 0
}
func (self *SElbBackend) GetPort() int {
return self.Target.Port
}
func (self *SElbBackend) GetBackendType() string {
return api.LB_BACKEND_GUEST
}
func (self *SElbBackend) GetBackendRole() string {
return api.LB_BACKEND_ROLE_DEFAULT
}
func (self *SElbBackend) GetBackendId() string {
return self.Target.ID
}
func (self *SElbBackend) SyncConf(port, weight int) error {
return self.region.SyncElbBackend(self.GetId(), self.GetBackendId(), self.Target.Port, port)
}
func (self *SRegion) SyncElbBackend(backendId, serverId string, oldPort, newPort int) error {
err := self.RemoveElbBackend(backendId, serverId, 0, oldPort)
if err != nil {
return err
}
_, err = self.AddElbBackend(backendId, serverId, 0, newPort)
if err != nil {
return err
}
return nil
}
+493
View File
@@ -0,0 +1,493 @@
package aws
import (
"fmt"
"strconv"
"strings"
"github.com/aws/aws-sdk-go/service/elbv2"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SElbBackendGroup struct {
region *SRegion
lb *SElb
TargetGroupName string `json:"TargetGroupName"`
Protocol string `json:"Protocol"`
Port int64 `json:"Port"`
VpcID string `json:"VpcId"`
TargetType string `json:"TargetType"`
HealthyThresholdCount int `json:"HealthyThresholdCount"`
Matcher Matcher `json:"Matcher"`
UnhealthyThresholdCount int `json:"UnhealthyThresholdCount"`
HealthCheckPath string `json:"HealthCheckPath"`
HealthCheckProtocol string `json:"HealthCheckProtocol"`
HealthCheckPort string `json:"HealthCheckPort"`
HealthCheckIntervalSeconds int `json:"HealthCheckIntervalSeconds"`
HealthCheckTimeoutSeconds int `json:"HealthCheckTimeoutSeconds"`
TargetGroupArn string `json:"TargetGroupArn"`
LoadBalancerArns []string `json:"LoadBalancerArns"`
}
func (self *SElbBackendGroup) GetLoadbalancerId() string {
if len(self.LoadBalancerArns) > 0 {
return self.LoadBalancerArns[0]
}
return ""
}
type Matcher struct {
HTTPCode string `json:"HttpCode"`
}
func (self *SElbBackendGroup) GetId() string {
return self.TargetGroupArn
}
func (self *SElbBackendGroup) GetName() string {
return self.TargetGroupName
}
func (self *SElbBackendGroup) GetGlobalId() string {
return self.GetId()
}
func (self *SElbBackendGroup) GetStatus() string {
return api.LB_STATUS_ENABLED
}
func (self *SElbBackendGroup) Refresh() error {
lbbg, err := self.region.GetElbBackendgroup(self.GetId())
if err != nil {
return err
}
err = jsonutils.Update(self, lbbg)
if err != nil {
return err
}
return nil
}
func (self *SElbBackendGroup) IsEmulated() bool {
return false
}
func (self *SElbBackendGroup) GetMetadata() *jsonutils.JSONDict {
metadata := jsonutils.NewDict()
metadata.Add(jsonutils.NewInt(self.Port), "port")
metadata.Add(jsonutils.NewString(self.TargetType), "target_type")
metadata.Add(jsonutils.NewString(strings.ToLower(self.HealthCheckProtocol)), "health_check_protocol")
metadata.Add(jsonutils.NewInt(int64(self.HealthCheckIntervalSeconds)), "health_check_interval")
return metadata
}
func (self *SElbBackendGroup) GetProjectId() string {
return ""
}
func (self *SElbBackendGroup) IsDefault() bool {
return false
}
func (self *SElbBackendGroup) GetType() string {
return api.LB_BACKENDGROUP_TYPE_NORMAL
}
func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) {
backends, err := self.region.GetELbBackends(self.GetId())
if err != nil {
return nil, err
}
ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends))
for i := range backends {
backends[i].region = self.region
backends[i].group = self
ibackends[i] = &backends[i]
}
return ibackends, nil
}
func (self *SElbBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) {
backend, err := self.region.GetELbBackend(backendId)
if err != nil {
return nil, err
}
backend.group = self
return backend, nil
}
func (self *SElbBackendGroup) GetProtocolType() string {
switch self.Protocol {
case "TCP":
return api.LB_LISTENER_TYPE_TCP
case "UDP":
return api.LB_LISTENER_TYPE_UDP
case "HTTP":
return api.LB_LISTENER_TYPE_HTTP
case "HTTPS":
return api.LB_LISTENER_TYPE_HTTPS
case "TCP_UDP":
return api.LB_LISTENER_TYPE_TCP_UDP
default:
return ""
}
}
func (self *SElbBackendGroup) GetScheduler() string {
return ""
}
func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) {
health := &cloudprovider.SLoadbalancerHealthCheck{}
health.HealthCheck = api.LB_BOOL_ON
health.HealthCheckRise = self.HealthyThresholdCount
health.HealthCheckInterval = self.HealthCheckIntervalSeconds
health.HealthCheckURI = self.HealthCheckPath
health.HealthCheckType = self.HealthCheckProtocol
health.HealthCheckTimeout = self.HealthCheckTimeoutSeconds
health.HealthCheckHttpCode = ToOnecloudHealthCode(self.Matcher.HTTPCode)
return health, nil
}
func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) {
attrs, err := self.region.GetElbBackendgroupAttributesById(self.GetId())
if err != nil {
return nil, err
}
cookieTime := 0
if t, ok := attrs["stickiness.lb_cookie.duration_seconds"]; !ok {
cookieTime, err = strconv.Atoi(t)
}
ret := &cloudprovider.SLoadbalancerStickySession{
StickySession: attrs["stickiness.enabled"],
StickySessionCookie: "",
StickySessionType: api.LB_STICKY_SESSION_TYPE_INSERT,
StickySessionCookieTimeout: cookieTime,
}
return ret, nil
}
func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) {
backend, err := self.region.AddElbBackend(self.GetId(), serverId, weight, port)
if err != nil {
return nil, err
}
backend.region = self.region
backend.group = self
return backend, nil
}
func (self *SElbBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error {
return self.region.RemoveElbBackend(self.GetId(), serverId, weight, port)
}
func (self *SElbBackendGroup) Delete() error {
return self.region.DeleteElbBackendGroup(self.GetId())
}
func (self *SElbBackendGroup) Sync(group *cloudprovider.SLoadbalancerBackendGroup) error {
return self.region.SyncELbBackendGroup(self.GetId(), group)
}
func (self *SRegion) GetELbBackends(backendgroupId string) ([]SElbBackend, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
group, err := self.GetElbBackendgroup(backendgroupId)
if err != nil {
return nil, err
}
params := &elbv2.DescribeTargetHealthInput{}
params.SetTargetGroupArn(backendgroupId)
output, err := client.DescribeTargetHealth(params)
if err != nil {
return nil, err
}
backends := []SElbBackend{}
err = unmarshalAwsOutput(output, "TargetHealthDescriptions", &backends)
if err != nil {
return nil, err
}
ret := []SElbBackend{}
for i := range backends {
if !utils.IsInStringArray(backends[i].TargetHealth.Reason, []string{"Target.InvalidState", "Target.DeregistrationInProgress"}) {
backends[i].region = self
backends[i].group = group
ret = append(ret, backends[i])
}
}
return ret, nil
}
func (self *SRegion) GetELbBackend(backendId string) (*SElbBackend, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
groupId, instanceId, port, err := parseElbBackendId(backendId)
if err != nil {
return nil, err
}
params := &elbv2.DescribeTargetHealthInput{}
desc := &elbv2.TargetDescription{}
desc.SetPort(int64(port))
desc.SetId(instanceId)
params.SetTargets([]*elbv2.TargetDescription{desc})
params.SetTargetGroupArn(groupId)
ret, err := client.DescribeTargetHealth(params)
if err != nil {
return nil, err
}
backends := []SElbBackend{}
err = unmarshalAwsOutput(ret, "TargetHealthDescriptions", &backends)
if err != nil {
return nil, err
}
if len(backends) == 1 {
backends[0].region = self
return &backends[0], nil
}
return nil, ErrorNotFound()
}
func parseElbBackendId(id string) (string, string, int, error) {
segs := strings.Split(id, "::")
if len(segs) != 3 {
return "", "", 0, fmt.Errorf("%s is not a valid backend id", id)
}
port, err := strconv.Atoi(segs[2])
if err != nil {
return "", "", 0, fmt.Errorf("%s is not a valid backend id, %s", id, err)
}
return segs[0], segs[1], port, nil
}
func genElbBackendId(backendgroupId string, serverId string, port int) string {
return strings.Join([]string{backendgroupId, serverId, strconv.Itoa(port)}, "::")
}
func (self *SRegion) AddElbBackend(backendgroupId, serverId string, weight int, port int) (*SElbBackend, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.RegisterTargetsInput{}
params.SetTargetGroupArn(backendgroupId)
desc := &elbv2.TargetDescription{}
desc.SetId(serverId)
desc.SetPort(int64(port))
params.SetTargets([]*elbv2.TargetDescription{desc})
_, err = client.RegisterTargets(params)
if err != nil {
return nil, err
}
return self.GetELbBackend(genElbBackendId(backendgroupId, serverId, port))
}
func (self *SRegion) RemoveElbBackend(backendgroupId, serverId string, weight int, port int) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
params := &elbv2.DeregisterTargetsInput{}
params.SetTargetGroupArn(backendgroupId)
desc := &elbv2.TargetDescription{}
desc.SetId(serverId)
desc.SetPort(int64(port))
params.SetTargets([]*elbv2.TargetDescription{desc})
_, err = client.DeregisterTargets(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) DeleteElbBackendGroup(backendgroupId string) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
params := &elbv2.DeleteTargetGroupInput{}
params.SetTargetGroupArn(backendgroupId)
_, err = client.DeleteTargetGroup(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) SyncELbBackendGroup(backendgroupId string, group *cloudprovider.SLoadbalancerBackendGroup) error {
err := self.modifyELbBackendGroup(backendgroupId, group.HealthCheck)
if err != nil {
return err
}
err = self.RemoveElbBackends(backendgroupId)
if err != nil {
return err
}
return self.AddElbBackends(backendgroupId, group.Backends)
}
func (self *SRegion) modifyELbBackendGroup(backendgroupId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
params := &elbv2.ModifyTargetGroupInput{}
params.SetTargetGroupArn(backendgroupId)
params.SetHealthCheckProtocol(strings.ToUpper(healthCheck.HealthCheckType))
params.SetHealthyThresholdCount(int64(healthCheck.HealthCheckRise))
if utils.IsInStringArray(healthCheck.HealthCheckType, []string{api.LB_HEALTH_CHECK_HTTP, api.LB_LISTENER_TYPE_HTTPS}) {
params.SetUnhealthyThresholdCount(int64(healthCheck.HealthCheckFail))
params.SetHealthCheckTimeoutSeconds(int64(healthCheck.HealthCheckTimeout))
params.SetHealthCheckIntervalSeconds(int64(healthCheck.HealthCheckInterval))
if len(healthCheck.HealthCheckURI) > 0 {
params.SetHealthCheckPath(healthCheck.HealthCheckURI)
}
codes := ToAwsHealthCode(healthCheck.HealthCheckHttpCode)
if len(codes) > 0 {
matcher := &elbv2.Matcher{}
matcher.SetHttpCode(codes)
params.SetMatcher(matcher)
}
}
_, err = client.ModifyTargetGroup(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) RemoveElbBackends(backendgroupId string) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
backends, err := self.GetELbBackends(backendgroupId)
if err != nil {
return err
}
if len(backends) == 0 {
return nil
}
targets := []*elbv2.TargetDescription{}
for i := range backends {
target := &elbv2.TargetDescription{}
target.SetId(backends[i].GetBackendId())
target.SetPort(int64(backends[i].GetPort()))
targets = append(targets, target)
}
params := &elbv2.DeregisterTargetsInput{}
params.SetTargetGroupArn(backendgroupId)
params.SetTargets(targets)
_, err = client.DeregisterTargets(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) AddElbBackends(backendgroupId string, backends []cloudprovider.SLoadbalancerBackend) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
if len(backends) == 0 {
return nil
}
params := &elbv2.RegisterTargetsInput{}
params.SetTargetGroupArn(backendgroupId)
targets := []*elbv2.TargetDescription{}
for i := range backends {
desc := &elbv2.TargetDescription{}
desc.SetId(backends[i].ExternalID)
desc.SetPort(int64(backends[i].Port))
targets = append(targets, desc)
}
params.SetTargets(targets)
_, err = client.RegisterTargets(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) GetElbBackendgroupAttributesById(backendgroupId string) (map[string]string, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeTargetGroupAttributesInput{}
params.SetTargetGroupArn(backendgroupId)
output, err := client.DescribeTargetGroupAttributes(params)
if err != nil {
return nil, err
}
attrs := []map[string]string{}
err = unmarshalAwsOutput(output, "Attributes", &attrs)
if err != nil {
return nil, err
}
ret := map[string]string{}
for i := range attrs {
for k, v := range attrs[i] {
ret[k] = v
}
}
return ret, nil
}
+183
View File
@@ -0,0 +1,183 @@
package aws
import (
"crypto/sha1"
"crypto/x509"
"encoding/pem"
"fmt"
"strings"
"time"
"github.com/aws/aws-sdk-go/service/iam"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SElbCertificate struct {
region *SRegion
cert *x509.Certificate
Path string `json:"Path"`
ServerCertificateName string `json:"ServerCertificateName"`
ServerCertificateID string `json:"ServerCertificateId"`
Arn string `json:"Arn"`
UploadDate time.Time `json:"UploadDate"`
Expiration time.Time `json:"Expiration"`
PublicKey string
}
func (self *SElbCertificate) GetId() string {
return self.Arn
}
func (self *SElbCertificate) GetName() string {
return self.ServerCertificateName
}
func (self *SElbCertificate) GetGlobalId() string {
return self.GetId()
}
func (self *SElbCertificate) GetStatus() string {
return api.LB_STATUS_ENABLED
}
func (self *SElbCertificate) Refresh() error {
icert, err := self.region.GetILoadBalancerCertificateById(self.GetId())
if err != nil {
return err
}
err = jsonutils.Update(self, icert)
if err != nil {
return err
}
return nil
}
func (self *SElbCertificate) IsEmulated() bool {
return false
}
func (self *SElbCertificate) GetMetadata() *jsonutils.JSONDict {
return jsonutils.NewDict()
}
func (self *SElbCertificate) GetProjectId() string {
return ""
}
func (self *SElbCertificate) Sync(name, privateKey, publickKey string) error {
return cloudprovider.ErrNotSupported
}
func (self *SElbCertificate) Delete() error {
return self.region.deleteElbCertificate(self.GetName())
}
func (self *SElbCertificate) GetCommonName() string {
cert, err := self.ParsePublicKey()
if err != nil {
return ""
}
return cert.Issuer.CommonName
}
func (self *SElbCertificate) GetSubjectAlternativeNames() string {
// todo: fix me
_, err := self.ParsePublicKey()
if err != nil {
return ""
}
return ""
}
func (self *SElbCertificate) GetFingerprint() string {
publicKey := self.GetPublickKey()
if len(publicKey) == 0 {
return ""
}
_fp := sha1.Sum([]byte(publicKey))
fp := fmt.Sprintf("sha1:% x", _fp)
return strings.Replace(fp, " ", ":", -1)
}
func (self *SElbCertificate) GetExpireTime() time.Time {
return self.Expiration
}
func (self *SElbCertificate) GetPublickKey() string {
if self.PublicKey == "" {
ret, err := self.region.getPublicKey(self.GetName())
if err != nil {
log.Errorf("GetPublickKey %s", err)
return ""
}
self.PublicKey = ret
}
return self.PublicKey
}
func (self *SElbCertificate) GetPrivateKey() string {
return ""
}
func (self *SElbCertificate) ParsePublicKey() (*x509.Certificate, error) {
if self.cert != nil {
return self.cert, nil
}
publicKey := self.GetPublickKey()
if len(publicKey) == 0 {
return nil, fmt.Errorf("SElbCertificate ParsePublicKey public key is empty")
}
block, _ := pem.Decode([]byte(publicKey))
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
self.cert = cert
return cert, nil
}
func (self *SRegion) getPublicKey(certName string) (string, error) {
client, err := self.getIamClient()
if err != nil {
return "", err
}
params := &iam.GetServerCertificateInput{}
params.SetServerCertificateName(certName)
ret, err := client.GetServerCertificate(params)
if err != nil {
return "", err
}
return StrVal(ret.ServerCertificate.CertificateBody), nil
}
func (self *SRegion) deleteElbCertificate(certName string) error {
client, err := self.getIamClient()
if err != nil {
return err
}
params := &iam.DeleteServerCertificateInput{}
params.SetServerCertificateName(certName)
_, err = client.DeleteServerCertificate(params)
if err != nil {
return err
}
return nil
}
+724
View File
@@ -0,0 +1,724 @@
package aws
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SElbListener struct {
region *SRegion
lb *SElb
group *SElbBackendGroup
Port int `json:"Port"`
Protocol string `json:"Protocol"`
DefaultActions []DefaultAction `json:"DefaultActions"`
SSLPolicy string `json:"SslPolicy"`
Certificates []Certificate `json:"Certificates"`
LoadBalancerArn string `json:"LoadBalancerArn"`
ListenerArn string `json:"ListenerArn"`
}
type Certificate struct {
CertificateArn string `json:"CertificateArn"`
}
type DefaultAction struct {
TargetGroupArn string `json:"TargetGroupArn"`
Type string `json:"Type"`
}
func (self *SElbListener) GetId() string {
return self.ListenerArn
}
func (self *SElbListener) GetName() string {
return self.ListenerArn
}
func (self *SElbListener) GetGlobalId() string {
return self.GetId()
}
func (self *SElbListener) GetStatus() string {
return api.LB_STATUS_ENABLED
}
func (self *SElbListener) Refresh() error {
listener, err := self.region.GetElbListener(self.GetId())
if err != nil {
return err
}
err = jsonutils.Update(self, listener)
if err != nil {
return err
}
return nil
}
func (self *SElbListener) IsEmulated() bool {
return false
}
func (self *SElbListener) GetMetadata() *jsonutils.JSONDict {
return jsonutils.NewDict()
}
func (self *SElbListener) GetProjectId() string {
return ""
}
func (self *SElbListener) GetListenerType() string {
switch self.Protocol {
case "TCP":
return api.LB_LISTENER_TYPE_TCP
case "UDP":
return api.LB_LISTENER_TYPE_UDP
case "HTTP":
return api.LB_LISTENER_TYPE_HTTP
case "HTTPS":
return api.LB_LISTENER_TYPE_HTTPS
case "TCP_SSL":
return api.LB_LISTENER_TYPE_TCP
case "TCP_UDP":
return api.LB_LISTENER_TYPE_TCP_UDP
default:
return ""
}
}
func (self *SElbListener) GetListenerPort() int {
return self.Port
}
func (self *SElbListener) GetScheduler() string {
// api.LB_SCHEDULER_RR ?
return ""
}
func (self *SElbListener) GetAclStatus() string {
return api.LB_BOOL_OFF
}
func (self *SElbListener) GetAclType() string {
return ""
}
func (self *SElbListener) GetAclId() string {
return ""
}
func (self *SElbListener) GetEgressMbps() int {
return 0
}
func (self *SElbListener) GetHealthCheck() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
health, err := group.GetHealthCheck()
if err != nil {
return ""
}
return health.HealthCheck
}
func (self *SElbListener) getBackendGroup() (*SElbBackendGroup, error) {
if self.group != nil {
return self.group, nil
}
lbbg, err := self.region.GetElbBackendgroup(self.DefaultActions[0].TargetGroupArn)
if err != nil {
return nil, err
}
self.group = lbbg
return self.group, nil
}
func (self *SElbListener) GetHealthCheckType() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
health, err := group.GetHealthCheck()
if err != nil {
return ""
}
return health.HealthCheckType
}
func (self *SElbListener) GetHealthCheckTimeout() int {
group, err := self.getBackendGroup()
if err != nil {
return 0
}
health, err := group.GetHealthCheck()
if err != nil {
return 0
}
return health.HealthCheckTimeout
}
func (self *SElbListener) GetHealthCheckInterval() int {
group, err := self.getBackendGroup()
if err != nil {
return 0
}
health, err := group.GetHealthCheck()
if err != nil {
return 0
}
return health.HealthCheckInterval
}
func (self *SElbListener) GetHealthCheckRise() int {
group, err := self.getBackendGroup()
if err != nil {
return 0
}
health, err := group.GetHealthCheck()
if err != nil {
return 0
}
return health.HealthCheckRise
}
func (self *SElbListener) GetHealthCheckFail() int {
group, err := self.getBackendGroup()
if err != nil {
return 0
}
health, err := group.GetHealthCheck()
if err != nil {
return 0
}
return health.HealthCheckFail
}
func (self *SElbListener) GetHealthCheckReq() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
health, err := group.GetHealthCheck()
if err != nil {
return ""
}
return health.HealthCheckReq
}
func (self *SElbListener) GetHealthCheckExp() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
health, err := group.GetHealthCheck()
if err != nil {
return ""
}
return health.HealthCheckExp
}
func (self *SElbListener) GetBackendGroupId() string {
return self.DefaultActions[0].TargetGroupArn
}
func (self *SElbListener) GetBackendServerPort() int {
return 0
}
func (self *SElbListener) GetHealthCheckDomain() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
health, err := group.GetHealthCheck()
if err != nil {
return ""
}
return health.HealthCheckDomain
}
func (self *SElbListener) GetHealthCheckURI() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
health, err := group.GetHealthCheck()
if err != nil {
return ""
}
return health.HealthCheckURI
}
func (self *SElbListener) GetHealthCheckCode() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
health, err := group.GetHealthCheck()
if err != nil {
return ""
}
return health.HealthCheckHttpCode
}
func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
rules, err := self.GetILoadbalancerListenerRules()
if err != nil {
return nil, err
} else {
if err := self.region.UpdateRulesPriority(rules); err != nil {
return nil, err
}
}
ret, err := self.region.CreateElbListenerRule(self.GetId(), rule)
if err != nil {
return nil, err
}
ret.listener = self
ret.region = self.region
return ret, nil
}
func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
rule, err := self.region.GetElbListenerRuleById(ruleId)
if err != nil {
return nil, err
}
rule.listener = self
return rule, nil
}
func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) {
rules, err := self.region.GetElbListenerRules(self.GetId(), "")
if err != nil {
return nil, err
}
irules := make([]cloudprovider.ICloudLoadbalancerListenerRule, len(rules))
for i := range rules {
rules[i].listener = self
irules[i] = &rules[i]
}
return irules, nil
}
func (self *SElbListener) GetStickySession() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
session, err := group.GetStickySession()
if err != nil {
return ""
}
return session.StickySession
}
func (self *SElbListener) GetStickySessionType() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
session, err := group.GetStickySession()
if err != nil {
return ""
}
return session.StickySessionType
}
func (self *SElbListener) GetStickySessionCookie() string {
group, err := self.getBackendGroup()
if err != nil {
return ""
}
session, err := group.GetStickySession()
if err != nil {
return ""
}
return session.StickySessionCookie
}
func (self *SElbListener) GetStickySessionCookieTimeout() int {
group, err := self.getBackendGroup()
if err != nil {
return 0
}
session, err := group.GetStickySession()
if err != nil {
return 0
}
return session.StickySessionCookieTimeout
}
func (self *SElbListener) XForwardedForEnabled() bool {
return false
}
func (self *SElbListener) GzipEnabled() bool {
return false
}
func (self *SElbListener) GetCertificateId() string {
if len(self.Certificates) > 0 {
return self.Certificates[0].CertificateArn
}
return ""
}
func (self *SElbListener) GetTLSCipherPolicy() string {
return self.SSLPolicy
}
func (self *SElbListener) HTTP2Enabled() bool {
return false
}
func (self *SElbListener) Start() error {
return nil
}
func (self *SElbListener) Stop() error {
return cloudprovider.ErrNotSupported
}
func (self *SElbListener) Sync(listener *cloudprovider.SLoadbalancerListener) error {
return self.region.SyncElbListener(self, listener)
}
func (self *SElbListener) Delete() error {
return self.region.DeleteElbListener(self.GetId())
}
func (self *SRegion) GetElbListeners(elbId string) ([]SElbListener, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeListenersInput{}
params.SetLoadBalancerArn(elbId)
ret, err := client.DescribeListeners(params)
if err != nil {
return nil, err
}
listeners := []SElbListener{}
err = unmarshalAwsOutput(ret, "Listeners", &listeners)
if err != nil {
return nil, err
}
for i := range listeners {
listeners[i].region = self
}
return listeners, nil
}
func unmarshalAwsOutput(output interface{}, respKey string, result interface{}) error {
_ret, err := json.Marshal(output)
if err != nil {
return err
}
obj, err := jsonutils.Parse(_ret)
if err != nil {
return err
}
if len(respKey) == 0 {
err = obj.Unmarshal(result)
if err != nil {
return err
}
} else {
err = obj.Unmarshal(result, respKey)
if err != nil {
return err
}
}
return nil
}
func (self *SRegion) GetElbListener(listenerId string) (*SElbListener, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeListenersInput{}
params.SetListenerArns([]*string{&listenerId})
ret, err := client.DescribeListeners(params)
if err != nil {
return nil, err
}
listeners := []SElbListener{}
err = unmarshalAwsOutput(ret, "Listeners", &listeners)
if err != nil {
return nil, err
}
if len(listeners) == 1 {
listeners[0].region = self
return &listeners[0], nil
}
return nil, ErrorNotFound()
}
func (self *SRegion) CreateElbListener(listener *cloudprovider.SLoadbalancerListener) (*SElbListener, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
listenerType := strings.ToUpper(listener.ListenerType)
params := &elbv2.CreateListenerInput{}
params.SetLoadBalancerArn(listener.LoadbalancerID)
params.SetPort(int64(listener.ListenerPort))
params.SetProtocol(listenerType)
action := &elbv2.Action{}
action.SetType("forward")
action.SetTargetGroupArn(listener.BackendGroupID)
params.SetDefaultActions([]*elbv2.Action{action})
if listenerType == "HTTPS" {
cert := &elbv2.Certificate{
CertificateArn: &listener.CertificateID,
}
params.SetCertificates([]*elbv2.Certificate{cert})
params.SetSslPolicy("ELBSecurityPolicy-2016-08")
}
ret, err := client.CreateListener(params)
if err != nil {
return nil, err
}
listeners := []SElbListener{}
err = unmarshalAwsOutput(ret, "Listeners", &listeners)
if err != nil {
return nil, err
}
if len(listeners) == 1 {
listeners[0].region = self
return &listeners[0], nil
}
return nil, fmt.Errorf("CreateElbListener err %#v", listeners)
}
func (self *SRegion) GetElbListenerRules(listenerId string, ruleId string) ([]SElbListenerRule, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeRulesInput{}
if len(listenerId) > 0 {
params.SetListenerArn(listenerId)
}
if len(ruleId) > 0 {
params.SetRuleArns([]*string{&ruleId})
}
ret, err := client.DescribeRules(params)
if err != nil {
return nil, err
}
rules := []SElbListenerRule{}
err = unmarshalAwsOutput(ret, "Rules", &rules)
if err != nil {
return nil, err
}
for i := range rules {
rules[i].region = self
}
return rules, nil
}
func (self *SRegion) GetElbListenerRuleById(ruleId string) (*SElbListenerRule, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeRulesInput{}
if len(ruleId) > 0 {
params.SetRuleArns([]*string{&ruleId})
}
ret, err := client.DescribeRules(params)
if err != nil {
return nil, err
}
rules := []SElbListenerRule{}
err = unmarshalAwsOutput(ret, "Rules", &rules)
if err != nil {
return nil, err
}
if len(rules) == 1 {
rules[0].region = self
return &rules[0], nil
} else {
log.Errorf("GetElbListenerRuleById %s %d found", ruleId, len(rules))
return nil, ErrorNotFound()
}
}
func (self *SRegion) DeleteElbListener(listenerId string) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
params := &elbv2.DeleteListenerInput{}
params.SetListenerArn(listenerId)
_, err = client.DeleteListener(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) SyncElbListener(listener *SElbListener, config *cloudprovider.SLoadbalancerListener) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
params := &elbv2.ModifyListenerInput{}
params.SetListenerArn(listener.GetId())
params.SetPort(int64(config.ListenerPort))
params.SetProtocol(strings.ToUpper(config.ListenerType))
action := &elbv2.Action{}
action.SetType("forward")
action.SetTargetGroupArn(config.BackendGroupID)
params.SetDefaultActions([]*elbv2.Action{action})
if config.ListenerType == api.LB_LISTENER_TYPE_HTTPS {
cert := &elbv2.Certificate{}
cert.SetCertificateArn(config.CertificateID)
params.SetCertificates([]*elbv2.Certificate{cert})
}
_, err = client.ModifyListener(params)
if err != nil {
return err
}
hc := &cloudprovider.SLoadbalancerHealthCheck{
HealthCheckType: config.HealthCheckType,
HealthCheckReq: config.HealthCheckReq,
HealthCheckExp: config.HealthCheckExp,
HealthCheck: config.HealthCheck,
HealthCheckTimeout: config.HealthCheckTimeout,
HealthCheckDomain: config.HealthCheckDomain,
HealthCheckHttpCode: config.HealthCheckHttpCode,
HealthCheckURI: config.HealthCheckURI,
HealthCheckInterval: config.HealthCheckInterval,
HealthCheckRise: config.HealthCheckRise,
HealthCheckFail: config.HealthCheckFail,
}
err = self.modifyELbBackendGroup(config.BackendGroupID, hc)
if err != nil {
return errors.Wrap(err, "region.SyncElbListener.updateELbBackendGroup")
}
return nil
}
func (self *SRegion) UpdateRulesPriority(rules []cloudprovider.ICloudLoadbalancerListenerRule) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
ps := []*elbv2.RulePriorityPair{}
for i := range rules {
rule := rules[i].(*SElbListenerRule)
if !rule.IsDefault {
v, _ := strconv.Atoi(rule.Priority)
p := &elbv2.RulePriorityPair{}
p.SetRuleArn(rules[i].GetId())
p.SetPriority(int64(v + 1))
ps = append(ps, p)
}
}
if len(ps) == 0 {
return nil
}
params := &elbv2.SetRulePrioritiesInput{}
params.SetRulePriorities(ps)
_, err = client.SetRulePriorities(params)
if err != nil {
return err
}
return nil
}
+464
View File
@@ -0,0 +1,464 @@
package aws
import (
"encoding/json"
"fmt"
"strings"
"github.com/aws/aws-sdk-go/service/elbv2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SElbListenerRule struct {
listener *SElbListener
region *SRegion
Priority string `json:"Priority"`
IsDefault bool `json:"IsDefault"`
Actions []Action `json:"Actions"`
RuleArn string `json:"RuleArn"`
Conditions []Condition `json:"Conditions"`
}
type Action struct {
TargetGroupArn string `json:"TargetGroupArn"`
Type string `json:"Type"`
}
type Condition struct {
Field string `json:"field"`
HTTPRequestMethodConfig *Config `json:"httpRequestMethodConfig,omitempty"`
Values []string `json:"values"`
SourceIPConfig *Config `json:"sourceIpConfig,omitempty"`
QueryStringConfig *QueryStringConfig `json:"queryStringConfig,omitempty"`
HTTPHeaderConfig *HTTPHeaderConfig `json:"httpHeaderConfig,omitempty"`
PathPatternConfig *Config `json:"pathPatternConfig,omitempty"`
HostHeaderConfig *Config `json:"hostHeaderConfig,omitempty"`
}
type HTTPHeaderConfig struct {
HTTPHeaderName string `json:"HttpHeaderName"`
Values []string `json:"values"`
}
type Config struct {
Values []string `json:"values"`
}
type QueryStringConfig struct {
Values []Query `json:"values"`
}
type Query struct {
Key string `json:"key"`
Value string `json:"value"`
}
func (self *SElbListenerRule) GetId() string {
return self.RuleArn
}
func (self *SElbListenerRule) GetName() string {
return self.RuleArn
}
func (self *SElbListenerRule) GetGlobalId() string {
return self.GetId()
}
func (self *SElbListenerRule) GetStatus() string {
return api.LB_STATUS_ENABLED
}
func (self *SElbListenerRule) Refresh() error {
rule, err := self.region.GetElbListenerRuleById(self.GetId())
if err != nil {
return err
}
err = jsonutils.Update(self, rule)
if err != nil {
return err
}
return nil
}
func (self *SElbListenerRule) IsEmulated() bool {
return false
}
func (self *SElbListenerRule) GetMetadata() *jsonutils.JSONDict {
return jsonutils.NewDict()
}
func (self *SElbListenerRule) GetProjectId() string {
return ""
}
func (self *SElbListenerRule) GetDomain() string {
for _, condition := range self.Conditions {
if condition.Field == "host-header" {
return strings.Join(condition.Values, ",")
}
}
return ""
}
func (self *SElbListenerRule) GetCondition() string {
conditon, err := json.Marshal(self.Conditions)
if err != nil {
log.Errorf("GetCondition %s", err)
return ""
}
return string(conditon)
}
func (self *SElbListenerRule) GetPath() string {
for _, condition := range self.Conditions {
if condition.Field == "path-pattern" {
return strings.Join(condition.Values, ",")
}
}
return ""
}
func (self *SElbListenerRule) GetBackendGroupId() string {
for _, action := range self.Actions {
if action.Type == "forward" {
return action.TargetGroupArn
}
}
return ""
}
func (self *SElbListenerRule) Delete() error {
return self.region.DeleteElbListenerRule(self.GetId())
}
func (self *SRegion) DeleteElbListenerRule(ruleId string) error {
client, err := self.GetElbV2Client()
if err != nil {
return err
}
params := &elbv2.DeleteRuleInput{}
params.SetRuleArn(ruleId)
_, err = client.DeleteRule(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) CreateElbListenerRule(listenerId string, config *cloudprovider.SLoadbalancerListenerRule) (*SElbListenerRule, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
forward := "forward"
action := &elbv2.Action{
TargetGroupArn: &config.BackendGroupID,
Type: &forward,
}
condtions, err := parseConditions(config.Condition)
if err != nil {
return nil, err
}
params := &elbv2.CreateRuleInput{}
params.SetListenerArn(listenerId)
params.SetActions([]*elbv2.Action{action})
params.SetConditions(condtions)
params.SetPriority(int64(1))
ret, err := client.CreateRule(params)
if err != nil {
return nil, err
}
rule := SElbListenerRule{}
err = unmarshalAwsOutput(ret, "", &rule)
if err != nil {
return nil, err
}
rule.region = self
return &rule, nil
}
func parseConditions(conditions string) ([]*elbv2.RuleCondition, error) {
obj, err := jsonutils.ParseString(conditions)
if err != nil {
return nil, err
}
conditionArray, ok := obj.(*jsonutils.JSONArray)
if !ok {
return nil, fmt.Errorf("parseConditions invalid condition fromat.")
}
ret := []*elbv2.RuleCondition{}
cs := conditionArray.Value()
for i := range cs {
c, err := parseCondition(cs[i])
if err != nil {
return nil, err
}
ret = append(ret, c)
}
return ret, nil
}
func parseCondition(condition jsonutils.JSONObject) (*elbv2.RuleCondition, error) {
conditionDict, ok := condition.(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("parseCondition invalid condition fromat.")
}
dict := conditionDict.Value()
field, ok := dict["field"]
if !ok {
return nil, fmt.Errorf("parseCondition invalid condition, missing field: %#v", condition)
}
f, _ := field.GetString()
switch f {
case "http-header":
return parseHttpHeaderCondition(conditionDict)
case "path-pattern":
return parsePathPatternCondition(conditionDict)
case "http-request-method":
return parseRequestModthdCondition(conditionDict)
case "host-header":
return parseHostHeaderCondition(conditionDict)
case "query-string":
return parseQueryStringCondition(conditionDict)
case "source-ip":
return parseSourceIpCondition(conditionDict)
default:
return nil, fmt.Errorf("parseCondition invalid condition key %#v", field)
}
}
func parseHttpHeaderCondition(conditon *jsonutils.JSONDict) (*elbv2.RuleCondition, error) {
ret := &elbv2.RuleCondition{}
ret.SetField("http-header")
values, err := conditon.GetMap("httpHeaderConfig")
if err != nil {
return nil, err
}
name, ok := values["HttpHeaderName"]
if !ok {
return nil, fmt.Errorf("parseHttpHeaderCondition missing filed HttpHeaderName")
}
nameObj, ok := name.(*jsonutils.JSONString)
if !ok {
return nil, fmt.Errorf("parseHttpHeaderCondition missing invalid data %#v", name)
}
config := &elbv2.HttpHeaderConditionConfig{}
config.SetHttpHeaderName(nameObj.Value())
vs, ok := values["values"]
if !ok {
return nil, fmt.Errorf("parseHttpHeaderCondition missing filed values")
}
_vs, err := parseConditionStringArrayValues(vs)
if err != nil {
return nil, err
}
config.SetValues(_vs)
ret.SetHttpHeaderConfig(config)
return ret, nil
}
func parsePathPatternCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) {
ret := &elbv2.RuleCondition{}
ret.SetField("path-pattern")
values, err := condition.GetMap("pathPatternConfig")
if err != nil {
return nil, err
}
config := &elbv2.PathPatternConditionConfig{}
vs, ok := values["values"]
if !ok {
return nil, fmt.Errorf("parsePathPatternCondition missing filed values")
}
_vs, err := parseConditionStringArrayValues(vs)
if err != nil {
return nil, err
}
config.SetValues(_vs)
ret.SetPathPatternConfig(config)
return ret, nil
}
func parseRequestModthdCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) {
ret := &elbv2.RuleCondition{}
ret.SetField("http-request-method")
values, err := condition.GetMap("httpRequestMethodConfig")
if err != nil {
return nil, err
}
config := &elbv2.HttpRequestMethodConditionConfig{}
vs, ok := values["values"]
if !ok {
return nil, fmt.Errorf("parseRequestModthdCondition missing filed values")
}
_vs, err := parseConditionStringArrayValues(vs)
if err != nil {
return nil, err
}
config.SetValues(_vs)
return ret, nil
}
func parseHostHeaderCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) {
ret := &elbv2.RuleCondition{}
ret.SetField("host-header")
values, err := condition.GetMap("hostHeaderConfig")
if err != nil {
return nil, err
}
config := &elbv2.HostHeaderConditionConfig{}
vs, ok := values["values"]
if !ok {
return nil, fmt.Errorf("parseHostHeaderCondition missing filed values")
}
_vs, err := parseConditionStringArrayValues(vs)
if err != nil {
return nil, err
}
config.SetValues(_vs)
ret.SetHostHeaderConfig(config)
return ret, nil
}
func parseQueryStringCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) {
ret := &elbv2.RuleCondition{}
ret.SetField("query-string")
values, err := condition.GetMap("queryStringConfig")
if err != nil {
return nil, err
}
config := &elbv2.QueryStringConditionConfig{}
vs, ok := values["values"]
if !ok {
return nil, fmt.Errorf("parseQueryStringCondition missing filed values")
}
_vs, err := parseConditionDictArrayValues(vs)
if err != nil {
return nil, err
}
config.SetValues(_vs)
ret.SetQueryStringConfig(config)
return ret, nil
}
func parseSourceIpCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) {
ret := &elbv2.RuleCondition{}
ret.SetField("source-ip")
values, err := condition.GetMap("sourceIpConfig")
if err != nil {
return nil, err
}
config := &elbv2.SourceIpConditionConfig{}
vs, ok := values["values"]
if !ok {
return nil, fmt.Errorf("parseSourceIpCondition missing filed values")
}
_vs, err := parseConditionStringArrayValues(vs)
if err != nil {
return nil, err
}
config.SetValues(_vs)
return ret, nil
}
func parseConditionStringArrayValues(values jsonutils.JSONObject) ([]*string, error) {
objs, ok := values.(*jsonutils.JSONArray)
if !ok {
return nil, fmt.Errorf("parseConditionStringArrayValues invalid values format, required array: %#v", values)
}
ret := []*string{}
vs := objs.Value()
for i := range vs {
v, ok := vs[i].(*jsonutils.JSONString)
if !ok {
return nil, fmt.Errorf("parseConditionStringArrayValues invalid value, required string: %#v", v)
}
_v := v.Value()
ret = append(ret, &_v)
}
return ret, nil
}
func parseConditionDictArrayValues(values jsonutils.JSONObject) ([]*elbv2.QueryStringKeyValuePair, error) {
objs, ok := values.(*jsonutils.JSONArray)
if !ok {
return nil, fmt.Errorf("parseConditionDictArrayValues invalid values format, required array: %#v", values)
}
ret := []*elbv2.QueryStringKeyValuePair{}
vs := objs.Value()
for i := range vs {
v, ok := vs[i].(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("parseConditionDictArrayValues invalid value, required dict: %#v", v)
}
key, err := v.GetString("key")
if err != nil {
return nil, err
}
value, err := v.GetString("value")
if err != nil {
return nil, err
}
pair := &elbv2.QueryStringKeyValuePair{}
pair.SetKey(key)
pair.SetValue(value)
ret = append(ret, pair)
}
return ret, nil
}
+1 -1
View File
@@ -170,7 +170,7 @@ func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
return &networks[0], nil
}
+222 -30
View File
@@ -34,6 +34,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/s3"
@@ -41,6 +42,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"github.com/aws/aws-sdk-go/service/acm"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
@@ -79,10 +81,12 @@ const (
type SRegion struct {
multicloud.SRegion
client *SAwsClient
ec2Client *ec2.EC2
iamClient *iam.IAM
s3Client *s3.S3
client *SAwsClient
ec2Client *ec2.EC2
iamClient *iam.IAM
s3Client *s3.S3
elbv2Client *elbv2.ELBV2
acmClient *acm.ACM
izones []cloudprovider.ICloudZone
ivpcs []cloudprovider.ICloudVpc
@@ -311,6 +315,20 @@ func (self *SRegion) ec2Request(apiName string, params map[string]string, retval
return jsonRequest(client, apiName, params, retval, true)
}
func (self *SRegion) GetElbV2Client() (*elbv2.ELBV2, error) {
if self.elbv2Client == nil {
s, err := self.getAwsSession()
if err != nil {
return nil, err
}
self.elbv2Client = elbv2.New(s)
}
return self.elbv2Client, nil
}
/////////////////////////////////////////////////////////////////////////////
func (self *SRegion) fetchZones() error {
// todo: 这里将过滤出指定region下全部的zones。是否只过滤出可用的zone即可? The state of the Availability Zone (available | information | impaired | unavailable)
@@ -492,7 +510,7 @@ func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
@@ -507,7 +525,7 @@ func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
@@ -519,11 +537,11 @@ func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
ihost, err := izones[i].GetIHostById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
} else if err != ErrorNotFound() {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
@@ -535,11 +553,11 @@ func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, er
istore, err := izones[i].GetIStorageById(id)
if err == nil {
return istore, nil
} else if err != cloudprovider.ErrNotFound {
} else if err != ErrorNotFound() {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
@@ -584,7 +602,7 @@ func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStorag
if self.storageCache.GetGlobalId() == id {
return self.storageCache, nil
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
@@ -628,7 +646,7 @@ func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error)
return nil, err
}
if total == 0 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
if total > 1 {
return nil, cloudprovider.ErrDuplicateId
@@ -673,40 +691,192 @@ func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, me
return nil, fmt.Errorf("cannot find vswitch %s", networkId)
}
func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeLoadBalancersInput{}
ret, err := client.DescribeLoadBalancers(params)
if err != nil {
return nil, err
}
result := make([]SElb, 0)
err = unmarshalAwsOutput(ret, "LoadBalancers", &result)
if err != nil {
return nil, err
}
ielbs := make([]cloudprovider.ICloudLoadbalancer, len(result))
for i := range result {
result[i].region = self
ielbs[i] = &result[i]
}
return ielbs, nil
}
func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeLoadBalancersInput{}
params.SetLoadBalancerArns([]*string{&loadbalancerId})
ret, err := client.DescribeLoadBalancers(params)
if err != nil {
return nil, err
}
elbs := []SElb{}
err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs)
if err != nil {
return nil, err
}
if len(elbs) == 1 {
elbs[0].region = self
return &elbs[0], nil
}
return nil, ErrorNotFound()
}
func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) getElbAttributesById(loadbalancerId string) (map[string]string, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.DescribeLoadBalancerAttributesInput{}
params.SetLoadBalancerArn(loadbalancerId)
output, err := client.DescribeLoadBalancerAttributes(params)
if err != nil {
return nil, err
}
attrs := []map[string]string{}
err = unmarshalAwsOutput(output, "Attributes", &attrs)
if err != nil {
return nil, err
}
ret := map[string]string{}
for i := range attrs {
for k, v := range attrs[i] {
ret[k] = v
}
}
return ret, nil
}
func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
return nil, cloudprovider.ErrNotSupported
}
func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
certs, err := self.GetILoadBalancerCertificates()
if err != nil {
return nil, err
}
for i := range certs {
if certs[i].GetId() == certId {
return certs[i], nil
}
}
return nil, ErrorNotFound()
}
func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
client, err := self.getIamClient()
if err != nil {
return nil, err
}
params := &iam.UploadServerCertificateInput{}
params.SetServerCertificateName(cert.Name)
params.SetPrivateKey(cert.PrivateKey)
params.SetCertificateBody(cert.Certificate)
ret, err := client.UploadServerCertificate(params)
if err != nil {
return nil, err
}
return self.GetILoadBalancerCertificateById(*ret.ServerCertificateMetadata.ServerCertificateId)
}
func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
return nil, cloudprovider.ErrNotSupported
}
func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
client, err := self.getIamClient()
if err != nil {
return nil, err
}
params := &iam.ListServerCertificatesInput{}
ret, err := client.ListServerCertificates(params)
if err != nil {
return nil, err
}
certs := []SElbCertificate{}
err = unmarshalAwsOutput(ret, "ServerCertificateMetadataList", &certs)
if err != nil {
return nil, err
}
icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs))
for i := range certs {
certs[i].region = self
icerts[i] = &certs[i]
}
return icerts, nil
}
func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
return nil, cloudprovider.ErrNotImplemented
func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) {
client, err := self.GetElbV2Client()
if err != nil {
return nil, err
}
params := &elbv2.CreateLoadBalancerInput{}
params.SetName(loadbalancer.Name)
params.SetType(loadbalancer.LoadbalancerSpec)
params.SetIpAddressType("ipv4")
if loadbalancer.AddressType == api.LB_ADDR_TYPE_INTERNET {
params.SetScheme("internet-facing")
} else {
params.SetScheme("internal")
}
// params.SetSecurityGroups()
params.SetSubnets(ConvertedList(loadbalancer.NetworkIDs))
ret, err := client.CreateLoadBalancer(params)
if err != nil {
return nil, err
}
elbs := []SElb{}
err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs)
if err != nil {
return nil, err
}
if len(elbs) == 1 {
elbs[0].region = self
return &elbs[0], nil
}
return nil, fmt.Errorf("CreateILoadBalancer error %#v", elbs)
}
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
@@ -814,3 +984,25 @@ func (region *SRegion) getS3Endpoint() string {
func (region *SRegion) getEc2Endpoint() string {
return region.RegionEndpoint
}
func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
return nil, cloudprovider.ErrNotSupported
}
func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
backendgroups, err := self.GetElbBackendgroups("", nil)
if err != nil {
return nil, err
}
ret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(backendgroups))
for i := range backendgroups {
ret[i] = &backendgroups[i]
}
return ret, nil
}
+3 -3
View File
@@ -84,7 +84,7 @@ func (self *SSnapshot) Refresh() error {
if snapshots, total, err := self.region.GetSnapshots("", "", "", []string{self.SnapshotId}, 0, 1); err != nil {
return err
} else if total != 1 {
return cloudprovider.ErrNotFound
return ErrorNotFound()
} else if err := jsonutils.Update(self, snapshots[0]); err != nil {
return err
}
@@ -141,7 +141,7 @@ func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName
err = parseNotFoundError(err)
if err != nil {
if strings.Contains(err.Error(), "InvalidSnapshot.NotFound") {
return nil, 0, cloudprovider.ErrNotFound
return nil, 0, ErrorNotFound()
}
return nil, 0, err
@@ -176,7 +176,7 @@ func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSn
if snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil {
return nil, err
} else if total != 1 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
} else {
return &snapshots[0], nil
}
+1 -1
View File
@@ -224,7 +224,7 @@ func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.To
for {
_, err = self.region.GetImageByName(imageName, ImageOwnerSelf)
if err != nil {
if err == cloudprovider.ErrNotFound {
if err == ErrorNotFound() {
break
} else {
return "", err
+11 -5
View File
@@ -19,14 +19,15 @@ import (
"net"
"reflect"
"regexp"
"runtime/debug"
"sort"
"strings"
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/pkg/util/secrules"
)
@@ -133,9 +134,9 @@ func AppendSingleValueFilter(filters []*ec2.Filter, name string, value string) [
func ConvertedList(list []string) []*string {
result := make([]*string, 0)
for _, item := range list {
if len(item) > 0 {
result = append(result, &item)
for i := range list {
if len(list[i]) > 0 {
result = append(result, &list[i])
}
}
@@ -491,8 +492,13 @@ func parseNotFoundError(err error) error {
}
if strings.Contains(err.Error(), ".NotFound") {
return cloudprovider.ErrNotFound
return ErrorNotFound()
} else {
return err
}
}
func ErrorNotFound() error {
log.Errorf("Not found: %s", string(debug.Stack()))
return cloudprovider.ErrNotFound
}
+2 -2
View File
@@ -151,7 +151,7 @@ func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error)
return self.iwires[i], nil
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) {
@@ -255,7 +255,7 @@ func (self *SRegion) getVpc(vpcId string) (*SVpc, error) {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
vpcs[0].region = self
return &vpcs[0], nil
+2 -2
View File
@@ -90,7 +90,7 @@ func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, e
return networks[i], nil
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
@@ -103,7 +103,7 @@ func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudp
network := self.getNetworkById(networkId)
if network == nil {
log.Errorf("cannot find network after create????")
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
return network, nil
}
+2 -2
View File
@@ -140,7 +140,7 @@ func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
if host.GetGlobalId() == id {
return host, nil
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
@@ -159,7 +159,7 @@ func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, erro
return self.istorages[i], nil
}
}
return nil, cloudprovider.ErrNotFound
return nil, ErrorNotFound()
}
func (self *SZone) getStorageByCategory(category string) (*SStorage, error) {
+4
View File
@@ -57,6 +57,10 @@ type SRegion struct {
Longitude string
}
func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
/////////////////////////////////////////////////////////////////////////////
func (self *SRegion) Refresh() error {
// do nothing
+4
View File
@@ -145,3 +145,7 @@ func (cli *SESXiClient) GetIStoragecacheById(idstr string) (cloudprovider.ICloud
func (cli *SESXiClient) GetISkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
return nil, cloudprovider.ErrNotSupported
}
func (cli *SESXiClient) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
+3 -3
View File
@@ -65,7 +65,7 @@ type Pool struct {
}
func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) {
return nil, cloudprovider.ErrNotImplemented
return self.eip, nil
}
func (self *SLoadbalancer) GetId() string {
@@ -120,8 +120,8 @@ func (self *SLoadbalancer) GetNetworkType() string {
return api.LB_NETWORK_TYPE_VPC
}
func (self *SLoadbalancer) GetNetworkId() string {
return self.VipSubnetID
func (self *SLoadbalancer) GetNetworkIds() []string {
return []string{self.VipSubnetID}
}
func (self *SLoadbalancer) GetNetwork() *SNetwork {
@@ -26,6 +26,10 @@ type SElbBackendGroup struct {
SessionPersistence StickySession `json:"session_persistence"`
}
func (self *SElbBackendGroup) GetLoadbalancerId() string {
return self.lb.GetId()
}
type StickySession struct {
Type string `json:"type"`
CookieName string `json:"cookie_name"`
+1 -1
View File
@@ -557,7 +557,7 @@ func (self *SRegion) UpdateLoadBalancerListener(listenerId string, listener *clo
if len(listener.BackendGroupID) > 0 {
listenerObj.Set("default_pool_id", jsonutils.NewString(listener.BackendGroupID))
} else {
listenerObj.Set("zdefault_pool_id", jsonutils.JSONNull)
listenerObj.Set("default_pool_id", jsonutils.JSONNull)
}
if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS {
@@ -119,6 +119,10 @@ func (self *SElbListenerPolicy) GetDomain() string {
return ""
}
func (self *SElbListenerPolicy) GetCondition() string {
return ""
}
func (self *SElbListenerPolicy) GetPath() string {
rules, err := self.GetRules()
if err != nil {
+5 -1
View File
@@ -57,6 +57,10 @@ type SRegion struct {
storageCache *SStoragecache
}
func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetClient() *SHuaweiClient {
return self.client
}
@@ -836,7 +840,7 @@ func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalanc
// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html
func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (SLoadbalancer, error) {
ret := SLoadbalancer{}
subnet, err := self.getNetwork(loadbalancer.NetworkID)
subnet, err := self.getNetwork(loadbalancer.NetworkIDs[0])
if err != nil {
return ret, err
}
+4 -4
View File
@@ -27,10 +27,10 @@ func init() {
}
shellutils.R(&ElbCreateOptions{}, "elb-create", "create loadbalancer", func(cli *huawei.SRegion, args *ElbCreateOptions) error {
loadbalancer := &cloudprovider.SLoadbalancer{
Name: args.Name,
NetworkID: args.SUBNET,
EipID: args.EipID,
Address: args.PrivateIP,
Name: args.Name,
NetworkIDs: []string{args.SUBNET},
EipID: args.EipID,
Address: args.PrivateIP,
}
elb, err := cli.CreateLoadBalancer(loadbalancer)
+4
View File
@@ -41,6 +41,10 @@ type SRegion struct {
storageCache *SStoragecache
}
func (region *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (region *SRegion) GetClient() *SOpenStackClient {
return region.client
}
+2 -2
View File
@@ -273,8 +273,8 @@ func (self *SLoadbalancer) GetNetworkType() string {
return api.LB_NETWORK_TYPE_VPC
}
func (self *SLoadbalancer) GetNetworkId() string {
return self.SubnetId
func (self *SLoadbalancer) GetNetworkIds() []string {
return []string{self.SubnetId}
}
func (self *SLoadbalancer) GetVpcId() string {
@@ -32,6 +32,10 @@ type SLBBackendGroup struct {
rule *SLBListenerRule // tcp、udp、tcp_ssl监听rule 为nil
}
func (self *SLBBackendGroup) GetLoadbalancerId() string {
return self.lb.GetId()
}
func (self *SLBBackendGroup) GetProtocolType() string {
return ""
}
@@ -90,6 +90,10 @@ func (self *SLBListenerRule) GetDomain() string {
return self.Domain
}
func (self *SLBListenerRule) GetCondition() string {
return ""
}
func (self *SLBListenerRule) GetPath() string {
return self.URL
}
+9 -1
View File
@@ -57,6 +57,14 @@ type SRegion struct {
fetchLocation bool
}
func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
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 {
@@ -181,7 +189,7 @@ func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalanc
}
if loadbalancer.AddressType != api.LB_ADDR_TYPE_INTERNET {
params["SubnetId"] = loadbalancer.NetworkID
params["SubnetId"] = loadbalancer.NetworkIDs[0]
}
resp, err := self.clbRequest("CreateLoadBalancer", params)
+4
View File
@@ -45,6 +45,10 @@ type SRegion struct {
fetchLocation bool
}
func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SRegion) GetId() string {
return self.RegionID
}
+4
View File
@@ -39,6 +39,10 @@ type SRegion struct {
ivpcs []cloudprovider.ICloudVpc
}
func (region *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (region *SRegion) GetClient() *SZStackClient {
return region.client
}
+1 -1
View File
@@ -1,3 +1,3 @@
AWS SDK for Go
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Copyright 2014-2015 Stripe, Inc.
+21 -2
View File
@@ -138,8 +138,27 @@ type RequestFailure interface {
RequestID() string
}
// NewRequestFailure returns a new request error wrapper for the given Error
// provided.
// NewRequestFailure returns a wrapped error with additional information for
// request status code, and service requestID.
//
// Should be used to wrap all request which involve service requests. Even if
// the request failed without a service response, but had an HTTP status code
// that may be meaningful.
func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure {
return newRequestError(err, statusCode, reqID)
}
// UnmarshalError provides the interface for the SDK failing to unmarshal data.
type UnmarshalError interface {
awsError
Bytes() []byte
}
// NewUnmarshalError returns an initialized UnmarshalError error wrapper adding
// the bytes that fail to unmarshal to the error.
func NewUnmarshalError(err error, msg string, bytes []byte) UnmarshalError {
return &unmarshalError{
awsError: New("UnmarshalError", msg, err),
bytes: bytes,
}
}
+29 -2
View File
@@ -1,6 +1,9 @@
package awserr
import "fmt"
import (
"encoding/hex"
"fmt"
)
// SprintError returns a string of the formatted error code.
//
@@ -119,6 +122,7 @@ type requestError struct {
awsError
statusCode int
requestID string
bytes []byte
}
// newRequestError returns a wrapped error with additional information for
@@ -170,6 +174,29 @@ func (r requestError) OrigErrs() []error {
return []error{r.OrigErr()}
}
type unmarshalError struct {
awsError
bytes []byte
}
// Error returns the string representation of the error.
// Satisfies the error interface.
func (e unmarshalError) Error() string {
extra := hex.Dump(e.bytes)
return SprintError(e.Code(), e.Message(), extra, e.OrigErr())
}
// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (e unmarshalError) String() string {
return e.Error()
}
// Bytes returns the bytes that failed to unmarshal.
func (e unmarshalError) Bytes() []byte {
return e.bytes
}
// An error list that satisfies the golang interface
type errorList []error
@@ -181,7 +208,7 @@ func (e errorList) Error() string {
// How do we want to handle the array size being zero
if size := len(e); size > 0 {
for i := 0; i < size; i++ {
msg += fmt.Sprintf("%s", e[i].Error())
msg += e[i].Error()
// We check the next index to see if it is within the slice.
// If it is, then we append a newline. We do this, because unit tests
// could be broken with the additional '\n'
+1 -1
View File
@@ -15,7 +15,7 @@ func DeepEqual(a, b interface{}) bool {
rb := reflect.Indirect(reflect.ValueOf(b))
if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid {
// If the elements are both nil, and of the same type the are equal
// If the elements are both nil, and of the same type they are equal
// If they are of different types they are not equal
return reflect.TypeOf(a) == reflect.TypeOf(b)
} else if raValid != rbValid {
+5 -6
View File
@@ -185,13 +185,12 @@ func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
// SetValueAtPath sets a value at the case insensitive lexical path inside
// of a structure.
func SetValueAtPath(i interface{}, path string, v interface{}) {
if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil {
for _, rval := range rvals {
if rval.Kind() == reflect.Ptr && rval.IsNil() {
continue
}
setValue(rval, v)
rvals := rValuesAtPath(i, path, true, false, v == nil)
for _, rval := range rvals {
if rval.Kind() == reflect.Ptr && rval.IsNil() {
continue
}
setValue(rval, v)
}
}
+12 -13
View File
@@ -23,28 +23,27 @@ func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
case reflect.Struct:
buf.WriteString("{\n")
names := []string{}
for i := 0; i < v.Type().NumField(); i++ {
name := v.Type().Field(i).Name
f := v.Field(i)
if name[0:1] == strings.ToLower(name[0:1]) {
ft := v.Type().Field(i)
fv := v.Field(i)
if ft.Name[0:1] == strings.ToLower(ft.Name[0:1]) {
continue // ignore unexported fields
}
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() {
if (fv.Kind() == reflect.Ptr || fv.Kind() == reflect.Slice) && fv.IsNil() {
continue // ignore unset fields
}
names = append(names, name)
}
for i, n := range names {
val := v.FieldByName(n)
buf.WriteString(strings.Repeat(" ", indent+2))
buf.WriteString(n + ": ")
stringValue(val, indent+2, buf)
buf.WriteString(ft.Name + ": ")
if i < len(names)-1 {
buf.WriteString(",\n")
if tag := ft.Tag.Get("sensitive"); tag == "true" {
buf.WriteString("<sensitive>")
} else {
stringValue(fv, indent+2, buf)
}
buf.WriteString(",\n")
}
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
+1 -1
View File
@@ -18,7 +18,7 @@ type Config struct {
// States that the signing name did not come from a modeled source but
// was derived based on other data. Used by service client constructors
// to determine if the signin name can be overriden based on metadata the
// to determine if the signin name can be overridden based on metadata the
// service has.
SigningNameDerived bool
}
+14 -4
View File
@@ -67,10 +67,14 @@ func logRequest(r *request.Request) {
if !bodySeekable {
r.SetReaderBody(aws.ReadSeekCloser(r.HTTPRequest.Body))
}
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
// Body as a NoOpCloser and will not be reset after read by the HTTP
// client reader.
r.ResetBody()
// Reset the request body because dumpRequest will re-wrap the
// r.HTTPRequest's Body as a NoOpCloser and will not be reset after
// read by the HTTP client reader.
if err := r.Error; err != nil {
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
r.ClientInfo.ServiceName, r.Operation.Name, err))
return
}
}
r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
@@ -118,6 +122,12 @@ var LogHTTPResponseHandler = request.NamedHandler{
func logResponse(r *request.Request) {
lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)}
if r.HTTPResponse == nil {
lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
r.ClientInfo.ServiceName, r.Operation.Name, "request's HTTPResponse is nil"))
return
}
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
if logBody {
r.HTTPResponse.Body = &teeReaderCloser{
+18
View File
@@ -239,6 +239,13 @@ type Config struct {
// Key: aws.String("/foo/bar/moo"),
// })
EnableEndpointDiscovery *bool
// DisableEndpointHostPrefix will disable the SDK's behavior of prefixing
// request endpoint hosts with modeled information.
//
// Disabling this feature is useful when you want to use local endpoints
// for testing that do not support the modeled host prefix pattern.
DisableEndpointHostPrefix *bool
}
// NewConfig returns a new Config pointer that can be chained with builder
@@ -399,6 +406,13 @@ func (c *Config) WithEndpointDiscovery(t bool) *Config {
return c
}
// WithDisableEndpointHostPrefix will set whether or not to use modeled host prefix
// when making requests.
func (c *Config) WithDisableEndpointHostPrefix(t bool) *Config {
c.DisableEndpointHostPrefix = &t
return c
}
// MergeIn merges the passed in configs into the existing config object.
func (c *Config) MergeIn(cfgs ...*Config) {
for _, other := range cfgs {
@@ -502,6 +516,10 @@ func mergeInConfig(dst *Config, other *Config) {
if other.EnableEndpointDiscovery != nil {
dst.EnableEndpointDiscovery = other.EnableEndpointDiscovery
}
if other.DisableEndpointHostPrefix != nil {
dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix
}
}
// Copy will return a shallow copy of the Config object. If any additional
@@ -1,8 +1,8 @@
// +build !go1.9
package aws
import (
"time"
)
import "time"
// Context is an copy of the Go v1.7 stdlib's context.Context interface.
// It is represented as a SDK interface to enable you to use the "WithContext"
@@ -35,37 +35,3 @@ type Context interface {
// functions.
Value(key interface{}) interface{}
}
// BackgroundContext returns a context that will never be canceled, has no
// values, and no deadline. This context is used by the SDK to provide
// backwards compatibility with non-context API operations and functionality.
//
// Go 1.6 and before:
// This context function is equivalent to context.Background in the Go stdlib.
//
// Go 1.7 and later:
// The context returned will be the value returned by context.Background()
//
// See https://golang.org/pkg/context for more information on Contexts.
func BackgroundContext() Context {
return backgroundCtx
}
// SleepWithContext will wait for the timer duration to expire, or the context
// is canceled. Which ever happens first. If the context is canceled the Context's
// error will be returned.
//
// Expects Context to always return a non-nil error if the Done channel is closed.
func SleepWithContext(ctx Context, dur time.Duration) error {
t := time.NewTimer(dur)
defer t.Stop()
select {
case <-t.C:
break
case <-ctx.Done():
return ctx.Err()
}
return nil
}
-9
View File
@@ -1,9 +0,0 @@
// +build go1.7
package aws
import "context"
var (
backgroundCtx = context.Background()
)
+11
View File
@@ -0,0 +1,11 @@
// +build go1.9
package aws
import "context"
// Context is an alias of the Go stdlib's context.Context interface.
// It can be used within the SDK's API operation "WithContext" methods.
//
// See https://golang.org/pkg/context on how to use contexts.
type Context = context.Context
@@ -39,3 +39,18 @@ func (e *emptyCtx) String() string {
var (
backgroundCtx = new(emptyCtx)
)
// BackgroundContext returns a context that will never be canceled, has no
// values, and no deadline. This context is used by the SDK to provide
// backwards compatibility with non-context API operations and functionality.
//
// Go 1.6 and before:
// This context function is equivalent to context.Background in the Go stdlib.
//
// Go 1.7 and later:
// The context returned will be the value returned by context.Background()
//
// See https://golang.org/pkg/context for more information on Contexts.
func BackgroundContext() Context {
return backgroundCtx
}
+20
View File
@@ -0,0 +1,20 @@
// +build go1.7
package aws
import "context"
// BackgroundContext returns a context that will never be canceled, has no
// values, and no deadline. This context is used by the SDK to provide
// backwards compatibility with non-context API operations and functionality.
//
// Go 1.6 and before:
// This context function is equivalent to context.Background in the Go stdlib.
//
// Go 1.7 and later:
// The context returned will be the value returned by context.Background()
//
// See https://golang.org/pkg/context for more information on Contexts.
func BackgroundContext() Context {
return context.Background()
}
+24
View File
@@ -0,0 +1,24 @@
package aws
import (
"time"
)
// SleepWithContext will wait for the timer duration to expire, or the context
// is canceled. Which ever happens first. If the context is canceled the Context's
// error will be returned.
//
// Expects Context to always return a non-nil error if the Done channel is closed.
func SleepWithContext(ctx Context, dur time.Duration) error {
t := time.NewTimer(dur)
defer t.Stop()
select {
case <-t.C:
break
case <-ctx.Done():
return ctx.Err()
}
return nil
}
+2 -2
View File
@@ -72,9 +72,9 @@ var ValidateReqSigHandler = request.NamedHandler{
signedTime = r.LastSignedAt
}
// 10 minutes to allow for some clock skew/delays in transmission.
// 5 minutes to allow for some clock skew/delays in transmission.
// Would be improved with aws/aws-sdk-go#423
if signedTime.Add(10 * time.Minute).After(time.Now()) {
if signedTime.Add(5 * time.Minute).After(time.Now()) {
return
}
+1 -1
View File
@@ -17,7 +17,7 @@ var SDKVersionUserAgentHandler = request.NamedHandler{
}
const execEnvVar = `AWS_EXECUTION_ENV`
const execEnvUAKey = `exec_env`
const execEnvUAKey = `exec-env`
// AddHostExecEnvUserAgentHander is a request handler appending the SDK's
// execution environment to the user agent.
+42
View File
@@ -49,8 +49,11 @@
package credentials
import (
"fmt"
"sync"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
)
// AnonymousCredentials is an empty Credential object that can be used as
@@ -81,6 +84,12 @@ type Value struct {
ProviderName string
}
// HasKeys returns if the credentials Value has both AccessKeyID and
// SecretAccessKey value set.
func (v Value) HasKeys() bool {
return len(v.AccessKeyID) != 0 && len(v.SecretAccessKey) != 0
}
// A Provider is the interface for any component which will provide credentials
// Value. A provider is required to manage its own Expired state, and what to
// be expired means.
@@ -97,6 +106,14 @@ type Provider interface {
IsExpired() bool
}
// An Expirer is an interface that Providers can implement to expose the expiration
// time, if known. If the Provider cannot accurately provide this info,
// it should not implement this interface.
type Expirer interface {
// The time at which the credentials are no longer valid
ExpiresAt() time.Time
}
// An ErrorProvider is a stub credentials provider that always returns an error
// this is used by the SDK when construction a known provider is not possible
// due to an error.
@@ -163,6 +180,11 @@ func (e *Expiry) IsExpired() bool {
return e.expiration.Before(curTime())
}
// ExpiresAt returns the expiration time of the credential
func (e *Expiry) ExpiresAt() time.Time {
return e.expiration
}
// A Credentials provides concurrency safe retrieval of AWS credentials Value.
// Credentials will cache the credentials value until they expire. Once the value
// expires the next Get will attempt to retrieve valid credentials.
@@ -255,3 +277,23 @@ func (c *Credentials) IsExpired() bool {
func (c *Credentials) isExpired() bool {
return c.forceRefresh || c.provider.IsExpired()
}
// ExpiresAt provides access to the functionality of the Expirer interface of
// the underlying Provider, if it supports that interface. Otherwise, it returns
// an error.
func (c *Credentials) ExpiresAt() (time.Time, error) {
c.m.RLock()
defer c.m.RUnlock()
expirer, ok := c.provider.(Expirer)
if !ok {
return time.Time{}, awserr.New("ProviderNotExpirer",
fmt.Sprintf("provider %s does not support ExpiresAt()", c.creds.ProviderName),
nil)
}
if c.forceRefresh {
// set expiration time to the distant past
return time.Time{}, nil
}
return expirer.ExpiresAt(), nil
}
@@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/internal/sdkuri"
)
@@ -142,7 +143,8 @@ func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
}
if err := s.Err(); err != nil {
return nil, awserr.New("SerializationError", "failed to read EC2 instance role from metadata service", err)
return nil, awserr.New(request.ErrCodeSerialization,
"failed to read EC2 instance role from metadata service", err)
}
return credsList, nil
@@ -164,7 +166,7 @@ func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCred
respCreds := ec2RoleCredRespBody{}
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil {
return ec2RoleCredRespBody{},
awserr.New("SerializationError",
awserr.New(request.ErrCodeSerialization,
fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName),
err)
}
+10 -5
View File
@@ -39,6 +39,7 @@ import (
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
)
// ProviderName is the name of the credentials provider.
@@ -174,7 +175,7 @@ func unmarshalHandler(r *request.Request) {
out := r.Data.(*getCredentialsOutput)
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil {
r.Error = awserr.New("SerializationError",
r.Error = awserr.New(request.ErrCodeSerialization,
"failed to decode endpoint credentials",
err,
)
@@ -185,11 +186,15 @@ func unmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
var errOut errorOutput
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil {
r.Error = awserr.New("SerializationError",
"failed to decode endpoint credentials",
err,
err := jsonutil.UnmarshalJSONError(&errOut, r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to decode error message", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
// Response body format is not consistent between metadata endpoints.
@@ -0,0 +1,425 @@
/*
Package processcreds is a credential Provider to retrieve `credential_process`
credentials.
WARNING: The following describes a method of sourcing credentials from an external
process. This can potentially be dangerous, so proceed with caution. Other
credential providers should be preferred if at all possible. If using this
option, you should make sure that the config file is as locked down as possible
using security best practices for your operating system.
You can use credentials from a `credential_process` in a variety of ways.
One way is to setup your shared config file, located in the default
location, with the `credential_process` key and the command you want to be
called. You also need to set the AWS_SDK_LOAD_CONFIG environment variable
(e.g., `export AWS_SDK_LOAD_CONFIG=1`) to use the shared config file.
[default]
credential_process = /command/to/call
Creating a new session will use the credential process to retrieve credentials.
NOTE: If there are credentials in the profile you are using, the credential
process will not be used.
// Initialize a session to load credentials.
sess, _ := session.NewSession(&aws.Config{
Region: aws.String("us-east-1")},
)
// Create S3 service client to use the credentials.
svc := s3.New(sess)
Another way to use the `credential_process` method is by using
`credentials.NewCredentials()` and providing a command to be executed to
retrieve credentials:
// Create credentials using the ProcessProvider.
creds := processcreds.NewCredentials("/path/to/command")
// Create service client value configured for credentials.
svc := s3.New(sess, &aws.Config{Credentials: creds})
You can set a non-default timeout for the `credential_process` with another
constructor, `credentials.NewCredentialsTimeout()`, providing the timeout. To
set a one minute timeout:
// Create credentials using the ProcessProvider.
creds := processcreds.NewCredentialsTimeout(
"/path/to/command",
time.Duration(500) * time.Millisecond)
If you need more control, you can set any configurable options in the
credentials using one or more option functions. For example, you can set a two
minute timeout, a credential duration of 60 minutes, and a maximum stdout
buffer size of 2k.
creds := processcreds.NewCredentials(
"/path/to/command",
func(opt *ProcessProvider) {
opt.Timeout = time.Duration(2) * time.Minute
opt.Duration = time.Duration(60) * time.Minute
opt.MaxBufSize = 2048
})
You can also use your own `exec.Cmd`:
// Create an exec.Cmd
myCommand := exec.Command("/path/to/command")
// Create credentials using your exec.Cmd and custom timeout
creds := processcreds.NewCredentialsCommand(
myCommand,
func(opt *processcreds.ProcessProvider) {
opt.Timeout = time.Duration(1) * time.Second
})
*/
package processcreds
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"runtime"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
)
const (
// ProviderName is the name this credentials provider will label any
// returned credentials Value with.
ProviderName = `ProcessProvider`
// ErrCodeProcessProviderParse error parsing process output
ErrCodeProcessProviderParse = "ProcessProviderParseError"
// ErrCodeProcessProviderVersion version error in output
ErrCodeProcessProviderVersion = "ProcessProviderVersionError"
// ErrCodeProcessProviderRequired required attribute missing in output
ErrCodeProcessProviderRequired = "ProcessProviderRequiredError"
// ErrCodeProcessProviderExecution execution of command failed
ErrCodeProcessProviderExecution = "ProcessProviderExecutionError"
// errMsgProcessProviderTimeout process took longer than allowed
errMsgProcessProviderTimeout = "credential process timed out"
// errMsgProcessProviderProcess process error
errMsgProcessProviderProcess = "error in credential_process"
// errMsgProcessProviderParse problem parsing output
errMsgProcessProviderParse = "parse failed of credential_process output"
// errMsgProcessProviderVersion version error in output
errMsgProcessProviderVersion = "wrong version in process output (not 1)"
// errMsgProcessProviderMissKey missing access key id in output
errMsgProcessProviderMissKey = "missing AccessKeyId in process output"
// errMsgProcessProviderMissSecret missing secret acess key in output
errMsgProcessProviderMissSecret = "missing SecretAccessKey in process output"
// errMsgProcessProviderPrepareCmd prepare of command failed
errMsgProcessProviderPrepareCmd = "failed to prepare command"
// errMsgProcessProviderEmptyCmd command must not be empty
errMsgProcessProviderEmptyCmd = "command must not be empty"
// errMsgProcessProviderPipe failed to initialize pipe
errMsgProcessProviderPipe = "failed to initialize pipe"
// DefaultDuration is the default amount of time in minutes that the
// credentials will be valid for.
DefaultDuration = time.Duration(15) * time.Minute
// DefaultBufSize limits buffer size from growing to an enormous
// amount due to a faulty process.
DefaultBufSize = 1024
// DefaultTimeout default limit on time a process can run.
DefaultTimeout = time.Duration(1) * time.Minute
)
// ProcessProvider satisfies the credentials.Provider interface, and is a
// client to retrieve credentials from a process.
type ProcessProvider struct {
staticCreds bool
credentials.Expiry
originalCommand []string
// Expiry duration of the credentials. Defaults to 15 minutes if not set.
Duration time.Duration
// ExpiryWindow will allow the credentials to trigger refreshing prior to
// the credentials actually expiring. This is beneficial so race conditions
// with expiring credentials do not cause request to fail unexpectedly
// due to ExpiredTokenException exceptions.
//
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
// 10 seconds before the credentials are actually expired.
//
// If ExpiryWindow is 0 or less it will be ignored.
ExpiryWindow time.Duration
// A string representing an os command that should return a JSON with
// credential information.
command *exec.Cmd
// MaxBufSize limits memory usage from growing to an enormous
// amount due to a faulty process.
MaxBufSize int
// Timeout limits the time a process can run.
Timeout time.Duration
}
// NewCredentials returns a pointer to a new Credentials object wrapping the
// ProcessProvider. The credentials will expire every 15 minutes by default.
func NewCredentials(command string, options ...func(*ProcessProvider)) *credentials.Credentials {
p := &ProcessProvider{
command: exec.Command(command),
Duration: DefaultDuration,
Timeout: DefaultTimeout,
MaxBufSize: DefaultBufSize,
}
for _, option := range options {
option(p)
}
return credentials.NewCredentials(p)
}
// NewCredentialsTimeout returns a pointer to a new Credentials object with
// the specified command and timeout, and default duration and max buffer size.
func NewCredentialsTimeout(command string, timeout time.Duration) *credentials.Credentials {
p := NewCredentials(command, func(opt *ProcessProvider) {
opt.Timeout = timeout
})
return p
}
// NewCredentialsCommand returns a pointer to a new Credentials object with
// the specified command, and default timeout, duration and max buffer size.
func NewCredentialsCommand(command *exec.Cmd, options ...func(*ProcessProvider)) *credentials.Credentials {
p := &ProcessProvider{
command: command,
Duration: DefaultDuration,
Timeout: DefaultTimeout,
MaxBufSize: DefaultBufSize,
}
for _, option := range options {
option(p)
}
return credentials.NewCredentials(p)
}
type credentialProcessResponse struct {
Version int
AccessKeyID string `json:"AccessKeyId"`
SecretAccessKey string
SessionToken string
Expiration *time.Time
}
// Retrieve executes the 'credential_process' and returns the credentials.
func (p *ProcessProvider) Retrieve() (credentials.Value, error) {
out, err := p.executeCredentialProcess()
if err != nil {
return credentials.Value{ProviderName: ProviderName}, err
}
// Serialize and validate response
resp := &credentialProcessResponse{}
if err = json.Unmarshal(out, resp); err != nil {
return credentials.Value{ProviderName: ProviderName}, awserr.New(
ErrCodeProcessProviderParse,
fmt.Sprintf("%s: %s", errMsgProcessProviderParse, string(out)),
err)
}
if resp.Version != 1 {
return credentials.Value{ProviderName: ProviderName}, awserr.New(
ErrCodeProcessProviderVersion,
errMsgProcessProviderVersion,
nil)
}
if len(resp.AccessKeyID) == 0 {
return credentials.Value{ProviderName: ProviderName}, awserr.New(
ErrCodeProcessProviderRequired,
errMsgProcessProviderMissKey,
nil)
}
if len(resp.SecretAccessKey) == 0 {
return credentials.Value{ProviderName: ProviderName}, awserr.New(
ErrCodeProcessProviderRequired,
errMsgProcessProviderMissSecret,
nil)
}
// Handle expiration
p.staticCreds = resp.Expiration == nil
if resp.Expiration != nil {
p.SetExpiration(*resp.Expiration, p.ExpiryWindow)
}
return credentials.Value{
ProviderName: ProviderName,
AccessKeyID: resp.AccessKeyID,
SecretAccessKey: resp.SecretAccessKey,
SessionToken: resp.SessionToken,
}, nil
}
// IsExpired returns true if the credentials retrieved are expired, or not yet
// retrieved.
func (p *ProcessProvider) IsExpired() bool {
if p.staticCreds {
return false
}
return p.Expiry.IsExpired()
}
// prepareCommand prepares the command to be executed.
func (p *ProcessProvider) prepareCommand() error {
var cmdArgs []string
if runtime.GOOS == "windows" {
cmdArgs = []string{"cmd.exe", "/C"}
} else {
cmdArgs = []string{"sh", "-c"}
}
if len(p.originalCommand) == 0 {
p.originalCommand = make([]string, len(p.command.Args))
copy(p.originalCommand, p.command.Args)
// check for empty command because it succeeds
if len(strings.TrimSpace(p.originalCommand[0])) < 1 {
return awserr.New(
ErrCodeProcessProviderExecution,
fmt.Sprintf(
"%s: %s",
errMsgProcessProviderPrepareCmd,
errMsgProcessProviderEmptyCmd),
nil)
}
}
cmdArgs = append(cmdArgs, p.originalCommand...)
p.command = exec.Command(cmdArgs[0], cmdArgs[1:]...)
p.command.Env = os.Environ()
return nil
}
// executeCredentialProcess starts the credential process on the OS and
// returns the results or an error.
func (p *ProcessProvider) executeCredentialProcess() ([]byte, error) {
if err := p.prepareCommand(); err != nil {
return nil, err
}
// Setup the pipes
outReadPipe, outWritePipe, err := os.Pipe()
if err != nil {
return nil, awserr.New(
ErrCodeProcessProviderExecution,
errMsgProcessProviderPipe,
err)
}
p.command.Stderr = os.Stderr // display stderr on console for MFA
p.command.Stdout = outWritePipe // get creds json on process's stdout
p.command.Stdin = os.Stdin // enable stdin for MFA
output := bytes.NewBuffer(make([]byte, 0, p.MaxBufSize))
stdoutCh := make(chan error, 1)
go readInput(
io.LimitReader(outReadPipe, int64(p.MaxBufSize)),
output,
stdoutCh)
execCh := make(chan error, 1)
go executeCommand(*p.command, execCh)
finished := false
var errors []error
for !finished {
select {
case readError := <-stdoutCh:
errors = appendError(errors, readError)
finished = true
case execError := <-execCh:
err := outWritePipe.Close()
errors = appendError(errors, err)
errors = appendError(errors, execError)
if errors != nil {
return output.Bytes(), awserr.NewBatchError(
ErrCodeProcessProviderExecution,
errMsgProcessProviderProcess,
errors)
}
case <-time.After(p.Timeout):
finished = true
return output.Bytes(), awserr.NewBatchError(
ErrCodeProcessProviderExecution,
errMsgProcessProviderTimeout,
errors) // errors can be nil
}
}
out := output.Bytes()
if runtime.GOOS == "windows" {
// windows adds slashes to quotes
out = []byte(strings.Replace(string(out), `\"`, `"`, -1))
}
return out, nil
}
// appendError conveniently checks for nil before appending slice
func appendError(errors []error, err error) []error {
if err != nil {
return append(errors, err)
}
return errors
}
func executeCommand(cmd exec.Cmd, exec chan error) {
// Start the command
err := cmd.Start()
if err == nil {
err = cmd.Wait()
}
exec <- err
}
func readInput(r io.Reader, w io.Writer, read chan error) {
tee := io.TeeReader(r, w)
_, err := ioutil.ReadAll(tee)
if err == io.EOF {
err = nil
}
read <- err // will only arrive here when write end of pipe is closed
}

Some files were not shown because too many files have changed in this diff Show More