cloud-maker 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/cloud-maker +67 -1
- data/lib/cloud-maker.rb +2 -0
- data/lib/cloud_maker/config.rb +64 -7
- data/lib/cloud_maker/ec2.rb +3 -3
- metadata +3 -3
data/bin/cloud-maker
CHANGED
@@ -4,6 +4,17 @@ require 'cloud-maker'
|
|
4
4
|
class CloudMakerCLI < Thor
|
5
5
|
include Thor::Actions
|
6
6
|
|
7
|
+
CONFIG_PATH = '~/.cloud-maker.yaml'
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
begin
|
12
|
+
@global_options = YAML::load(File.open(File.expand_path(CONFIG_PATH)))
|
13
|
+
rescue
|
14
|
+
@global_options = {}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
7
18
|
map "--version" => :version, "-v" => :version
|
8
19
|
|
9
20
|
desc "user_data [INSTANCE_CONFIG_YAML]", "Generate the Cloud Init user data for an instance described by INSTANCE_CONFIG_YAML"
|
@@ -28,6 +39,37 @@ class CloudMakerCLI < Thor
|
|
28
39
|
say "cloud-maker #{Gem::Specification.find_by_name('cloud-maker').version.version}"
|
29
40
|
end
|
30
41
|
|
42
|
+
desc "authorize_github", "Fetch an API authorization token from github."
|
43
|
+
def authorize_github
|
44
|
+
say "This will generate an OAuth token for use when fetching #{"github://".cyan} urls. It will be saved in #{CONFIG_PATH.cyan}."
|
45
|
+
say "You can remove this authorization from the GitHub interface if needed."
|
46
|
+
say "Your password will not be saved to disk.".green
|
47
|
+
user = ask("What is your GitHub #{"username".cyan}?")
|
48
|
+
password = ask("What is your GitHub #{"password".cyan}?")
|
49
|
+
begin
|
50
|
+
response = JSON.parse(RestClient::Request.new(
|
51
|
+
:method => "POST",
|
52
|
+
:url => 'https://api.github.com/authorizations',
|
53
|
+
:user => user,
|
54
|
+
:password => password,
|
55
|
+
:payload => {
|
56
|
+
:note => "CloudMaker",
|
57
|
+
:note_url => "https://github.com/airbnb/cloud-maker",
|
58
|
+
:scopes => ["repo"]
|
59
|
+
}.to_json,
|
60
|
+
:headers => {
|
61
|
+
:content_type => 'application/json'
|
62
|
+
}
|
63
|
+
).execute)
|
64
|
+
@global_options['github_token'] = response["token"]
|
65
|
+
save_options!
|
66
|
+
say "Your GitHub credentials have been successfully updated.".green
|
67
|
+
rescue Exception => e
|
68
|
+
say e.to_s.red
|
69
|
+
say "Your GitHub credentials could not be updated.".red
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
31
73
|
desc "terminate [AWS_INSTANCE_ID]", "Terminate the specified AWS instance"
|
32
74
|
method_option :aws_access_key_id,
|
33
75
|
:desc => "Your AWS access key id",
|
@@ -167,8 +209,32 @@ class CloudMakerCLI < Thor
|
|
167
209
|
puts
|
168
210
|
end
|
169
211
|
|
212
|
+
def save_options!
|
213
|
+
path = File.expand_path(CONFIG_PATH)
|
214
|
+
File.open(path, 'w+') {|f| f.write(@global_options.to_yaml)}
|
215
|
+
end
|
216
|
+
|
170
217
|
def build_config(instance_config_yaml, options)
|
171
|
-
|
218
|
+
begin
|
219
|
+
config = CloudMaker::Config.from_yaml(instance_config_yaml, 'import_ec2' => true, 'github_token' => @global_options['github_token'])
|
220
|
+
rescue CloudMaker::Config::GitHubContentNotFound => e
|
221
|
+
say e.to_s.red
|
222
|
+
if @global_options['github_token']
|
223
|
+
say "You do have GitHub OAuth configured, however you can redo the configuration if the current OAuth token is no longer valid.".yellow
|
224
|
+
else
|
225
|
+
say "You don't have a GitHub OAuth token configured, if this is a private repo doing so is necessary.".yellow
|
226
|
+
end
|
227
|
+
if yes?("Would you like to configure OAuth and retry now?")
|
228
|
+
authorize_github
|
229
|
+
retry
|
230
|
+
else
|
231
|
+
exit 1
|
232
|
+
end
|
233
|
+
rescue Exception => e
|
234
|
+
say e.to_s.red
|
235
|
+
exit 1
|
236
|
+
end
|
237
|
+
|
172
238
|
options.set.each_pair {|key, val| config[key] = val}
|
173
239
|
|
174
240
|
config['tags'] ||= {}
|
data/lib/cloud-maker.rb
CHANGED
data/lib/cloud_maker/config.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
module CloudMaker
|
2
2
|
class Config
|
3
|
+
class ContentNotFound < RuntimeError
|
4
|
+
attr_accessor :path
|
5
|
+
def initialize(message, path)
|
6
|
+
super(message)
|
7
|
+
self.path = path
|
8
|
+
end
|
9
|
+
end
|
10
|
+
class GitHubContentNotFound < ContentNotFound
|
11
|
+
end
|
12
|
+
class HTTPContentNotFound < ContentNotFound
|
13
|
+
end
|
14
|
+
class FileContentNotFound < ContentNotFound
|
15
|
+
end
|
16
|
+
|
3
17
|
# Public: Gets/Sets the CloudMaker specific properties. The options hash
|
4
18
|
# is formatted as:
|
5
19
|
# {
|
@@ -84,9 +98,23 @@ module CloudMaker
|
|
84
98
|
self.cloud_config = cloud_config
|
85
99
|
|
86
100
|
self.import(self.class.new(EC2::CLOUD_MAKER_CONFIG)) if (extra_options['import_ec2'])
|
101
|
+
|
102
|
+
# It's important here that reverse duplicates the imports array as executing the import will
|
103
|
+
# add the imported configs imports to the list and we do NOT want to reimport those as well.
|
87
104
|
self.imports.reverse.each do |import_path|
|
88
|
-
self.import(self.class.from_yaml(import_path))
|
105
|
+
self.import(self.class.from_yaml(import_path, self.extra_options))
|
89
106
|
end
|
107
|
+
self['tags'] ||= {}
|
108
|
+
self['tags']['cloud_maker_config'] = self.config_name
|
109
|
+
end
|
110
|
+
|
111
|
+
def config_name
|
112
|
+
files = self.imports.dup
|
113
|
+
files.push self.extra_options['config_path'] if self.extra_options['config_path']
|
114
|
+
|
115
|
+
files.reverse.map { |import|
|
116
|
+
import[import.rindex('/')+1..-1].gsub(/\..*/, '').gsub(/[^\w]/, '-')
|
117
|
+
}.join(':')
|
90
118
|
end
|
91
119
|
|
92
120
|
# Public: Check if the CloudMaker config is in a valid state.
|
@@ -208,14 +236,42 @@ module CloudMaker
|
|
208
236
|
# options - Any options to pass through as options to CloudMaker::Config::initialize
|
209
237
|
#
|
210
238
|
# Returns a new Config
|
211
|
-
# Raises:
|
239
|
+
# Raises: GitHubContentNotFound, HTTPContentNotFound, or FileContentNotFound if the file doesn't exist.
|
212
240
|
# Raises: SyntaxError if the YAML file is invalid.
|
213
241
|
def from_yaml(instance_config_yaml, options={})
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
242
|
+
if instance_config_yaml =~ /\Agithub:\/\//
|
243
|
+
begin
|
244
|
+
user, repo, *path = instance_config_yaml.split('/')[2..-1]
|
245
|
+
begin
|
246
|
+
if options['github_token']
|
247
|
+
response = RestClient.get(
|
248
|
+
"https://api.github.com/repos/#{user}/#{repo}/contents/#{path.join('/')}",
|
249
|
+
"Authorization" => "token #{options['github_token']}"
|
250
|
+
)
|
251
|
+
else
|
252
|
+
response = RestClient.get("https://api.github.com/repos/#{user}/#{repo}/contents/#{path.join('/')}")
|
253
|
+
end
|
254
|
+
cloud_yaml = Base64.decode64(JSON.parse(response)['content'])
|
255
|
+
rescue
|
256
|
+
raise GitHubContentNotFound.new(
|
257
|
+
"Unable to access the configuration #{instance_config_yaml} from GitHub.",
|
258
|
+
instance_config_yaml
|
259
|
+
)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
elsif instance_config_yaml =~ /\Ahttps?:\/\//
|
263
|
+
begin
|
264
|
+
cloud_yaml = RestClient.get(instance_config_yaml)
|
265
|
+
rescue
|
266
|
+
raise HTTPContentNotFound.new("Unable to access the configuration via HTTP from #{instance_config_yaml}.", instance_config_yaml)
|
267
|
+
end
|
268
|
+
else
|
269
|
+
begin
|
270
|
+
full_path = File.expand_path(instance_config_yaml)
|
271
|
+
cloud_yaml = File.open(full_path, "r") #Right_AWS will base64 encode this for us
|
272
|
+
rescue
|
273
|
+
raise FileContentNotFound.new("Unable to access the configuration via your local file system from #{full_path}.", instance_config_yaml)
|
274
|
+
end
|
219
275
|
end
|
220
276
|
|
221
277
|
# loading a blank config file returns false, it's an odd degenerate case but handling
|
@@ -340,6 +396,7 @@ module CloudMaker
|
|
340
396
|
def import(cloud_maker_config)
|
341
397
|
self.options = cloud_maker_config.options.deep_merge!(self.options)
|
342
398
|
self.includes = cloud_maker_config.includes.concat(self.includes).uniq
|
399
|
+
self.imports = cloud_maker_config.imports.concat(self.imports).uniq
|
343
400
|
self.cloud_config = cloud_maker_config.cloud_config.deep_merge!(self.cloud_config)
|
344
401
|
self.extra_options = cloud_maker_config.extra_options.deep_merge!(self.extra_options)
|
345
402
|
end
|
data/lib/cloud_maker/ec2.rb
CHANGED
@@ -100,7 +100,6 @@ module CloudMaker
|
|
100
100
|
else
|
101
101
|
region = ec2 # .instances.create will just put things in the default region
|
102
102
|
end
|
103
|
-
|
104
103
|
instance = region.instances.create(
|
105
104
|
:image_id => cloud_maker_config['ami'],
|
106
105
|
:security_groups => cloud_maker_config['security_group'],
|
@@ -110,7 +109,7 @@ module CloudMaker
|
|
110
109
|
:user_data => user_data
|
111
110
|
)
|
112
111
|
|
113
|
-
instance.tags.set(cloud_maker_config[
|
112
|
+
instance.tags.set(cloud_maker_config['tags']) if cloud_maker_config['tags']
|
114
113
|
instance.associate_elastic_ip(cloud_maker_config["elastic_ip"]) if cloud_maker_config["elastic_ip"]
|
115
114
|
|
116
115
|
archiver = S3Archiver.new(
|
@@ -174,7 +173,8 @@ module CloudMaker
|
|
174
173
|
:private_ip_address => instance.private_ip_address,
|
175
174
|
:key_name => instance.key_name,
|
176
175
|
:owner_id => instance.owner_id,
|
177
|
-
:status => instance.status
|
176
|
+
:status => instance.status,
|
177
|
+
:tags => instance.tags.inject({}) {|hash, tag| hash[tag.first] = tag.last;hash}
|
178
178
|
}
|
179
179
|
end
|
180
180
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloud-maker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-08-
|
13
|
+
date: 2012-08-17 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: colorize
|
@@ -128,5 +128,5 @@ rubyforge_project:
|
|
128
128
|
rubygems_version: 1.8.24
|
129
129
|
signing_key:
|
130
130
|
specification_version: 3
|
131
|
-
summary:
|
131
|
+
summary: Extends Ubuntu CloudInit to launch and configure cloud servers.
|
132
132
|
test_files: []
|