| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- // 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/logclient"
- "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")
- }
- opts.CertificateId = cert.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 {
- opts := &cloudprovider.SLoadbalancerBackend{
- Weight: backends[i].Weight,
- Port: backends[i].Port,
- ExternalId: backends[i].ExternalId,
- }
- _, err := iLbbg.AddBackendServer(opts)
- 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(ctx, 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(ctx, 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(ctx, 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) 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)
- }
- func (self *SAwsRegionDriver) RequestRemoteUpdateElasticcache(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *models.SElasticcache, replaceTags bool, task taskman.ITask) error {
- taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
- iRegion, err := elasticcache.GetIRegion(ctx)
- if err != nil {
- return nil, errors.Wrap(err, "elasticcache.GetIRegion")
- }
- iElasticcache, err := iRegion.GetIElasticcacheById(elasticcache.ExternalId)
- if err != nil {
- return nil, errors.Wrapf(err, "GetIElasticcacheById(%s)", elasticcache.ExternalId)
- }
- oldTags, err := iElasticcache.GetTags()
- if err != nil {
- if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented {
- return nil, nil
- }
- return nil, errors.Wrap(err, "iElasticcache.GetTags()")
- }
- tags, err := elasticcache.GetAllUserMetadata()
- if err != nil {
- return nil, errors.Wrapf(err, "GetAllUserMetadata")
- }
- tagsUpdateInfo := cloudprovider.TagsUpdateInfo{OldTags: oldTags, NewTags: tags}
- mangerId := ""
- if vpc, _ := elasticcache.GetVpc(); vpc != nil {
- mangerId = vpc.ManagerId
- }
- err = cloudprovider.SetTags(ctx, iElasticcache, mangerId, tags, replaceTags)
- if err != nil {
- if errors.Cause(err) == cloudprovider.ErrNotSupported || errors.Cause(err) == cloudprovider.ErrNotImplemented {
- return nil, nil
- }
- logclient.AddActionLogWithStartable(task, elasticcache, logclient.ACT_UPDATE_TAGS, err, userCred, false)
- return nil, errors.Wrap(err, "iElasticcache.SetTags")
- }
- cloudprovider.WaitMultiStatus(iElasticcache, []string{api.ELASTIC_CACHE_STATUS_RUNNING}, 15*time.Second, 2*time.Minute)
- logclient.AddActionLogWithStartable(task, elasticcache, logclient.ACT_UPDATE_TAGS, tagsUpdateInfo, userCred, true)
- return nil, nil
- })
- return nil
- }
|