mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-21 00:24:07 +08:00
430 lines
16 KiB
Go
430 lines
16 KiB
Go
// Copyright 2019 Yunion
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
package regiondrivers
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
"unicode"
|
||
|
||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||
"yunion.io/x/jsonutils"
|
||
"yunion.io/x/pkg/errors"
|
||
"yunion.io/x/pkg/util/secrules"
|
||
"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/compute/models"
|
||
"yunion.io/x/onecloud/pkg/httperrors"
|
||
"yunion.io/x/onecloud/pkg/mcclient"
|
||
"yunion.io/x/onecloud/pkg/util/seclib2"
|
||
)
|
||
|
||
type SAwsRegionDriver struct {
|
||
SManagedVirtualizationRegionDriver
|
||
}
|
||
|
||
func init() {
|
||
driver := SAwsRegionDriver{}
|
||
models.RegisterRegionDriver(&driver)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) GetProvider() string {
|
||
return api.CLOUD_PROVIDER_AWS
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) IsSupportedDBInstance() bool {
|
||
return true
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) GetRdsSupportSecgroupCount() int {
|
||
return 1
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) IsSupportedElasticcache() bool {
|
||
return true
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) IsSupportedElasticcacheSecgroup() bool {
|
||
return false
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) GetMaxElasticcacheSecurityGroupCount() int {
|
||
return 0
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateElasticcacheData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input *api.ElasticcacheCreateInput) (*api.ElasticcacheCreateInput, error) {
|
||
if len(input.Password) > 0 && len(input.Password) < 16 {
|
||
passwd := seclib2.RandomPassword2(30)
|
||
input.Password = ""
|
||
for _, s := range passwd {
|
||
if ok, _ := utils.InArray(s, []rune{'!', '&', '#', '$', '^', '<', '>', '-', '.'}); ok || unicode.IsDigit(s) || unicode.IsLetter(s) {
|
||
input.Password += string(s)
|
||
}
|
||
}
|
||
}
|
||
return self.SManagedVirtualizationRegionDriver.ValidateCreateElasticcacheData(ctx, userCred, ownerId, input)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateDBInstanceData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input api.DBInstanceCreateInput, skus []models.SDBInstanceSku, network *models.SNetwork) (api.DBInstanceCreateInput, error) {
|
||
if len(input.Password) > 0 {
|
||
for _, s := range input.Password {
|
||
if s == '/' || s == '"' || s == '@' || s == '\'' {
|
||
return input, httperrors.NewInputParameterError("aws rds not support password character %s", string(s))
|
||
}
|
||
}
|
||
}
|
||
if len(input.Password) == 0 {
|
||
for _, s := range seclib2.RandomPassword2(100) {
|
||
if s == '/' || s == '"' || s == '@' || s == '\'' {
|
||
continue
|
||
}
|
||
input.Password += string(s)
|
||
if len(input.Password) >= 20 {
|
||
break
|
||
}
|
||
}
|
||
}
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateDBInstanceBackupData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceBackupCreateInput) (api.DBInstanceBackupCreateInput, error) {
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateDBInstanceDatabaseData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceDatabaseCreateInput) (api.DBInstanceDatabaseCreateInput, error) {
|
||
return input, httperrors.NewNotSupportedError("aws not support create rds database")
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateDBInstanceAccountData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, instance *models.SDBInstance, input api.DBInstanceAccountCreateInput) (api.DBInstanceAccountCreateInput, error) {
|
||
return input, httperrors.NewNotSupportedError("aws not support create rds account")
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) InitDBInstanceUser(ctx context.Context, instance *models.SDBInstance, task taskman.ITask, desc *cloudprovider.SManagedDBInstanceCreateConfig) error {
|
||
user := "admin"
|
||
if desc.Engine == api.DBINSTANCE_TYPE_POSTGRESQL || desc.Category == api.DBINSTANCE_TYPE_POSTGRESQL {
|
||
user = "postgres"
|
||
}
|
||
|
||
account := models.SDBInstanceAccount{}
|
||
account.DBInstanceId = instance.Id
|
||
account.Name = user
|
||
account.Status = api.DBINSTANCE_USER_AVAILABLE
|
||
account.SetModelManager(models.DBInstanceAccountManager, &account)
|
||
err := models.DBInstanceAccountManager.TableSpec().Insert(ctx, &account)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return account.SetPassword(desc.Password)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateLoadbalancerData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input *api.LoadbalancerCreateInput) (*api.LoadbalancerCreateInput, error) {
|
||
if len(input.LoadbalancerSpec) == 0 {
|
||
input.LoadbalancerSpec = api.LB_AWS_SPEC_APPLICATION
|
||
}
|
||
if !utils.IsInStringArray(input.LoadbalancerSpec, api.LB_AWS_SPECS) {
|
||
return nil, httperrors.NewInputParameterError("invalid loadbalancer_spec %s", input.LoadbalancerSpec)
|
||
}
|
||
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerData(ctx, userCred, ownerId, input)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential,
|
||
ownerId mcclient.IIdentityProvider, input *api.LoadbalancerListenerCreateInput,
|
||
lb *models.SLoadbalancer, lbbg *models.SLoadbalancerBackendGroup) (*api.LoadbalancerListenerCreateInput, error) {
|
||
input.Scheduler = api.LB_SCHEDULER_RR
|
||
input.AclStatus = api.LB_BOOL_OFF
|
||
input.StickySession = api.LB_BOOL_OFF
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context.Context, userCred mcclient.TokenCredential,
|
||
lblis *models.SLoadbalancerListener, input *api.LoadbalancerListenerUpdateInput) (*api.LoadbalancerListenerUpdateInput, error) {
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, input *api.LoadbalancerListenerRuleCreateInput) (*api.LoadbalancerListenerRuleCreateInput, error) {
|
||
segs := []string{}
|
||
if len(input.Path) > 0 {
|
||
segs = append(segs, fmt.Sprintf(`{"field":"path-pattern","pathPatternConfig":{"values":["%s"]},"values":["%s"]}`, input.Path, input.Path))
|
||
}
|
||
|
||
if len(input.Domain) > 0 {
|
||
segs = append(segs, fmt.Sprintf(`{"field":"host-header","hostHeaderConfig":{"values":["%s"]},"values":["%s"]}`, input.Domain, input.Domain))
|
||
}
|
||
input.Condition = fmt.Sprintf(`[%s]`, strings.Join(segs, ","))
|
||
err := models.ValidateListenerRuleConditions(input.Condition)
|
||
if err != nil {
|
||
return nil, httperrors.NewInputParameterError("%s", err)
|
||
}
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateUpdateLoadbalancerListenerRuleData(ctx context.Context, userCred mcclient.TokenCredential, input *api.LoadbalancerListenerRuleUpdateInput) (*api.LoadbalancerListenerRuleUpdateInput, error) {
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential,
|
||
lb *models.SLoadbalancer, lbbg *models.SLoadbalancerBackendGroup,
|
||
input *api.LoadbalancerBackendCreateInput) (*api.LoadbalancerBackendCreateInput, error) {
|
||
return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerBackendData(ctx, userCred, lb, lbbg, input)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateUpdateLoadbalancerBackendData(ctx context.Context, userCred mcclient.TokenCredential, lbbg *models.SLoadbalancerBackendGroup, input *api.LoadbalancerBackendUpdateInput) (*api.LoadbalancerBackendUpdateInput, error) {
|
||
// 不能更新端口和权重
|
||
if input.Port != nil {
|
||
return input, fmt.Errorf("can not update backend port.")
|
||
}
|
||
|
||
if input.Weight != nil {
|
||
return input, fmt.Errorf("can not update backend weight.")
|
||
}
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) RequestCreateLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *models.SLoadbalancerListener, task taskman.ITask) error {
|
||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||
provider := lblis.GetCloudprovider()
|
||
if provider == nil {
|
||
return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name)
|
||
}
|
||
|
||
lbbg, err := lblis.GetLoadbalancerBackendGroup()
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetLoadbalancerBackendGroup")
|
||
}
|
||
lb, err := lblis.GetLoadbalancer()
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetLoadbalancer")
|
||
}
|
||
iLb, err := lb.GetILoadbalancer(ctx)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetILoadbalancer")
|
||
}
|
||
|
||
opts, err := lblis.GetLoadbalancerListenerParams()
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetLoadbalancerListenerParams")
|
||
}
|
||
|
||
{
|
||
if lblis.ListenerType == api.LB_LISTENER_TYPE_HTTPS && len(lblis.CertificateId) > 0 {
|
||
cert, err := lblis.GetCertificate()
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetCertificate")
|
||
}
|
||
|
||
lbcert, err := models.CachedLoadbalancerCertificateManager.GetOrCreateCachedCertificate(ctx, userCred, provider, lblis, cert)
|
||
if err != nil {
|
||
return nil, errors.Wrap(err, "CachedLoadbalancerCertificateManager.GetOrCreateCachedCertificate")
|
||
}
|
||
opts.CertificateId = lbcert.ExternalId
|
||
}
|
||
}
|
||
|
||
if len(lbbg.ExternalId) == 0 {
|
||
vpc, err := lb.GetVpc()
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetVpc")
|
||
}
|
||
lbbgOpts := &cloudprovider.SLoadbalancerBackendGroup{
|
||
Name: lbbg.Name,
|
||
Scheduler: lblis.Scheduler,
|
||
Protocol: lblis.ListenerType,
|
||
ListenPort: lblis.ListenerPort,
|
||
VpcId: vpc.ExternalId,
|
||
}
|
||
|
||
iLbbg, err := iLb.CreateILoadBalancerBackendGroup(lbbgOpts)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "CreateILoadBalancerBackendGroup")
|
||
}
|
||
err = db.SetExternalId(lbbg, userCred, iLbbg.GetGlobalId())
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "db.SetExternalId")
|
||
}
|
||
opts.BackendGroupId = iLbbg.GetGlobalId()
|
||
}
|
||
|
||
iLis, err := iLb.CreateILoadBalancerListener(ctx, opts)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "CreateILoadBalancerListener")
|
||
}
|
||
err = db.SetExternalId(lblis, userCred, iLis.GetGlobalId())
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "lblis.SetExternalId")
|
||
}
|
||
backends, err := lbbg.GetBackends()
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetBackends")
|
||
}
|
||
if len(backends) == 0 {
|
||
return nil, nil
|
||
}
|
||
iLbbg, err := lbbg.GetICloudLoadbalancerBackendGroup(ctx)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "GetICloudLoadbalancerBackendGroup")
|
||
}
|
||
for i := range backends {
|
||
_, err := iLbbg.AddBackendServer(backends[i].ExternalId, backends[i].Port, backends[i].Weight)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "AddBackendServer")
|
||
}
|
||
}
|
||
return nil, nil
|
||
})
|
||
return nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) RequestStartLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lblis *models.SLoadbalancerListener, task taskman.ITask) error {
|
||
return task.ScheduleRun(nil)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) RequestCreateLoadbalancerBackendGroup(ctx context.Context, userCred mcclient.TokenCredential, lbbg *models.SLoadbalancerBackendGroup, task taskman.ITask) error {
|
||
return task.ScheduleRun(nil)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) IsCertificateBelongToRegion() bool {
|
||
return false
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateVpcData(ctx context.Context, userCred mcclient.TokenCredential, input api.VpcCreateInput) (api.VpcCreateInput, error) {
|
||
cidrV := validators.NewIPv4PrefixValidator("cidr_block")
|
||
if err := cidrV.Validate(jsonutils.Marshal(input).(*jsonutils.JSONDict)); err != nil {
|
||
return input, err
|
||
}
|
||
if cidrV.Value.MaskLen < 16 || cidrV.Value.MaskLen > 28 {
|
||
return input, httperrors.NewInputParameterError("%s request the mask range should be between 16 and 28", self.GetProvider())
|
||
}
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) RequestAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, eip *models.SElasticip, input api.ElasticipAssociateInput, obj db.IStatusStandaloneModel, task taskman.ITask) error {
|
||
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
|
||
iEip, err := eip.GetIEip(ctx)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "eip.GetIEip")
|
||
}
|
||
|
||
conf := &cloudprovider.AssociateConfig{
|
||
InstanceId: input.InstanceExternalId,
|
||
Bandwidth: eip.Bandwidth,
|
||
AssociateType: api.EIP_ASSOCIATE_TYPE_SERVER,
|
||
}
|
||
|
||
err = iEip.Associate(conf)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "iEip.Associate")
|
||
}
|
||
|
||
err = cloudprovider.WaitStatus(iEip, api.EIP_STATUS_READY, 3*time.Second, 60*time.Second)
|
||
if err != nil {
|
||
return nil, errors.Wrap(err, "cloudprovider.WaitStatus")
|
||
}
|
||
|
||
if obj.GetStatus() != api.INSTANCE_ASSOCIATE_EIP {
|
||
db.StatusBaseSetStatus(obj, userCred, api.INSTANCE_ASSOCIATE_EIP, "associate eip")
|
||
}
|
||
|
||
err = eip.AssociateInstance(ctx, userCred, input.InstanceType, obj)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "eip.AssociateVM")
|
||
}
|
||
|
||
if input.InstanceType == api.EIP_ASSOCIATE_TYPE_SERVER {
|
||
// 如果aws已经绑定了EIP,则要把多余的公有IP删除
|
||
if iEip.GetMode() == api.EIP_MODE_STANDALONE_EIP {
|
||
server := obj.(*models.SGuest)
|
||
publicIP, err := server.GetPublicIp()
|
||
if err != nil {
|
||
return nil, errors.Wrap(err, "AwsGuestDriver.GetPublicIp")
|
||
}
|
||
|
||
if publicIP != nil {
|
||
err = db.DeleteModel(ctx, userCred, publicIP)
|
||
if err != nil {
|
||
return nil, errors.Wrap(err, "AwsGuestDriver.DeletePublicIp")
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
eip.SetStatus(userCred, api.EIP_STATUS_READY, "associate")
|
||
return nil, nil
|
||
})
|
||
return nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateWafInstanceData(ctx context.Context, userCred mcclient.TokenCredential, input api.WafInstanceCreateInput) (api.WafInstanceCreateInput, error) {
|
||
if len(input.Type) == 0 {
|
||
input.Type = cloudprovider.WafTypeRegional
|
||
}
|
||
switch input.Type {
|
||
case cloudprovider.WafTypeRegional:
|
||
case cloudprovider.WafTypeCloudFront:
|
||
_region, err := models.CloudregionManager.FetchById(input.CloudregionId)
|
||
if err != nil {
|
||
return input, err
|
||
}
|
||
region := _region.(*models.SCloudregion)
|
||
if !strings.HasSuffix(region.ExternalId, "us-east-1") {
|
||
return input, httperrors.NewUnsupportOperationError("only us-east-1 support %s", input.Type)
|
||
}
|
||
default:
|
||
return input, httperrors.NewInputParameterError("Invalid aws waf type %s", input.Type)
|
||
}
|
||
if input.DefaultAction == nil {
|
||
input.DefaultAction = &cloudprovider.DefaultAction{
|
||
Action: cloudprovider.WafActionAllow,
|
||
}
|
||
}
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateWafRuleData(ctx context.Context, userCred mcclient.TokenCredential, waf *models.SWafInstance, input api.WafRuleCreateInput) (api.WafRuleCreateInput, error) {
|
||
return input, nil
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateCreateSecurityGroupInput(ctx context.Context, userCred mcclient.TokenCredential, input *api.SSecgroupCreateInput) (*api.SSecgroupCreateInput, error) {
|
||
for i := range input.Rules {
|
||
if input.Rules[i].Action != string(secrules.SecurityRuleAllow) {
|
||
return nil, httperrors.NewInputParameterError("invalid action %s, only support allow", input.Rules[i].Action)
|
||
}
|
||
|
||
if len(input.Rules[i].Ports) > 0 && strings.Contains(input.Rules[i].Ports, ",") {
|
||
return nil, httperrors.NewInputParameterError("invalid ports %s", input.Rules[i].Ports)
|
||
}
|
||
|
||
}
|
||
return self.SManagedVirtualizationRegionDriver.ValidateCreateSecurityGroupInput(ctx, userCred, input)
|
||
}
|
||
|
||
func (self *SAwsRegionDriver) ValidateUpdateSecurityGroupRuleInput(ctx context.Context, userCred mcclient.TokenCredential, input *api.SSecgroupRuleUpdateInput) (*api.SSecgroupRuleUpdateInput, error) {
|
||
if input.Action != nil && *input.Action != string(secrules.SecurityRuleAllow) {
|
||
return nil, httperrors.NewInputParameterError("invalid action %s", *input.Action)
|
||
}
|
||
|
||
if input.Ports != nil && strings.Contains(*input.Ports, ",") {
|
||
return nil, httperrors.NewInputParameterError("invalid ports %s", *input.Ports)
|
||
}
|
||
|
||
return self.SManagedVirtualizationRegionDriver.ValidateUpdateSecurityGroupRuleInput(ctx, userCred, input)
|
||
}
|