限制虚机绑定安全组数量

This commit is contained in:
屈轩
2018-12-05 12:40:47 +08:00
parent 2608e8e6b9
commit e34e45d008
13 changed files with 157 additions and 125 deletions
+11 -7
View File
@@ -306,9 +306,9 @@ func init() {
if err != nil {
return err
}
srv, e := modules.Servers.PerformAction(s, opts.ID, "add-secgroup", params)
if e != nil {
return e
srv, err := modules.Servers.PerformAction(s, opts.ID, "add-secgroup", params)
if err != nil {
return err
}
printObject(srv)
return nil
@@ -340,10 +340,14 @@ func init() {
return nil
})
R(&options.ServerIdOptions{}, "server-revoke-secgroup", "Assign security group to a VM", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error {
srv, e := modules.Servers.PerformAction(s, opts.ID, "revoke-secgroup", nil)
if e != nil {
return e
R(&options.ServerSecGroupOptions{}, "server-revoke-secgroup", "Revoke security group from VM", func(s *mcclient.ClientSession, opts *options.ServerSecGroupOptions) error {
params, err := options.StructToParams(opts)
if err != nil {
return err
}
srv, err := modules.Servers.PerformAction(s, opts.ID, "revoke-secgroup", params)
if err != nil {
return err
}
printObject(srv)
return nil
+55 -29
View File
@@ -14,6 +14,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -636,33 +637,27 @@ func (self *SGuest) PerformAddSecgroup(ctx context.Context, userCred mcclient.To
if !utils.IsInStringArray(self.Status, []string{VM_READY, VM_RUNNING, VM_SUSPEND}) {
return nil, httperrors.NewInputParameterError("Cannot assign security rules in status %s", self.Status)
}
secgrp, err := data.GetString("secgrp")
if err != nil {
secgrpV := validators.NewModelIdOrNameValidator("secgrp", "secgroup", userCred.GetProjectId())
if err := secgrpV.Validate(data.(*jsonutils.JSONDict)); err != nil {
return nil, err
}
sg, err := SecurityGroupManager.FetchByIdOrName(userCred, secgrp)
if err != nil {
return nil, httperrors.NewNotFoundError("SecurityGroup %s not found", secgrp)
}
maxCount := self.GetDriver().GetMaxSecurityGroupCount()
if maxCount == 0 {
return nil, httperrors.NewUnsupportOperationError("Cannot assign security group for this guest %s", self.Name)
}
secgroups := self.GetSecgroups()
if len(secgroups) >= maxCount {
return nil, httperrors.NewUnsupportOperationError("guest %s band to up to %d security groups", self.Name, maxCount)
}
secgroup := sg.(*SSecurityGroup)
secgroup := secgrpV.Model.(*SSecurityGroup)
if _, err := GuestsecgroupManager.newGuestSecgroup(ctx, userCred, self, secgroup); err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
}
if err := self.StartSyncTask(ctx, userCred, true, ""); err != nil {
return nil, err
}
return nil, nil
return nil, self.StartSyncTask(ctx, userCred, true, "")
}
func (self *SGuest) AllowPerformAssignSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
@@ -673,44 +668,75 @@ func (self *SGuest) AllowPerformRevokeSecgroup(ctx context.Context, userCred mcc
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "revoke-secgroup")
}
func (self *SGuest) revokeSecgroup(ctx context.Context, userCred mcclient.TokenCredential, secgroup *SSecurityGroup) error {
if secgroup == nil {
return fmt.Errorf("failed to revoke null secgroup")
}
if self.SecgrpId != secgroup.Id {
return GuestsecgroupManager.DeleteGuestSecgroup(ctx, userCred, self, secgroup)
}
secgroups := self.GetSecgroups()
if len(secgroups) == 1 {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.SecgrpId = "default"
return nil
})
return err
}
for _, _secgroup := range secgroups {
if _secgroup.Id != secgroup.Id {
err := GuestsecgroupManager.DeleteGuestSecgroup(ctx, userCred, self, &_secgroup)
if err != nil {
return err
}
_, err = self.GetModelManager().TableSpec().Update(self, func() error {
self.SecgrpId = _secgroup.Id
return nil
})
return err
}
}
return nil
}
func (self *SGuest) PerformRevokeSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(self.Status, []string{VM_READY, VM_RUNNING, VM_SUSPEND}) {
return nil, httperrors.NewInputParameterError("Cannot revoke security rules in status %s", self.Status)
}
if _, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.SecgrpId = "default"
return nil
}); err != nil {
secgrpV := validators.NewModelIdOrNameValidator("secgrp", "secgroup", userCred.GetProjectId())
secgrpV.Optional(true)
if err := secgrpV.Validate(data.(*jsonutils.JSONDict)); err != nil {
return nil, err
}
if err := self.StartSyncTask(ctx, userCred, true, ""); err != nil {
secgroup, ok := secgrpV.Model.(*SSecurityGroup)
if !ok {
secgroup = self.getSecgroup()
}
if err := self.revokeSecgroup(ctx, userCred, secgroup); err != nil {
return nil, err
}
return nil, nil
return nil, self.StartSyncTask(ctx, userCred, true, "")
}
func (self *SGuest) PerformAssignSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(self.Status, []string{VM_READY, VM_RUNNING, VM_SUSPEND}) {
return nil, httperrors.NewInputParameterError("Cannot assign security rules in status %s", self.Status)
}
secgrp, err := data.GetString("secgrp")
if err != nil {
secgrpV := validators.NewModelIdOrNameValidator("secgrp", "secgroup", userCred.GetProjectId())
if err := secgrpV.Validate(data.(*jsonutils.JSONDict)); err != nil {
return nil, err
}
sg, err := SecurityGroupManager.FetchByIdOrName(userCred, secgrp)
if err != nil {
return nil, httperrors.NewNotFoundError("SecurityGroup %s not found", secgrp)
}
if _, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.SecgrpId = sg.GetId()
self.SecgrpId = secgrpV.Model.GetId()
return nil
}); err != nil {
return nil, err
}
if err := self.StartSyncTask(ctx, userCred, true, ""); err != nil {
return nil, err
}
return nil, nil
return nil, self.StartSyncTask(ctx, userCred, true, "")
}
func (self *SGuest) AllowPerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
+55 -25
View File
@@ -8,6 +8,7 @@ import (
"strconv"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/tristate"
@@ -264,10 +265,11 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ
if secgrp == nil {
return nil, httperrors.NewResourceNotFoundError("secgroup %s not found", secgrpFilter)
}
guestsecgroups := GuestsecgroupManager.Query().SubQuery()
q = q.Join(guestsecgroups, sqlchemy.Equals(q.Field("id"), guestsecgroups.Field("guest_id")))
q = q.Filter(sqlchemy.OR(sqlchemy.Equals(q.Field("secgrp_id"), secgrp.GetId()),
sqlchemy.Equals(guestsecgroups.Field("secgroup_id"), secgrp.GetId())),
q = q.Filter(
sqlchemy.OR(
sqlchemy.In(q.Field("id"), GuestsecgroupManager.Query("guest_id").Equals("secgroup_id", secgrp.GetId()).SubQuery()),
sqlchemy.Equals(q.Field("secgrp_id"), secgrp.GetId()),
),
)
}
@@ -1394,16 +1396,17 @@ func (self *SGuest) getSecgroupJson() []jsonutils.JSONObject {
}
func (self *SGuest) GetSecgroups() []SSecurityGroup {
q := SecurityGroupManager.Query()
guestsecgroups := GuestsecgroupManager.Query().SubQuery()
q = q.Join(guestsecgroups, sqlchemy.Equals(guestsecgroups.Field("guest_id"), self.Id)).Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("id"), self.SecgrpId),
sqlchemy.Equals(q.Field("id"), guestsecgroups.Field("secgroup_id")),
))
secgrpQuery := SecurityGroupManager.Query()
secgrpQuery.Filter(
sqlchemy.OR(
sqlchemy.Equals(secgrpQuery.Field("id"), self.SecgrpId),
sqlchemy.In(secgrpQuery.Field("id"), GuestsecgroupManager.Query("secgroup_id").Equals("guest_id", self.Id).SubQuery()),
),
)
secgroups := []SSecurityGroup{}
if err := db.FetchModelObjects(SecurityGroupManager, q, &secgroups); err != nil {
if err := db.FetchModelObjects(SecurityGroupManager, secgrpQuery, &secgroups); err != nil {
log.Errorf("Get security group error: %v", err)
return nil
}
return secgroups
}
@@ -1457,6 +1460,7 @@ func (self *SGuest) getSecurityRules() string {
}
}
//获取多个安全组规则,优先级降序排序
func (self *SGuest) getSecurityGroupsRules() string {
secgroups := self.GetSecgroups()
secgroupids := []string{}
@@ -1541,12 +1545,23 @@ func (self *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.Token
self.BillingType = extVM.GetBillingType()
self.ExpiredAt = extVM.GetExpiredAt()
if metaData != nil && metaData.Contains("secgroupId") {
if secgroupId, err := metaData.GetString("secgroupId"); err == nil && len(secgroupId) > 0 {
if secgrp, err := SecurityGroupManager.FetchByExternalId(secgroupId); err == nil && secgrp != nil {
self.SecgrpId = secgrp.GetId()
} else {
log.Errorf("Failed find secgroup %s for guest %s error: %v", secgroupId, self.Name, err)
if metaData != nil && metaData.Contains("secgroupIds") {
secgroupIds := []string{}
if err := metaData.Unmarshal(&secgroupIds, "secgroupIds"); err == nil {
for _, secgroupId := range secgroupIds {
secgrp, err := SecurityGroupManager.FetchByExternalId(secgroupId)
if err != nil {
log.Errorf("Failed find secgroup %s for guest %s error: %v", secgroupId, self.Name, err)
continue
}
secgroup := secgrp.(*SSecurityGroup)
if len(self.SecgrpId) == 0 {
self.SecgrpId = secgroup.Id
} else {
if _, err := GuestsecgroupManager.newGuestSecgroup(ctx, userCred, self, secgroup); err != nil {
log.Errorf("failed to bind secgroup %s for guest %s error: %v", secgroup.Name, self.Name, err)
}
}
}
}
}
@@ -1626,12 +1641,22 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
guest.ProjectId = projectId
}
if metaData != nil && metaData.Contains("secgroupId") {
if secgroupId, err := metaData.GetString("secgroupId"); err == nil && len(secgroupId) > 0 {
if secgrp, err := SecurityGroupManager.FetchByExternalId(secgroupId); err == nil && secgrp != nil {
guest.SecgrpId = secgrp.GetId()
} else {
log.Errorf("Failed find secgroup %s for guest %s error: %v", secgroupId, guest.Name, err)
extraSecgroups := []*SSecurityGroup{}
if metaData != nil && metaData.Contains("secgroupIds") {
secgroupIds := []string{}
if err := metaData.Unmarshal(&secgroupIds, "secgroupIds"); err == nil {
for _, secgroupId := range secgroupIds {
secgrp, err := SecurityGroupManager.FetchByExternalId(secgroupId)
if err != nil {
log.Errorf("Failed find secgroup %s for guest %s error: %v", secgroupId, guest.Name, err)
continue
}
secgroup := secgrp.(*SSecurityGroup)
if len(guest.SecgrpId) == 0 {
guest.SecgrpId = secgroup.Id
} else {
extraSecgroups = append(extraSecgroups, secgroup)
}
}
}
}
@@ -1641,6 +1666,12 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.
log.Errorf("Insert fail %s", err)
}
for _, secgroup := range extraSecgroups {
if _, err := GuestsecgroupManager.newGuestSecgroup(ctx, userCred, &guest, secgroup); err != nil {
log.Errorf("failed to bind secgroup %s for guest %s error: %v", secgroup.Name, guest.Name, err)
}
}
if metaData != nil {
meta := make(map[string]string, 0)
if err := metaData.Unmarshal(meta); err != nil {
@@ -2643,7 +2674,6 @@ func (self *SGuest) GetJsonDescAtHypervisor(ctx context.Context, host *SHost) *j
if srs.estimatedSinglePortRuleCount() <= options.FirewallFlowCountLimit {
*/
//获取多个安全组规则,优先级降序排序
rules := self.getSecurityGroupsRules()
if len(rules) > 0 {
desc.Add(jsonutils.NewString(rules), "security_rules")
+7 -8
View File
@@ -37,22 +37,21 @@ type SGuestsecgroup struct {
}
func (self *SGuestsecgroup) getSecgroup() *SSecurityGroup {
secgroup := SSecurityGroup{}
secgroup.SetModelManager(SecurityGroupManager)
q := SecurityGroupManager.Query()
q = q.Equals("id", self.SecgroupId)
if err := q.First(&secgroup); err != nil {
secgrp, err := SecurityGroupManager.FetchById(self.SecgroupId)
if err != nil {
log.Errorf("failed to find secgroup %s", self.SecgroupId)
return nil
}
return &secgroup
secgroup := secgrp.(*SSecurityGroup)
secgroup.SetModelManager(SecurityGroupManager)
return secgroup
}
func (manager *SGuestsecgroupManager) newGuestSecgroup(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, secgroup *SSecurityGroup) (*SGuestsecgroup, error) {
q := manager.Query()
q = q.Equals("guest_id", guest.Id).Equals("secgroup_id", secgroup.Id)
if count := q.Count(); count > 0 {
return nil, fmt.Errorf("security group %s has assign guest %s", secgroup.Name, guest.Name)
return nil, fmt.Errorf("security group %s has already been assigned to guest %s", secgroup.Name, guest.Name)
}
gs := SGuestsecgroup{SecgroupId: secgroup.Id}
@@ -68,7 +67,7 @@ func (manager *SGuestsecgroupManager) newGuestSecgroup(ctx context.Context, user
func (manager *SGuestsecgroupManager) DeleteGuestSecgroup(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, secgroup *SSecurityGroup) error {
gss := []SGuestsecgroup{}
q := manager.Query()
q = q.Equals(guest.Id, q.Field("guest_id")).Equals(secgroup.Id, q.Field("secgroup_id"))
q = q.Equals("guest_id", guest.Id).Equals("secgroup_id", secgroup.Id)
if err := db.FetchModelObjects(manager, q, &gss); err != nil {
return err
}
+8 -7
View File
@@ -50,12 +50,13 @@ type SSecurityGroup struct {
}
func (self *SSecurityGroup) GetGuestsQuery() *sqlchemy.SQuery {
guests := GuestManager.Query()
guestsecgroups := GuestsecgroupManager.Query().SubQuery()
query := guests.Join(guestsecgroups, sqlchemy.AND(sqlchemy.Equals(guestsecgroups.Field("guest_id"), guests.Field("id"))))
return query.Filter(sqlchemy.OR(sqlchemy.Equals(guests.Field("secgrp_id"), self.Id),
sqlchemy.Equals(guests.Field("admin_secgrp_id"), self.Id),
sqlchemy.Equals(guestsecgroups.Field("secgroup_id"), self.Id)),
guests := GuestManager.Query().SubQuery()
return guests.Query().Filter(
sqlchemy.OR(
sqlchemy.Equals(guests.Field("secgrp_id"), self.Id),
sqlchemy.Equals(guests.Field("admin_secgrp_id"), self.Id),
sqlchemy.In(guests.Field("id"), GuestsecgroupManager.Query("guest_id").Equals("secgroup_id", self.Id).SubQuery()),
),
)
}
@@ -64,7 +65,7 @@ func (self *SSecurityGroup) GetGuestsCount() int {
}
func (self *SSecurityGroup) GetGuests() []SGuest {
guests := make([]SGuest, 0)
guests := []SGuest{}
q := self.GetGuestsQuery()
err := db.FetchModelObjects(GuestManager, q, &guests)
if err != nil {
+4 -5
View File
@@ -11,6 +11,7 @@ import (
"yunion.io/x/pkg/utils"
"context"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
@@ -227,13 +228,11 @@ func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
data.Update(meta)
}
}
secgroupIds := jsonutils.NewArray()
for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId {
if len(secgroupId) > 0 {
data.Add(jsonutils.NewString(secgroupId), "secgroupId")
break
}
secgroupIds.Add(jsonutils.NewString(secgroupId))
}
data.Add(secgroupIds, "secgroupIds")
return data
}
+1 -16
View File
@@ -501,22 +501,7 @@ func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.Secur
}
func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error {
params := map[string]string{"InstanceId": instanceId, "SecurityGroupId": secgroupId}
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
return self.AssignSecurityGroups([]string{secgroupId}, instanceId)
}
func (self *SRegion) AssignSecurityGroups(secgroupIds []string, instanceId string) error {
+3 -5
View File
@@ -172,13 +172,11 @@ func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
data.Update(meta)
}
}
secgroupIds := jsonutils.NewArray()
for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId {
if len(secgroupId) > 0 {
data.Add(jsonutils.NewString(secgroupId), "secgroupId")
break
}
secgroupIds.Add(jsonutils.NewString(secgroupId))
}
data.Add(secgroupIds, "secgroupIds")
return data
}
+2 -18
View File
@@ -246,23 +246,7 @@ func (self *SRegion) revokeSecurityGroup(secgroupId, instanceId string, keep boo
}
func (self *SRegion) assignSecurityGroup(secgroupId, instanceId string) error {
instance, err := self.GetInstance(instanceId)
if err != nil {
return err
}
for _, eth := range instance.NetworkInterfaces.NetworkInterface {
params := &ec2.ModifyNetworkInterfaceAttributeInput{}
params.SetNetworkInterfaceId(eth.NetworkInterfaceId)
params.SetGroups([]*string{&secgroupId})
_, err := self.ec2Client.ModifyNetworkInterfaceAttribute(params)
if err != nil {
return err
}
}
return nil
return self.assignSecurityGroups([]*string{&secgroupId}, instanceId)
}
func (self *SRegion) assignSecurityGroups(secgroupIds []*string, instanceId string) error {
@@ -285,7 +269,7 @@ func (self *SRegion) assignSecurityGroups(secgroupIds []*string, instanceId stri
return nil
}
func (self *SRegion) DeleteSecurityGroup(vpcId string, secGrpId string) error {
func (self *SRegion) DeleteSecurityGroup(vpcId, secGrpId string) error {
params := &ec2.DeleteSecurityGroupInput{}
params.SetGroupId(secGrpId)
+5 -1
View File
@@ -6,6 +6,7 @@ import (
"time"
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -129,9 +130,12 @@ func (self *SClassicInstance) GetMetadata() *jsonutils.JSONDict {
data := jsonutils.NewDict()
priceKey := fmt.Sprintf("%s::%s", self.Properties.HardwareProfile.Size, self.host.zone.region.Name)
data.Add(jsonutils.NewString(priceKey), "price_key")
data.Add(jsonutils.NewString(self.host.zone.GetGlobalId()), "zone_ext_id")
secgroupIds := jsonutils.NewArray()
if self.Properties.NetworkProfile.NetworkSecurityGroup != nil {
data.Add(jsonutils.NewString(self.Properties.NetworkProfile.NetworkSecurityGroup.ID), "secgroupId")
secgroupIds.Add(jsonutils.NewString(self.Properties.NetworkProfile.NetworkSecurityGroup.ID))
}
data.Add(secgroupIds, "secgroupIds")
return data
}
+4 -2
View File
@@ -6,6 +6,7 @@ import (
"time"
"context"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -211,17 +212,18 @@ func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
data.Add(jsonutils.NewString(self.host.zone.GetGlobalId()), "zone_ext_id")
priceKey := fmt.Sprintf("%s::%s", self.Properties.HardwareProfile.VMSize, self.host.zone.region.Name)
data.Add(jsonutils.NewString(priceKey), "price_key")
secgroupIds := jsonutils.NewArray()
if nics, err := self.getNics(); err == nil {
for _, nic := range nics {
if nic.Properties.NetworkSecurityGroup != nil {
if len(nic.Properties.NetworkSecurityGroup.ID) > 0 {
data.Add(jsonutils.NewString(nic.Properties.NetworkSecurityGroup.ID), "secgroupId")
secgroupIds.Add(jsonutils.NewString(nic.Properties.NetworkSecurityGroup.ID))
break
}
}
}
}
data.Add(secgroupIds, "secgroupIds")
return data
}
-1
View File
@@ -145,7 +145,6 @@ func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
data.Add(jsonutils.NewString(self.host.zone.GetGlobalId()), "zone_ext_id")
secgroupIds := jsonutils.NewArray()
for _, secgroupId := range self.SecurityGroupIds {
data.Add(jsonutils.NewString(secgroupId), "secgroupId")
secgroupIds.Add(jsonutils.NewString(secgroupId))
}
data.Add(secgroupIds, "secgroupIds")
+2 -1
View File
@@ -1,6 +1,7 @@
package shell
import (
"context"
"fmt"
"yunion.io/x/onecloud/pkg/util/qcloud"
@@ -64,7 +65,7 @@ func init() {
SIZE int64 `help:"Disk Size GB"`
}
shellutils.R(&DiskResizeOptions{}, "disk-resize", "Resize disk", func(cli *qcloud.SRegion, args *DiskResizeOptions) error {
return cli.ResizeDisk(args.ID, args.SIZE)
return cli.ResizeDisk(context.Background(), args.ID, args.SIZE)
})
type DiskResetOptions struct {