From 834fa414b435695a89ddee661327c3df7a2d18f0 Mon Sep 17 00:00:00 2001 From: Evan Hazlett Date: Thu, 22 Jan 2015 16:36:51 -0500 Subject: [PATCH] allow specifying sg; re-use existing sg; fix race conditions with ip assigning and eventual consistency with sgs Signed-off-by: Evan Hazlett --- drivers/amazonec2/amazonec2.go | 113 +++++++++++++++--------- drivers/amazonec2/amazonec2_test.go | 24 ++--- drivers/amazonec2/amz/ec2.go | 17 +++- drivers/amazonec2/amz/ip_permission.go | 8 +- drivers/amazonec2/amz/security_group.go | 5 +- 5 files changed, 108 insertions(+), 59 deletions(-) diff --git a/drivers/amazonec2/amazonec2.go b/drivers/amazonec2/amazonec2.go index 1ecef1d94b..9f42c3fe43 100644 --- a/drivers/amazonec2/amazonec2.go +++ b/drivers/amazonec2/amazonec2.go @@ -32,28 +32,29 @@ const ( ) type Driver struct { - Id string - AccessKey string - SecretKey string - SessionToken string - Region string - AMI string - SSHKeyID int - KeyName string - InstanceId string - InstanceType string - IPAddress string - MachineName string - SecurityGroupId string - ReservationId string - RootSize int64 - VpcId string - SubnetId string - Zone string - CaCertPath string - PrivateKeyPath string - storePath string - keyPath string + Id string + AccessKey string + SecretKey string + SessionToken string + Region string + AMI string + SSHKeyID int + KeyName string + InstanceId string + InstanceType string + IPAddress string + MachineName string + SecurityGroupName string + SecurityGroupId string + ReservationId string + RootSize int64 + VpcId string + SubnetId string + Zone string + CaCertPath string + PrivateKeyPath string + storePath string + keyPath string } type CreateFlags struct { @@ -123,6 +124,12 @@ func GetCreateFlags() []cli.Flag { Value: "", EnvVar: "AWS_SUBNET_ID", }, + cli.StringFlag{ + Name: "amazonec2-security-group-name", + Usage: "AWS VPC security group name", + Value: "docker-machine", + EnvVar: "AWS_SECURITY_GROUP_NAME", + }, cli.StringFlag{ Name: "amazonec2-instance-type", Usage: "AWS instance type", @@ -152,6 +159,7 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { d.InstanceType = flags.String("amazonec2-instance-type") d.VpcId = flags.String("amazonec2-vpc-id") d.SubnetId = flags.String("amazonec2-subnet-id") + d.SecurityGroupName = flags.String("amazonec2-security-group-name") zone := flags.String("amazonec2-zone") d.Zone = zone[:] d.RootSize = int64(flags.Int("amazonec2-root-size")) @@ -182,7 +190,7 @@ func (d *Driver) Create() error { return fmt.Errorf("unable to create key pair: %s", err) } - if err := d.configureSecurityGroup(); err != nil { + if err := d.configureSecurityGroup(d.SecurityGroupName); err != nil { return err } @@ -427,8 +435,21 @@ func (d *Driver) updateDriver() error { if err != nil { return err } - d.InstanceId = inst.InstanceId - d.IPAddress = inst.IpAddress + // wait for ipaddress + for { + i, err := d.getInstance() + if err != nil { + return err + } + if i.IpAddress == "" { + time.Sleep(1 * time.Second) + continue + } + + d.InstanceId = inst.InstanceId + d.IPAddress = inst.IpAddress + break + } return nil } @@ -500,18 +521,19 @@ func (d *Driver) terminate() error { return nil } -func (d *Driver) configureSecurityGroup() error { +func (d *Driver) configureSecurityGroup(groupName string) error { log.Debugf("configuring security group in %s", d.VpcId) + var securityGroup *amz.SecurityGroup + groups, err := d.getClient().GetSecurityGroups() if err != nil { return err } - var securityGroup *amz.SecurityGroup for _, grp := range groups { - if grp.GroupName == machineSecurityGroupName { - log.Debugf("found existing security group (%s) in %s", machineSecurityGroupName, d.VpcId) + if grp.GroupName == groupName { + log.Debugf("found existing security group (%s) in %s", groupName, d.VpcId) securityGroup = &grp break } @@ -519,21 +541,32 @@ func (d *Driver) configureSecurityGroup() error { // if not found, create if securityGroup == nil { - log.Debugf("creating security group (%s) in %s", machineSecurityGroupName, d.VpcId) - group, err := d.getClient().CreateSecurityGroup(machineSecurityGroupName, "Docker Machine", d.VpcId) + log.Debugf("creating security group (%s) in %s", groupName, d.VpcId) + group, err := d.getClient().CreateSecurityGroup(groupName, "Docker Machine", d.VpcId) if err != nil { return err } securityGroup = group + // wait until created (dat eventual consistency) + log.Debugf("waiting for group (%s) to become available", group.GroupId) + for { + _, err := d.getClient().GetSecurityGroupById(group.GroupId) + if err == nil { + break + } + log.Debug(err) + time.Sleep(1 * time.Second) + } } d.SecurityGroupId = securityGroup.GroupId - log.Debugf("configuring authorization %s", ipRange) + log.Debugf("configuring security group authorization for %s", ipRange) perms := configureSecurityGroupPermissions(securityGroup) if len(perms) != 0 { + log.Debugf("authorizing group %s with permissions: %v", securityGroup.GroupName, perms) if err := d.getClient().AuthorizeSecurityGroup(d.SecurityGroupId, perms); err != nil { return err } @@ -559,10 +592,10 @@ func configureSecurityGroupPermissions(group *amz.SecurityGroup) []amz.IpPermiss if !hasSshPort { perm := amz.IpPermission{ - Protocol: "tcp", - FromPort: 22, - ToPort: 22, - IpRange: ipRange, + IpProtocol: "tcp", + FromPort: 22, + ToPort: 22, + IpRange: ipRange, } perms = append(perms, perm) @@ -570,10 +603,10 @@ func configureSecurityGroupPermissions(group *amz.SecurityGroup) []amz.IpPermiss if !hasDockerPort { perm := amz.IpPermission{ - Protocol: "tcp", - FromPort: dockerPort, - ToPort: dockerPort, - IpRange: ipRange, + IpProtocol: "tcp", + FromPort: dockerPort, + ToPort: dockerPort, + IpRange: ipRange, } perms = append(perms, perm) diff --git a/drivers/amazonec2/amazonec2_test.go b/drivers/amazonec2/amazonec2_test.go index 9ea1161f45..225ddcd6c4 100644 --- a/drivers/amazonec2/amazonec2_test.go +++ b/drivers/amazonec2/amazonec2_test.go @@ -32,9 +32,9 @@ func TestConfigureSecurityGroupPermissionsSshOnly(t *testing.T) { group.IpPermissions = []amz.IpPermission{ { - Protocol: "tcp", - FromPort: testSshPort, - ToPort: testSshPort, + IpProtocol: "tcp", + FromPort: testSshPort, + ToPort: testSshPort, }, } @@ -54,9 +54,9 @@ func TestConfigureSecurityGroupPermissionsDockerOnly(t *testing.T) { group.IpPermissions = []amz.IpPermission{ { - Protocol: "tcp", - FromPort: testDockerPort, - ToPort: testDockerPort, + IpProtocol: "tcp", + FromPort: testDockerPort, + ToPort: testDockerPort, }, } @@ -76,14 +76,14 @@ func TestConfigureSecurityGroupPermissionsDockerAndSsh(t *testing.T) { group.IpPermissions = []amz.IpPermission{ { - Protocol: "tcp", - FromPort: testSshPort, - ToPort: testSshPort, + IpProtocol: "tcp", + FromPort: testSshPort, + ToPort: testSshPort, }, { - Protocol: "tcp", - FromPort: testDockerPort, - ToPort: testDockerPort, + IpProtocol: "tcp", + FromPort: testDockerPort, + ToPort: testDockerPort, }, } diff --git a/drivers/amazonec2/amz/ec2.go b/drivers/amazonec2/amz/ec2.go index 71cbcab12c..e431e1b42c 100644 --- a/drivers/amazonec2/amz/ec2.go +++ b/drivers/amazonec2/amz/ec2.go @@ -347,7 +347,7 @@ func (e *EC2) AuthorizeSecurityGroup(groupId string, permissions []IpPermission) for index, perm := range permissions { n := index + 1 // amazon starts counting from 1 not 0 - v.Set(fmt.Sprintf("IpPermissions.%d.IpProtocol", n), perm.Protocol) + v.Set(fmt.Sprintf("IpPermissions.%d.IpProtocol", n), perm.IpProtocol) v.Set(fmt.Sprintf("IpPermissions.%d.FromPort", n), strconv.Itoa(perm.FromPort)) v.Set(fmt.Sprintf("IpPermissions.%d.ToPort", n), strconv.Itoa(perm.ToPort)) v.Set(fmt.Sprintf("IpPermissions.%d.IpRanges.1.CidrIp", n), perm.IpRange) @@ -401,6 +401,21 @@ func (e *EC2) GetSecurityGroups() ([]SecurityGroup, error) { return sgs, nil } + +func (e *EC2) GetSecurityGroupById(id string) (*SecurityGroup, error) { + groups, err := e.GetSecurityGroups() + if err != nil { + return nil, err + } + + for _, g := range groups { + if g.GroupId == id { + return &g, nil + } + } + return nil, nil +} + func (e *EC2) GetSubnets() ([]Subnet, error) { subnets := []Subnet{} resp, err := e.performStandardAction("DescribeSubnets") diff --git a/drivers/amazonec2/amz/ip_permission.go b/drivers/amazonec2/amz/ip_permission.go index 325de3b699..fe3a9df346 100644 --- a/drivers/amazonec2/amz/ip_permission.go +++ b/drivers/amazonec2/amz/ip_permission.go @@ -1,8 +1,8 @@ package amz type IpPermission struct { - Protocol string - FromPort int - ToPort int - IpRange string + IpProtocol string `xml:"ipProtocol"` + FromPort int `xml:"fromPort"` + ToPort int `xml:"toPort"` + IpRange string `xml:"ipRanges"` } diff --git a/drivers/amazonec2/amz/security_group.go b/drivers/amazonec2/amz/security_group.go index c01d3605ed..2893206b98 100644 --- a/drivers/amazonec2/amz/security_group.go +++ b/drivers/amazonec2/amz/security_group.go @@ -15,6 +15,7 @@ type SecurityGroup struct { GroupName string `xml:"groupName"` GroupId string `xml:"groupId"` VpcId string `xml:"vpcId"` - IpPermissions []IpPermission `xml:"ipPermissions,omitempty"` - IpPermissionsEgress []IpPermission `xml:"ipPermissionsEgress,omitempty"` + OwnerId string `xml:"ownerId"` + IpPermissions []IpPermission `xml:"ipPermissions>item,omitempty"` + IpPermissionsEgress []IpPermission `xml:"ipPermissionsEgress>item,omitempty"` }