cloud-maker 0.2.1 → 0.3.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 +7 -6
- data/lib/cloud-maker.rb +1 -1
- data/lib/cloud_maker/config.rb +2 -2
- data/lib/cloud_maker/ec2.rb +83 -40
- data/lib/cloud_maker/s3_archiver.rb +15 -11
- metadata +5 -5
data/bin/cloud-maker
CHANGED
@@ -43,7 +43,7 @@ class CloudMakerCLI < Thor
|
|
43
43
|
puts
|
44
44
|
|
45
45
|
if yes?("Are you sure you wish to terminate this instance?".red + " (y/n)")
|
46
|
-
cloud_maker = CloudMaker::
|
46
|
+
cloud_maker = CloudMaker::EC2.new(
|
47
47
|
:aws_access_key_id => options.aws_access_key_id,
|
48
48
|
:aws_secret_access_key => options.aws_secret_access_key
|
49
49
|
)
|
@@ -64,7 +64,7 @@ class CloudMakerCLI < Thor
|
|
64
64
|
:default => ENV['AWS_SECRET_ACCESS_KEY'],
|
65
65
|
:required => true
|
66
66
|
def info(aws_instance_id)
|
67
|
-
cloud_maker = CloudMaker::
|
67
|
+
cloud_maker = CloudMaker::EC2.new(
|
68
68
|
:aws_access_key_id => options.aws_access_key_id,
|
69
69
|
:aws_secret_access_key => options.aws_secret_access_key
|
70
70
|
)
|
@@ -111,16 +111,17 @@ class CloudMakerCLI < Thor
|
|
111
111
|
print_config_hash(config.to_hash)
|
112
112
|
|
113
113
|
if options.yes || yes?("Launch a new EC2 instance with the options above? (y/n)")
|
114
|
-
cloud_maker = CloudMaker::
|
114
|
+
cloud_maker = CloudMaker::EC2.new(
|
115
115
|
:aws_access_key_id => options.aws_access_key_id,
|
116
|
-
:aws_secret_access_key => options.aws_secret_access_key
|
116
|
+
:aws_secret_access_key => options.aws_secret_access_key,
|
117
|
+
:region => config['region']
|
117
118
|
)
|
118
119
|
|
119
120
|
instance = cloud_maker.launch(config)
|
120
121
|
puts
|
121
|
-
say "Successfully launched new EC2 instance: ".green + instance
|
122
|
+
say "Successfully launched new EC2 instance: ".green + instance.id.magenta
|
122
123
|
puts
|
123
|
-
print_colored_hash(instance)
|
124
|
+
print_colored_hash(CloudMaker::EC2.instance_to_hash(instance))
|
124
125
|
else
|
125
126
|
say "Launch aborted!".red
|
126
127
|
end
|
data/lib/cloud-maker.rb
CHANGED
data/lib/cloud_maker/config.rb
CHANGED
@@ -70,7 +70,7 @@ module CloudMaker
|
|
70
70
|
# extra_options - Options that describe the config as opposed to being part
|
71
71
|
# of the config.
|
72
72
|
# 'config_path' - The path the config was loaded from. Used for archival purposes.
|
73
|
-
# 'import_ec2' - CloudMaker::
|
73
|
+
# 'import_ec2' - CloudMaker::EC2 defines properties it relies on, if this value
|
74
74
|
# is true then we pull those property definitions in.
|
75
75
|
#
|
76
76
|
# Returns a CloudMaker object
|
@@ -83,7 +83,7 @@ module CloudMaker
|
|
83
83
|
self.imports = extract_imports!(cloud_config)
|
84
84
|
self.cloud_config = cloud_config
|
85
85
|
|
86
|
-
self.import(self.class.new(
|
86
|
+
self.import(self.class.new(EC2::CLOUD_MAKER_CONFIG)) if (extra_options['import_ec2'])
|
87
87
|
self.imports.reverse.each do |import_path|
|
88
88
|
self.import(self.class.from_yaml(import_path))
|
89
89
|
end
|
data/lib/cloud_maker/ec2.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'right_aws'
|
2
2
|
|
3
3
|
module CloudMaker
|
4
|
-
class
|
4
|
+
class EC2
|
5
5
|
# Public: Gets/Sets the AWS access key.
|
6
6
|
attr_accessor :aws_secret_access_key
|
7
7
|
# Public: Gets/Sets the AWS secret.
|
8
8
|
attr_accessor :aws_access_key_id
|
9
|
-
# Internal: Gets/Sets the
|
9
|
+
# Internal: Gets/Sets the AWS::EC2 instance.
|
10
10
|
attr_accessor :ec2
|
11
11
|
|
12
|
-
# Public: A CloudMaker::Config hash that describes the config properties
|
12
|
+
# Public: A CloudMaker::Config hash that describes the config properties EC2 relies on.
|
13
13
|
CLOUD_MAKER_CONFIG = {
|
14
14
|
'cloud-maker' => {
|
15
15
|
'ami' => {
|
@@ -42,7 +42,7 @@ module CloudMaker
|
|
42
42
|
# Public: The name of the tag that will be used to find the name of an s3 bucket for archiving/information retrieval
|
43
43
|
BUCKET_TAG = 's3_archive_bucket'
|
44
44
|
|
45
|
-
# Public: Creates a new
|
45
|
+
# Public: Creates a new EC2 instance
|
46
46
|
#
|
47
47
|
# cloud_maker_config - A CloudMaker::Config object describing the instance
|
48
48
|
# to be managed.
|
@@ -50,7 +50,7 @@ module CloudMaker
|
|
50
50
|
# :aws_access_key_id - (required) The AWS access key
|
51
51
|
# :aws_secret_access_key - (required) The AWS secret
|
52
52
|
#
|
53
|
-
# Returns a new CloudMaker::
|
53
|
+
# Returns a new CloudMaker::EC2 instance
|
54
54
|
# Raises RuntimeError if any of the required options are not specified
|
55
55
|
def initialize(options)
|
56
56
|
required_keys = [:aws_access_key_id, :aws_secret_access_key]
|
@@ -61,80 +61,123 @@ module CloudMaker
|
|
61
61
|
self.aws_access_key_id = options[:aws_access_key_id]
|
62
62
|
self.aws_secret_access_key = options[:aws_secret_access_key]
|
63
63
|
|
64
|
-
self.ec2 =
|
64
|
+
self.ec2 = AWS::EC2.new(:access_key_id => self.aws_access_key_id, :secret_access_key => self.aws_secret_access_key)
|
65
65
|
end
|
66
66
|
|
67
67
|
# Public: Fetch archived information about an instance
|
68
68
|
#
|
69
69
|
# Returns a hash of information about the instance as it was launched
|
70
70
|
def info(instance_id)
|
71
|
-
|
71
|
+
instance = find_instance(instance_id)
|
72
|
+
bucket = instance.tags[BUCKET_TAG]
|
73
|
+
|
72
74
|
archiver = S3Archiver.new(
|
73
75
|
:instance_id => instance_id,
|
74
76
|
:aws_access_key_id => self.aws_access_key_id,
|
75
77
|
:aws_secret_access_key => self.aws_secret_access_key,
|
76
78
|
:bucket_name => bucket
|
77
79
|
)
|
80
|
+
|
78
81
|
archiver.load_archive
|
79
82
|
end
|
80
83
|
|
81
84
|
# Public: Terminates the specified EC2 instance.
|
82
85
|
#
|
83
|
-
# Returns
|
86
|
+
# Returns nothing.
|
84
87
|
def terminate(instance_id)
|
85
|
-
|
88
|
+
find_instance(instance_id).terminate
|
86
89
|
end
|
87
90
|
|
88
91
|
# Public: Launches a new EC2 instance, associates any specified elastic IPS
|
89
92
|
# with it, adds any specified tags, and archives the launch details to S3.
|
90
93
|
#
|
91
|
-
# Returns
|
94
|
+
# Returns an AWS::EC2 object for the launched instance.
|
92
95
|
def launch(cloud_maker_config)
|
93
96
|
user_data = cloud_maker_config.to_user_data
|
94
97
|
|
95
|
-
|
96
|
-
|
98
|
+
if !cloud_maker_config['availability_zone'].nil? && !cloud_maker_config['availability_zone'].empty?
|
99
|
+
region = find_region(cloud_maker_config['availability_zone'])
|
100
|
+
else
|
101
|
+
region = ec2 # .instances.create will just put things in the default region
|
102
|
+
end
|
103
|
+
|
104
|
+
instance = region.instances.create(
|
105
|
+
:image_id => cloud_maker_config['ami'],
|
106
|
+
:security_groups => cloud_maker_config['security_group'],
|
97
107
|
:instance_type => cloud_maker_config['instance_type'],
|
98
108
|
:key_name => cloud_maker_config['key_pair'],
|
99
109
|
:availability_zone => cloud_maker_config['availability_zone'],
|
100
110
|
:user_data => user_data
|
101
|
-
)
|
102
|
-
|
103
|
-
instance_id = instance[:aws_instance_id]
|
104
|
-
|
105
|
-
ec2.create_tags(instance_id, cloud_maker_config["tags"]) if cloud_maker_config["tags"]
|
106
|
-
|
107
|
-
if (cloud_maker_config["elastic_ip"])
|
108
|
-
#we can't associate IPs while the state is pending
|
109
|
-
while instance[:aws_state] == 'pending'
|
110
|
-
#this is going to hammer EC2 a bit, it might be necessary to add some delay in here
|
111
|
-
instance = ec2.describe_instances([instance_id]).first
|
112
|
-
end
|
113
|
-
|
114
|
-
ec2.associate_address(instance_id, :public_ip => cloud_maker_config["elastic_ip"])
|
115
|
-
end
|
111
|
+
)
|
116
112
|
|
117
|
-
|
118
|
-
|
119
|
-
rescue RightAws::AwsError => e
|
120
|
-
tries ||= 0
|
121
|
-
tries += 1
|
122
|
-
if tries <= 5
|
123
|
-
sleep 2**tries
|
124
|
-
else
|
125
|
-
raise e
|
126
|
-
end
|
127
|
-
end
|
113
|
+
instance.tags.set(cloud_maker_config["tags"]) if cloud_maker_config["tags"]
|
114
|
+
instance.associate_elastic_ip(cloud_maker_config["elastic_ip"]) if cloud_maker_config["elastic_ip"]
|
128
115
|
|
129
116
|
archiver = S3Archiver.new(
|
130
|
-
:instance_id =>
|
117
|
+
:instance_id => instance.id,
|
131
118
|
:aws_access_key_id => self.aws_access_key_id,
|
132
119
|
:aws_secret_access_key => self.aws_secret_access_key,
|
133
120
|
:bucket_name => cloud_maker_config["tags"][BUCKET_TAG]
|
134
121
|
)
|
135
|
-
archiver.store_archive(cloud_maker_config, instance)
|
122
|
+
archiver.store_archive(cloud_maker_config, self.class.instance_to_hash(instance))
|
136
123
|
|
137
124
|
instance
|
138
125
|
end
|
126
|
+
|
127
|
+
# Internal: Find the instance object for an instance ID regardless of what
|
128
|
+
# region the instance is in. It looks in the default region (us-east-1) first
|
129
|
+
# and then looks in all regions if it's not there.
|
130
|
+
#
|
131
|
+
# Returns nil or an AWS::EC2::Instance
|
132
|
+
def find_instance(instance_id)
|
133
|
+
# Check the default region first
|
134
|
+
return ec2.instances[instance_id] if ec2.instances[instance_id].exists?
|
135
|
+
|
136
|
+
# If we don't find it there look in every region
|
137
|
+
instance = nil
|
138
|
+
ec2.regions.each do |region|
|
139
|
+
if region.instances[instance_id].exists?
|
140
|
+
instance = region.instances[instance_id]
|
141
|
+
break
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
instance
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# Internal: Find the region object for a given availability zone. Currently works
|
150
|
+
# based on amazon naming conventions and will break if they change.
|
151
|
+
#
|
152
|
+
# Returns an AWS::EC2::Region
|
153
|
+
# Raises a RuntimeError if the region doesn't exist
|
154
|
+
def find_region(availability_zone)
|
155
|
+
region_name = availability_zone.gsub(/(\d)\w$/, '\1')
|
156
|
+
if ec2.regions[region_name].exists?
|
157
|
+
ec2.regions[region_name]
|
158
|
+
else
|
159
|
+
raise RuntimeError.new("The region #{region_name} doesn't exist - region name generated from availability_zone: #{availability_zone}.")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class << self
|
164
|
+
# Public: Generates a hash of properties from an AWS::EC2 instance
|
165
|
+
#
|
166
|
+
# Returns a hash of properties for the instance.
|
167
|
+
def instance_to_hash(instance)
|
168
|
+
{
|
169
|
+
:instance_id => instance.id,
|
170
|
+
:ami => instance.image_id,
|
171
|
+
:api_termination_disabled => instance.api_termination_disabled?,
|
172
|
+
:dns_name => instance.dns_name,
|
173
|
+
:ip_address => instance.ip_address,
|
174
|
+
:private_ip_address => instance.private_ip_address,
|
175
|
+
:key_name => instance.key_name,
|
176
|
+
:owner_id => instance.owner_id,
|
177
|
+
:status => instance.status
|
178
|
+
}
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
139
182
|
end
|
140
183
|
end
|
@@ -7,7 +7,7 @@ module CloudMaker
|
|
7
7
|
attr_accessor :aws_access_key_id
|
8
8
|
# Public: Gets/Sets the EC2 instance ID string.
|
9
9
|
attr_accessor :instance_id
|
10
|
-
# Internal: Gets/Sets the
|
10
|
+
# Internal: Gets/Sets the bucket object used for storing/loading archives.
|
11
11
|
attr_accessor :bucket
|
12
12
|
|
13
13
|
# Public: All archive keys will be prefixed with KEY_PREFIX/
|
@@ -37,22 +37,26 @@ module CloudMaker
|
|
37
37
|
self.aws_access_key_id = options[:aws_access_key_id]
|
38
38
|
self.aws_secret_access_key = options[:aws_secret_access_key]
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
self.bucket = AWS::S3.new(
|
41
|
+
:access_key_id => self.aws_access_key_id,
|
42
|
+
:secret_access_key => self.aws_secret_access_key
|
43
|
+
).buckets[options[:bucket_name]]
|
44
|
+
|
45
|
+
raise RuntimeError.new("The S3 bucket #{options[:bucket_name]} does not exist.") unless self.bucket.exists?
|
42
46
|
end
|
43
47
|
|
44
48
|
# Public: Generates an archive with all information relevant to an instance
|
45
49
|
# launch and stores it to S3.
|
46
50
|
#
|
47
51
|
# cloud_maker_config - The CloudMaker::Config the instance was launched with
|
48
|
-
#
|
52
|
+
# properties - A Hash describing the properties of the launched instance
|
49
53
|
#
|
50
54
|
# Returns nothing.
|
51
|
-
def store_archive(cloud_maker_config,
|
55
|
+
def store_archive(cloud_maker_config, properties)
|
52
56
|
userdata = cloud_maker_config.to_user_data
|
53
|
-
self.bucket.
|
54
|
-
self.bucket.
|
55
|
-
self.bucket.
|
57
|
+
self.bucket.objects.create(self.user_data_key, :data => userdata)
|
58
|
+
self.bucket.objects.create(self.instance_yaml_key, :data => properties.to_yaml)
|
59
|
+
self.bucket.objects.create(self.cloud_config_yaml_key, :data => cloud_maker_config.to_hash.to_yaml)
|
56
60
|
true
|
57
61
|
end
|
58
62
|
|
@@ -61,9 +65,9 @@ module CloudMaker
|
|
61
65
|
# Returns the content of the archive.
|
62
66
|
def load_archive
|
63
67
|
{
|
64
|
-
:user_data => self.bucket.
|
65
|
-
:cloud_config => YAML::load(self.bucket.
|
66
|
-
:instance => YAML::load(self.bucket.
|
68
|
+
:user_data => self.bucket.objects[self.user_data_key].read,
|
69
|
+
:cloud_config => YAML::load(self.bucket.objects[self.cloud_config_yaml_key].read),
|
70
|
+
:instance => YAML::load(self.bucket.objects[self.instance_yaml_key].read)
|
67
71
|
}
|
68
72
|
end
|
69
73
|
|
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.3.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-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: colorize
|
@@ -45,13 +45,13 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0.15'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: aws-sdk
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '1.6'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
57
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -59,7 +59,7 @@ dependencies:
|
|
59
59
|
requirements:
|
60
60
|
- - ~>
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
62
|
+
version: '1.6'
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
64
|
name: deep_merge
|
65
65
|
requirement: !ruby/object:Gem::Requirement
|