Merge pull request #119 from aaronfeng/retrieve-default-zone-from-aws

ec2 service: Support VPC and other fixes
This commit is contained in:
Solomon Hykes 2014-07-31 14:39:18 -07:00
commit 8ca1d40f38
2 changed files with 69 additions and 31 deletions

View File

@ -122,6 +122,8 @@ Control an [Orchard](https://www.orchardup.com/) host from libswarm. It takes tw
*Aaron Feng* *Aaron Feng*
[README](http://bit.ly/ec2-libswarm-readme)
### Consul ### Consul
*Help wanted!* *Help wanted!*

View File

@ -3,7 +3,6 @@ package backends
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/docker/libswarm"
"net" "net"
"net/http" "net/http"
"os" "os"
@ -15,21 +14,24 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/docker/libswarm"
"launchpad.net/goamz/aws" "launchpad.net/goamz/aws"
"launchpad.net/goamz/ec2" "launchpad.net/goamz/ec2"
) )
type ec2Config struct { type ec2Config struct {
securityGroup string securityGroupId string
instanceType string instanceType string
zone string zone string
ami string ami string
tag string tag string
sshUser string sshUser string
sshKey string sshKey string
sshPort string
sshLocalPort string sshLocalPort string
sshRemotePort string sshRemotePort string
keypair string keypair string
subnetId string
region aws.Region region aws.Region
} }
@ -71,8 +73,9 @@ func (c *ec2Client) start(ctx *libswarm.Message) error {
c.waitForSsh() c.waitForSsh()
c.startSshTunnel() c.startSshTunnel()
c.waitForDockerDaemon() c.waitForDockerDaemon()
fmt.Printf("ec2 service up and running: region: %s zone: %s\n", // TODO (aaron): display zone info
c.config.region.Name, c.config.zone) fmt.Printf("ec2 service up and running: region: %s\n",
c.config.region.Name)
ctx.Ret.Send(&libswarm.Message{Verb: libswarm.Ack, Ret: c.Server}) ctx.Ret.Send(&libswarm.Message{Verb: libswarm.Ack, Ret: c.Server})
return nil return nil
@ -125,17 +128,29 @@ func defaultSshKeyPath() string {
func defaultConfigValues() (config *ec2Config) { func defaultConfigValues() (config *ec2Config) {
config = new(ec2Config) config = new(ec2Config)
config.region = aws.USEast config.region = aws.USEast
config.ami = "ami-7c807d14" config.instanceType = "t2.micro"
config.instanceType = "t1.micro"
config.zone = "us-east-1a"
config.sshUser = "ec2-user" config.sshUser = "ec2-user"
config.tag = "docker-ec2-swarm" config.sshPort = "22"
config.tag = "docker-ec2-libswarm"
config.sshLocalPort = "4910" config.sshLocalPort = "4910"
config.sshRemotePort = "4243" config.sshRemotePort = "4243"
config.sshKey = defaultSshKeyPath() config.sshKey = defaultSshKeyPath()
return config return config
} }
func defaultAMI(conn *ec2.EC2) (string, error) {
filter := ec2.NewFilter()
imageName := "amzn-ami-hvm-2014.03.2.x86_64-ebs"
filter.Add("name", imageName)
resp, _ := conn.Images(nil, filter)
if len(resp.Images) == 0 {
return "", fmt.Errorf("Unable to retrieve ami id for image name: %s", imageName)
}
return resp.Images[0].Id, nil
}
func newConfig(args []string) (config *ec2Config, err error) { func newConfig(args []string) (config *ec2Config, err error) {
var optValPair []string var optValPair []string
var opt, val string var opt, val string
@ -157,18 +172,23 @@ func newConfig(args []string) (config *ec2Config, err error) {
config.ami = val config.ami = val
case "--keypair": case "--keypair":
config.keypair = val config.keypair = val
case "--security_group": case "--security_group_id":
config.securityGroup = val config.securityGroupId = val
case "--instance_type": case "--instance_type":
config.instanceType = val config.instanceType = val
case "--ssh_user": case "--ssh_user":
config.sshUser = val config.sshUser = val
case "--ssh_port":
config.sshPort = val
case "--ssh_key": case "--ssh_key":
config.sshKey = val config.sshKey = val
case "--subnet_id":
config.subnetId = val
default: default:
fmt.Printf("Unrecognizable option: %s value: %s", opt, val) fmt.Printf("Unrecognizable option: %s value: %s", opt, val)
} }
} }
return config, nil return config, nil
} }
@ -203,7 +223,20 @@ func awsInit(config *ec2Config) (ec2Conn *ec2.EC2, err error) {
return nil, err return nil, err
} }
return ec2.New(auth, config.region), nil conn := ec2.New(auth, config.region)
if config.ami == "" {
fmt.Println("No AMI specified. Retrieving default ami")
amiId, err := defaultAMI(conn)
if err != nil {
return nil, fmt.Errorf("Please manually specify an ami.")
}
config.ami = amiId
}
return conn, nil
} }
func (c *ec2Client) findInstance() (instance *ec2.Instance, err error) { func (c *ec2Client) findInstance() (instance *ec2.Instance, err error) {
@ -237,13 +270,14 @@ func (c *ec2Client) tagtInstance() error {
} }
func (c *ec2Client) startInstance() error { func (c *ec2Client) startInstance() error {
// TODO: allow more than one sg in the future
options := ec2.RunInstances{ options := ec2.RunInstances{
SubnetId: c.config.subnetId,
ImageId: c.config.ami, ImageId: c.config.ami,
InstanceType: c.config.instanceType, InstanceType: c.config.instanceType,
KeyName: c.config.keypair, KeyName: c.config.keypair,
AvailZone: c.config.zone, AvailZone: c.config.zone,
// TODO: allow more than one sg in the future SecurityGroups: []ec2.SecurityGroup{ec2.SecurityGroup{Id: c.config.securityGroupId}},
SecurityGroups: []ec2.SecurityGroup{ec2.SecurityGroup{Name: c.config.securityGroup}},
UserData: []byte(userdata), UserData: []byte(userdata),
} }
@ -293,7 +327,7 @@ func (c *ec2Client) initDockerClientInstance(instance *ec2.Instance) error {
} }
func (c *ec2Client) waitForDockerDaemon() { func (c *ec2Client) waitForDockerDaemon() {
fmt.Println("waiting for docker daemon on remote machine to be available.") fmt.Println("Waiting for docker daemon on remote machine to be available.")
for { for {
resp, _ := http.Get("http://localhost:" + c.config.sshLocalPort) resp, _ := http.Get("http://localhost:" + c.config.sshLocalPort)
// wait for a response. any response to know docker daemon is up // wait for a response. any response to know docker daemon is up
@ -307,8 +341,8 @@ func (c *ec2Client) waitForDockerDaemon() {
} }
func (c *ec2Client) waitForSsh() { func (c *ec2Client) waitForSsh() {
fmt.Println("waiting for ssh to be available. make sure ssh is open on port 22.") fmt.Printf("Waiting for ssh to be available. make sure ssh is open on port %s.\n", c.config.sshPort)
conn := waitFor(c.instance.IPAddress, "22") conn := waitFor(c.instance.IPAddress, c.config.sshPort)
conn.Close() conn.Close()
} }
@ -351,11 +385,13 @@ func Ec2() libswarm.Sender {
} }
ec2Conn, err := awsInit(config) ec2Conn, err := awsInit(config)
if err != nil { if err != nil {
return err return err
} }
client := &ec2Client{config, ec2Conn, libswarm.NewServer(), nil, nil, nil} client := &ec2Client{config, ec2Conn, libswarm.NewServer(), nil, nil, nil}
client.Server.OnVerb(libswarm.Spawn, libswarm.Handler(client.spawn)) client.Server.OnVerb(libswarm.Spawn, libswarm.Handler(client.spawn))
client.Server.OnVerb(libswarm.Start, libswarm.Handler(client.start)) client.Server.OnVerb(libswarm.Start, libswarm.Handler(client.start))
client.Server.OnVerb(libswarm.Stop, libswarm.Handler(client.stop)) client.Server.OnVerb(libswarm.Stop, libswarm.Handler(client.stop))
@ -396,7 +432,7 @@ func (c *ec2Client) startSshTunnel() error {
"-o", "StrictHostKeyChecking=no", "-o", "StrictHostKeyChecking=no",
"-i", c.config.sshKey, "-i", c.config.sshKey,
"-A", "-A",
"-p", "22", "-p", c.config.sshPort,
fmt.Sprintf("%s@%s", c.config.sshUser, c.instance.IPAddress), fmt.Sprintf("%s@%s", c.config.sshUser, c.instance.IPAddress),
"-N", "-N",
"-f", "-f",