stemcell 0.0.11 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +75 -11
- data/bin/stemcell +47 -14
- data/examples/stemcellrc +10 -0
- data/lib/stemcell/templates/bootstrap.sh.erb +80 -66
- data/lib/stemcell/version.rb +1 -1
- data/lib/stemcell.rb +81 -53
- metadata +3 -2
data/README.md
CHANGED
@@ -1,28 +1,92 @@
|
|
1
|
-
# Stemcell
|
1
|
+
# Stemcell #
|
2
2
|
|
3
|
-
Stemcell launches instances
|
3
|
+
Stemcell launches instances in EC2.
|
4
|
+
These instances are created to your specification, with knobs like AMI, instance type, and region exposed.
|
5
|
+
The instances are bootstrapped with chef-solo, using a specified git repo and branch as the source of roles and recipes.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
Add this line to your application's Gemfile:
|
8
10
|
|
9
|
-
|
11
|
+
```bash
|
12
|
+
gem 'stemcell'
|
13
|
+
```
|
10
14
|
|
11
15
|
And then execute:
|
12
16
|
|
13
|
-
|
17
|
+
```bash
|
18
|
+
$ bundle
|
19
|
+
```
|
14
20
|
|
15
21
|
Or install it yourself as:
|
16
22
|
|
17
|
-
|
23
|
+
```bash
|
24
|
+
$ gem install stemcell
|
25
|
+
```
|
26
|
+
|
27
|
+
## Configuration
|
28
|
+
|
29
|
+
You should create an rc file for stemcell with your standard options
|
30
|
+
(and place it in the root dir as .stemcellrc?). You can see an example
|
31
|
+
in examples/stemcellrc. You can get most of the options from your
|
32
|
+
.chef/knife.rb but you will need to get the new chef deploy key so
|
33
|
+
that instances that you launch can download code.
|
18
34
|
|
19
35
|
## Usage
|
20
36
|
|
37
|
+
### Include your base config:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
$ source .stemcellrc
|
41
|
+
```
|
42
|
+
|
43
|
+
### Simple launch:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
$ ./bin/stemcell --chef-role $your_chef_role --git-branch $your_chef_branch
|
47
|
+
```
|
48
|
+
|
49
|
+
This will cause instance(s) to be launched and their ip's and instance
|
50
|
+
id to be printed to the screen.
|
51
|
+
|
52
|
+
### More options:
|
53
|
+
|
54
|
+
```bash
|
55
|
+
$ ./bin/stemcell --help
|
56
|
+
```
|
57
|
+
|
58
|
+
### Watching install:
|
59
|
+
|
60
|
+
```bash
|
61
|
+
$ ssh unbutu@$IP 'tail -f /var/log/init*'
|
62
|
+
```
|
63
|
+
|
64
|
+
### Terminating:
|
65
|
+
|
66
|
+
This still needs to be completed. For now, you can kill using the
|
67
|
+
amazon cli tools or the web ui.
|
68
|
+
|
69
|
+
## Automation ##
|
70
|
+
|
71
|
+
This README presents `stemcell` as a tool for administrators to use to create instances.
|
72
|
+
However, we designed `stemcell` to be easily useful for automated systems which control server infrastructure.
|
73
|
+
These automated systems can call out to `stemcell` on the command-line or use the ruby classes directly.
|
74
|
+
|
75
|
+
To see how we manage our cloud, check out the rest of SmartStack, especially Cortex, our auto-scaling system.
|
76
|
+
|
77
|
+
## Similar Tools ##
|
78
|
+
|
79
|
+
There are a few additional tools which bootstrap EC2 instances with chef-solo.
|
80
|
+
If you're using chef-server, obvious answer is [knife-ec2](https://github.com/opscode/knife-ec2).
|
81
|
+
Unless you're working on a big team where lots of people edit cookbooks simultaneously, we strongly recommend this approach!
|
82
|
+
It's especially excellent when paired with [hosted chef](http://www.opscode.com/hosted-chef/), which makes getting off the ground with configuration management fast and easy.
|
21
83
|
|
22
|
-
|
84
|
+
If you want to use knife-ec2 with chef-solo, you could use [knife solo](http://matschaffer.github.com/knife-solo/).
|
85
|
+
Another approach which is great for interactive usage involves [using fabric to bootstrap chef](http://unfoldthat.com/2012/06/02/quick-deploy-chef-solo-fabric.html)([with gist](https://gist.github.com/va1en0k/2859812)).
|
23
86
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
87
|
+
Finally, we couldn't resist doing a bit of code archeology.
|
88
|
+
People have been using chef with EC2 for a long time!
|
89
|
+
One early article is [this one](http://web.archive.org/web/20110404114025/http://probablyinteractive.com/2009/3/29/Amazon%20EC2%20+%20Chef%20=%20Mmmmm.html), which isn't even on the web anymore.
|
90
|
+
However, it's spawned some recently-active tools like [this](https://github.com/conormullen/chef-bootstrap) and [this](https://github.com/grempe/chef-solo-bootstrap).
|
91
|
+
Similar approaches are mentioned [here](http://www.opinionatedprogrammer.com/2011/06/chef-solo-tutorial-managing-a-single-server-with-chef/), with code [herh](https://github.com/ciastek/ubuntu-chef-solo) or [here](https://github.com/riywo/ubuntu-chef-solo) (with accompanying [blog post](http://weblog.riywo.com/post/35976125760))
|
92
|
+
[This article](http://illuminatedcomputing.com/posts/2012/02/simple-chef-solo-tutorial/), also mentions many worthwhile predecessors.
|
data/bin/stemcell
CHANGED
@@ -30,22 +30,22 @@ END_OF_BANNER
|
|
30
30
|
:default => ENV['REGION'] ? ENV['REGION'] : 'us-east-1',
|
31
31
|
)
|
32
32
|
|
33
|
-
opt('
|
34
|
-
'
|
33
|
+
opt('instance_type',
|
34
|
+
'machine type to launch',
|
35
35
|
:type => String,
|
36
|
-
:default => ENV['
|
36
|
+
:default => ENV['INSTANCE_TYPE'] ? ENV['INSTANCE_TYPE'] : 'm1.small',
|
37
37
|
)
|
38
38
|
|
39
|
-
opt('
|
39
|
+
opt('image_id',
|
40
40
|
'ami to use for launch',
|
41
41
|
:type => String,
|
42
|
-
:default => ENV['
|
42
|
+
:default => ENV['IMAGE_ID'] ? ENV['IMAGE_ID'] : 'ami-d726abbe',
|
43
43
|
)
|
44
44
|
|
45
|
-
opt('
|
46
|
-
'security
|
45
|
+
opt('security_groups',
|
46
|
+
'security groups to launch instance with',
|
47
47
|
:type => String,
|
48
|
-
:default => ENV['
|
48
|
+
:default => ENV['SECURITY_GROUPS'] ? ENV['SECURITY_GROUPS'] : 'default',
|
49
49
|
)
|
50
50
|
|
51
51
|
opt('availability-zone',
|
@@ -55,7 +55,7 @@ END_OF_BANNER
|
|
55
55
|
)
|
56
56
|
|
57
57
|
opt('tags',
|
58
|
-
'
|
58
|
+
'comma-separated list of key=value pairs to apply',
|
59
59
|
:type => String,
|
60
60
|
:default => ENV['TAGS'],
|
61
61
|
)
|
@@ -78,6 +78,12 @@ END_OF_BANNER
|
|
78
78
|
:default => ENV['CHEF_ROLE'],
|
79
79
|
)
|
80
80
|
|
81
|
+
opt('chef_environment',
|
82
|
+
'chef environment in which this instance will run',
|
83
|
+
:type => String,
|
84
|
+
:default => ENV['CHEF_ENVIRONMENT'],
|
85
|
+
)
|
86
|
+
|
81
87
|
opt('git_origin',
|
82
88
|
'git origin to use',
|
83
89
|
:type => String,
|
@@ -87,7 +93,7 @@ END_OF_BANNER
|
|
87
93
|
opt('git_branch',
|
88
94
|
'git branch to run off',
|
89
95
|
:type => String,
|
90
|
-
:default => ENV['GIT_BRANCH'],
|
96
|
+
:default => ENV['GIT_BRANCH'] ? ENV['GIT_BRANCH'] : 'production',
|
91
97
|
)
|
92
98
|
|
93
99
|
opt('git_key',
|
@@ -98,8 +104,8 @@ END_OF_BANNER
|
|
98
104
|
|
99
105
|
opt('count',
|
100
106
|
'number of instances to launch',
|
101
|
-
:type =>
|
102
|
-
:default => ENV['COUNT'],
|
107
|
+
:type => Integer,
|
108
|
+
:default => ENV['COUNT'] ? ENV['COUNT'] : 1,
|
103
109
|
)
|
104
110
|
|
105
111
|
end
|
@@ -108,6 +114,8 @@ required_parameters = [
|
|
108
114
|
'aws_access_key',
|
109
115
|
'aws_secret_key',
|
110
116
|
'chef_role',
|
117
|
+
'chef_environment',
|
118
|
+
'chef_data_bag_secret',
|
111
119
|
'git_branch',
|
112
120
|
'git_key',
|
113
121
|
'git_origin',
|
@@ -120,6 +128,7 @@ by the #{arg.upcase.gsub('-','_')} environment variable" if
|
|
120
128
|
options[arg].nil? or ! options[arg]
|
121
129
|
end
|
122
130
|
|
131
|
+
|
123
132
|
# convert tags from string to ruby hash
|
124
133
|
tags = {}
|
125
134
|
if options['tags']
|
@@ -130,6 +139,30 @@ if options['tags']
|
|
130
139
|
end
|
131
140
|
options['tags'] = tags
|
132
141
|
|
133
|
-
stemcell = Stemcell::Stemcell.new(options)
|
134
|
-
stemcell.launch({'count' => options['count']})
|
135
142
|
|
143
|
+
# convert security_groups from comma seperated string to ruby array
|
144
|
+
options['security_groups'] = options['security_groups'].split(',')
|
145
|
+
|
146
|
+
|
147
|
+
# create stemcell object
|
148
|
+
stemcell = Stemcell::Stemcell.new({
|
149
|
+
'aws_access_key' => options['aws_access_key'],
|
150
|
+
'aws_secret_key' => options['aws_secret_key'],
|
151
|
+
'region' => options['region'],
|
152
|
+
})
|
153
|
+
|
154
|
+
|
155
|
+
# launch instance(s)
|
156
|
+
stemcell.launch({
|
157
|
+
'instance_type' => options['instance_type'],
|
158
|
+
'image_id' => options['image_id'],
|
159
|
+
'security_groups' => options['security_groups'],
|
160
|
+
'chef_role' => options['chef_role'],
|
161
|
+
'chef_environment' => options['chef_environment'],
|
162
|
+
'chef_data_bag_secret' => options['chef_data_bag_secret'],
|
163
|
+
'git_branch' => options['git_branch'],
|
164
|
+
'git_key' => options['git_key'],
|
165
|
+
'git_origin' => options['git_origin'],
|
166
|
+
'key_name' => options['key_name'],
|
167
|
+
'count' => options['count'],
|
168
|
+
})
|
data/examples/stemcellrc
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# these options need to be set
|
2
|
+
export AWS_ACCESS_KEY=your_aws_access_key
|
3
|
+
export AWS_SECRET_KEY=your_aws_secret_key
|
4
|
+
export KEY_NAME=your_aws_ssh_key_name
|
5
|
+
export CHEF_DATA_BAG_SECRET=/path/to/encrypted/data/bag/secret
|
6
|
+
export GIT_KEY=/path/to/chef/deploy/key
|
7
|
+
|
8
|
+
# these options should not need to be set
|
9
|
+
export SECURITY_GROUP=default
|
10
|
+
export GIT_ORIGIN=git@github.com:airbnb/chef.git
|
@@ -31,12 +31,14 @@ exec 2> /var/log/init.err
|
|
31
31
|
|
32
32
|
|
33
33
|
chef_version=11.4.0
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
chef_dir=/etc/chef
|
35
|
+
converge=/usr/local/bin/converge
|
36
|
+
role=<%= opts['chef_role'] %>
|
37
|
+
environment=<%= opts['chef_environment'] %>
|
38
|
+
origin=<%= opts['git_origin'] %>
|
39
|
+
branch=<%= opts['git_branch'] %>
|
40
|
+
git_key='<%= opts["git_key"] %>'
|
41
|
+
data_bag_secret='<%= opts["chef_data_bag_secret"] %>'
|
40
42
|
|
41
43
|
|
42
44
|
##
|
@@ -69,8 +71,6 @@ install_chef() {
|
|
69
71
|
if ! which chef-solo > /dev/null ; then
|
70
72
|
echo installing chef via omnibus...
|
71
73
|
curl -L --silent https://www.opscode.com/chef/install.sh | sudo bash -s -- -v $chef_version 1>&2
|
72
|
-
# TODO(mkr): this is a hack to get chef-solo-search working
|
73
|
-
/opt/chef/embedded/bin/gem install --no-ri --no-rdoc treetop
|
74
74
|
else
|
75
75
|
echo chef is already installed
|
76
76
|
fi
|
@@ -78,80 +78,86 @@ install_chef() {
|
|
78
78
|
|
79
79
|
|
80
80
|
update_repo() {
|
81
|
-
|
82
|
-
|
81
|
+
echo -e "$git_key" > $keyfile
|
82
|
+
chmod 0400 $keyfile
|
83
|
+
|
84
|
+
echo "ssh -i $keyfile -o StrictHostKeyChecking=no \$1 \$2" > $git_wrapper
|
85
|
+
chmod 0500 $git_wrapper
|
86
|
+
|
83
87
|
mkdir -p $(dirname $repo_dir)
|
84
|
-
if [ -d $repo_dir ]; then
|
85
|
-
echo
|
86
|
-
(cd $repo_dir && GIT_SSH=$git_wrapper git fetch && git reset --hard origin/$branch && git clean -fdx)
|
87
|
-
else
|
88
|
-
echo -e "$git_key" > $keyfile
|
89
|
-
chmod 0400 $keyfile
|
90
|
-
echo "ssh -i $keyfile -o StrictHostKeyChecking=no \$1 \$2" > $git_wrapper
|
91
|
-
chmod 0500 $git_wrapper
|
92
|
-
echo downloading cookbook repo...
|
88
|
+
if [ ! -d $repo_dir ]; then
|
89
|
+
echo "downloading cookbook repo..."
|
93
90
|
GIT_SSH=$git_wrapper git clone --branch $branch --depth 1 $origin $repo_dir
|
91
|
+
else
|
92
|
+
echo "cookbook repo already exists"
|
94
93
|
fi
|
95
|
-
|
94
|
+
|
95
|
+
echo "done updating code"
|
96
96
|
}
|
97
97
|
|
98
98
|
|
99
99
|
configure_chef() {
|
100
|
-
echo
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
"
|
111
|
-
|
112
|
-
}
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
cat<<EOF>/etc/chef/solo.json
|
117
|
-
{
|
118
|
-
"run_list": "role[$role]",
|
119
|
-
"branch": "$branch",
|
120
|
-
"role": "$role"
|
121
|
-
}
|
122
|
-
EOF
|
123
|
-
fi
|
100
|
+
echo "saving current branch ($branch), role ($role), and environment ($environment)"
|
101
|
+
echo "$branch" > $branchfile
|
102
|
+
chmod 644 $branchfile
|
103
|
+
|
104
|
+
echo "$role" > $rolefile
|
105
|
+
chmod 644 $rolefile
|
106
|
+
|
107
|
+
echo "$environment" > $envfile
|
108
|
+
chmod 644 $envfile
|
109
|
+
|
110
|
+
echo "configuring chef solo..."
|
111
|
+
cat<<EOF > ${chef_dir}/solo.rb
|
112
|
+
repo_dir = "${repo_dir}"
|
113
|
+
cookbook_path "#{repo_dir}/cookbooks"
|
114
|
+
role_path "#{repo_dir}/roles"
|
115
|
+
data_bag_path "#{repo_dir}/data_bags"
|
124
116
|
|
125
|
-
cat<<EOF>/etc/chef/solo.rb
|
126
117
|
log_level :info
|
127
118
|
log_location STDOUT
|
128
|
-
cookbook_path "$repo_dir/cookbooks"
|
129
|
-
role_path "$repo_dir/roles"
|
130
|
-
data_bag_path "$repo_dir/data_bags"
|
131
|
-
json_attribs '/etc/chef/solo.json'
|
132
119
|
EOF
|
133
|
-
|
134
|
-
echo
|
120
|
+
|
121
|
+
echo -e "$data_bag_secret" > ${chef_dir}/encrypted_data_bag_secret
|
122
|
+
echo "chef configured"
|
135
123
|
}
|
136
124
|
|
137
125
|
|
138
126
|
configure_converger() {
|
139
|
-
cat<<EOF
|
140
|
-
#!/bin/bash -
|
127
|
+
cat<<EOF > $converge
|
128
|
+
#!/bin/bash -eu
|
129
|
+
|
130
|
+
repo="${repo_dir}"
|
131
|
+
branch=\`cat ${branchfile}\`
|
132
|
+
role=\`cat ${rolefile}\`
|
133
|
+
env=\`cat ${envfile}\`
|
134
|
+
|
135
|
+
cd \${repo}
|
136
|
+
|
137
|
+
runlist="role[\${role}]"
|
138
|
+
if [ -f "roles/\${env}.rb" ]
|
139
|
+
then
|
140
|
+
runlist+=",role[\${env}]"
|
141
|
+
fi
|
141
142
|
|
142
|
-
echo doing a hard reset to origin
|
143
|
-
|
144
|
-
|
145
|
-
git reset --hard origin/$branch
|
143
|
+
echo doing a hard reset to origin/\${branch}
|
144
|
+
GIT_SSH=${git_wrapper} git fetch
|
145
|
+
git reset --hard origin/\${branch}
|
146
146
|
git clean -fdx
|
147
|
-
|
147
|
+
|
148
|
+
json="{\"role\": \"\${role}\", \"env\": \"\${env}\", \"branch\": \"\${branch}\"}"
|
149
|
+
json_file=\`tempfile\`
|
150
|
+
echo \$json > \$json_file
|
151
|
+
trap "{ rm -f '\$json_file' ; }" EXIT
|
152
|
+
|
153
|
+
echo "running chef-solo with runlist \$runlist and json \$json (in file \$json_file)"
|
154
|
+
chef-solo -o "\${runlist}" -j \${json_file} "\$@"
|
148
155
|
EOF
|
149
|
-
chmod
|
156
|
+
chmod 544 $converge
|
150
157
|
}
|
151
158
|
|
152
|
-
|
153
159
|
configure_chef_daemon() {
|
154
|
-
cat<<EOF
|
160
|
+
cat<<EOF > /etc/init/chef-solo.conf
|
155
161
|
description "chef-solo"
|
156
162
|
author "Martin Rhoads"
|
157
163
|
start on networking
|
@@ -164,12 +170,11 @@ EOF
|
|
164
170
|
|
165
171
|
|
166
172
|
run_chef() {
|
167
|
-
echo
|
168
|
-
|
169
|
-
echo
|
173
|
+
echo "doing initial chef run..."
|
174
|
+
$converge 1>&2
|
175
|
+
echo "initial chef run complete"
|
170
176
|
}
|
171
177
|
|
172
|
-
|
173
178
|
start_chef_daemon() {
|
174
179
|
start chef-solo
|
175
180
|
}
|
@@ -179,8 +184,16 @@ start_chef_daemon() {
|
|
179
184
|
## main
|
180
185
|
##
|
181
186
|
|
187
|
+
#some derived vars
|
188
|
+
repo_dir=${chef_dir}/src
|
189
|
+
keyfile=${chef_dir}/git_key
|
190
|
+
envfile=${chef_dir}/environment
|
191
|
+
rolefile=${chef_dir}/role
|
192
|
+
branchfile=${chef_dir}/branch
|
193
|
+
git_wrapper=${chef_dir}/git_wrapper
|
182
194
|
|
183
|
-
echo starting chef bootstrapping...
|
195
|
+
echo "starting chef bootstrapping..."
|
196
|
+
mkdir -p ${chef_dir}
|
184
197
|
update
|
185
198
|
install curl
|
186
199
|
install git
|
@@ -190,6 +203,7 @@ update_repo
|
|
190
203
|
configure_chef
|
191
204
|
configure_converger
|
192
205
|
run_chef
|
206
|
+
|
193
207
|
configure_chef_daemon
|
194
208
|
# start_chef_daemon
|
195
209
|
|
data/lib/stemcell/version.rb
CHANGED
data/lib/stemcell.rb
CHANGED
@@ -8,65 +8,81 @@ module Stemcell
|
|
8
8
|
class Stemcell
|
9
9
|
def initialize(opts={})
|
10
10
|
@log = Logger.new(STDOUT)
|
11
|
+
@log.level = Logger::INFO unless ENV['DEBUG']
|
12
|
+
@log.debug "creating new stemcell object"
|
11
13
|
@log.debug "opts are #{opts.inspect}"
|
12
14
|
['aws_access_key',
|
13
15
|
'aws_secret_key',
|
14
16
|
'region',
|
15
|
-
'machine_type',
|
16
|
-
'image',
|
17
|
-
'security_group',
|
18
|
-
|
19
|
-
'chef_role',
|
20
|
-
'git_branch',
|
21
|
-
'git_key',
|
22
|
-
'git_origin',
|
23
|
-
'key_name',
|
24
17
|
].each do |req|
|
25
18
|
raise ArgumentError, "missing required param #{req}" unless opts[req]
|
26
19
|
instance_variable_set("@#{req}",opts[req])
|
27
20
|
end
|
28
21
|
|
29
|
-
@zone = opts.include?('availability_zone') ? opts['availability_zone'] : nil
|
30
22
|
@ec2_url = "ec2.#{@region}.amazonaws.com"
|
31
23
|
@timeout = 120
|
32
24
|
@start_time = Time.new
|
33
25
|
|
34
|
-
@tags = {
|
35
|
-
'Name' => "#{@chef_role}-#{@git_branch}",
|
36
|
-
'Group' => "#{@chef_role}-#{@git_branch}",
|
37
|
-
'created_by' => ENV['USER'],
|
38
|
-
'stemcell' => VERSION,
|
39
|
-
}
|
40
|
-
@tags.merge!(opts['tags']) if opts['tags']
|
41
|
-
|
42
|
-
begin
|
43
|
-
@git_key_contents = File.read(@git_key)
|
44
|
-
rescue Object => e
|
45
|
-
@git_key_contents = @git_key # assume content is passed in
|
46
|
-
end
|
47
|
-
|
48
|
-
if opts.include?('chef_data_bag_secret')
|
49
|
-
begin
|
50
|
-
@chef_data_bag_secret = File.read(opts['chef_data_bag_secret'])
|
51
|
-
rescue Object => e
|
52
|
-
@chef_data_bag_secret = opts['chef_data_bag_secret'] # assume secret is passed in
|
53
|
-
end
|
54
|
-
else
|
55
|
-
@chef_data_bag_secret = ''
|
56
|
-
end
|
57
|
-
|
58
26
|
AWS.config({:access_key_id => @aws_access_key, :secret_access_key => @aws_secret_key})
|
59
27
|
@ec2 = AWS::EC2.new(:ec2_endpoint => @ec2_url)
|
60
28
|
@ec2_region = @ec2.regions[@region]
|
61
|
-
@user_data = render_template
|
62
29
|
end
|
63
30
|
|
31
|
+
|
64
32
|
def launch(opts={})
|
65
|
-
|
66
|
-
|
33
|
+
verify_required_options(opts,[
|
34
|
+
'image_id',
|
35
|
+
'security_groups',
|
36
|
+
'key_name',
|
37
|
+
'count',
|
38
|
+
'chef_role',
|
39
|
+
'chef_environment',
|
40
|
+
'chef_data_bag_secret',
|
41
|
+
'git_branch',
|
42
|
+
'git_key',
|
43
|
+
'git_origin',
|
44
|
+
'instance_type',
|
45
|
+
])
|
46
|
+
|
47
|
+
# attempt to accept keys as file paths
|
48
|
+
opts['git_key'] = try_file(opts['git_key'])
|
49
|
+
opts['chef_data_bag_secret'] = try_file(opts['chef_data_bag_secret'])
|
50
|
+
|
51
|
+
# generate tags and merge in any that were specefied as in inputs
|
52
|
+
tags = {
|
53
|
+
'Name' => "#{opts['chef_role']}-#{opts['chef_environment']}",
|
54
|
+
'Group' => "#{opts['chef_role']}-#{opts['chef_environment']}",
|
55
|
+
'created_by' => ENV['USER'],
|
56
|
+
'stemcell' => VERSION,
|
57
|
+
}
|
58
|
+
tags.merge!(opts['tags']) if opts['tags']
|
59
|
+
|
60
|
+
# generate user data script to boot strap instance based on the
|
61
|
+
# opts that we were passed.
|
62
|
+
user_data = render_template(opts)
|
63
|
+
|
64
|
+
launch_options = {
|
65
|
+
:image_id => opts['image_id'],
|
66
|
+
:security_groups => opts['security_groups'],
|
67
|
+
:user_data => opts['user_data'],
|
68
|
+
:instance_type => opts['instance_type'],
|
69
|
+
:key_name => opts['key_name'],
|
70
|
+
:count => opts['count'],
|
71
|
+
:user_data => user_data,
|
72
|
+
}
|
73
|
+
launch_options.merge({:availability_zone => opts['availability_zone']}) if opts['availability_zone']
|
74
|
+
|
75
|
+
# launch instances
|
76
|
+
instances = do_launch(launch_options)
|
77
|
+
|
78
|
+
# wait for aws to report instance stats
|
67
79
|
wait(instances)
|
68
|
-
|
80
|
+
|
81
|
+
# set tags on all instances launched
|
82
|
+
set_tags(instances, tags)
|
83
|
+
|
69
84
|
print_run_info(instances)
|
85
|
+
@log.info "launched instances successfully"
|
70
86
|
return instances
|
71
87
|
end
|
72
88
|
|
@@ -83,7 +99,7 @@ module Stemcell
|
|
83
99
|
end
|
84
100
|
|
85
101
|
def wait(instances)
|
86
|
-
@log.info "Waiting for #{instances.count} instances (#{instances.inspect}):"
|
102
|
+
@log.info "Waiting up to #{@timeout} seconds for #{instances.count} instances (#{instances.inspect}):"
|
87
103
|
|
88
104
|
while true
|
89
105
|
sleep 5
|
@@ -100,18 +116,18 @@ module Stemcell
|
|
100
116
|
@log.info "all instances in running state"
|
101
117
|
end
|
102
118
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
}
|
111
|
-
options[:availability_zone] = @zone if @zone
|
112
|
-
options[:count] = opts['count'] if opts.include?('count')
|
119
|
+
def verify_required_options(params,required_options)
|
120
|
+
@log.debug "params is #{params}"
|
121
|
+
@log.debug "required_options are #{required_options}"
|
122
|
+
required_options.each do |required|
|
123
|
+
raise ArgumentError, "you need to provide option #{required}" unless params[required]
|
124
|
+
end
|
125
|
+
end
|
113
126
|
|
114
|
-
|
127
|
+
def do_launch(opts={})
|
128
|
+
@log.debug "about to launch instance(s) with options #{opts}"
|
129
|
+
@log.info "launching instances"
|
130
|
+
instances = @ec2_region.instances.create(opts)
|
115
131
|
instances = [instances] unless instances.class == Array
|
116
132
|
instances.each do |instance|
|
117
133
|
@log.info "launched instance #{instance.instance_id}"
|
@@ -119,19 +135,21 @@ module Stemcell
|
|
119
135
|
return instances
|
120
136
|
end
|
121
137
|
|
122
|
-
def set_tags(instances=[])
|
138
|
+
def set_tags(instances=[],tags)
|
139
|
+
@log.info "setting tags on instance(s)"
|
123
140
|
instances.each do |instance|
|
124
|
-
instance.tags.set(
|
141
|
+
instance.tags.set(tags)
|
125
142
|
end
|
126
143
|
end
|
127
144
|
|
128
|
-
def render_template
|
145
|
+
def render_template(opts={})
|
129
146
|
this_file = File.expand_path __FILE__
|
130
147
|
base_dir = File.dirname this_file
|
131
148
|
template_file_path = File.join(base_dir,'stemcell','templates','bootstrap.sh.erb')
|
132
149
|
template_file = File.read(template_file_path)
|
133
150
|
erb_template = ERB.new(template_file)
|
134
151
|
generated_template = erb_template.result(binding)
|
152
|
+
@log.debug "genereated template is #{generated_template}"
|
135
153
|
return generated_template
|
136
154
|
end
|
137
155
|
|
@@ -142,5 +160,15 @@ module Stemcell
|
|
142
160
|
instance.delete
|
143
161
|
end
|
144
162
|
end
|
163
|
+
|
164
|
+
# attempt to accept keys as file paths
|
165
|
+
def try_file(opt="")
|
166
|
+
begin
|
167
|
+
return File.read(opt)
|
168
|
+
rescue Object => e
|
169
|
+
return opt
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
145
173
|
end
|
146
174
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stemcell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: trollop
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- README.md
|
58
58
|
- Rakefile
|
59
59
|
- bin/stemcell
|
60
|
+
- examples/stemcellrc
|
60
61
|
- lib/stemcell.rb
|
61
62
|
- lib/stemcell/templates/bootstrap.sh.erb
|
62
63
|
- lib/stemcell/version.rb
|