WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 6bd1f80

Browse files
thesurlydevalexellis
authored andcommitted
Various fixes for ec2 provider create command
The create command failed when a default VPC was not present for the ec2 provider. When the failure occurred there was also a side effect of dangling security groups that got created but not cleaned up in the event of failure. Two additional arguments were added, vpc-id and subnet-id, to mitigate the failure while also giving users the option to choose a specific VPC and subnet if more than one VPC exists. New validation checks that if one of these new arguments are specified then the other must be as well. Additional logic was added so that in the event of ec2 instance creation failure any security groups created will get deleted. Signed-off-by: Shane Witbeck <[email protected]>
1 parent 8bc3d04 commit 6bd1f80

File tree

3 files changed

+78
-22
lines changed

3 files changed

+78
-22
lines changed

cmd/create.go

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ func init() {
3535
createCmd.Flags().StringP("access-token", "a", "", "The access token for your cloud")
3636
createCmd.Flags().StringP("access-token-file", "f", "", "Read this file for the access token for your cloud")
3737

38+
createCmd.Flags().String("vpc-id", "", "The VPC ID to create the exit-node in (EC2)")
39+
createCmd.Flags().String("subnet-id", "", "The Subnet ID where the exit-node should be placed (EC2)")
3840
createCmd.Flags().String("secret-key", "", "The access token for your cloud (Scaleway, EC2)")
3941
createCmd.Flags().String("secret-key-file", "", "Read this file for the access token for your cloud (Scaleway, EC2)")
4042
createCmd.Flags().String("organisation-id", "", "Organisation ID (Scaleway)")
@@ -131,6 +133,8 @@ func runCreate(cmd *cobra.Command, _ []string) error {
131133
var secretKey string
132134
var organisationID string
133135
var projectID string
136+
var vpcID string
137+
var subnetID string
134138
if provider == "scaleway" || provider == "ec2" {
135139

136140
var secretKeyErr error
@@ -145,6 +149,23 @@ func runCreate(cmd *cobra.Command, _ []string) error {
145149
return fmt.Errorf("--organisation-id flag must be set")
146150
}
147151
}
152+
153+
if provider == "ec2" {
154+
vpcID, err = cmd.Flags().GetString("vpc-id")
155+
if err != nil {
156+
return errors.Wrap(err, "failed to get 'vpc-id' value")
157+
}
158+
159+
subnetID, err = cmd.Flags().GetString("subnet-id")
160+
if err != nil {
161+
return errors.Wrap(err, "failed to get 'subnet-id' value")
162+
}
163+
164+
if (len(vpcID) == 0 && len(subnetID) > 0) || (len(subnetID) == 0 && len(vpcID) > 0) {
165+
return fmt.Errorf("both --vpc-id and --subnet-id must be set")
166+
}
167+
}
168+
148169
} else if provider == "gce" || provider == "packet" {
149170
projectID, _ = cmd.Flags().GetString("project-id")
150171
if len(projectID) == 0 {
@@ -173,7 +194,7 @@ func runCreate(cmd *cobra.Command, _ []string) error {
173194

174195
userData := makeUserdata(inletsToken, inletsControlPort, remoteTCP)
175196

176-
hostReq, err := createHost(provider, name, region, zone, projectID, userData, strconv.Itoa(inletsControlPort), pro)
197+
hostReq, err := createHost(provider, name, region, zone, projectID, userData, strconv.Itoa(inletsControlPort), vpcID, subnetID, pro)
177198
if err != nil {
178199
return err
179200
}
@@ -274,7 +295,7 @@ func generateAuth() (string, error) {
274295
return pwdRes, pwdErr
275296
}
276297

277-
func createHost(provider, name, region, zone, projectID, userData, inletsPort string, pro bool) (*provision.BasicHost, error) {
298+
func createHost(provider, name, region, zone, projectID, userData, inletsPort string, vpcID string, subnetID string, pro bool) (*provision.BasicHost, error) {
278299
if provider == "digitalocean" {
279300
return &provision.BasicHost{
280301
Name: name,
@@ -331,16 +352,27 @@ func createHost(provider, name, region, zone, projectID, userData, inletsPort st
331352
} else if provider == "ec2" {
332353
// Ubuntu images can be found here https://cloud-images.ubuntu.com/locator/ec2/
333354
// Name is used in the OS field so the ami can be lookup up in the region specified
355+
356+
var additional = map[string]string{
357+
"inlets-port": inletsPort,
358+
"pro": fmt.Sprint(pro),
359+
}
360+
361+
if len(vpcID) > 0 {
362+
additional["vpc-id"] = vpcID
363+
}
364+
365+
if len(subnetID) > 0 {
366+
additional["subnet-id"] = subnetID
367+
}
368+
334369
return &provision.BasicHost{
335-
Name: name,
336-
OS: "ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20191114",
337-
Plan: "t3.nano",
338-
Region: region,
339-
UserData: base64.StdEncoding.EncodeToString([]byte(userData)),
340-
Additional: map[string]string{
341-
"inlets-port": inletsPort,
342-
"pro": fmt.Sprint(pro),
343-
},
370+
Name: name,
371+
OS: "ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20191114",
372+
Plan: "t3.nano",
373+
Region: region,
374+
UserData: base64.StdEncoding.EncodeToString([]byte(userData)),
375+
Additional: additional,
344376
}, nil
345377
} else if provider == "azure" {
346378
// Ubuntu images can be found here https://docs.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage#list-popular-images

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
109109
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
110110
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
111111
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
112+
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
112113
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
113114
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
114115
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=

pkg/provision/ec2.go

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,27 +40,44 @@ func (p *EC2Provisioner) Provision(host BasicHost) (*ProvisionedHost, error) {
4040
}
4141
pro := host.Additional["pro"]
4242

43-
groupID, name, err := p.creteEC2SecurityGroup(port, pro)
43+
var vpcID = host.Additional["vpc-id"]
44+
var subnetID = host.Additional["subnet-id"]
45+
46+
groupID, name, err := p.createEC2SecurityGroup(vpcID, port, pro)
4447
if err != nil {
4548
return nil, err
4649
}
4750

51+
var networkSpec = ec2.InstanceNetworkInterfaceSpecification{
52+
DeviceIndex: aws.Int64(int64(0)),
53+
AssociatePublicIpAddress: aws.Bool(true),
54+
DeleteOnTermination: aws.Bool(true),
55+
Groups: []*string{groupID},
56+
}
57+
58+
if len(subnetID) > 0 {
59+
networkSpec.SubnetId = aws.String(subnetID)
60+
}
61+
4862
runResult, err := p.ec2Provisioner.RunInstances(&ec2.RunInstancesInput{
4963
ImageId: image,
5064
InstanceType: aws.String(host.Plan),
5165
MinCount: aws.Int64(1),
5266
MaxCount: aws.Int64(1),
5367
UserData: &host.UserData,
5468
NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{
55-
{
56-
DeviceIndex: aws.Int64(int64(0)),
57-
AssociatePublicIpAddress: aws.Bool(true),
58-
DeleteOnTermination: aws.Bool(true),
59-
Groups: []*string{groupID},
60-
},
69+
&networkSpec,
6170
},
6271
})
6372
if err != nil {
73+
// clean up SG if there was an issue provisioning the EC2 instance
74+
input := ec2.DeleteSecurityGroupInput {
75+
GroupId: groupID,
76+
}
77+
_, sgErr := p.ec2Provisioner.DeleteSecurityGroup(&input)
78+
if sgErr != nil {
79+
return nil, fmt.Errorf("error provisioning ec2 instance: %v; error deleting SG: %v", err, sgErr)
80+
}
6481
return nil, err
6582
}
6683

@@ -229,15 +246,21 @@ func (p *EC2Provisioner) lookupID(request HostDeleteRequest) (string, error) {
229246
return "", fmt.Errorf("no host with ip: %s", request.IP)
230247
}
231248

232-
// creteEC2SecurityGroup creates a security group for the exit-node
233-
func (p *EC2Provisioner) creteEC2SecurityGroup(controlPort int, pro string) (*string, *string, error) {
249+
// createEC2SecurityGroup creates a security group for the exit-node
250+
func (p *EC2Provisioner) createEC2SecurityGroup(vpcID string, controlPort int, pro string) (*string, *string, error) {
234251
ports := []int{80, 443, controlPort}
235252
proPorts := []int{1024, 65535}
236253
groupName := "inlets-" + uuid.New().String()
237-
group, err := p.ec2Provisioner.CreateSecurityGroup(&ec2.CreateSecurityGroupInput{
254+
var input = &ec2.CreateSecurityGroupInput{
238255
Description: aws.String("inlets security group"),
239256
GroupName: aws.String(groupName),
240-
})
257+
}
258+
259+
if len(vpcID) > 0 {
260+
input.VpcId = aws.String(vpcID)
261+
}
262+
263+
group, err := p.ec2Provisioner.CreateSecurityGroup(input)
241264
if err != nil {
242265
return nil, nil, err
243266
}

0 commit comments

Comments
 (0)