diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index b95751ee11..7b2af44862 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -44,6 +44,9 @@ type ICloudRegion interface { GetIStorageById(id string) (ICloudStorage, error) GetIStoragecacheById(id string) (ICloudStoragecache, error) + DeleteSecurityGroup(vpcId, secgroupId string) error + SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) + CreateIVpc(name string, desc string, cidr string) (ICloudVpc, error) CreateEIP(name string, bwMbps int, chargeType string) (ICloudEIP, error) @@ -163,7 +166,8 @@ type ICloudVM interface { GetBios() string GetMachine() string - SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error + AssignSecurityGroup(secgroupId string) error + GetHypervisor() string // GetSecurityGroup() ICloudSecurityGroup @@ -219,6 +223,7 @@ type ICloudSecurityGroup interface { ICloudResource GetDescription() string GetRules() ([]secrules.SecurityRule, error) + GetVpcId() string } type ICloudRouteTable interface { @@ -291,8 +296,6 @@ type ICloudVpc interface { Delete() error GetIWireById(wireId string) (ICloudWire, error) - - SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) (string, error) } type ICloudWire interface { diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index ae607e644e..22b08f58bd 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -212,21 +212,27 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu nets := guest.GetNetworks() net := nets[0].GetNetwork() vpc := net.GetVpc() - - ivpc, err := vpc.GetIVpc() + iregion, err := host.GetIRegion() if err != nil { - log.Errorf("getIVPC fail %s", err) return nil, err } - secgrpId, err := ivpc.SyncSecurityGroup(desc.SecGroupId, desc.SecGroupName, desc.SecRules) + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), desc.SecGroupId, vpc.Id, vpc.CloudregionId, vpc.ManagerId) + if secgroupCache == nil { + return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s, vpc: %s", desc.SecGroupId, vpc.Name) + } + + secgroupExtId, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpc.ExternalId, desc.SecGroupName, "", desc.SecRules) if err != nil { log.Errorf("SyncSecurityGroup fail %s", err) return nil, err } + if err := secgroupCache.SetExternalId(secgroupExtId); err != nil { + return nil, fmt.Errorf("failed to set externalId for secgroup %s externalId %s: error: %v", desc.SecGroupId, secgroupExtId, err) + } iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId, - desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgrpId, userData) + desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData) if err != nil { return nil, err } diff --git a/pkg/compute/guestdrivers/aws.go b/pkg/compute/guestdrivers/aws.go index ff6bb28987..fd3198f1b1 100644 --- a/pkg/compute/guestdrivers/aws.go +++ b/pkg/compute/guestdrivers/aws.go @@ -106,20 +106,27 @@ func (self *SAwsGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest net := nets[0].GetNetwork() vpc := net.GetVpc() - ivpc, err := vpc.GetIVpc() + iregion, err := host.GetIRegion() if err != nil { - log.Errorf("getIVPC fail %s", err) return nil, err } - secgrpId, err := ivpc.SyncSecurityGroup(desc.SecGroupId, desc.SecGroupName, desc.SecRules) + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), desc.SecGroupId, vpc.Id, vpc.CloudregionId, vpc.ManagerId) + if secgroupCache == nil { + return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s, vpc: %s", desc.SecGroupId, vpc.Name) + } + + secgroupExtId, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpc.ExternalId, desc.SecGroupName, "", desc.SecRules) if err != nil { log.Errorf("SyncSecurityGroup fail %s", err) return nil, err } + if err := secgroupCache.SetExternalId(secgroupExtId); err != nil { + return nil, fmt.Errorf("failed to set externalId for secgroup %s externalId %s: error: %v", desc.SecGroupId, secgroupExtId, err) + } iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId, - desc.IpAddr, desc.Description, "", desc.StorageType, desc.DataDisks, publicKey, secgrpId, userData) + desc.IpAddr, desc.Description, "", desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData) if err != nil { return nil, err } diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 6afc543997..3f2af8a3cd 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -3,6 +3,7 @@ package guestdrivers import ( "context" "fmt" + "strings" "time" "yunion.io/x/log" @@ -11,6 +12,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/ansible" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/utils" "yunion.io/x/jsonutils" @@ -127,48 +129,64 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue if err := config.Unmarshal(&desc, "desc"); err != nil { return err } - if action, err := config.GetString("action"); err != nil { + action, err := config.GetString("action") + if err != nil { return err - } else if ihost, err := host.GetIHost(); err != nil { + } + ihost, err := host.GetIHost() + if err != nil { return err - } else if action == "create" { + } + if action == "create" { taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + if len(passwd) == 0 { + //Azure创建必须要设置密码 + passwd = seclib2.RandomPassword2(12) + } + nets := guest.GetNetworks() net := nets[0].GetNetwork() vpc := net.GetVpc() - ivpc, err := vpc.GetIVpc() + iregion, err := host.GetIRegion() if err != nil { - log.Errorf("getIVPC fail %s", err) return nil, err } - if len(passwd) == 0 { - passwd = seclib2.RandomPassword2(12) + vpcId := "normal" + if strings.HasSuffix(host.Name, "-classic") { + vpcId = "classic" } - secgrpId, err := ivpc.SyncSecurityGroup(desc.SecGroupId, desc.SecGroupName, desc.SecRules) + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), desc.SecGroupId, vpcId, vpc.CloudregionId, vpc.ManagerId) + if secgroupCache == nil { + return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s, vpc: %s", desc.SecGroupId, vpc.Name) + } + + secgroupExtId, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpcId, desc.SecGroupName, "", desc.SecRules) if err != nil { log.Errorf("SyncSecurityGroup fail %s", err) return nil, err } - - if iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId, - desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgrpId, userData); err != nil { - return nil, err - } else { - log.Debugf("VMcreated %s, wait status running ...", iVM.GetGlobalId()) - if err = cloudprovider.WaitStatus(iVM, models.VM_RUNNING, time.Second*5, time.Second*1800); err != nil { - return nil, err - } - if iVM, err = ihost.GetIVMById(iVM.GetGlobalId()); err != nil { - log.Errorf("cannot find vm %s", err) - return nil, err - } - - data := fetchIVMinfo(desc, iVM, guest.Id, ansible.PUBLIC_CLOUD_ANSIBLE_USER, passwd, action) - return data, nil + if err := secgroupCache.SetExternalId(secgroupExtId); err != nil { + return nil, fmt.Errorf("failed to set externalId for secgroup %s externalId %s: error: %v", desc.SecGroupId, secgroupExtId, err) } + + iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId, + desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData) + if err != nil { + return nil, err + } + log.Debugf("VMcreated %s, wait status running ...", iVM.GetGlobalId()) + if err = cloudprovider.WaitStatus(iVM, models.VM_RUNNING, time.Second*5, time.Second*1800); err != nil { + return nil, err + } + if iVM, err = ihost.GetIVMById(iVM.GetGlobalId()); err != nil { + log.Errorf("cannot find vm %s", err) + return nil, err + } + + return fetchIVMinfo(desc, iVM, guest.Id, ansible.PUBLIC_CLOUD_ANSIBLE_USER, passwd, action), nil }) } else if action == "deploy" { iVM, err := ihost.GetIVMById(guest.GetExternalId()) @@ -283,3 +301,70 @@ func (self *SAzureGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context guest.SaveDeployInfo(ctx, task.GetUserCred(), data) return nil } + +func (self *SAzureGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + ihost, err := host.GetIHost() + if err != nil { + return nil, err + } + iVM, err := ihost.GetIVMById(guest.ExternalId) + if err != nil { + return nil, err + } + + if fwOnly, _ := task.GetParams().Bool("fw_only"); fwOnly { + vpcID := "normal" + if strings.HasSuffix(host.Name, "-classic") { + vpcID = "classic" + } + iregion, err := host.GetIRegion() + if err != nil { + return nil, err + } + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), guest.SecgrpId, vpcID, host.GetRegion().Id, host.ManagerId) + if secgroupCache == nil { + return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s vpc: %s", guest.SecgrpId, vpcID) + } + extID, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpcID, guest.GetSecgroupName(), "", guest.GetSecRules()) + if err != nil { + return nil, err + } + if err = secgroupCache.SetExternalId(extID); err != nil { + return nil, err + } + return nil, iVM.AssignSecurityGroup(extID) + } + + iDisks, err := iVM.GetIDisks() + if err != nil { + return nil, err + } + disks := make([]models.SDisk, 0) + for _, guestdisk := range guest.GetDisks() { + disk := guestdisk.GetDisk() + disks = append(disks, *disk) + } + + added := make([]models.SDisk, 0) + commondb := make([]models.SDisk, 0) + commonext := make([]cloudprovider.ICloudDisk, 0) + removed := make([]cloudprovider.ICloudDisk, 0) + + if err := compare.CompareSets(disks, iDisks, &added, &commondb, &commonext, &removed); err != nil { + return nil, err + } + for _, disk := range removed { + if err := iVM.DetachDisk(disk.GetId()); err != nil { + return nil, err + } + } + for _, disk := range added { + if err := iVM.AttachDisk(disk.ExternalId); err != nil { + return nil, err + } + } + return nil, nil + }) + return nil +} diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 6c27c3484b..d4b4b52360 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -301,53 +301,6 @@ func (self *SManagedVirtualizedGuestDriver) RequestChangeVmConfig(ctx context.Co return nil } -func (self *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { - taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { - if ihost, err := host.GetIHost(); err != nil { - return nil, err - } else if iVM, err := ihost.GetIVMById(guest.ExternalId); err != nil { - return nil, err - } else { - if fw_only, _ := task.GetParams().Bool("fw_only"); fw_only { - if err := iVM.SyncSecurityGroup(guest.SecgrpId, guest.GetSecgroupName(), guest.GetSecRules()); err != nil { - return nil, err - } - } else { - if iDisks, err := iVM.GetIDisks(); err != nil { - return nil, err - } else { - disks := make([]models.SDisk, 0) - for _, guestdisk := range guest.GetDisks() { - disk := guestdisk.GetDisk() - disks = append(disks, *disk) - } - - added := make([]models.SDisk, 0) - commondb := make([]models.SDisk, 0) - commonext := make([]cloudprovider.ICloudDisk, 0) - removed := make([]cloudprovider.ICloudDisk, 0) - - if err := compare.CompareSets(disks, iDisks, &added, &commondb, &commonext, &removed); err != nil { - return nil, err - } - for _, disk := range removed { - if err := iVM.DetachDisk(disk.GetId()); err != nil { - return nil, err - } - } - for _, disk := range added { - if err := iVM.AttachDisk(disk.ExternalId); err != nil { - return nil, err - } - } - } - } - } - return nil, nil - }) - return nil -} - func (self *SManagedVirtualizedGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error { iDisk, _ := models.DiskManager.FetchById(diskId) disk := iDisk.(*models.SDisk) @@ -368,3 +321,73 @@ func (self *SManagedVirtualizedGuestDriver) RequestDiskSnapshot(ctx context.Cont }) return nil } + +func (self *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + ihost, err := host.GetIHost() + if err != nil { + return nil, err + } + iVM, err := ihost.GetIVMById(guest.ExternalId) + if err != nil { + return nil, err + } + + if fwOnly, _ := task.GetParams().Bool("fw_only"); fwOnly { + vpcId := "" + for _, network := range guest.GetNetworks() { + if vpc := network.GetNetwork().GetVpc(); vpc != nil { + vpcId = vpc.ExternalId + break + } + } + iregion, err := host.GetIRegion() + if err != nil { + return nil, err + } + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), guest.SecgrpId, vpcId, host.GetRegion().Id, host.ManagerId) + if secgroupCache == nil { + return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s vpc: %s", guest.SecgrpId, vpcId) + } + extID, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpcId, guest.GetSecgroupName(), "", guest.GetSecRules()) + if err != nil { + return nil, err + } + if err = secgroupCache.SetExternalId(extID); err != nil { + return nil, err + } + return nil, iVM.AssignSecurityGroup(extID) + } + + iDisks, err := iVM.GetIDisks() + if err != nil { + return nil, err + } + disks := make([]models.SDisk, 0) + for _, guestdisk := range guest.GetDisks() { + disk := guestdisk.GetDisk() + disks = append(disks, *disk) + } + + added := make([]models.SDisk, 0) + commondb := make([]models.SDisk, 0) + commonext := make([]cloudprovider.ICloudDisk, 0) + removed := make([]cloudprovider.ICloudDisk, 0) + + if err := compare.CompareSets(disks, iDisks, &added, &commondb, &commonext, &removed); err != nil { + return nil, err + } + for _, disk := range removed { + if err := iVM.DetachDisk(disk.GetId()); err != nil { + return nil, err + } + } + for _, disk := range added { + if err := iVM.AttachDisk(disk.ExternalId); err != nil { + return nil, err + } + } + return nil, nil + }) + return nil +} diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index 7e9556c0e3..64c5b5a47f 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -139,20 +139,27 @@ func (self *SQcloudGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu net := nets[0].GetNetwork() vpc := net.GetVpc() - ivpc, err := vpc.GetIVpc() + iregion, err := host.GetIRegion() if err != nil { - log.Errorf("getIVPC fail %s", err) return nil, err } - secgrpId, err := ivpc.SyncSecurityGroup(desc.SecGroupId, desc.SecGroupName, desc.SecRules) + secgroupCache := models.SecurityGroupCacheManager.Register(ctx, task.GetUserCred(), desc.SecGroupId, "normal", vpc.CloudregionId, vpc.ManagerId) + if secgroupCache == nil { + return nil, fmt.Errorf("failed to registor secgroupCache for secgroup: %s, vpc: %s", desc.SecGroupId, vpc.Name) + } + + secgroupExtId, err := iregion.SyncSecurityGroup(secgroupCache.ExternalId, vpc.ExternalId, desc.SecGroupName, "", desc.SecRules) if err != nil { log.Errorf("SyncSecurityGroup fail %s", err) return nil, err } + if err := secgroupCache.SetExternalId(secgroupExtId); err != nil { + return nil, fmt.Errorf("failed to set externalId for secgroup %s externalId %s: error: %v", desc.SecGroupId, secgroupExtId, err) + } iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId, - desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgrpId, userData) + desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgroupExtId, userData) if err != nil { return nil, err } diff --git a/pkg/compute/handlers.go b/pkg/compute/handlers.go index ad2ec0a97a..47f2c511f5 100644 --- a/pkg/compute/handlers.go +++ b/pkg/compute/handlers.go @@ -57,6 +57,7 @@ func InitHandlers(app *appsrv.Application) { models.KeypairManager, models.IsolatedDeviceManager, models.SecurityGroupManager, + models.SecurityGroupCacheManager, models.SecurityGroupRuleManager, // models.VCenterManager, models.DnsRecordManager, diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index c05f30ab93..9ec7dfc202 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -1632,6 +1632,23 @@ func (self *SHost) GetIHost() (cloudprovider.ICloudHost, error) { return ihost, nil } +func (self *SHost) GetIRegion() (cloudprovider.ICloudRegion, error) { + provider, err := self.GetDriver() + if err != nil { + return nil, fmt.Errorf("No cloudprovide for host %s: %s", self.Name, err) + } + region := self.GetRegion() + if region == nil { + return nil, fmt.Errorf("failed to find host %s region info", self.Name) + } + iregion, err := provider.GetIRegionById(region.ExternalId) + if err != nil { + msg := fmt.Sprintf("fail to find iregion by id %s: %v", region.ExternalId, err) + return nil, fmt.Errorf(msg) + } + return iregion, nil +} + func (self *SHost) getDiskConfig() jsonutils.JSONObject { bs := self.GetBaremetalstorage() if bs != nil { diff --git a/pkg/compute/models/secgroupcache.go b/pkg/compute/models/secgroupcache.go new file mode 100644 index 0000000000..052151822e --- /dev/null +++ b/pkg/compute/models/secgroupcache.go @@ -0,0 +1,155 @@ +package models + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "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/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/pkg/util/stringutils" + "yunion.io/x/sqlchemy" +) + +type SSecurityGroupCacheManager struct { + db.SResourceBaseManager +} + +type SSecurityGroupCache struct { + db.SResourceBase + SManagedResourceBase + + Id string `width:"128" charset:"ascii" primary:"true" list:"user"` + SecgroupId string `width:"128" charset:"ascii" create:"required"` + VpcId string `width:"128" charset:"ascii" create:"required"` + CloudregionId string `width:"128" charset:"ascii" create:"required"` + ExternalId string `width:"256" charset:"utf8" index:"true" list:"admin" create:"admin_optional"` +} + +var SecurityGroupCacheManager *SSecurityGroupCacheManager + +func init() { + SecurityGroupCacheManager = &SSecurityGroupCacheManager{SResourceBaseManager: db.NewResourceBaseManager(SSecurityGroupCache{}, "secgroupcache_tbl", "secgroupcache", "secgroupcaches")} +} + +func (self *SSecurityGroupCache) BeforeInsert() { + if len(self.Id) == 0 { + self.Id = stringutils.UUID4() + } +} + +func (manager *SSecurityGroupCacheManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return false +} + +func (manager *SSecurityGroupCacheManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return true +} + +func (self *SSecurityGroupCache) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { + return false +} + +func (self *SSecurityGroupCache) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return false +} + +func (manager *SSecurityGroupCacheManager) FilterById(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery { + return q.Equals("id", idStr) +} + +func (manager *SSecurityGroupCacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (sql *sqlchemy.SQuery, err error) { + sql, err = manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query) + if err != nil { + return nil, err + } + if defsecgroup, _ := query.GetString("secgroup"); len(defsecgroup) > 0 { + if secgroup, _ := SecurityGroupManager.FetchByIdOrName(userCred, defsecgroup); secgroup != nil { + sql = sql.Equals("secgroup_id", secgroup.GetId()) + } else { + return nil, httperrors.NewNotFoundError("Security Group %s not found", defsecgroup) + } + } + return sql, nil +} + +func (self *SSecurityGroupCache) GetIRegion() (cloudprovider.ICloudRegion, error) { + provider, err := self.GetDriver() + if err != nil { + return nil, err + } + if region := CloudregionManager.FetchRegionById(self.CloudregionId); region != nil { + return provider.GetIRegionById(region.ExternalId) + } + return nil, fmt.Errorf("failed to find iregion for secgroupcache %s vpc: %s externalId: %s", self.Id, self.VpcId, self.ExternalId) +} + +func (self *SSecurityGroupCache) DeleteCloudSecurityGroup(ctx context.Context, userCred mcclient.TokenCredential) error { + if len(self.ExternalId) > 0 { + iregion, err := self.GetIRegion() + if err != nil { + return err + } + return iregion.DeleteSecurityGroup(self.VpcId, self.ExternalId) + } + return nil +} + +func (self *SSecurityGroupCache) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + if err := self.DeleteCloudSecurityGroup(ctx, userCred); err != nil { + log.Errorf("delete secgroup cache %v error: %v", self, err) + } + return db.DeleteModel(ctx, userCred, self) +} + +func (manager *SSecurityGroupCacheManager) GetSecgroupCache(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId string, regionId string, providerId string) *SSecurityGroupCache { + secgroupCache := SSecurityGroupCache{} + query := manager.Query() + cond := sqlchemy.AND(sqlchemy.Equals(query.Field("secgroup_id"), secgroupId), sqlchemy.Equals(query.Field("vpc_id"), vpcId), sqlchemy.Equals(query.Field("cloudregion_id"), regionId), sqlchemy.Equals(query.Field("manager_id"), providerId)) + query = query.Filter(cond) + + count := query.Count() + if count > 1 { + log.Errorf("duplicate secgroupcache for secgroup: %s vpcId: %s regionId: %s", secgroupId, vpcId, regionId) + } else if count == 0 { + return nil + } + query.First(&secgroupCache) + secgroupCache.SetModelManager(manager) + return &secgroupCache +} + +func (manager *SSecurityGroupCacheManager) Register(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId, regionId string, providerId string) *SSecurityGroupCache { + lockman.LockClass(ctx, manager, userCred.GetProjectId()) + defer lockman.ReleaseClass(ctx, manager, userCred.GetProjectId()) + + secgroupCache := manager.GetSecgroupCache(ctx, userCred, secgroupId, vpcId, regionId, providerId) + if secgroupCache != nil { + return secgroupCache + } + + secgroupCache = &SSecurityGroupCache{ + SecgroupId: secgroupId, + VpcId: vpcId, + CloudregionId: regionId, + } + secgroupCache.ManagerId = providerId + secgroupCache.SetModelManager(manager) + if err := manager.TableSpec().Insert(secgroupCache); err != nil { + log.Errorf("insert secgroupcache error: %v", err) + return nil + } + return secgroupCache +} + +func (self *SSecurityGroupCache) SetExternalId(externalId string) error { + _, err := self.GetModelManager().TableSpec().Update(self, func() error { + self.ExternalId = externalId + return nil + }) + return err +} diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index 616659f9b9..95f0d7d514 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -15,6 +15,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" @@ -201,64 +202,7 @@ func (manager *SSecurityGroupManager) getSecurityGroups() ([]SSecurityGroup, err } } -func (manager *SSecurityGroupManager) SyncSecgroups(ctx context.Context, userCred mcclient.TokenCredential, secgroups []cloudprovider.ICloudSecurityGroup, projectId string, projectSync bool) ([]SSecurityGroup, []cloudprovider.ICloudSecurityGroup, compare.SyncResult) { - localSecgroups := make([]SSecurityGroup, 0) - remoteSecgroups := make([]cloudprovider.ICloudSecurityGroup, 0) - syncResult := compare.SyncResult{} - - if dbSecgroups, err := manager.getSecurityGroups(); err != nil { - syncResult.Error(err) - return nil, nil, syncResult - } else { - removed := make([]SSecurityGroup, 0) - commondb := make([]SSecurityGroup, 0) - commonext := make([]cloudprovider.ICloudSecurityGroup, 0) - added := make([]cloudprovider.ICloudSecurityGroup, 0) - if err := compare.CompareSets(dbSecgroups, secgroups, &removed, &commondb, &commonext, &added); err != nil { - syncResult.Error(err) - return nil, nil, syncResult - } - - for i := 0; i < len(commondb); i += 1 { - if rules, err := commonext[i].GetRules(); err != nil { - syncResult.Error(err) - } else if len(rules) > 0 { - if err = commondb[i].SyncWithCloudSecurityGroup(userCred, commonext[i], projectId, projectSync); err != nil { - syncResult.UpdateError(err) - } else { - localSecgroups = append(localSecgroups, commondb[i]) - remoteSecgroups = append(remoteSecgroups, commonext[i]) - SecurityGroupRuleManager.SyncRules(ctx, userCred, &commondb[i], rules) - syncResult.Update() - } - } - } - - for i := 0; i < len(added); i += 1 { - if metadata := added[i].GetMetadata(); metadata != nil && metadata.Contains("id") { - secgroupId, _ := metadata.GetString("id") - if secgrp, _ := manager.FetchById(secgroupId); secgrp != nil { - continue - } - } - if rules, err := added[i].GetRules(); err != nil { - syncResult.AddError(err) - } else if len(rules) > 0 { - if new, err := manager.newFromCloudVpc(userCred, added[i], projectId); err != nil { - syncResult.AddError(err) - } else if len(rules) > 0 { - localSecgroups = append(localSecgroups, *new) - remoteSecgroups = append(remoteSecgroups, added[i]) - SecurityGroupRuleManager.SyncRules(ctx, userCred, new, rules) - syncResult.Add() - } - } - } - } - return localSecgroups, remoteSecgroups, syncResult -} - -func (self *SSecurityGroup) SyncWithCloudSecurityGroup(userCred mcclient.TokenCredential, extSec cloudprovider.ICloudSecurityGroup, projectId string, projectSync bool) error { +func (self *SSecurityGroup) SyncWithCloudSecurityGroup(userCred mcclient.TokenCredential, extSec cloudprovider.ICloudSecurityGroup, vpc *SVpc, projectId string, projectSync bool) error { if _, err := self.GetModelManager().TableSpec().Update(self, func() error { extSec.Refresh() self.Name = extSec.GetName() @@ -272,10 +216,17 @@ func (self *SSecurityGroup) SyncWithCloudSecurityGroup(userCred mcclient.TokenCr log.Errorf("syncWithCloudSecurityGroup error %s", err) return err } + + if secgroupcache := SecurityGroupCacheManager.Register(context.Background(), userCred, self.Id, extSec.GetVpcId(), vpc.CloudregionId, vpc.ManagerId); secgroupcache != nil { + if err := secgroupcache.SetExternalId(self.ExternalId); err != nil { + log.Errorf("set secgroupcache %s externalId error: %v", secgroupcache.Id, err) + } + } + return nil } -func (manager *SSecurityGroupManager) newFromCloudVpc(userCred mcclient.TokenCredential, extSec cloudprovider.ICloudSecurityGroup, projectId string) (*SSecurityGroup, error) { +func (manager *SSecurityGroupManager) newFromCloudVpc(userCred mcclient.TokenCredential, extSec cloudprovider.ICloudSecurityGroup, vpc *SVpc, projectId string) (*SSecurityGroup, error) { secgroup := SSecurityGroup{} secgroup.SetModelManager(manager) secgroup.Name = extSec.GetName() @@ -289,9 +240,70 @@ func (manager *SSecurityGroupManager) newFromCloudVpc(userCred mcclient.TokenCre if err := manager.TableSpec().Insert(&secgroup); err != nil { return nil, err } + + if secgroupcache := SecurityGroupCacheManager.Register(context.Background(), userCred, secgroup.Id, extSec.GetVpcId(), vpc.CloudregionId, vpc.ManagerId); secgroupcache != nil { + if err := secgroupcache.SetExternalId(secgroup.ExternalId); err != nil { + log.Errorf("set secgroupcache %s externalId error: %v", secgroupcache.Id, err) + } + } + return &secgroup, nil } +func (manager *SSecurityGroupManager) SyncSecgroups(ctx context.Context, userCred mcclient.TokenCredential, secgroups []cloudprovider.ICloudSecurityGroup, vpc *SVpc, projectId string, projectSync bool) ([]SSecurityGroup, []cloudprovider.ICloudSecurityGroup, compare.SyncResult) { + localSecgroups := make([]SSecurityGroup, 0) + remoteSecgroups := make([]cloudprovider.ICloudSecurityGroup, 0) + syncResult := compare.SyncResult{} + + dbSecgroups, err := manager.getSecurityGroups() + if err != nil { + syncResult.Error(err) + return nil, nil, syncResult + } + removed := make([]SSecurityGroup, 0) + commondb := make([]SSecurityGroup, 0) + commonext := make([]cloudprovider.ICloudSecurityGroup, 0) + added := make([]cloudprovider.ICloudSecurityGroup, 0) + if err := compare.CompareSets(dbSecgroups, secgroups, &removed, &commondb, &commonext, &added); err != nil { + syncResult.Error(err) + return nil, nil, syncResult + } + + for i := 0; i < len(commondb); i += 1 { + rules, err := commonext[i].GetRules() + if err != nil { + syncResult.Error(err) + continue + } + if err := commondb[i].SyncWithCloudSecurityGroup(userCred, commonext[i], vpc, projectId, projectSync); err != nil { + syncResult.UpdateError(err) + continue + } + localSecgroups = append(localSecgroups, commondb[i]) + remoteSecgroups = append(remoteSecgroups, commonext[i]) + SecurityGroupRuleManager.SyncRules(ctx, userCred, &commondb[i], rules) + syncResult.Update() + } + + for i := 0; i < len(added); i += 1 { + rules, err := added[i].GetRules() + if err != nil { + syncResult.AddError(err) + continue + } + new, err := manager.newFromCloudVpc(userCred, added[i], vpc, projectId) + if err != nil { + syncResult.AddError(err) + continue + } + localSecgroups = append(localSecgroups, *new) + remoteSecgroups = append(remoteSecgroups, added[i]) + SecurityGroupRuleManager.SyncRules(ctx, userCred, new, rules) + syncResult.Add() + } + return localSecgroups, remoteSecgroups, syncResult +} + func (manager *SSecurityGroupManager) DelaySync(ctx context.Context, userCred mcclient.TokenCredential, idStr string) { if secgrp := manager.FetchSecgroupById(idStr); secgrp == nil { log.Errorf("DelaySync secgroup failed") @@ -393,3 +405,35 @@ func (self *SSecurityGroup) ValidateDeleteCondition(ctx context.Context) error { } return self.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx) } + +func (self *SSecurityGroup) GetSecurityGroupCaches() []SSecurityGroupCache { + caches := []SSecurityGroupCache{} + q := SecurityGroupCacheManager.Query() + q = q.Filter(sqlchemy.Equals(q.Field("secgroup_id"), self.Id)) + if err := db.FetchModelObjects(SecurityGroupCacheManager, q, &caches); err != nil { + log.Errorf("get secgroupcache for secgroup %s error: %v", self.Name, err) + } + return caches +} + +func (self *SSecurityGroup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + return self.StartDeleteSecurityGroupTask(ctx, userCred, jsonutils.NewDict(), "") +} + +func (self *SSecurityGroup) StartDeleteSecurityGroupTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error { + task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupDeleteTask", self, userCred, params, parentTaskId, "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + return nil +} + +func (self *SSecurityGroup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + log.Infof("SecurityGroup delete do nothing") + return nil +} + +func (self *SSecurityGroup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error { + return self.SVirtualResourceBase.Delete(ctx, userCred) +} diff --git a/pkg/compute/tasks/cloud_provider_sync_info_task.go b/pkg/compute/tasks/cloud_provider_sync_info_task.go index 06dccfdd0a..84b563631d 100644 --- a/pkg/compute/tasks/cloud_provider_sync_info_task.go +++ b/pkg/compute/tasks/cloud_provider_sync_info_task.go @@ -220,7 +220,7 @@ func syncVpcSecGroup(ctx context.Context, provider *models.SCloudprovider, task logSyncFailed(provider, task, msg) return } else { - _, _, result := models.SecurityGroupManager.SyncSecgroups(ctx, task.UserCred, secgroups, provider.ProjectId, syncRange.ProjectSync) + _, _, result := models.SecurityGroupManager.SyncSecgroups(ctx, task.UserCred, secgroups, localVpc, provider.ProjectId, syncRange.ProjectSync) msg := result.Result() notes := fmt.Sprintf("SyncSecurityGroup for VPC %s result: %s", localVpc.Name, msg) log.Infof(notes) diff --git a/pkg/compute/tasks/security_group_delete_task.go b/pkg/compute/tasks/security_group_delete_task.go new file mode 100644 index 0000000000..54fe0fc2e2 --- /dev/null +++ b/pkg/compute/tasks/security_group_delete_task.go @@ -0,0 +1,28 @@ +package tasks + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type SecurityGroupDeleteTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(SecurityGroupDeleteTask{}) +} + +func (self *SecurityGroupDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + secgroup := obj.(*models.SSecurityGroup) + secgroupCache := secgroup.GetSecurityGroupCaches() + for _, cache := range secgroupCache { + cache.Delete(ctx, self.GetUserCred()) + } + secgroup.RealDelete(ctx, self.GetUserCred()) + self.SetStageComplete(ctx, nil) +} diff --git a/pkg/mcclient/modules/managers.go b/pkg/mcclient/modules/managers.go index f1cc0ded38..62c7cb6d1a 100644 --- a/pkg/mcclient/modules/managers.go +++ b/pkg/mcclient/modules/managers.go @@ -155,4 +155,4 @@ func NewCloudmetaManager(keyword, keywordPlural string, columns, adminColumns [] adminColumns: adminColumns, serviceType: "cloudmeta"}, Keyword: keyword, KeywordPlural: keywordPlural} -} \ No newline at end of file +} diff --git a/pkg/mcclient/modules/resource.go b/pkg/mcclient/modules/resource.go index 35399fa2a2..65528750c4 100644 --- a/pkg/mcclient/modules/resource.go +++ b/pkg/mcclient/modules/resource.go @@ -297,7 +297,7 @@ func (this *ResourceManager) params2Body(s *mcclient.ClientSession, params jsonu return body } -func (this *ResourceManager)Create(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (this *ResourceManager) Create(session *mcclient.ClientSession, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { return this.CreateInContexts(session, params, nil) } diff --git a/pkg/util/aliyun/host.go b/pkg/util/aliyun/host.go index ad1e28e7a4..10f5ad8def 100644 --- a/pkg/util/aliyun/host.go +++ b/pkg/util/aliyun/host.go @@ -197,25 +197,6 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int } var err error - - if len(secgroupId) == 0 { - secgroups, err := net.wire.vpc.GetISecurityGroups() - if err != nil { - return "", fmt.Errorf("get security group error %s", err) - } - - if len(secgroups) == 0 { - secId, err := self.zone.region.createDefaultSecurityGroup(net.wire.vpc.VpcId) - if err != nil { - return "", fmt.Errorf("no secgroup for vpc and failed to create a default One!!") - } else { - secgroupId = secId - } - } else { - secgroupId = secgroups[0].GetId() - } - } - keypair := "" if len(publicKey) > 0 { keypair, err = self.zone.region.syncKeypair(publicKey) diff --git a/pkg/util/aliyun/instance.go b/pkg/util/aliyun/instance.go index f43fe0e133..ce28c48bc8 100644 --- a/pkg/util/aliyun/instance.go +++ b/pkg/util/aliyun/instance.go @@ -8,7 +8,6 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/util/osprofile" "yunion.io/x/pkg/util/seclib" - "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -796,32 +795,6 @@ func (self *SRegion) AttachDisk(instanceId string, diskId string) error { return nil } -func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error { - if vpc, err := self.getVpc(); err != nil { - return err - } else if len(secgroupId) == 0 { - for index, secgrpId := range self.SecurityGroupIds.SecurityGroupId { - if err := vpc.revokeSecurityGroup(secgrpId, self.InstanceId, index == 0); err != nil { - return err - } - } - } else if secgrpId, err := vpc.SyncSecurityGroup(secgroupId, name, rules); err != nil { - return err - } else if err := vpc.assignSecurityGroup(secgrpId, self.InstanceId); err != nil { - return err - } else { - for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId { - if secgroupId != secgrpId { - if err := vpc.revokeSecurityGroup(secgroupId, self.InstanceId, false); err != nil { - return err - } - } - } - self.SecurityGroupIds.SecurityGroupId = []string{secgrpId} - } - return nil -} - func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { if len(self.PublicIpAddress.IpAddress) > 0 { eip := SEipAddress{} @@ -842,6 +815,10 @@ func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { } } +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.AssignSecurityGroup(secgroupId, self.InstanceId) +} + func (self *SInstance) GetBillingType() string { switch self.InstanceChargeType { case PrePaidInstanceChargeType: diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index e2c0905591..2c959519db 100644 --- a/pkg/util/aliyun/region.go +++ b/pkg/util/aliyun/region.go @@ -9,6 +9,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -637,3 +638,23 @@ func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) } return &eips[0], nil } + +func (region *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) { + if len(secgroupId) > 0 { + _, total, err := region.GetSecurityGroups("", []string{secgroupId}, 0, 1) + if err != nil { + return "", err + } + if total == 0 { + secgroupId = "" + } + } + if len(secgroupId) == 0 { + extID, err := region.CreateSecurityGroup(vpcId, name, desc) + if err != nil { + return "", err + } + secgroupId = extID + } + return secgroupId, region.syncSecgroupRules(secgroupId, rules) +} diff --git a/pkg/util/aliyun/securitygroup.go b/pkg/util/aliyun/securitygroup.go index f873f2adac..d49def0ec0 100644 --- a/pkg/util/aliyun/securitygroup.go +++ b/pkg/util/aliyun/securitygroup.go @@ -8,7 +8,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/utils" ) @@ -87,6 +86,10 @@ func (v PermissionSet) Less(i, j int) bool { return false } +func (self *SSecurityGroup) GetVpcId() string { + return self.VpcId +} + func (self *SSecurityGroup) GetMetadata() *jsonutils.JSONDict { if len(self.Tags.Tag) == 0 { return nil @@ -155,7 +158,7 @@ func (self *SSecurityGroup) Refresh() error { } } -func (self *SRegion) GetSecurityGroups(vpcId string, offset int, limit int) ([]SSecurityGroup, int, error) { +func (self *SRegion) GetSecurityGroups(vpcId string, securityGroupIds []string, offset int, limit int) ([]SSecurityGroup, int, error) { if limit > 50 || limit <= 0 { limit = 50 } @@ -167,6 +170,10 @@ func (self *SRegion) GetSecurityGroups(vpcId string, offset int, limit int) ([]S params["VpcId"] = vpcId } + if securityGroupIds != nil && len(securityGroupIds) > 0 { + params["SecurityGroupIds"] = jsonutils.Marshal(securityGroupIds).String() + } + body, err := self.ecsRequest("DescribeSecurityGroups", params) if err != nil { log.Errorf("GetSecurityGroups fail %s", err) @@ -204,11 +211,16 @@ func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup return &secgrp, nil } -func (self *SRegion) createSecurityGroup(vpcId string, name string, desc string) (string, error) { +func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (string, error) { params := make(map[string]string) if len(vpcId) > 0 { params["VpcId"] = vpcId } + + if name == "Default" { + name = "Default-copy" + } + if len(name) > 0 { params["SecurityGroupName"] = name } @@ -383,58 +395,6 @@ func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.Securi } } -func (self *SRegion) createDefaultSecurityGroup(vpcId string) (string, error) { - secId, err := self.createSecurityGroup(vpcId, "", "") - if err != nil { - return "", err - } - inRule := secrules.SecurityRule{ - Priority: 1, - Action: secrules.SecurityRuleAllow, - Protocol: "", - Direction: secrules.SecurityRuleIngress, - PortStart: -1, - PortEnd: -1, - } - err = self.addSecurityGroupRules(secId, &inRule) - if err != nil { - return "", err - } - outRule := secrules.SecurityRule{ - Priority: 1, - Action: secrules.SecurityRuleAllow, - Protocol: "", - Direction: secrules.SecurityRuleEgress, - PortStart: -1, - PortEnd: -1, - } - err = self.addSecurityGroupRules(secId, &outRule) - if err != nil { - return "", err - } - return secId, nil -} - -func (self *SRegion) getSecurityGroupByTag(vpcId, secgroupId string) (*SSecurityGroup, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - params["Tag.1.Key"] = "id" - params["Tag.1.Value"] = secgroupId - - secgrps := make([]SSecurityGroup, 0) - if body, err := self.ecsRequest("DescribeSecurityGroups", params); err != nil { - return nil, err - } else if err := body.Unmarshal(&secgrps, "SecurityGroups", "SecurityGroup"); err != nil { - return nil, err - } else if len(secgrps) != 1 { - return nil, httperrors.NewNotFoundError("failed to find SecurityGroup %s", secgroupId) - } - return &secgrps[0], nil -} - func (self *SPermission) String() string { action := secrules.SecurityRuleDeny if strings.ToLower(self.Policy) == "accept" { @@ -474,50 +434,6 @@ func (self *SPermission) String() string { return result } -func (self *SRegion) addTagToSecurityGroup(secgroupId, key, value string, index int) error { - if index > 5 || index < 1 { - index = 1 - } - params := map[string]string{"ResourceType": "securitygroup", "ResourceId": secgroupId} - params[fmt.Sprintf("Tag.%d.Key", index)] = key - params[fmt.Sprintf("Tag.%d.Value", index)] = value - _, err := self.ecsRequest("AddTags", params) - return err -} - -func (self *SRegion) revokeSecurityGroup(secgroupId, instanceId string, keep bool) error { - if !keep { - return self.leaveSecurityGroup(secgroupId, instanceId) - } - if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil { - return err - } else { - for _, permission := range secgroup.Permissions.Permission { - if rule, err := secrules.ParseSecurityRule(permission.String()); err != nil { - return err - } else { - rule.Priority = permission.Priority - if err := self.delSecurityGroupRule(secgroup.SecurityGroupId, rule); err != nil { - return err - } - } - } - if rule, err := secrules.ParseSecurityRule("in:allow any"); err != nil { - rule.Priority = 100 - if err := self.addSecurityGroupRules(secgroup.SecurityGroupId, rule); err != nil { - return err - } - } - if rule, err := secrules.ParseSecurityRule("out:allow any"); err != nil { - rule.Priority = 100 - if err := self.addSecurityGroupRules(secgroup.SecurityGroupId, rule); err != nil { - return err - } - } - } - return nil -} - func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error { if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil { return err @@ -584,10 +500,23 @@ func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.Secur return nil } -func (self *SRegion) assignSecurityGroup(secgroupId, instanceId string) error { +func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error { params := map[string]string{"InstanceId": instanceId, "SecurityGroupId": secgroupId} - _, err := self.ecsRequest("JoinSecurityGroup", params) - return err + if _, err := self.ecsRequest("JoinSecurityGroup", params); err != nil { + return err + } + instance, err := self.GetInstance(instanceId) + if err != nil { + return err + } + for _, _secgroupId := range instance.SecurityGroupIds.SecurityGroupId { + if _secgroupId != secgroupId { + if err := self.leaveSecurityGroup(_secgroupId, instanceId); err != nil { + return err + } + } + } + return nil } func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { @@ -596,7 +525,7 @@ func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { return err } -func (self *SRegion) deleteSecurityGroup(secGrpId string) error { +func (self *SRegion) DeleteSecurityGroup(vpcId, secGrpId string) error { params := make(map[string]string) params["SecurityGroupId"] = secGrpId diff --git a/pkg/util/aliyun/shell/secgroup.go b/pkg/util/aliyun/shell/secgroup.go index 89c71ac038..a215b87a54 100644 --- a/pkg/util/aliyun/shell/secgroup.go +++ b/pkg/util/aliyun/shell/secgroup.go @@ -1,18 +1,21 @@ package shell import ( + "fmt" + "yunion.io/x/onecloud/pkg/util/aliyun" "yunion.io/x/onecloud/pkg/util/shellutils" ) func init() { type SecurityGroupListOptions struct { - VpcId string `help:"VPC ID"` - Limit int `help:"page size"` - Offset int `help:"page offset"` + VpcId string `help:"VPC ID"` + SecurityGroupIds []string `help:"SecurityGroup ids"` + Limit int `help:"page size"` + Offset int `help:"page offset"` } shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *aliyun.SRegion, args *SecurityGroupListOptions) error { - secgrps, total, e := cli.GetSecurityGroups(args.VpcId, args.Offset, args.Limit) + secgrps, total, e := cli.GetSecurityGroups(args.VpcId, args.SecurityGroupIds, args.Offset, args.Limit) if e != nil { return e } @@ -31,4 +34,20 @@ func init() { printObject(secgrp) return nil }) + + type SecurityGroupCreateOptions struct { + NAME string `help:"SecurityGroup name"` + VpcId string `help:"VPC ID"` + Desc string `help:"SecurityGroup description"` + } + + shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create details of a security group", func(cli *aliyun.SRegion, args *SecurityGroupCreateOptions) error { + secgroupId, err := cli.CreateSecurityGroup(args.VpcId, args.NAME, args.Desc) + if err != nil { + return err + } + fmt.Println("secgroupId: %s", secgroupId) + return nil + }) + } diff --git a/pkg/util/aliyun/shell/vpc.go b/pkg/util/aliyun/shell/vpc.go index 045793ba5f..e6f3014b6b 100644 --- a/pkg/util/aliyun/shell/vpc.go +++ b/pkg/util/aliyun/shell/vpc.go @@ -18,4 +18,13 @@ func init() { printList(vpcs, total, args.Offset, args.Limit, []string{}) return nil }) + + type VpcOptions struct { + ID string `help:"VPC id"` + } + + shellutils.R(&VpcOptions{}, "vpc-delete", "Delete vpc", func(cli *aliyun.SRegion, args *VpcOptions) error { + return cli.DeleteVpc(args.ID) + }) + } diff --git a/pkg/util/aliyun/vpc.go b/pkg/util/aliyun/vpc.go index b567df76d2..402156dcf1 100644 --- a/pkg/util/aliyun/vpc.go +++ b/pkg/util/aliyun/vpc.go @@ -7,7 +7,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/pkg/util/secrules" ) const ( @@ -165,7 +164,7 @@ func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) func (self *SVpc) fetchSecurityGroups() error { secgroups := make([]SSecurityGroup, 0) for { - parts, total, err := self.region.GetSecurityGroups(self.VpcId, len(secgroups), 50) + parts, total, err := self.region.GetSecurityGroups(self.VpcId, []string{}, len(secgroups), 50) if err != nil { return err } @@ -234,7 +233,7 @@ func (self *SVpc) Delete() error { } for i := 0; i < len(self.secgroups); i += 1 { secgroup := self.secgroups[i].(*SSecurityGroup) - err := self.region.deleteSecurityGroup(secgroup.SecurityGroupId) + err := self.region.DeleteSecurityGroup(self.VpcId, secgroup.SecurityGroupId) if err != nil { log.Errorf("deleteSecurityGroup for VPC delete fail %s", err) return err @@ -242,40 +241,3 @@ func (self *SVpc) Delete() error { } return self.region.DeleteVpc(self.VpcId) } - -func (self *SVpc) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) (string, error) { - secgrpId := "" - if secgroup, err := self.region.getSecurityGroupByTag(self.VpcId, secgroupId); err != nil { - if secgrpId, err = self.region.createSecurityGroup(self.VpcId, name, ""); err != nil { - return "", err - } else if err := self.region.addTagToSecurityGroup(secgrpId, "id", secgroupId, 1); err != nil { - return "", err - } - //addRules - log.Debugf("Add Rules for %s", secgrpId) - for _, rule := range rules { - if err := self.region.addSecurityGroupRule(secgrpId, &rule); err != nil { - return "", err - } - } - } else { - //syncRules - secgrpId = secgroup.SecurityGroupId - log.Debugf("Sync Rules for %s", secgroup.GetName()) - if secgroup.GetName() != name { - if err := self.region.modifySecurityGroup(secgrpId, name, ""); err != nil { - log.Errorf("Change SecurityGroup name to %s failed: %v", name, err) - } - } - self.region.syncSecgroupRules(secgrpId, rules) - } - return secgrpId, nil -} - -func (self *SVpc) assignSecurityGroup(secgroupId string, instanceId string) error { - return self.region.assignSecurityGroup(secgroupId, instanceId) -} - -func (self *SVpc) revokeSecurityGroup(secgroupId string, instanceId string, keep bool) error { - return self.region.revokeSecurityGroup(secgroupId, instanceId, keep) -} diff --git a/pkg/util/aws/instance.go b/pkg/util/aws/instance.go index 02ff642841..306b57e718 100644 --- a/pkg/util/aws/instance.go +++ b/pkg/util/aws/instance.go @@ -10,7 +10,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/util/secrules" ) const ( @@ -269,33 +268,8 @@ func (self *SInstance) GetMachine() string { return "pc" } -func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error { - if vpc, err := self.getVpc(); err != nil { - return err - } else if len(secgroupId) == 0 { - // todo : 这里应该有问题。aws不能直接删除安全组。且至少选择一个安全组 - // for index, secgrpId := range self.SecurityGroupIds.SecurityGroupId { - // if err := vpc.revokeSecurityGroup(secgrpId, self.InstanceId, index == 0); err != nil { - // return err - // } - // } - return nil - } else if secgrpId, err := vpc.SyncSecurityGroup(secgroupId, name, rules); err != nil { - return err - } else if err := vpc.assignSecurityGroup(secgrpId, self.InstanceId); err != nil { - return err - } else { - // todo : 这里应该有问题。aws不能直接删除安全组。且至少选择一个安全组 - // for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId { - // if secgroupId != secgrpId { - // if err := vpc.revokeSecurityGroup(secgroupId, self.InstanceId, false); err != nil { - // return err - // } - // } - // } - self.SecurityGroupIds.SecurityGroupId = []string{secgrpId} - } - return nil +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.assignSecurityGroup(self.InstanceId, secgroupId) } func (self *SInstance) GetHypervisor() string { diff --git a/pkg/util/aws/securitygroup.go b/pkg/util/aws/securitygroup.go index 3fc04daf36..ba5b7109e9 100644 --- a/pkg/util/aws/securitygroup.go +++ b/pkg/util/aws/securitygroup.go @@ -2,11 +2,13 @@ package aws import ( "fmt" - "github.com/aws/aws-sdk-go/service/ec2" "sort" "strings" + + "github.com/aws/aws-sdk-go/service/ec2" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/pkg/util/secrules" ) @@ -39,6 +41,10 @@ func (self *SSecurityGroup) GetId() string { return self.SecurityGroupId } +func (self *SSecurityGroup) GetVpcId() string { + return self.VpcId +} + func (self *SSecurityGroup) GetName() string { if len(self.SecurityGroupName) > 0 { return self.SecurityGroupName @@ -194,13 +200,55 @@ func (self *SRegion) updateSecurityGroupRuleDescription(secGrpId string, rule *s return nil } -func (self *SRegion) createSecurityGroup(vpcId string, name string, secgroupIdTag string, desc string) (string, error) { +func (self *SRegion) DeleteSecurityGroup(vpcId, secgroupId string) error { + return self.deleteSecurityGroup(secgroupId) +} + +func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) { + if len(secgroupId) > 0 { + _, err := self.GetSecurityGroupDetails(secgroupId) + if err != nil { + if err != cloudprovider.ErrNotFound { + return "", err + } + secgroupId = "" + } + } + + if len(secgroupId) == 0 { + // 名称为default的安全组与aws默认安全组名冲突 + if strings.ToLower(name) == "default" { + name = fmt.Sprintf("%s-%s", vpcId, name) + } + var err error + secgroupId, err = self.createSecurityGroup(vpcId, name, desc) + if err != nil { + return "", err + } + } + + secgroup, err := self.GetSecurityGroupDetails(secgroupId) + if err != nil { + return "", err + } + + log.Debugf("Sync Rules for %s", secgroup.GetName()) + if secgroup.GetName() != name { + if err := self.modifySecurityGroup(secgroupId, name, ""); err != nil { + log.Errorf("Change SecurityGroup name to %s failed: %v", name, err) + } + } + if err := self.syncSecgroupRules(secgroupId, rules); err != nil { + return "", err + } + return secgroupId, nil +} + +func (self *SRegion) createSecurityGroup(vpcId string, name string, desc string) (string, error) { params := &ec2.CreateSecurityGroupInput{} params.SetVpcId(vpcId) // 这里的描述aws 上层代码拼接的描述。并非用户提交的描述,用户描述放置在Yunion本地数据库中。) params.SetDescription(desc) - // 这里使用id作为组名。原因name容易重名、另外有可能包含中文,aws不支持中文 - params.SetGroupName(secgroupIdTag) group, err := self.ec2Client.CreateSecurityGroup(params) if err != nil { @@ -208,7 +256,6 @@ func (self *SRegion) createSecurityGroup(vpcId string, name string, secgroupIdTa } tagspec := TagSpec{ResourceType: "security-group"} - tagspec.SetTag("id", secgroupIdTag) tagspec.SetNameTag(name) tagspec.SetDescTag(desc) tags, _ := tagspec.GetTagSpecifications() @@ -224,7 +271,7 @@ func (self *SRegion) createSecurityGroup(vpcId string, name string, secgroupIdTa } func (self *SRegion) createDefaultSecurityGroup(vpcId string) (string, error) { - secId, err := self.createSecurityGroup(vpcId, "vpc default", fmt.Sprintf("%s-default", vpcId), "vpc default group") + secId, err := self.createSecurityGroup(vpcId, "vpc default", "vpc default group") if err != nil { return "", err } diff --git a/pkg/util/aws/vpc.go b/pkg/util/aws/vpc.go index ad9946ee7f..a3b0a29eae 100644 --- a/pkg/util/aws/vpc.go +++ b/pkg/util/aws/vpc.go @@ -1,13 +1,11 @@ package aws import ( - "fmt" - "github.com/aws/aws-sdk-go/service/ec2" "strings" + + "github.com/aws/aws-sdk-go/service/ec2" "yunion.io/x/jsonutils" - "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/pkg/util/secrules" ) type SUserCIDRs struct { @@ -132,40 +130,6 @@ func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) return nil, cloudprovider.ErrNotFound } -func (self *SVpc) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) (string, error) { - secgrpId := "" - if secgroup, err := self.region.getSecurityGroupByTag(self.VpcId, secgroupId); err != nil { - // 名称为default的安全组与aws默认安全组名冲突 - if strings.ToLower(name) == "default" { - name = fmt.Sprintf("%s-%s", self.VpcId, name) - } - - desc := fmt.Sprintf("security group %s for vpc %s", name, self.VpcId) - if secgrpId, err = self.region.createSecurityGroup(self.VpcId, name, secgroupId, desc); err != nil { - return "", err - } - - //addRules - log.Debugf("Add Rules for %s : %s", secgrpId, rules) - for _, rule := range rules { - if err := self.region.addSecurityGroupRule(secgrpId, &rule); err != nil { - return "", err - } - } - } else { - //syncRules - secgrpId = secgroup.SecurityGroupId - log.Debugf("Sync Rules for %s", secgroup.GetName()) - if secgroup.GetName() != name { - if err := self.region.modifySecurityGroup(secgrpId, name, ""); err != nil { - log.Errorf("Change SecurityGroup name to %s failed: %v", name, err) - } - } - self.region.syncSecgroupRules(secgrpId, rules) - } - return secgrpId, nil -} - func (self *SVpc) getWireByZoneId(zoneId string) *SWire { for i := 0; i < len(self.iwires); i += 1 { wire := self.iwires[i].(*SWire) diff --git a/pkg/util/azure/azure.go b/pkg/util/azure/azure.go index 9d459333a5..af278ffe87 100644 --- a/pkg/util/azure/azure.go +++ b/pkg/util/azure/azure.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "net/http" + "strconv" "strings" "time" @@ -65,6 +66,7 @@ var DEFAULT_API_VERSION = map[string]string{ "Microsoft.Network": "2018-06-01", "Microsoft.ClassicNetwork/reservedIps": "2016-04-01", //2014-01-01,2014-06-01,2015-06-01,2015-12-01,2016-04-01,2016-11-01 "Microsoft.ClassicNetwork/networkSecurityGroups": "2016-11-01", //2015-06-01,2015-12-01,2016-04-01,2016-11-01 + "Microsoft.ClassicCompute/domainNames": "2015-12-01", //2014-01-01, 2014-06-01, 2015-06-01, 2015-10-01, 2015-12-01, 2016-04-01, 2016-11-01, 2017-11-01, 2017-11-15 } func NewAzureClient(providerId string, providerName string, accessKey string, secret string, envName string) (*SAzureClient, error) { @@ -301,6 +303,28 @@ type AzureError struct { Message string `json:"message,omitempty"` } +func (self *SAzureClient) getUniqName(cli *autorest.Client, resourceType, name string, body jsonutils.JSONObject) (string, string, error) { + url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s", self.subscriptionId, self.ressourceGroups[0].Name, resourceType, name) + if _, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, ""); err != nil { + if err == cloudprovider.ErrNotFound { + return url, body.String(), nil + } + return "", "", err + } + for i := 0; i < 20; i++ { + url = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s-%d", self.subscriptionId, self.ressourceGroups[0].Name, resourceType, name, i) + if _, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, ""); err == cloudprovider.ErrNotFound { + if err == cloudprovider.ErrNotFound { + data := body.(*jsonutils.JSONDict) + data.Set("name", jsonutils.NewString(fmt.Sprintf("%s-%d", name, i))) + return url, body.String(), nil + } + return "", "", err + } + } + return "", "", fmt.Errorf("not find uniq name for %s[%s]", resourceType, name) +} + func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{}) error { cli, err := self.getDefaultClient() if err != nil { @@ -320,8 +344,12 @@ func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{}) if len(self.ressourceGroups) == 0 { return fmt.Errorf("Create Default resourceGroup error?") } - url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s", self.subscriptionId, self.ressourceGroups[0].Name, params["type"], params["name"]) - result, err := jsonRequest(cli, "PUT", self.domain, url, self.subscriptionId, body.String()) + + url, reqString, err := self.getUniqName(cli, params["type"], params["name"], body) + if err != nil { + return err + } + result, err := jsonRequest(cli, "PUT", self.domain, url, self.subscriptionId, reqString) if err != nil { return err } @@ -459,10 +487,19 @@ func waitForComplatetion(client *autorest.Client, req *http.Request, resp *http. return nil, err } if asyncResp.StatusCode == 202 { + if _location := asyncResp.Header.Get("Location"); len(_location) > 0 { + location = _location + } if time.Now().Sub(startTime) > timeout { return nil, fmt.Errorf("Process request %s %s timeout", req.Method, req.URL.String()) } - time.Sleep(time.Second * 5) + timeSleep := time.Second * 5 + if _timeSleep := asyncResp.Header.Get("Retry-After"); len(_timeSleep) > 0 { + if _time, err := strconv.Atoi(_timeSleep); err != nil { + timeSleep = time.Second * time.Duration(_time) + } + } + time.Sleep(timeSleep) continue } if asyncResp.ContentLength == 0 { diff --git a/pkg/util/azure/classic_instance.go b/pkg/util/azure/classic_instance.go index af25b66a00..4653c6ca5f 100644 --- a/pkg/util/azure/classic_instance.go +++ b/pkg/util/azure/classic_instance.go @@ -10,18 +10,30 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/util/secrules" ) +type FormattedMessage struct { + Language string + Message string +} + +type GuestAgentStatus struct { + ProtocolVersion string `json:"protocolVersion,omitempty"` + Timestamp time.Time `json:"timestamp,omitempty"` + GuestAgentVersion string `json:"guestAgentVersion,omitempty"` + Status string `json:"status,omitempty"` + FormattedMessage FormattedMessage `json:"formattedMessage,omitempty"` +} + type ClassicVirtualMachineInstanceView struct { Status string `json:"status,omitempty"` PowerState string `json:"powerState,omitempty"` PublicIpAddresses []string `json:"publicIpAddresses,omitempty"` FullyQualifiedDomainName string `json:"fullyQualifiedDomainName,omitempty"` - UpdateDomain int - FaultDomain int - StatusMessage string + UpdateDomain int `json:"updateDomain,omitempty"` + FaultDomain int `json:"faultDomain,omitempty"` + StatusMessage string `json:"statusMessage,omitempty"` PrivateIpAddress string `json:"privateIpAddress,omitempty"` InstanceIpAddresses []string `json:"instanceIpAddresses,omitempty"` ComputerName string `json:"computerName,omitempty"` @@ -29,9 +41,9 @@ type ClassicVirtualMachineInstanceView struct { } type SubResource struct { - ID string - Name string - Type string + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` } type ClassicDisk struct { @@ -93,6 +105,7 @@ type ClassicNetworkProfile struct { } type ClassicVirtualMachineProperties struct { + DomainName *SubResource `json:"domainName,omitempty"` InstanceView *ClassicVirtualMachineInstanceView `json:"instanceView,omitempty"` NetworkProfile ClassicNetworkProfile `json:"networkProfile,omitempty"` HardwareProfile ClassicHardwareProfile `json:"hardwareProfile,omitempty"` @@ -306,6 +319,12 @@ func (self *SClassicInstance) DeleteVM() error { if err := self.host.zone.region.DeleteVM(self.ID); err != nil { return err } + if self.Properties.NetworkProfile.NetworkSecurityGroup != nil { + self.host.zone.region.client.Delete(self.Properties.NetworkProfile.NetworkSecurityGroup.ID) + } + if self.Properties.DomainName != nil { + self.host.zone.region.client.Delete(self.Properties.DomainName.ID) + } return nil } @@ -416,10 +435,6 @@ func (self *SRegion) StopClassicVM(instanceId string, isForce bool) error { return err } -func (self *SClassicInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error { - return cloudprovider.ErrNotSupported -} - func (self *SClassicInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { if self.Properties.NetworkProfile.ReservedIps != nil && len(*self.Properties.NetworkProfile.ReservedIps) > 0 { for _, reserveIp := range *self.Properties.NetworkProfile.ReservedIps { @@ -450,6 +465,42 @@ func (self *SClassicInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { return nil, nil } +type assignSecurityGroup struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Properties assignProperties `json:"properties,omitempty"` + Type string `json:"type,omitempty"` +} + +type assignProperties struct { + NetworkSecurityGroup SubResource `json:"networkSecurityGroup,omitempty"` +} + +func (self *SClassicInstance) AssignSecurityGroup(secgroupId string) error { + if self.Properties.NetworkProfile.NetworkSecurityGroup != nil { + if self.Properties.NetworkProfile.NetworkSecurityGroup.ID == secgroupId { + return nil + } + self.host.zone.region.client.Delete(fmt.Sprintf("%s/associatedNetworkSecurityGroups/%s", self.ID, self.Properties.NetworkProfile.NetworkSecurityGroup.Name)) + } + + secgroup, err := self.host.zone.region.GetClassicSecurityGroupDetails(secgroupId) + if err != nil { + return err + } + data := assignSecurityGroup{ + ID: fmt.Sprintf("%s/associatedNetworkSecurityGroups/%s", self.ID, secgroup.Name), + Name: secgroup.Name, + Properties: assignProperties{ + NetworkSecurityGroup: SubResource{ + ID: secgroup.ID, + Name: secgroup.Name, + }, + }, + } + return self.host.zone.region.client.Update(jsonutils.Marshal(data), nil) +} + func (self *SClassicInstance) GetBillingType() string { return models.BILLING_TYPE_POSTPAID } diff --git a/pkg/util/azure/classic_secruitygroup.go b/pkg/util/azure/classic_secruitygroup.go index f52a6ea3c2..54baefd144 100644 --- a/pkg/util/azure/classic_secruitygroup.go +++ b/pkg/util/azure/classic_secruitygroup.go @@ -16,7 +16,7 @@ import ( type SClassicSecurityGroup struct { vpc *SClassicVpc - Properties *SecurityGroupPropertiesFormat `json:"properties,omitempty"` + Properties ClassicSecurityGroupProperties `json:"properties,omitempty"` ID string Name string Location string @@ -24,17 +24,22 @@ type SClassicSecurityGroup struct { Tags map[string]string } +type ClassicSecurityGroupProperties struct { + NetworkSecurityGroupId string `json:"networkSecurityGroupId,omitempty"` + State string `json:"state,omitempty"` +} + type ClassicSecurityGroupRuleProperties struct { - State string - Protocol string - SourcePortRange string - DestinationPortRange string - SourceAddressPrefix string - DestinationAddressPrefix string - Action string - Priority uint32 - Type string - IsDefault bool + State string `json:"state,omitempty"` + Protocol string `json:"protocol,omitempty"` + SourcePortRange string `json:"sourcePortRange,omitempty"` + DestinationPortRange string `json:"destinationPortRange,omitempty"` + SourceAddressPrefix string `json:"sourceAddressPrefix,omitempty"` + DestinationAddressPrefix string `json:"destinationAddressPrefix,omitempty"` + Action string `json:"action,omitempty"` + Priority int32 `json:"priority,omitempty"` + Type string `json:"type,omitempty"` + IsDefault bool `json:"isDefault,omitempty"` } type SClassicSecurityGroupRule struct { @@ -125,6 +130,10 @@ func (self *ClassicSecurityGroupRuleProperties) String() string { return strings.Join(result, ";") } +func (self *SClassicSecurityGroup) GetVpcId() string { + return "classic" +} + func (self *SClassicSecurityGroup) GetMetadata() *jsonutils.JSONDict { if len(self.Tags) == 0 { return nil @@ -151,12 +160,7 @@ func (self *SClassicSecurityGroup) GetName() string { func (self *SClassicSecurityGroup) GetRules() ([]secrules.SecurityRule, error) { rules := make([]secrules.SecurityRule, 0) - secgrouprules := []SClassicSecurityGroupRule{} - body, err := self.vpc.region.client.jsonRequest("GET", fmt.Sprintf("%s/securityRules", self.ID), "") - if err != nil { - return nil, err - } - err = body.Unmarshal(&secgrouprules, "value") + secgrouprules, err := self.vpc.region.getClassicSecurityGroupRules(self.ID) if err != nil { return nil, err } @@ -193,8 +197,16 @@ func (self *SClassicSecurityGroup) IsEmulated() bool { return false } -func (region *SRegion) CreateClassicSecurityGroup(secName, tagId string) (*SClassicSecurityGroup, error) { - return nil, cloudprovider.ErrNotImplemented +func (region *SRegion) CreateClassicSecurityGroup(name string) (*SClassicSecurityGroup, error) { + if name == "Default" { + name = "Default-copy" + } + secgroup := SClassicSecurityGroup{ + Name: name, + Type: "Microsoft.ClassicNetwork/networkSecurityGroups", + Location: region.Name, + } + return &secgroup, region.client.Create(jsonutils.Marshal(secgroup), &secgroup) } func (region *SRegion) GetClassicSecurityGroups() ([]SClassicSecurityGroup, error) { @@ -217,6 +229,10 @@ func (region *SRegion) GetClassicSecurityGroupDetails(secgroupId string) (*SClas return &secgroup, region.client.Get(secgroupId, []string{}, &secgroup) } +func (region *SRegion) deleteClassicSecurityGroup(secgroupId string) error { + return region.client.Delete(secgroupId) +} + func (self *SClassicSecurityGroup) Refresh() error { sec, err := self.vpc.region.GetClassicSecurityGroupDetails(self.ID) if err != nil { @@ -225,102 +241,120 @@ func (self *SClassicSecurityGroup) Refresh() error { return jsonutils.Update(self, sec) } -func (region *SRegion) checkClassicSecurityGroup(tagId, name string) (*SClassicSecurityGroup, error) { - secgroups, err := region.GetClassicSecurityGroups() +func convertClassicSecurityGroupRules(rule secrules.SecurityRule, priority int32) ([]SClassicSecurityGroupRule, error) { + name := strings.Replace(rule.String(), ":", "_", -1) + name = strings.Replace(name, " ", "_", -1) + name = strings.Replace(name, "-", "_", -1) + name = strings.Replace(name, "/", "_", -1) + name = fmt.Sprintf("%s_%d", name, rule.Priority) + rules := []SClassicSecurityGroupRule{} + secRule := SClassicSecurityGroupRule{ + Name: name, + Properties: ClassicSecurityGroupRuleProperties{ + Action: utils.Capitalize(string(rule.Action)), + Priority: priority, + Type: utils.Capitalize(string(rule.Direction)) + "bound", + Protocol: utils.Capitalize(rule.Protocol), + SourcePortRange: "*", + DestinationPortRange: "*", + SourceAddressPrefix: "*", + DestinationAddressPrefix: "*", + }, + } + if rule.Protocol == secrules.PROTO_ANY { + secRule.Properties.Protocol = "*" + } + if rule.Protocol == secrules.PROTO_ICMP { + return nil, nil + } + ipAddr := "*" + if rule.IPNet != nil { + ipAddr = rule.IPNet.String() + } + if rule.Direction == secrules.DIR_IN { + secRule.Properties.SourceAddressPrefix = ipAddr + } else { + secRule.Properties.DestinationAddressPrefix = ipAddr + } + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + secRule.Properties.DestinationPortRange = fmt.Sprintf("%d", port) + rules = append(rules, secRule) + } + return rules, nil + } else if rule.PortStart > 0 && rule.PortEnd > 0 { + secRule.Properties.DestinationPortRange = fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd) + } + rules = append(rules, secRule) + return rules, nil +} + +func (self *SRegion) getClassicSecurityGroupRules(secgroupId string) ([]SClassicSecurityGroupRule, error) { + rules := []SClassicSecurityGroupRule{} + result, err := self.client.jsonRequest("GET", fmt.Sprintf("%s/securityRules?api-version=2015-06-01", secgroupId), "") if err != nil { return nil, err } - for i := 0; i < len(secgroups); i++ { - for k, v := range secgroups[i].Tags { - if k == "id" && v == tagId { - return &secgroups[i], nil - } - } - } - return region.CreateClassicSecurityGroup(name, tagId) -} - -func (region *SRegion) updateClassicSecurityGroupRules(secgroupId string, rules []secrules.SecurityRule) (string, error) { - secgroup, err := region.GetClassicSecurityGroupDetails(secgroupId) - if err != nil { - return "", err - } - securityRules := []SecurityRules{} - priority := int32(100) - for i := 0; i < len(rules); i++ { - if rule := convertSecurityGroupRule(rules[i], priority); rule != nil { - securityRules = append(securityRules, *rule) - priority++ - } - } - secgroup.Properties.SecurityRules = &securityRules - secgroup.Properties.ProvisioningState = "" - return secgroup.ID, region.client.Update(jsonutils.Marshal(secgroup), nil) -} - -func (region *SRegion) AssiginClassicSecurityGroup(instanceId, secgroupId string) error { - instance, err := region.GetClassicInstance(instanceId) - if err != nil { - return err - } - secgroup, err := region.GetClassicSecurityGroupDetails(secgroupId) - if err != nil { - return err - } - instance.Properties.NetworkProfile.NetworkSecurityGroup = &SubResource{ - ID: secgroupId, - Name: secgroup.Name, - Type: secgroup.Type, - } - return region.client.Update(jsonutils.Marshal(instance), nil) + return rules, result.Unmarshal(&rules, "value") } func (self *SRegion) syncClassicSecgroupRules(secgroupId string, rules []secrules.SecurityRule) (string, error) { - secgroup, err := self.GetClassicSecurityGroupDetails(secgroupId) + secgrouprules, err := self.getClassicSecurityGroupRules(secgroupId) if err != nil { return "", err } - sort.Sort(secrules.SecurityRuleSet(rules)) - sort.Sort(SecurityRulesSet(*secgroup.Properties.SecurityRules)) - - newRules := []secrules.SecurityRule{} - - i, j := 0, 0 - for i < len(rules) || j < len(*secgroup.Properties.SecurityRules) { - if i < len(rules) && j < len(*secgroup.Properties.SecurityRules) { - srcRule := (*secgroup.Properties.SecurityRules)[j].Properties.String() - destRule := rules[i].String() - cmp := strings.Compare(srcRule, destRule) - if cmp == 0 { - // keep secRule - newRules = append(newRules, rules[i]) - i++ - j++ - } else if cmp > 0 { - // remove srcRule - j++ - } else { - // add destRule - newRules = append(newRules, rules[i]) - i++ - } - } else if i >= len(rules) { - // del other rules - j++ - } else if j >= len(*secgroup.Properties.SecurityRules) { - // add rule - newRules = append(newRules, rules[i]) - i++ + for _, rule := range secgrouprules { + if rule.Properties.Priority >= 65000 { + continue + } + if err := self.client.Delete(rule.ID); err != nil { + return "", err } } - return self.updateClassicSecurityGroupRules(secgroup.ID, newRules) - -} - -func (self *SRegion) syncClassicSecurityGroup(tagId, name string, rules []secrules.SecurityRule) (string, error) { - secgroup, err := self.checkClassicSecurityGroup(tagId, name) - if err != nil { - return "", err + sort.Sort(secrules.SecurityRuleSet(rules)) + priority := int32(100) + ruleStrs := []string{} + for i, _rule := range rules { + ruleStr := rules[i].String() + if !utils.IsInStringArray(ruleStr, ruleStrs) { + _rules, err := convertClassicSecurityGroupRules(_rule, priority) + if err != nil { + return "", err + } + priority++ + ruleStrs = append(ruleStrs, ruleStr) + for _, rule := range _rules { + if err := self.addClassicSecgroupRule(secgroupId, rule); err != nil { + return "", err + } + } + } } - return self.syncClassicSecgroupRules(secgroup.ID, rules) + return secgroupId, nil +} + +func (self *SRegion) addClassicSecgroupRule(secgroupId string, rule SClassicSecurityGroupRule) error { + url := fmt.Sprintf("%s/securityRules/%s?api-version=2015-06-01", secgroupId, rule.Name) + _, err := self.client.jsonRequest("PUT", url, jsonutils.Marshal(rule).String()) + return err +} + +func (region *SRegion) syncClassicSecurityGroup(secgroupId, name, desc string, rules []secrules.SecurityRule) (string, error) { + if len(secgroupId) > 0 { + if _, err := region.GetClassicSecurityGroupDetails(secgroupId); err != nil { + if err != cloudprovider.ErrNotFound { + return "", err + } + secgroupId = "" + } + } + + if len(secgroupId) == 0 { + secgroup, err := region.CreateClassicSecurityGroup(name) + if err != nil { + return "", err + } + secgroupId = secgroup.ID + } + return region.syncClassicSecgroupRules(secgroupId, rules) } diff --git a/pkg/util/azure/classic_vpc.go b/pkg/util/azure/classic_vpc.go index 1cb6568441..4884c43614 100644 --- a/pkg/util/azure/classic_vpc.go +++ b/pkg/util/azure/classic_vpc.go @@ -6,7 +6,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/pkg/util/secrules" ) type ClassicAddressSpace struct { @@ -76,10 +75,6 @@ func (self *SClassicVpc) Delete() error { return self.region.client.Delete(self.ID) } -func (self *SClassicVpc) SyncSecurityGroup(tag string, name string, rules []secrules.SecurityRule) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - func (self *SClassicVpc) getWire() *SClassicWire { if self.iwires == nil { self.fetchWires() diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index 354b8197d5..9659ab3f58 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -10,7 +10,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/util/secrules" ) const ( @@ -109,42 +108,21 @@ type NetworkProfile struct { NetworkInterfaces []NetworkInterfaceReference `json:"networkInterfaces,omitempty"` } -type InstanceViewStatus struct { +type Statuses struct { Code string Level string - DisplayStatus string + DisplayStatus string `json:"displayStatus,omitempty"` Message string //Time time.Time } -type FormattedMessage struct { - Language string - Message string -} - -type GuestAgentStatus struct { - ProtocolVersion string - Timestamp time.Time - GuestAgentVersion string - Status string - FormattedMessage FormattedMessage +type VMAgent struct { + VmAgentVersion string `json:"vmAgentVersion,omitempty"` + Statuses Statuses `json:"statuses,omitempty"` } type VirtualMachineInstanceView struct { - UpdateDomain int - FaultDomain int - Status string - StatusMessage string - PowerState string - PrivateIpAddress string - PublicIpAddresses []string - FullyQualifiedDomainName string - GuestAgentStatus GuestAgentStatus - - ComputerName string - OsName string - OsVersion string - Statuses []InstanceViewStatus + Statuses []Statuses `json:"statuses,omitempty"` } type DomainName struct { @@ -965,7 +943,7 @@ func (self *SInstance) StartVM() error { if err := self.host.zone.region.StartVM(self.ID); err != nil { return err } - self.host.zone.region.client.jsonRequest("PATCH", self.ID, "") + self.host.zone.region.client.jsonRequest("PATCH", self.ID, jsonutils.Marshal(self).String()) return cloudprovider.WaitStatus(self, models.VM_RUNNING, 10*time.Second, 300*time.Second) } @@ -974,7 +952,7 @@ func (self *SInstance) StopVM(isForce bool) error { if err != nil { return err } - self.host.zone.region.client.jsonRequest("PATCH", self.ID, "") + self.host.zone.region.client.jsonRequest("PATCH", self.ID, jsonutils.Marshal(self).String()) return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) } @@ -983,31 +961,6 @@ func (self *SRegion) StopVM(instanceId string, isForce bool) error { return err } -func (self *SInstance) SyncSecurityGroup(dbSecgroupId string, name string, rules []secrules.SecurityRule) error { - nics, err := self.getNics() - if err != nil { - return err - } - if len(dbSecgroupId) == 0 { - for _, nic := range nics { - if err := nic.revokeSecurityGroup(); err != nil { - return err - } - } - return nil - } - extId, err := self.host.zone.region.syncSecurityGroup(dbSecgroupId, name, rules) - if err != nil { - return err - } - for _, nic := range nics { - if err := nic.assignSecurityGroup(extId); err != nil { - return err - } - } - return nil -} - func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { nics, err := self.getNics() if err != nil { @@ -1029,6 +982,10 @@ func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { return nil, nil } +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.AssiginSecurityGroup(self.ID, secgroupId) +} + func (self *SInstance) GetBillingType() string { return models.BILLING_TYPE_POSTPAID } diff --git a/pkg/util/azure/instancenic.go b/pkg/util/azure/instancenic.go index b41d437549..fd1ac7787d 100644 --- a/pkg/util/azure/instancenic.go +++ b/pkg/util/azure/instancenic.go @@ -1,8 +1,6 @@ package azure import ( - "fmt" - "regexp" "strings" "yunion.io/x/jsonutils" @@ -133,49 +131,7 @@ func (self *SRegion) GetNetworkInterfaces() ([]SInstanceNic, error) { return result, nil } -func (self *SRegion) isNetworkInstanceNameAvaliable(resourceGroupName, nicName string) (bool, error) { - nics := []SInstanceNic{} - err := self.client.ListByTypeWithResourceGroup(resourceGroupName, "Microsoft.Network/networkInterfaces", &nics) - if err != nil { - return false, err - } - for i := 0; i < len(nics); i++ { - if nics[i].Name == nicName { - return false, nil - } - } - return true, nil -} - -func getResourceGroupNameByID(id string) string { - reg := regexp.MustCompile("/resourceGroups/(.+)/providers/") - _resourceGroup := reg.FindStringSubmatch(id) - if len(_resourceGroup) == 2 { - return _resourceGroup[1] - } - return "" -} - func (self *SRegion) CreateNetworkInterface(nicName string, ipAddr string, subnetId string, secgrpId string) (*SInstanceNic, error) { - secgroup, err := self.GetSecurityGroupDetails(secgrpId) - if err != nil { - return nil, err - } - secgroup.Properties.ProvisioningState = "" - - resourceGroupName := getResourceGroupNameByID(subnetId) - nicNameBase := nicName - for i := 0; i < 5; i++ { - ok, err := self.isNetworkInstanceNameAvaliable(resourceGroupName, nicName) - if err != nil { - return nil, err - } - if ok { - break - } - nicName = fmt.Sprintf("%s-%d", nicNameBase, i) - } - instancenic := SInstanceNic{ Name: nicName, Location: self.Name, @@ -193,7 +149,7 @@ func (self *SRegion) CreateNetworkInterface(nicName string, ipAddr string, subne }, }, }, - NetworkSecurityGroup: secgroup, + NetworkSecurityGroup: &SSecurityGroup{ID: secgrpId}, }, Type: "Microsoft.Network/networkInterfaces", } diff --git a/pkg/util/azure/region.go b/pkg/util/azure/region.go index ff634bdb8c..014538b020 100644 --- a/pkg/util/azure/region.go +++ b/pkg/util/azure/region.go @@ -8,6 +8,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/pkg/util/secrules" ) type SVMSize struct { @@ -419,3 +420,51 @@ func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { } return ieips, nil } + +func (region *SRegion) DeleteSecurityGroup(vpcId, secgroupId string) error { + if vpcId == "classic" { + return region.deleteClassicSecurityGroup(secgroupId) + } + secgroup, err := region.GetSecurityGroupDetails(secgroupId) + if err != nil { + if err == cloudprovider.ErrNotFound { + return nil + } + return err + } + if secgroup.Properties.NetworkInterfaces != nil { + for _, nic := range *secgroup.Properties.NetworkInterfaces { + nic, err := region.GetNetworkInterfaceDetail(nic.ID) + if err != nil { + return err + } + nic.Properties.NetworkSecurityGroup = nil + if err := region.client.Update(jsonutils.Marshal(nic), nil); err != nil { + return err + } + } + } + return region.client.Delete(secgroupId) +} + +func (region *SRegion) SyncSecurityGroup(secgroupId, vpcId, name, desc string, rules []secrules.SecurityRule) (string, error) { + if vpcId == "classic" { + return region.syncClassicSecurityGroup(secgroupId, name, desc, rules) + } + if len(secgroupId) > 0 { + if _, err := region.GetSecurityGroupDetails(secgroupId); err != nil { + if err != cloudprovider.ErrNotFound { + return "", err + } + secgroupId = "" + } + } + if len(secgroupId) == 0 { + secgroup, err := region.CreateSecurityGroup(name) + if err != nil { + return "", err + } + secgroupId = secgroup.ID + } + return region.updateSecurityGroupRules(secgroupId, rules) +} diff --git a/pkg/util/azure/securitygroup.go b/pkg/util/azure/securitygroup.go index 2911130226..5cc52f9e97 100644 --- a/pkg/util/azure/securitygroup.go +++ b/pkg/util/azure/securitygroup.go @@ -60,11 +60,11 @@ type Interface struct { } type SecurityGroupPropertiesFormat struct { - SecurityRules *[]SecurityRules `json:"securityRules,omitempty"` - DefaultSecurityRules *[]SecurityRules `json:"defaultSecurityRules,omitempty"` - NetworkInterfaces *[]Interface `json:"networkInterfaces,omitempty"` - Subnets *[]Subnet `json:"subnets,omitempty"` - ProvisioningState string //Possible values are: 'Updating', 'Deleting', and 'Failed' + SecurityRules []SecurityRules `json:"securityRules,omitempty"` + DefaultSecurityRules []SecurityRules `json:"defaultSecurityRules,omitempty"` + NetworkInterfaces *[]Interface `json:"networkInterfaces,omitempty"` + Subnets *[]Subnet `json:"subnets,omitempty"` + ProvisioningState string //Possible values are: 'Updating', 'Deleting', and 'Failed' } type SSecurityGroup struct { vpc *SVpc @@ -306,9 +306,9 @@ func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) { if self.Properties.SecurityRules == nil { return rules, nil } - sort.Sort(SecurityRulesSet(*self.Properties.SecurityRules)) + sort.Sort(SecurityRulesSet(self.Properties.SecurityRules)) priority := 100 - for _, _rule := range *self.Properties.SecurityRules { + for _, _rule := range self.Properties.SecurityRules { _rule.Properties.Priority = int32(priority) secRules, err := _rule.Properties.toRules() if err != nil { @@ -331,13 +331,18 @@ func (self *SSecurityGroup) IsEmulated() bool { return false } -func (region *SRegion) CreateSecurityGroup(secName string, tagId string) (*SSecurityGroup, error) { - securityName := fmt.Sprintf("%s-%s", region.Name, secName) +func (self *SSecurityGroup) GetVpcId() string { + return "normal" +} + +func (region *SRegion) CreateSecurityGroup(secName string) (*SSecurityGroup, error) { + if secName == "Default" { + secName = "Default-copy" + } secgroup := SSecurityGroup{ - Name: securityName, + Name: secName, Type: "Microsoft.Network/networkSecurityGroups", Location: region.Name, - Tags: map[string]string{"id": tagId}, } return &secgroup, region.client.Create(jsonutils.Marshal(secgroup), &secgroup) } @@ -370,21 +375,6 @@ func (self *SSecurityGroup) Refresh() error { return jsonutils.Update(self, sec) } -func (region *SRegion) checkSecurityGroup(tagId, name string) (*SSecurityGroup, error) { - secgroups, err := region.GetSecurityGroups() - if err != nil { - return nil, err - } - for i := 0; i < len(secgroups); i++ { - for k, v := range secgroups[i].Tags { - if k == "id" && v == tagId || secgroups[i].Name == name { - return &secgroups[i], nil - } - } - } - return region.CreateSecurityGroup(name, tagId) -} - func convertRulePort(rule secrules.SecurityRule) []string { ports := []string{} if len(rule.Ports) > 0 { @@ -452,6 +442,7 @@ func (region *SRegion) updateSecurityGroupRules(secgroupId string, rules []secru if err != nil { return "", err } + sort.Sort(secrules.SecurityRuleSet(rules)) securityRules := []SecurityRules{} priority := int32(100) ruleStrs := []string{} @@ -466,84 +457,33 @@ func (region *SRegion) updateSecurityGroupRules(secgroupId string, rules []secru ruleStrs = append(ruleStrs, ruleStr) } } - secgroup.Properties.SecurityRules = &securityRules + secgroup.Properties.SecurityRules = securityRules secgroup.Properties.ProvisioningState = "" return secgroup.ID, region.client.Update(jsonutils.Marshal(secgroup), nil) } func (region *SRegion) AttachSecurityToInterfaces(secgroupId string, nicIds []string) error { - secgroup, err := region.GetSecurityGroupDetails(secgroupId) - if err != nil { - return err + for _, nicId := range nicIds { + nic, err := region.GetNetworkInterfaceDetail(nicId) + if err != nil { + return err + } + nic.Properties.NetworkSecurityGroup = &SSecurityGroup{ID: secgroupId} + if err := region.client.Update(jsonutils.Marshal(nic), nil); err != nil { + return err + } } - interfaces := []Interface{} - for i := 0; i < len(nicIds); i++ { - interfaces = append(interfaces, Interface{ID: nicIds[i]}) - } - secgroup.Properties.NetworkInterfaces = &interfaces - secgroup.Properties.ProvisioningState = "" - return region.client.Update(jsonutils.Marshal(secgroup), nil) + return nil } func (region *SRegion) AssiginSecurityGroup(instanceId, secgroupId string) error { - if instance, err := region.GetInstance(instanceId); err != nil { + instance, err := region.GetInstance(instanceId) + if err != nil { return err - } else { - nicIds := []string{} - for _, nic := range instance.Properties.NetworkProfile.NetworkInterfaces { - nicIds = append(nicIds, nic.ID) - } - return region.AttachSecurityToInterfaces(secgroupId, nicIds) } -} - -func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) (string, error) { - secgroup, err := self.GetSecurityGroupDetails(secgroupId) - if err != nil { - return "", err + nicIds := []string{} + for _, nic := range instance.Properties.NetworkProfile.NetworkInterfaces { + nicIds = append(nicIds, nic.ID) } - sort.Sort(secrules.SecurityRuleSet(rules)) - sort.Sort(SecurityRulesSet(*secgroup.Properties.SecurityRules)) - - newRules := []secrules.SecurityRule{} - - i, j := 0, 0 - for i < len(rules) || j < len(*secgroup.Properties.SecurityRules) { - if i < len(rules) && j < len(*secgroup.Properties.SecurityRules) { - (*secgroup.Properties.SecurityRules)[j].Properties.Priority = 1 - srcRule := (*secgroup.Properties.SecurityRules)[j].Properties.String() - destRule := rules[i].String() - cmp := strings.Compare(srcRule, destRule) - if cmp == 0 { - // keep secRule - newRules = append(newRules, rules[i]) - i++ - j++ - } else if cmp > 0 { - // remove srcRule - j++ - } else { - // add destRule - newRules = append(newRules, rules[i]) - i++ - } - } else if i >= len(rules) { - // del other rules - j++ - } else if j >= len(*secgroup.Properties.SecurityRules) { - // add rule - newRules = append(newRules, rules[i]) - i++ - } - } - return self.updateSecurityGroupRules(secgroup.ID, newRules) - -} - -func (self *SRegion) syncSecurityGroup(tagId, name string, rules []secrules.SecurityRule) (string, error) { - secgroup, err := self.checkSecurityGroup(tagId, name) - if err != nil { - return "", err - } - return self.syncSecgroupRules(secgroup.ID, rules) + return region.AttachSecurityToInterfaces(secgroupId, nicIds) } diff --git a/pkg/util/azure/shell/secgroup.go b/pkg/util/azure/shell/secgroup.go index 76deb7d46f..b2f993135a 100644 --- a/pkg/util/azure/shell/secgroup.go +++ b/pkg/util/azure/shell/secgroup.go @@ -52,16 +52,24 @@ func init() { }) type SecurityGroupCreateOptions struct { - NAME string `help:"Security Group name"` - TagId string `help:"Add a id tag to secgroup"` + NAME string `help:"Security Group name"` + Classic bool `help:"Create classic Security Group"` } shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *azure.SRegion, args *SecurityGroupCreateOptions) error { - if secgrp, err := cli.CreateSecurityGroup(args.NAME, args.TagId); err != nil { - return err - } else { + if args.Classic { + secgrp, err := cli.CreateClassicSecurityGroup(args.NAME) + if err != nil { + return err + } printObject(secgrp) return nil } + secgrp, err := cli.CreateSecurityGroup(args.NAME) + if err != nil { + return err + } + printObject(secgrp) + return nil }) } diff --git a/pkg/util/azure/shell/storage.go b/pkg/util/azure/shell/storage.go deleted file mode 100644 index 7728277f7d..0000000000 --- a/pkg/util/azure/shell/storage.go +++ /dev/null @@ -1,21 +0,0 @@ -package shell - -import ( - "yunion.io/x/onecloud/pkg/util/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&StorageListOptions{}, "storage-list", "List storage types", func(cli *azure.SRegion, args *StorageListOptions) error { - storageType, err := cli.GetStorageTypes() - if err != nil { - return err - } - printList(storageType, len(storageType), args.Offset, args.Limit, []string{}) - return nil - }) -} diff --git a/pkg/util/azure/storage.go b/pkg/util/azure/storage.go index 660b3bd69d..6040a9a0d3 100644 --- a/pkg/util/azure/storage.go +++ b/pkg/util/azure/storage.go @@ -15,6 +15,8 @@ type Capabilitie struct { Value string } +var STORAGETYPES = []string{"Standard_LRS", "Premium_LRS", "StandardSSD_LRS"} + type SStorage struct { zone *SZone diff --git a/pkg/util/azure/storagecache.go b/pkg/util/azure/storagecache.go index 0715ea4393..bcaf4036a5 100644 --- a/pkg/util/azure/storagecache.go +++ b/pkg/util/azure/storagecache.go @@ -134,65 +134,67 @@ func (self *SStoragecache) checkStorageAccount() (*SStorageAccount, error) { func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, isForce bool, tmpPath string) (string, error) { s := auth.GetAdminSession(options.Options.Region, "") - if meta, reader, err := modules.Images.Download(s, imageId); err != nil { + meta, reader, err := modules.Images.Download(s, imageId) + if err != nil { return "", err - } else { - // {"checksum":"d0ab0450979977c6ada8d85066a6e484","container_format":"bare","created_at":"2018-08-10T04:18:07","deleted":"False","disk_format":"vhd","id":"64189033-3ad4-413c-b074-6bf0b6be8508","is_public":"False","min_disk":"0","min_ram":"0","name":"centos-7.3.1611-20180104.vhd","owner":"5124d80475434da8b41fee48d5be94df","properties":{"os_arch":"x86_64","os_distribution":"CentOS","os_type":"Linux","os_version":"7.3.1611-VHD"},"protected":"False","size":"2028505088","status":"active","updated_at":"2018-08-10T04:20:59"} - log.Infof("meta data %s", meta) - - imageNameOnBlob, _ := meta.GetString("name") - if !strings.HasSuffix(imageNameOnBlob, ".vhd") { - imageNameOnBlob = fmt.Sprintf("%s.vhd", imageNameOnBlob) - } - tmpFile := fmt.Sprintf("%s/%s", tmpPath, imageNameOnBlob) - defer os.Remove(tmpFile) - f, err := os.Create(tmpFile) - if err != nil { - return "", err - } - defer f.Close() - if _, err := io.Copy(f, reader); err != nil { - return "", err - } - - storageaccount, err := self.checkStorageAccount() - if err != nil { - return "", err - } - - blobURI, err := storageaccount.UploadFile("image-cache", tmpFile) - if err != nil { - return "", err - } - - size, _ := meta.Int("size") - - imageBaseName := imageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", imageId) - } - imageName := imageBaseName - nameIdx := 1 - - // check image name, avoid name conflict - for { - if _, err = self.region.GetImageByName(imageName); err != nil { - if err == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - } - - if image, err := self.region.CreateImageByBlob(imageName, osType, blobURI, int32(size>>30)); err != nil { - return "", err - } else { - return image.GetGlobalId(), nil - } } + // { + // "checksum":"d0ab0450979977c6ada8d85066a6e484", + // "container_format":"bare", + // "created_at":"2018-08-10T04:18:07", + // "deleted":"False", + // "disk_format":"vhd", + // "id":"64189033-3ad4-413c-b074-6bf0b6be8508", + // "is_public":"False", + // "min_disk":"0", + // "min_ram":"0", + // "name":"centos-7.3.1611-20180104.vhd", + // "owner":"5124d80475434da8b41fee48d5be94df", + // "properties":{ + // "os_arch":"x86_64", + // "os_distribution":"CentOS", + // "os_type":"Linux", + // "os_version":"7.3.1611-VHD" + // }, + // "protected":"False", + // "size":"2028505088", + // "status":"active", + // "updated_at":"2018-08-10T04:20:59" + // } + log.Infof("meta data %s", meta) + + imageNameOnBlob, _ := meta.GetString("name") + if !strings.HasSuffix(imageNameOnBlob, ".vhd") { + imageNameOnBlob = fmt.Sprintf("%s.vhd", imageNameOnBlob) + } + tmpFile := fmt.Sprintf("%s/%s", tmpPath, imageNameOnBlob) + defer os.Remove(tmpFile) + f, err := os.Create(tmpFile) + if err != nil { + return "", err + } + defer f.Close() + if _, err := io.Copy(f, reader); err != nil { + return "", err + } + + storageaccount, err := self.checkStorageAccount() + if err != nil { + return "", err + } + + blobURI, err := storageaccount.UploadFile("image-cache", tmpFile) + if err != nil { + return "", err + } + + size, _ := meta.Int("size") + + image, err := self.region.CreateImageByBlob(imageId, osType, blobURI, int32(size>>30)) + if err != nil { + return "", err + } + return image.GetGlobalId(), nil } func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { diff --git a/pkg/util/azure/vpc.go b/pkg/util/azure/vpc.go index 3d4bb02dff..ea02295e6f 100644 --- a/pkg/util/azure/vpc.go +++ b/pkg/util/azure/vpc.go @@ -5,7 +5,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/pkg/util/secrules" ) type AddressSpace struct { @@ -107,14 +106,6 @@ func (self *SVpc) fetchSecurityGroups() error { } } -func (self *SVpc) SyncSecurityGroup(tag string, name string, rules []secrules.SecurityRule) (string, error) { - secgrp, err := self.region.checkSecurityGroup(tag, name) - if err != nil { - return "", err - } - return self.region.syncSecgroupRules(secgrp.ID, rules) -} - func (self *SVpc) getWire() *SWire { if self.iwires == nil { self.fetchWires() diff --git a/pkg/util/azure/zone.go b/pkg/util/azure/zone.go index eba090104f..17851ed4a5 100644 --- a/pkg/util/azure/zone.go +++ b/pkg/util/azure/zone.go @@ -6,7 +6,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/pkg/utils" ) type SZone struct { @@ -67,38 +66,6 @@ func (self *SZone) getClassicHost() *SClassicHost { return self.classicHost } -func (self *SZone) getStorageTypes() (err error) { - if len(self.storageTypes) > 0 { - return nil - } - storages, err := self.region.GetStorageTypes() - if err != nil { - return err - } - self.storageTypes = []string{} - for i := 0; i < len(storages); i++ { - if !utils.IsInStringArray(storages[i].Name, self.storageTypes) { - self.storageTypes = append(self.storageTypes, storages[i].Name) - } - } - return nil -} - -func (self *SRegion) GetStorageTypes() ([]SStorage, error) { - storages := []SStorage{} - err := self.client.ListAll("Microsoft.Storage/skus", &storages) - if err != nil { - return nil, err - } - result := []SStorage{} - for i := 0; i < len(storages); i++ { - if utils.IsInStringArray(self.Name, storages[i].Locations) { - result = append(result, storages[i]) - } - } - return result, nil -} - func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { return self.region } @@ -124,14 +91,8 @@ func (self *SZone) fetchClassicStorages() error { } func (self *SZone) fetchStorages() error { - if len(self.storageTypes) == 0 { - err := self.getStorageTypes() - if err != nil { - return err - } - } - self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes)) - for i, storageType := range self.storageTypes { + self.istorages = make([]cloudprovider.ICloudStorage, len(STORAGETYPES)) + for i, storageType := range STORAGETYPES { storage := SStorage{zone: self, storageType: storageType} self.istorages[i] = &storage } diff --git a/pkg/util/esxi/virtualmachine.go b/pkg/util/esxi/virtualmachine.go index 623a4da458..e9dd20138a 100644 --- a/pkg/util/esxi/virtualmachine.go +++ b/pkg/util/esxi/virtualmachine.go @@ -9,7 +9,6 @@ import ( "github.com/vmware/govmomi/vim25/types" "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/secrules" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" @@ -39,10 +38,6 @@ func (self *SVirtualMachine) GetGlobalId() string { return self.getUuid() } -func (self *SVirtualMachine) SyncSecurityGroup(secgroupId, name string, rules []secrules.SecurityRule) error { - return nil -} - func (self *SVirtualMachine) GetStatus() string { vm := object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) state, err := vm.PowerState(self.manager.context) @@ -238,6 +233,10 @@ func (dc *SVirtualMachine) ChangeConfig(instanceId string, ncpu int, vmem int) e return cloudprovider.ErrNotImplemented } +func (self *SVirtualMachine) AssignSecurityGroup(secgroupId string) error { + return cloudprovider.ErrNotImplemented +} + func (self *SVirtualMachine) GetBillingType() string { return models.BILLING_TYPE_POSTPAID } diff --git a/pkg/util/qcloud/instance.go b/pkg/util/qcloud/instance.go index aa51d86820..294ad1fef1 100644 --- a/pkg/util/qcloud/instance.go +++ b/pkg/util/qcloud/instance.go @@ -8,7 +8,6 @@ import ( "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/utils" ) @@ -676,30 +675,9 @@ func (self *SRegion) AttachDisk(instanceId string, diskId string) error { return nil } -func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error { - // if vpc, err := self.getVpc(); err != nil { - // return err - // } else if len(secgroupId) == 0 { - // for index, secgrpId := range self.SecurityGroupIds.SecurityGroupId { - // if err := vpc.revokeSecurityGroup(secgrpId, self.InstanceId, index == 0); err != nil { - // return err - // } - // } - // } else if secgrpId, err := vpc.SyncSecurityGroup(secgroupId, name, rules); err != nil { - // return err - // } else if err := vpc.assignSecurityGroup(secgrpId, self.InstanceId); err != nil { - // return err - // } else { - // for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId { - // if secgroupId != secgrpId { - // if err := vpc.revokeSecurityGroup(secgroupId, self.InstanceId, false); err != nil { - // return err - // } - // } - // } - // self.SecurityGroupIds.SecurityGroupId = []string{secgrpId} - // } - return nil +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + params := map[string]string{"SecurityGroups.0": secgroupId} + return self.host.zone.region.instanceOperation(self.InstanceId, "ModifyInstancesAttribute", params) } func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { diff --git a/pkg/util/qcloud/region.go b/pkg/util/qcloud/region.go index 2c74f880b5..86fc26df65 100644 --- a/pkg/util/qcloud/region.go +++ b/pkg/util/qcloud/region.go @@ -519,6 +519,10 @@ func (self *SRegion) instanceOperation(instanceId string, opname string, extra m return err } +func (self *SRegion) DeleteSecurityGroup(vpcId string, secgroupId string) error { + return self.deleteSecurityGroup(secgroupId) +} + func (self *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { params := make(map[string]string) params["InstanceId"] = instanceId diff --git a/pkg/util/qcloud/securitygroup.go b/pkg/util/qcloud/securitygroup.go index ad1d1d35eb..870edae808 100644 --- a/pkg/util/qcloud/securitygroup.go +++ b/pkg/util/qcloud/securitygroup.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/utils" ) @@ -102,6 +103,11 @@ func (self *SSecurityGroup) GetMetadata() *jsonutils.JSONDict { return nil } +func (self *SSecurityGroup) GetVpcId() string { + //腾讯云安全组未与vpc关联,统一使用normal + return "normal" +} + func (self *SSecurityGroup) GetId() string { return self.SecurityGroupId } @@ -293,6 +299,30 @@ func (self *SSecurityGroup) Refresh() error { } } +func (self *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) { + if len(secgroupId) > 0 { + _, err := self.GetSecurityGroupDetails(secgroupId) + if err != nil { + if err != cloudprovider.ErrNotFound { + return "", err + } + secgroupId = "" + } + } + if len(secgroupId) == 0 { + secgroup, err := self.CreateSecurityGroup(name, desc) + if err != nil { + return "", err + } + secgroupId = secgroup.SecurityGroupId + } + return self.syncSecgroupRules(secgroupId, rules) +} + +func (self *SRegion) syncSecgroupRules(secgroupid string, rules []secrules.SecurityRule) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { params := make(map[string]string) params["Region"] = self.Region @@ -313,7 +343,7 @@ func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup return &secgrp, nil } -func (self *SRegion) DeleteSecurityGroup(secGroupId string) error { +func (self *SRegion) deleteSecurityGroup(secGroupId string) error { params := make(map[string]string) params["Region"] = self.Region params["SecurityGroupId"] = secGroupId diff --git a/pkg/util/qcloud/shell/securitygroup.go b/pkg/util/qcloud/shell/securitygroup.go index 35d6536d34..86aa0e2f96 100644 --- a/pkg/util/qcloud/shell/securitygroup.go +++ b/pkg/util/qcloud/shell/securitygroup.go @@ -32,7 +32,7 @@ func init() { }) shellutils.R(&SecurityGroupOptions{}, "security-group-delete", "Delete SecurityGroup", func(cli *qcloud.SRegion, args *SecurityGroupOptions) error { - return cli.DeleteSecurityGroup(args.ID) + return cli.DeleteSecurityGroup("", args.ID) }) type SecurityGroupCreateOptions struct { diff --git a/pkg/util/qcloud/vpc.go b/pkg/util/qcloud/vpc.go index ba59f5609f..654256320c 100644 --- a/pkg/util/qcloud/vpc.go +++ b/pkg/util/qcloud/vpc.go @@ -6,7 +6,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/pkg/util/secrules" ) type SVpc struct { @@ -161,35 +160,6 @@ func (self *SVpc) Refresh() error { return jsonutils.Update(self, new) } -func (self *SVpc) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) (string, error) { - secgrpId := "" - // if secgroup, err := self.region.getSecurityGroupByTag(self.VpcId, secgroupId); err != nil { - // if secgrpId, err = self.region.createSecurityGroup(self.VpcId, name, ""); err != nil { - // return "", err - // } else if err := self.region.addTagToSecurityGroup(secgrpId, "id", secgroupId, 1); err != nil { - // return "", err - // } - // //addRules - // log.Debugf("Add Rules for %s", secgrpId) - // for _, rule := range rules { - // if err := self.region.addSecurityGroupRule(secgrpId, &rule); err != nil { - // return "", err - // } - // } - // } else { - // //syncRules - // secgrpId = secgroup.SecurityGroupId - // log.Debugf("Sync Rules for %s", secgroup.GetName()) - // if secgroup.GetName() != name { - // if err := self.region.modifySecurityGroup(secgrpId, name, ""); err != nil { - // log.Errorf("Change SecurityGroup name to %s failed: %v", name, err) - // } - // } - // self.region.syncSecgroupRules(secgrpId, rules) - // } - return secgrpId, nil -} - func (self *SVpc) addWire(wire *SWire) { if self.iwires == nil { self.iwires = make([]cloudprovider.ICloudWire, 0)