aws-carb 0.0.3
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.
- 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
|