Skip to content

Commit 494ba5f

Browse files
committed
Support multiple --amazonec2-security-groups.
Maintains support for loading old Driver config.json that use the singular `SecurityGroupName` field, but also adds a new plural `SecurityGroupNames` field. This change also bumps to latest stretchr/testify, in the course of adding a dep on stretchr/testify/mock to help test the modified `configureSecurityGroups` code. The unused `deleteSecurityGroup` is dropped as well. Signed-off-by: John Sirois <john.sirois@gmail.com> Signed-off-by: Bill Farner <terasurfer@gmail.com>
1 parent 83afe2b commit 494ba5f

38 files changed

+8396
-583
lines changed

Godeps/Godeps.json

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

drivers/amazonec2/amazonec2.go

Lines changed: 109 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,28 @@ var (
5555

5656
type Driver struct {
5757
*drivers.BaseDriver
58-
clientFactory func() Ec2Client
59-
awsCredentials awsCredentials
60-
Id string
61-
AccessKey string
62-
SecretKey string
63-
SessionToken string
64-
Region string
65-
AMI string
66-
SSHKeyID int
67-
KeyName string
68-
InstanceId string
69-
InstanceType string
70-
PrivateIPAddress string
71-
SecurityGroupId string
72-
SecurityGroupName string
58+
clientFactory func() Ec2Client
59+
awsCredentials awsCredentials
60+
Id string
61+
AccessKey string
62+
SecretKey string
63+
SessionToken string
64+
Region string
65+
AMI string
66+
SSHKeyID int
67+
KeyName string
68+
InstanceId string
69+
InstanceType string
70+
PrivateIPAddress string
71+
72+
// NB: SecurityGroupId expanded from single value to slice on 26 Feb 2016 - we maintain both for host storage backwards compatibility.
73+
SecurityGroupId string
74+
SecurityGroupIds []string
75+
76+
// NB: SecurityGroupName expanded from single value to slice on 26 Feb 2016 - we maintain both for host storage backwards compatibility.
77+
SecurityGroupName string
78+
SecurityGroupNames []string
79+
7380
Tags string
7481
ReservationId string
7582
DeviceName string
@@ -138,10 +145,10 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
138145
Usage: "AWS VPC subnet id",
139146
EnvVar: "AWS_SUBNET_ID",
140147
},
141-
mcnflag.StringFlag{
148+
mcnflag.StringSliceFlag{
142149
Name: "amazonec2-security-group",
143150
Usage: "AWS VPC security group",
144-
Value: defaultSecurityGroup,
151+
Value: []string{defaultSecurityGroup},
145152
EnvVar: "AWS_SECURITY_GROUP",
146153
},
147154
mcnflag.StringFlag{
@@ -225,14 +232,14 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
225232
func NewDriver(hostName, storePath string) *Driver {
226233
id := generateId()
227234
driver := &Driver{
228-
Id: id,
229-
AMI: defaultAmiId,
230-
Region: defaultRegion,
231-
InstanceType: defaultInstanceType,
232-
RootSize: defaultRootSize,
233-
Zone: defaultZone,
234-
SecurityGroupName: defaultSecurityGroup,
235-
SpotPrice: defaultSpotPrice,
235+
Id: id,
236+
AMI: defaultAmiId,
237+
Region: defaultRegion,
238+
InstanceType: defaultInstanceType,
239+
RootSize: defaultRootSize,
240+
Zone: defaultZone,
241+
SecurityGroupNames: []string{defaultSecurityGroup},
242+
SpotPrice: defaultSpotPrice,
236243
BaseDriver: &drivers.BaseDriver{
237244
SSHUser: defaultSSHUser,
238245
MachineName: hostName,
@@ -282,7 +289,7 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
282289
d.InstanceType = flags.String("amazonec2-instance-type")
283290
d.VpcId = flags.String("amazonec2-vpc-id")
284291
d.SubnetId = flags.String("amazonec2-subnet-id")
285-
d.SecurityGroupName = flags.String("amazonec2-security-group")
292+
d.SecurityGroupNames = flags.StringSlice("amazonec2-security-group")
286293
d.Tags = flags.String("amazonec2-tags")
287294
zone := flags.String("amazonec2-zone")
288295
d.Zone = zone[:]
@@ -448,6 +455,31 @@ func (d *Driver) instanceIpAvailable() bool {
448455
return false
449456
}
450457

458+
func makePointerSlice(stackSlice []string) []*string {
459+
pointerSlice := []*string{}
460+
for i := range stackSlice {
461+
pointerSlice = append(pointerSlice, &stackSlice[i])
462+
}
463+
return pointerSlice
464+
}
465+
466+
// Support migrating single string Driver fields to slices.
467+
func migrateStringToSlice(value string, values []string) (result []string) {
468+
if value != "" {
469+
result = append(result, value)
470+
}
471+
result = append(result, values...)
472+
return
473+
}
474+
475+
func (d *Driver) securityGroupNames() (ids []string) {
476+
return migrateStringToSlice(d.SecurityGroupName, d.SecurityGroupNames)
477+
}
478+
479+
func (d *Driver) securityGroupIds() (ids []string) {
480+
return migrateStringToSlice(d.SecurityGroupId, d.SecurityGroupIds)
481+
}
482+
451483
func (d *Driver) Create() error {
452484
if err := d.checkPrereqs(); err != nil {
453485
return err
@@ -459,7 +491,7 @@ func (d *Driver) Create() error {
459491
return fmt.Errorf("unable to create key pair: %s", err)
460492
}
461493

462-
if err := d.configureSecurityGroup(d.SecurityGroupName); err != nil {
494+
if err := d.configureSecurityGroups(d.securityGroupNames()); err != nil {
463495
return err
464496
}
465497

@@ -473,7 +505,7 @@ func (d *Driver) Create() error {
473505
}
474506
netSpecs := []*ec2.InstanceNetworkInterfaceSpecification{{
475507
DeviceIndex: aws.Int64(0), // eth0
476-
Groups: []*string{&d.SecurityGroupId},
508+
Groups: makePointerSlice(d.securityGroupIds()),
477509
SubnetId: &d.SubnetId,
478510
AssociatePublicIpAddress: aws.Bool(!d.PrivateIPOnly),
479511
}}
@@ -866,14 +898,18 @@ func (d *Driver) configureTags(tagGroups string) error {
866898
return nil
867899
}
868900

869-
func (d *Driver) configureSecurityGroup(groupName string) error {
870-
log.Debugf("configuring security group in %s", d.VpcId)
901+
func (d *Driver) configureSecurityGroups(groupNames []string) error {
902+
if len(groupNames) == 0 {
903+
log.Debugf("no security groups to configure in %s", d.VpcId)
904+
return nil
905+
}
906+
907+
log.Debugf("configuring security groups in %s", d.VpcId)
871908

872-
var group *ec2.SecurityGroup
873909
filters := []*ec2.Filter{
874910
{
875911
Name: aws.String("group-name"),
876-
Values: []*string{&groupName},
912+
Values: makePointerSlice(groupNames),
877913
},
878914
{
879915
Name: aws.String("vpc-id"),
@@ -887,47 +923,52 @@ func (d *Driver) configureSecurityGroup(groupName string) error {
887923
return err
888924
}
889925

890-
if len(groups.SecurityGroups) > 0 {
891-
log.Debugf("found existing security group (%s) in %s", groupName, d.VpcId)
892-
group = groups.SecurityGroups[0]
926+
var groupsByName = make(map[string]*ec2.SecurityGroup)
927+
for _, securityGroup := range groups.SecurityGroups {
928+
groupsByName[*securityGroup.GroupName] = securityGroup
893929
}
894930

895-
// if not found, create
896-
if group == nil {
897-
log.Debugf("creating security group (%s) in %s", groupName, d.VpcId)
898-
groupResp, err := d.getClient().CreateSecurityGroup(&ec2.CreateSecurityGroupInput{
899-
GroupName: &groupName,
900-
Description: aws.String("Docker Machine"),
901-
VpcId: &d.VpcId,
902-
})
903-
if err != nil {
904-
return err
905-
}
906-
// Manually translate into the security group construct
907-
group = &ec2.SecurityGroup{
908-
GroupId: groupResp.GroupId,
909-
VpcId: aws.String(d.VpcId),
910-
GroupName: aws.String(groupName),
911-
}
912-
// wait until created (dat eventual consistency)
913-
log.Debugf("waiting for group (%s) to become available", *group.GroupId)
914-
if err := mcnutils.WaitFor(d.securityGroupAvailableFunc(*group.GroupId)); err != nil {
915-
return err
931+
for _, groupName := range groupNames {
932+
var group *ec2.SecurityGroup
933+
securityGroup, ok := groupsByName[groupName]
934+
if ok {
935+
log.Debugf("found existing security group (%s) in %s", groupName, d.VpcId)
936+
group = securityGroup
937+
} else {
938+
log.Debugf("creating security group (%s) in %s", groupName, d.VpcId)
939+
groupResp, err := d.getClient().CreateSecurityGroup(&ec2.CreateSecurityGroupInput{
940+
GroupName: aws.String(groupName),
941+
Description: aws.String("Docker Machine"),
942+
VpcId: aws.String(d.VpcId),
943+
})
944+
if err != nil {
945+
return err
946+
}
947+
// Manually translate into the security group construct
948+
group = &ec2.SecurityGroup{
949+
GroupId: groupResp.GroupId,
950+
VpcId: aws.String(d.VpcId),
951+
GroupName: aws.String(groupName),
952+
}
953+
// wait until created (dat eventual consistency)
954+
log.Debugf("waiting for group (%s) to become available", *group.GroupId)
955+
if err := mcnutils.WaitFor(d.securityGroupAvailableFunc(*group.GroupId)); err != nil {
956+
return err
957+
}
916958
}
917-
}
918-
919-
d.SecurityGroupId = *group.GroupId
959+
d.SecurityGroupIds = append(d.SecurityGroupIds, *group.GroupId)
920960

921-
perms := d.configureSecurityGroupPermissions(group)
961+
perms := d.configureSecurityGroupPermissions(group)
922962

923-
if len(perms) != 0 {
924-
log.Debugf("authorizing group %s with permissions: %v", groupName, perms)
925-
_, err := d.getClient().AuthorizeSecurityGroupIngress(&ec2.AuthorizeSecurityGroupIngressInput{
926-
GroupId: group.GroupId,
927-
IpPermissions: perms,
928-
})
929-
if err != nil {
930-
return err
963+
if len(perms) != 0 {
964+
log.Debugf("authorizing group %s with permissions: %v", groupNames, perms)
965+
_, err := d.getClient().AuthorizeSecurityGroupIngress(&ec2.AuthorizeSecurityGroupIngressInput{
966+
GroupId: group.GroupId,
967+
IpPermissions: perms,
968+
})
969+
if err != nil {
970+
return err
971+
}
931972
}
932973
}
933974

@@ -985,19 +1026,6 @@ func (d *Driver) configureSecurityGroupPermissions(group *ec2.SecurityGroup) []*
9851026
return perms
9861027
}
9871028

988-
func (d *Driver) deleteSecurityGroup() error {
989-
log.Debugf("deleting security group %s", d.SecurityGroupId)
990-
991-
_, err := d.getClient().DeleteSecurityGroup(&ec2.DeleteSecurityGroupInput{
992-
GroupId: &d.SecurityGroupId,
993-
})
994-
if err != nil {
995-
return err
996-
}
997-
998-
return nil
999-
}
1000-
10011029
func (d *Driver) deleteKeyPair() error {
10021030
log.Debugf("deleting key pair: %s", d.KeyName)
10031031

0 commit comments

Comments
 (0)