aws-carb 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +3 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/aws-carb.gemspec +32 -0
- data/bin/carb +14 -0
- data/configs/config.yaml.example +24 -0
- data/lib/aws-carb/cli_argument_parser.rb +359 -0
- data/lib/aws-carb/config.rb +166 -0
- data/lib/aws-carb/helpers.rb +17 -0
- data/lib/aws-carb/monkey_patches.rb +78 -0
- data/lib/aws-carb/services/ec2.rb +97 -0
- data/lib/aws-carb/services/route53.rb +86 -0
- data/lib/aws-carb/user_data.rb +103 -0
- data/lib/aws-carb/version.rb +3 -0
- data/lib/aws-carb.rb +129 -0
- data/templates/basic.cloud-config.erb +84 -0
- metadata +204 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a8091f519cc7a1feb9f06b8e7970b160e9fa18d8
|
4
|
+
data.tar.gz: 3ec84346a2226990efd24aa108e5a8f346c42977
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4042bb7bdb921791fa89ff6c6c76da063b95a95dbf89c91df3c66ce4b3bb7f95cdcd58c69c6f475dfdc560d30f5439d42bc14a41873d84127998d51fcac10ab5
|
7
|
+
data.tar.gz: 189636adab38df5f0412792e82e2173fbf861e8a76b49b2634719b7faad8c252c52887400c720b21efead5976afc2b5d220613df363d30368c752e8bd01a203e
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# aws-carb: amazon web services - cloudinit and route53 bootstrap
|
2
|
+
|
3
|
+
## Install
|
4
|
+
|
5
|
+
via rubygems:
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install aws-carb
|
9
|
+
```
|
10
|
+
|
11
|
+
using bundler:
|
12
|
+
|
13
|
+
```
|
14
|
+
bundler install
|
15
|
+
```
|
16
|
+
|
17
|
+
## Configuration
|
18
|
+
|
19
|
+
At minimum, Carb needs to know your aws-ec2 credentials. The simplest way to allow this is to edit ~/.carb/config/config.yaml. See config/config.yaml.example for an example config.
|
20
|
+
|
21
|
+
|
22
|
+
## Example usage
|
23
|
+
|
24
|
+
carb can be used to create ec2 instances
|
25
|
+
|
26
|
+
```
|
27
|
+
aws create
|
28
|
+
```
|
29
|
+
|
30
|
+
|
31
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/aws-carb.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'aws-carb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "aws-carb"
|
8
|
+
spec.version = AWSCarb::VERSION
|
9
|
+
spec.authors = ["Rob Wilson"]
|
10
|
+
spec.email = ["roobert@gmail.com"]
|
11
|
+
spec.summary = "aws - cloudinit and route53 bootstrap"
|
12
|
+
spec.description = "a tool for provisioning ec2 instances with a templated cloudinit configuration, with the optional ability to update route53 with dns records to point at your new instance"
|
13
|
+
spec.homepage = "http://github.com/roobert/aws-carb"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0.0"
|
23
|
+
|
24
|
+
spec.add_dependency "activesupport", ">= 4.0.0"
|
25
|
+
spec.add_dependency "andand", ">= 1.3.0"
|
26
|
+
spec.add_dependency "awesome_print", ">= 1.2.0"
|
27
|
+
spec.add_dependency "aws-sdk", ">= 1.33.0"
|
28
|
+
spec.add_dependency "colorize", ">= 0.6.0"
|
29
|
+
spec.add_dependency "erubis", ">= 2.7.0"
|
30
|
+
spec.add_dependency "shell-spinner", ">= 1.0.0"
|
31
|
+
spec.add_dependency "subcommand", ">= 1.0.0"
|
32
|
+
end
|
data/bin/carb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '../lib'))
|
4
|
+
|
5
|
+
require 'aws-carb'
|
6
|
+
require 'aws-carb/helpers'
|
7
|
+
require 'aws-carb/cli_argument_parser'
|
8
|
+
require 'aws-carb/config'
|
9
|
+
require 'aws-carb/user_data'
|
10
|
+
require 'aws-carb/services/route53'
|
11
|
+
require 'aws-carb/services/ec2'
|
12
|
+
require 'aws-carb/monkey_patches'
|
13
|
+
|
14
|
+
AWSCarb.run
|
@@ -0,0 +1,24 @@
|
|
1
|
+
common:
|
2
|
+
domain: <domain>
|
3
|
+
|
4
|
+
ec2:
|
5
|
+
access_key_id: <key_id>
|
6
|
+
secret_access_key: <secret_key>
|
7
|
+
|
8
|
+
template_options:
|
9
|
+
repository_server: <repo_server>
|
10
|
+
debian_distro: <distro>
|
11
|
+
puppet_master: <puppetmaster>
|
12
|
+
s3_access_key_id: <key_id>
|
13
|
+
s3_secret_access_key: <secret_key>
|
14
|
+
s3_region: us-east-1
|
15
|
+
ssh_keys:
|
16
|
+
- <key>
|
17
|
+
- <key>
|
18
|
+
- <key>
|
19
|
+
|
20
|
+
route53:
|
21
|
+
access_key_id: <key_id>
|
22
|
+
secret_access_key: <secret_key>
|
23
|
+
zone: <zone_id>
|
24
|
+
ttl: 600
|
@@ -0,0 +1,359 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
include Subcommands
|
4
|
+
|
5
|
+
module AWSCarb
|
6
|
+
module CliArgumentParser
|
7
|
+
def self.parse
|
8
|
+
cli_arguments = OpenStruct.new
|
9
|
+
cli_arguments.global = OpenStruct.new
|
10
|
+
cli_arguments.subcommand = OpenStruct.new
|
11
|
+
cli_arguments.subcommand.user_data_template = OpenStruct.new
|
12
|
+
cli_arguments.subcommand.config_overrides = OpenStruct.new
|
13
|
+
cli_arguments.subcommand.ec2 = OpenStruct.new
|
14
|
+
cli_arguments.subcommand.route53 = OpenStruct.new
|
15
|
+
|
16
|
+
indent = ' ' * 10
|
17
|
+
|
18
|
+
banner = <<-HEREDOC.strip_heredoc
|
19
|
+
#{File.basename($0)}(1)
|
20
|
+
|
21
|
+
#{'NAME'.colorize({:color => :white, :mode => :bold})}
|
22
|
+
|
23
|
+
carb
|
24
|
+
|
25
|
+
#{'DESCRIPTION'.colorize({:color => :white, :mode => :bold})}
|
26
|
+
|
27
|
+
amazon web services - cloudinit and route53 bootstrap
|
28
|
+
|
29
|
+
HEREDOC
|
30
|
+
|
31
|
+
|
32
|
+
# these are the only defaults we need to bother setting since they get used before we load the config file..
|
33
|
+
cli_arguments.global.verbose = false
|
34
|
+
cli_arguments.global.config_file = File.join(Dir.home, ".carb/config", "config.yaml")
|
35
|
+
|
36
|
+
global_options do |option|
|
37
|
+
|
38
|
+
option.summary_width = 50
|
39
|
+
option.summary_indent = ' '
|
40
|
+
|
41
|
+
synopsis = <<-HEREDOC.strip_heredoc
|
42
|
+
#{"SYNOPSIS".colorize({:color => :white, :mode => :bold})}
|
43
|
+
|
44
|
+
#{File.basename($0)} [global options] [subcommand [options]]
|
45
|
+
|
46
|
+
HEREDOC
|
47
|
+
|
48
|
+
option.banner = banner + synopsis
|
49
|
+
option.separator "#{'GLOBAL OPTIONS'.colorize({:color => :white, :mode => :bold})}"
|
50
|
+
option.separator ""
|
51
|
+
|
52
|
+
option.on("-c", "--config=FILE", "") do |file|
|
53
|
+
cli_arguments.global.config_file = file
|
54
|
+
end
|
55
|
+
|
56
|
+
option.separator ""
|
57
|
+
|
58
|
+
option.on("-v", "--verbose", "") do |boolean|
|
59
|
+
cli_arguments.global.verbose = boolean
|
60
|
+
|
61
|
+
# FIXME: use a stupidly named global(!!!!!) variable to avoid clashing with rubys $VERBOSE
|
62
|
+
$GLOBAL_VERBOSE = boolean
|
63
|
+
end
|
64
|
+
|
65
|
+
option.separator ""
|
66
|
+
option.separator " -h, --help"
|
67
|
+
end
|
68
|
+
|
69
|
+
command :create do |option|
|
70
|
+
|
71
|
+
option.summary_width = 50
|
72
|
+
option.summary_indent = ' '
|
73
|
+
|
74
|
+
synopsis = <<-HEREDOC.strip_heredoc
|
75
|
+
#{'SYNOPSIS'.colorize({:color => :white, :mode => :bold})}
|
76
|
+
|
77
|
+
#{File.basename($0)} create [options]
|
78
|
+
|
79
|
+
HEREDOC
|
80
|
+
|
81
|
+
option.banner = banner + synopsis
|
82
|
+
option.description = "create an ec2 instance"
|
83
|
+
|
84
|
+
option.separator ""
|
85
|
+
option.separator " user_data tempate options:"
|
86
|
+
option.separator ""
|
87
|
+
|
88
|
+
option.on "--user-data-template=FILE", "\n\n#{indent}user data template" do |user_data_template|
|
89
|
+
cli_arguments.subcommand.user_data_template.file = user_data_template
|
90
|
+
end
|
91
|
+
|
92
|
+
option.separator ""
|
93
|
+
|
94
|
+
option.on "--show-parsed-template=BOOLEAN", "\n\n#{indent}display parsed template file" do |show_parsed_template|
|
95
|
+
cli_arguments.subcommand.user_data_template.show_parsed_template = show_parsed_template
|
96
|
+
end
|
97
|
+
|
98
|
+
option.separator ""
|
99
|
+
|
100
|
+
option.separator ""
|
101
|
+
option.separator " config file overrides:"
|
102
|
+
option.separator ""
|
103
|
+
|
104
|
+
option.on "--common-variables=HASH", String, "\n\n#{indent}common variables" do |common_variables|
|
105
|
+
begin
|
106
|
+
data = eval(common_variables)
|
107
|
+
raise unless data.class == Hash
|
108
|
+
cli_arguments.subcommand.config_overrides.common_variables = data.deep_symbolize_keys
|
109
|
+
rescue => e
|
110
|
+
puts "# could not parse argument for --common-variables, is it a valid hash?"
|
111
|
+
die e
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
option.separator ""
|
116
|
+
|
117
|
+
option.on "--general-variables=HASH", String, "\n\n#{indent}general variables" do |general_variables|
|
118
|
+
begin
|
119
|
+
data = eval(general_variables)
|
120
|
+
raise unless data.class == Hash
|
121
|
+
cli_arguments.subcommand.config_overrides.general_variables = data.deep_symbolize_keys
|
122
|
+
rescue => e
|
123
|
+
puts "# could not parse argument for --general-variables, is it a valid hash?"
|
124
|
+
die e
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
option.separator ""
|
129
|
+
|
130
|
+
option.on "--ec2-variables=HASH", String, "\n\n#{indent}ec2 variables" do |ec2_variables|
|
131
|
+
begin
|
132
|
+
data = eval(ec2_variables)
|
133
|
+
raise unless data.class == Hash
|
134
|
+
cli_arguments.subcommand.config_overrides.ec2_variables = data.deep_symbolize_keys
|
135
|
+
rescue => e
|
136
|
+
puts "# could not parse argument for --ec2-variables, is it a valid hash?"
|
137
|
+
die e
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
option.separator ""
|
142
|
+
|
143
|
+
option.on "--route53-variables=HASH", String, "\n\n#{indent}route53 variables" do |route53_variables|
|
144
|
+
begin
|
145
|
+
data = eval(route53_variables)
|
146
|
+
raise unless data.class == Hash
|
147
|
+
cli_arguments.subcommand.config_overrides.route53_variables = data.deep_symbolize_keys
|
148
|
+
rescue => e
|
149
|
+
puts "# could not parse argument for --route53-variables, is it a valid hash?"
|
150
|
+
die e
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
option.separator ""
|
155
|
+
|
156
|
+
option.on "--user-data-template-variables=HASH", String, "\n\n#{indent}user data template variables" do |user_data_template_variables|
|
157
|
+
begin
|
158
|
+
data = eval(user_data_template_variables)
|
159
|
+
raise unless data.class == Hash
|
160
|
+
cli_arguments.subcommand.config_overrides.user_data_template_variables = data.deep_symbolize_keys
|
161
|
+
rescue => e
|
162
|
+
puts "# could not parse argument for --user-data-template-variables, is it a valid hash?"
|
163
|
+
die e
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
option.separator ""
|
168
|
+
option.separator " long descriptions for these parameters can be found here:\n http://<TODO>"
|
169
|
+
option.separator ""
|
170
|
+
|
171
|
+
option.separator ""
|
172
|
+
option.separator " ec2 config convenience arguments:"
|
173
|
+
option.separator ""
|
174
|
+
|
175
|
+
option.on "--ec2-access-key-id=STRING", "\n\n#{indent}access key id".downcase do |access_key_id|
|
176
|
+
cli_arguments.subcommand.ec2.access_key_id = access_key_id
|
177
|
+
end
|
178
|
+
|
179
|
+
option.separator ""
|
180
|
+
|
181
|
+
option.on "--ec2-secret-access-key=STRING", "\n\n#{indent}secret access key".downcase do |secret_access_key|
|
182
|
+
cli_arguments.subcommand.ec2.secret_access_key = secret_access_key
|
183
|
+
end
|
184
|
+
|
185
|
+
option.separator ""
|
186
|
+
|
187
|
+
option.on "--image-id=STRING", "\n\n#{indent}ID of the AMI you want to launch.".downcase do |image_id|
|
188
|
+
cli_arguments.subcommand.ec2.image_id = image_id
|
189
|
+
end
|
190
|
+
|
191
|
+
option.separator ""
|
192
|
+
|
193
|
+
option.on "--instance-type=STRING", "\n\n#{indent}The type of instance to launch, for example \"m1.small\".".downcase do |instance_type|
|
194
|
+
cli_arguments.subcommand.ec2.instance_type = instance_type
|
195
|
+
end
|
196
|
+
|
197
|
+
option.separator ""
|
198
|
+
|
199
|
+
option.on "--key-name=STRING", "\n\n#{indent}The name of the key pair to use.".downcase do |key_name|
|
200
|
+
cli_arguments.subcommand.ec2.key_name = key_name
|
201
|
+
end
|
202
|
+
|
203
|
+
option.separator ""
|
204
|
+
|
205
|
+
|
206
|
+
block_device_help = <<-HEREDOC.strip_heredoc
|
207
|
+
|
208
|
+
:virtual_name - (String) Specifies the virtual device name.
|
209
|
+
:device_name - (String) Specifies the device name (e.g., /dev/sdh).
|
210
|
+
:ebs - (Hash) Specifies parameters used to automatically setup Amazon\n#{indent} EBS volumes when the instance is launched.
|
211
|
+
:snapshot_id - (String) The ID of the snapshot from which the volume will be created.
|
212
|
+
:volume_size - (Integer) The size of the volume, in gigabytes.
|
213
|
+
:delete_on_termination - (Boolean) Specifies whether the Amazon EBS volume is\n#{indent} deleted on instance termination.
|
214
|
+
:volume_type - (String) Valid values include:
|
215
|
+
standard
|
216
|
+
io1
|
217
|
+
:iops - (Integer)
|
218
|
+
:no_device - (String) Specifies the device name to suppress during instance launch.
|
219
|
+
HEREDOC
|
220
|
+
|
221
|
+
block_device_help = block_device_help.lines.map { |line| indent + " #{line}" }
|
222
|
+
|
223
|
+
block_device_help = "\n\n#{indent}Specifies how block devices are exposed to the instance. Each mapping\n#{indent}is made up of a virtualName and a deviceName.\n" + block_device_help.join.downcase
|
224
|
+
|
225
|
+
option.on "--block-device-mappings=HASH", block_device_help do |key_name|
|
226
|
+
cli_arguments.subcommand.ec2.key_name = key_name
|
227
|
+
end
|
228
|
+
|
229
|
+
option.separator ""
|
230
|
+
|
231
|
+
option.on "--user-data=STRING", "\n\n#{indent}Arbitrary user data. note: this is merged with user_data_template if also specified.".downcase do |user_data|
|
232
|
+
cli_arguments.subcommand.ec2.user_data = user_data
|
233
|
+
end
|
234
|
+
|
235
|
+
option.separator ""
|
236
|
+
|
237
|
+
option.on "--iam-instance-profile=STRING", "\n\n#{indent}the name or ARN of an IAM instance profile.".downcase do |profile|
|
238
|
+
cli_arguments.subcommand.ec2.iam_instance_profile = profile
|
239
|
+
end
|
240
|
+
|
241
|
+
option.separator ""
|
242
|
+
|
243
|
+
option.on "--monitoring-enabled=BOOLEAN", "\n\n#{indent}enable CloudWatch monitoring.".downcase do |boolean|
|
244
|
+
cli_arguments.subcommand.ec2.monitoring_enabled = boolean
|
245
|
+
end
|
246
|
+
|
247
|
+
option.separator ""
|
248
|
+
|
249
|
+
option.on "--availability-zone=STRING", "\n\n#{indent}availability zone.".downcase do |zone|
|
250
|
+
cli_arguments.subcommand.ec2.availability_zone = zone
|
251
|
+
end
|
252
|
+
|
253
|
+
option.separator ""
|
254
|
+
|
255
|
+
option.on "--security-groups=ARRAY", Array, "\n\n#{indent}Security groups. can be a single value or an array of values.\n#{indent}Values should be space deliminated group name strings.".downcase do |groups|
|
256
|
+
cli_arguments.subcommand.ec2.security_groups = groups
|
257
|
+
end
|
258
|
+
|
259
|
+
option.separator ""
|
260
|
+
|
261
|
+
option.on "--security-group-ids=ARRAY", Array, "\n\n#{indent}security_group_ids accepts a single ID or an array of\n#{indent}security group IDs.".downcase do |group_ids|
|
262
|
+
cli_arguments.subcommand.ec2.security_group_ids = group_ids
|
263
|
+
end
|
264
|
+
|
265
|
+
option.separator ""
|
266
|
+
|
267
|
+
option.on "--disable-api-termination=BOOLEAN", "\n\n#{indent}instance termination via the instance API.".downcase do |api_termination|
|
268
|
+
cli_arguments.subcommand.ec2.disable_api_termination = api_termination
|
269
|
+
end
|
270
|
+
|
271
|
+
option.separator ""
|
272
|
+
|
273
|
+
option.on "--instance-initiated-shutdown-behavior=STRING", "\n\n#{indent}instance termination on instance-initiated shutdown".downcase do |shutdown_behavior|
|
274
|
+
cli_arguments.subcommand.ec2.instance_initiated_shutdown_behavior = shutdown_behavior
|
275
|
+
end
|
276
|
+
|
277
|
+
option.separator ""
|
278
|
+
|
279
|
+
option.on "--subnet=STRING", "\n\n#{indent}The VPC Subnet (or subnet id string) to launch the instance in.".downcase do |subnet|
|
280
|
+
cli_arguments.subcommand.ec2.subnet = subnet
|
281
|
+
end
|
282
|
+
|
283
|
+
option.separator ""
|
284
|
+
|
285
|
+
option.on "--private_ip_address=STRING", "\n\n#{indent}If you're using VPC, you can optionally use this option to assign the\n#{indent}instance a specific available IP address from the subnet (e.g., '10.0.0.25').\n#{indent}This option is not valid for instances launched outside a VPC (i.e.\n#{indent}those launched without the :subnet option).".downcase do |ip|
|
286
|
+
cli_arguments.subcommand.ec2.private_ip_address = ip
|
287
|
+
end
|
288
|
+
|
289
|
+
option.separator ""
|
290
|
+
|
291
|
+
option.on "--dedicated-tenancy=BOOLEAN", "\n\n#{indent}Instances with dedicated tenancy will not share physical hardware with\n#{indent}instances outside their VPC. NOTE: Dedicated tenancy incurs an \n#{indent}additional service charge. This option is not valid for\n#{indent}instances launched outside a VPC (e.g.those launched without the :subnet option).".downcase do |tenancy|
|
292
|
+
cli_arguments.subcommand.ec2.dedicated_tenancy = tenancy
|
293
|
+
end
|
294
|
+
|
295
|
+
option.separator ""
|
296
|
+
|
297
|
+
option.on "--ebs-optimized=BOOLEAN", "\n\n#{indent}EBS-Optimized instances enable Amazon EC2 instances to fully utilize the\n#{indent}IOPS provisioned on an EBS volume. EBS-optimized instances deliver dedicated\n#{indent}throughput between Amazon EC2 and Amazon EBS, with options between\n#{indent}500 Mbps and 1000 Mbps depending on the instance type used. When attached\n#{indent}to EBS-Optimized instances, Provisioned IOPS volumes are designed to\n#{indent}deliver within 10% of their provisioned performance 99.9% of the time.\n#{indent}NOTE: EBS Optimized instances incur an additional service charge.\n#{indent}This option is only valid for certain instance types.".downcase do |ebs_optimized|
|
298
|
+
cli_arguments.subcommand.ec2.ebs_optimized = ebs_optimized
|
299
|
+
end
|
300
|
+
|
301
|
+
option.separator ""
|
302
|
+
option.separator " long descriptions for these parameters can be found here:\n http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/InstanceCollection.html"
|
303
|
+
option.separator ""
|
304
|
+
|
305
|
+
option.separator ""
|
306
|
+
option.separator " route53 convenience arguments:"
|
307
|
+
option.separator ""
|
308
|
+
|
309
|
+
option.on "--route53-access-key-id=STRING", "\n\n#{indent}access key id".downcase do |access_key_id|
|
310
|
+
cli_arguments.subcommand.route53.access_key_id = access_key_id
|
311
|
+
end
|
312
|
+
|
313
|
+
option.separator ""
|
314
|
+
|
315
|
+
option.on "--route53-secret-access-key=STRING", "\n\n#{indent}secret access key".downcase do |secret_access_key|
|
316
|
+
cli_arguments.subcommand.route53.secret_access_key = secret_access_key
|
317
|
+
end
|
318
|
+
|
319
|
+
option.separator ""
|
320
|
+
|
321
|
+
|
322
|
+
option.on "--zone=STRING", "\n\n#{indent}route53 zone".downcase do |zone|
|
323
|
+
cli_arguments.subcommand.route53.route = route
|
324
|
+
end
|
325
|
+
|
326
|
+
option.separator ""
|
327
|
+
|
328
|
+
option.on "--ttl=STRING", "\n\n#{indent}ttl".downcase do |ttl|
|
329
|
+
cli_arguments.subcommand.route53.ttl = ttl
|
330
|
+
end
|
331
|
+
|
332
|
+
option.separator ""
|
333
|
+
|
334
|
+
end
|
335
|
+
|
336
|
+
begin
|
337
|
+
#cli_arguments.chosen_subcommand = opt_parse
|
338
|
+
subcommand = opt_parse
|
339
|
+
|
340
|
+
# show help if no arguments passed in
|
341
|
+
if subcommand.nil?
|
342
|
+
add_subcommand_help
|
343
|
+
puts @global
|
344
|
+
|
345
|
+
exit 1
|
346
|
+
end
|
347
|
+
|
348
|
+
if ARGV.length > 0
|
349
|
+
raise ArgumentError, "unknown command line argument(s): #{ARGV.inspect.to_s}"
|
350
|
+
end
|
351
|
+
rescue => e
|
352
|
+
puts e
|
353
|
+
exit 1
|
354
|
+
end
|
355
|
+
|
356
|
+
return cli_arguments
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module AWSCarb
|
4
|
+
class Config
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
def create(cli_arguments)
|
10
|
+
|
11
|
+
@config = load_file(cli_arguments.global.config_file)
|
12
|
+
|
13
|
+
merge_cli_arguments_with_config(cli_arguments)
|
14
|
+
|
15
|
+
establish_hostname_and_domain
|
16
|
+
|
17
|
+
check_route53_settings
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_route53_settings
|
21
|
+
die 'route53: no zone id specified!' if @config[:route53][:zone].nil?
|
22
|
+
die 'route53: no ttl specified!' if @config[:route53][:zone].nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge_cli_arguments_with_config(cli_arguments)
|
26
|
+
begin
|
27
|
+
|
28
|
+
config_sections = [:common, :general, :ec2, :route53, :user_data_template_variables, :user_data_template]
|
29
|
+
|
30
|
+
# special condition: common command line arguments are shared between all instances first..
|
31
|
+
if cli_arguments.subcommand.config_overrides.common_variables
|
32
|
+
@config[:common] ||= {}
|
33
|
+
@config[:common].merge! cli_arguments.subcommand.config_overrides.common_variables
|
34
|
+
end
|
35
|
+
|
36
|
+
# all sections share 'common' variables..
|
37
|
+
config_sections.each do |section|
|
38
|
+
@config[section] ||= {}
|
39
|
+
@config[section].merge! @config[:common]
|
40
|
+
end
|
41
|
+
|
42
|
+
# merge the config overrides hashes into config
|
43
|
+
if cli_arguments.subcommand.config_overrides
|
44
|
+
cli_arguments.subcommand.config_overrides.marshal_dump.each do |key, value|
|
45
|
+
|
46
|
+
next if key == :common
|
47
|
+
|
48
|
+
# key differs from command line argument - we lose the _variables suffix
|
49
|
+
config_key = key.to_s.gsub('_variables', '').to_sym
|
50
|
+
|
51
|
+
@config[config_key] ||= {}
|
52
|
+
@config[config_key].merge! cli_arguments.subcommand.config_overrides.send(key)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# merge the convenience arguments..
|
57
|
+
config_sections.each do |section|
|
58
|
+
if cli_arguments.subcommand.send(section.to_s)
|
59
|
+
@config[section].merge! cli_arguments.subcommand.send(section.to_s).marshal_dump
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# merge the convenience argument parameters with config
|
64
|
+
@config.deep_symbolize_keys!
|
65
|
+
|
66
|
+
rescue => e
|
67
|
+
puts "# failed to merge cli arguments with config"
|
68
|
+
die e
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_file(cli_argument_config_file)
|
73
|
+
|
74
|
+
# allow forcing of no config file..
|
75
|
+
return if cli_argument_config_file.empty?
|
76
|
+
|
77
|
+
config_file = cli_argument_config_file
|
78
|
+
|
79
|
+
begin
|
80
|
+
# make keys symbols so we can more easily merge with cli arg structs..
|
81
|
+
@config = YAML.load_file(config_file).deep_symbolize_keys
|
82
|
+
rescue => e
|
83
|
+
puts "# failed to load config file: '#{config_file}'"
|
84
|
+
die e
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# when looking for a key, check 'common' section first, then override if a value
|
89
|
+
# in the supplied context is found..
|
90
|
+
def find_with_context(key, context)
|
91
|
+
return @config[context][key] if @config[context][key]
|
92
|
+
return @config[:common][key] if @config[:common][key]
|
93
|
+
return nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def [](key)
|
97
|
+
@config[key]
|
98
|
+
end
|
99
|
+
|
100
|
+
# try and work out the hostname, presidence is:
|
101
|
+
#
|
102
|
+
# * config file
|
103
|
+
# * user_data_template_variables cli args
|
104
|
+
#
|
105
|
+
# note: raw user_data is not checked (not to be confused with user_data_template or user_data_template_variables..)
|
106
|
+
#
|
107
|
+
def establish_hostname_and_domain
|
108
|
+
ShellSpinner "# checking whether hostname and domain have been set", false do
|
109
|
+
|
110
|
+
hostname, domain = nil
|
111
|
+
|
112
|
+
@config[:route53][:hostname] = find_with_context(:hostname, :user_data_template_variables) if find_with_context(:hostname, :user_data_template_variables)
|
113
|
+
@config[:route53][:domain] = find_with_context(:domain, :user_data_template_variables) if find_with_context(:domain, :user_data_template_variables)
|
114
|
+
@config[:route53][:hostname] = find_with_context(:hostname, :route53) if find_with_context(:hostname, :route53)
|
115
|
+
@config[:route53][:domain] = find_with_context(:domain, :route53) if find_with_context(:domain, :route53)
|
116
|
+
|
117
|
+
help = <<-HEREDOC.strip_heredoc
|
118
|
+
#
|
119
|
+
# checked:
|
120
|
+
# 'common', 'user_data_template_variables',
|
121
|
+
# and 'route53' sections of config
|
122
|
+
# --common-variables, --route53-variables,
|
123
|
+
# and --user-data-template-variables
|
124
|
+
#
|
125
|
+
# route53 dynamic DNS will not be updated!
|
126
|
+
HEREDOC
|
127
|
+
|
128
|
+
domain = @config[:route53][:domain]
|
129
|
+
hostname = @config[:route53][:hostname]
|
130
|
+
|
131
|
+
if domain.nil? and hostname.nil?
|
132
|
+
debug "# WARNING: hostname and domain not found"
|
133
|
+
debug help
|
134
|
+
debug
|
135
|
+
elsif domain and hostname.nil?
|
136
|
+
debug "# WARNING: hostname not found"
|
137
|
+
debug help
|
138
|
+
debug
|
139
|
+
elsif domain.nil? and hostname
|
140
|
+
debug "# WARNING: domain not found"
|
141
|
+
debug help
|
142
|
+
debug
|
143
|
+
else
|
144
|
+
debug "# found hostname and domain:"
|
145
|
+
debug "hostname: #{hostname}"
|
146
|
+
debug "domain: #{domain}"
|
147
|
+
debug
|
148
|
+
|
149
|
+
@config[:route53][:new_dns_records] = {
|
150
|
+
:public => { :alias => "#{hostname}.#{domain}.", :target => nil },
|
151
|
+
:private => { :alias => "#{hostname}-private.#{domain}.", :target => nil }
|
152
|
+
}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
puts
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
def display
|
161
|
+
puts "# config:"
|
162
|
+
ap @config
|
163
|
+
puts
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
def die(error)
|
4
|
+
if $GLOBAL_VERBOSE and error.respond_to?('backtrace')
|
5
|
+
puts "# stack trace:"
|
6
|
+
puts error.backtrace
|
7
|
+
puts
|
8
|
+
end
|
9
|
+
|
10
|
+
puts "error: #{error}"
|
11
|
+
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def debug(message = nil)
|
16
|
+
puts message if @GLOBAL_VERBOSE
|
17
|
+
end
|