mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
aws elb support
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -22,6 +22,10 @@ import (
|
||||
type SFakeOnPremiseRegion struct {
|
||||
}
|
||||
|
||||
func (region *SFakeOnPremiseRegion) GetILoadBalancerBackendGroups() ([]ICloudLoadbalancerBackendGroup, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (region *SFakeOnPremiseRegion) GetId() string {
|
||||
return "default"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 .后端云服务器组的后端协议。
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ func InitDB() error {
|
||||
SecurityGroupManager,
|
||||
NetworkManager,
|
||||
LoadbalancerCertificateManager,
|
||||
LoadbalancerAclManager,
|
||||
LoadbalancerManager,
|
||||
LoadbalancerListenerManager,
|
||||
LoadbalancerListenerRuleManager,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
// required:backend,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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ""
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Generated
Vendored
+3
-37
@@ -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
@@ -1,9 +0,0 @@
|
||||
// +build go1.7
|
||||
|
||||
package aws
|
||||
|
||||
import "context"
|
||||
|
||||
var (
|
||||
backgroundCtx = context.Background()
|
||||
)
|
||||
+11
@@ -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
|
||||
Generated
Vendored
+15
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Generated
Vendored
+4
-2
@@ -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
@@ -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.
|
||||
|
||||
+425
@@ -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
Reference in New Issue
Block a user