diff --git a/cmd/climc/shell/servers.go b/cmd/climc/shell/servers.go index 228108d488..998aa88638 100644 --- a/cmd/climc/shell/servers.go +++ b/cmd/climc/shell/servers.go @@ -313,7 +313,7 @@ func init() { return nil }) - R(&options.ServerSecGroupOptions{}, "server-add-secgroup", "Add security group to a VM", func(s *mcclient.ClientSession, opts *options.ServerSecGroupOptions) error { + R(&options.ServerSecGroupsOptions{}, "server-add-secgroup", "Add security group to a VM", func(s *mcclient.ClientSession, opts *options.ServerSecGroupsOptions) error { params, err := options.StructToParams(opts) if err != nil { return err diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index b9d046fda0..2742b69371 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -644,25 +644,46 @@ func (self *SGuest) PerformAddSecgroup(ctx context.Context, userCred mcclient.To return nil, httperrors.NewInputParameterError("Cannot assign security rules in status %s", self.Status) } - secgrpV := validators.NewModelIdOrNameValidator("secgrp", "secgroup", userCred.GetProjectId()) - if err := secgrpV.Validate(data.(*jsonutils.JSONDict)); err != nil { - return nil, err - } - maxCount := self.GetDriver().GetMaxSecurityGroupCount() if maxCount == 0 { return nil, httperrors.NewUnsupportOperationError("Cannot assign security group for this guest %s", self.Name) } + secgrps := []string{} + if err := data.Unmarshal(&secgrps, "secgrps"); err != nil { + return nil, httperrors.NewInputParameterError(err.Error()) + } + secgroups := self.GetSecgroups() - if len(secgroups) >= maxCount { + if len(secgroups)+len(secgrps) >= maxCount { return nil, httperrors.NewUnsupportOperationError("guest %s band to up to %d security groups", self.Name, maxCount) } - secgroup := secgrpV.Model.(*SSecurityGroup) - if _, err := GuestsecgroupManager.newGuestSecgroup(ctx, userCred, self, secgroup); err != nil { - return nil, httperrors.NewInputParameterError(err.Error()) + secgroupIds := []string{} + for _, secgroup := range secgroups { + secgroupIds = append(secgroupIds, secgroup.Id) } + + addSecgroups := []*SSecurityGroup{} + + for _, _secgrp := range secgrps { + secgrp, err := SecurityGroupManager.FetchByIdOrName(userCred, _secgrp) + if err != nil { + return nil, httperrors.NewInputParameterError(err.Error()) + } + + if utils.IsInStringArray(secgrp.GetId(), secgroupIds) { + return nil, httperrors.NewInputParameterError("security group %s has already been assigned to guest %s", secgrp.GetName(), self.Name) + } + addSecgroups = append(addSecgroups, secgrp.(*SSecurityGroup)) + } + + for _, secgroup := range addSecgroups { + if _, err := GuestsecgroupManager.newGuestSecgroup(ctx, userCred, self, secgroup); err != nil { + return nil, httperrors.NewInputParameterError(err.Error()) + } + } + return nil, self.StartSyncTask(ctx, userCred, true, "") } diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index db3727a3ee..172c7d1d27 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -263,6 +263,11 @@ type ServerSecGroupOptions struct { Secgrp string `help:"ID of Security Group" metavar:"Security Group" positional:"true"` } +type ServerSecGroupsOptions struct { + ID string `help:"ID or Name of server" metavar:"Guest" json:"-"` + Secgrps []string `help:"Ids of Security Groups" metavar:"Security Groups" positional:"true"` +} + type ServerSendKeyOptions struct { ID string `help:"ID or Name of server" metavar:"Guest" json:"-"` KEYS string `help:"Special keys to send, eg. ctrl, alt, f12, shift, etc, separated by \"-\""`