wombat-cli 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/DESIGN.md +2 -1
- data/README.md +10 -32
- data/Rakefile +1 -52
- data/cookbooks/automate/.kitchen.ec2.yml +8 -1
- data/cookbooks/automate/.kitchen.yml +0 -1
- data/cookbooks/automate/metadata.rb +0 -2
- data/cookbooks/automate/recipes/default.rb +4 -3
- data/cookbooks/automate/test/integration/default/automate_spec.rb +3 -2
- data/cookbooks/build_node/.kitchen.ec2.yml +8 -1
- data/cookbooks/build_node/metadata.rb +0 -3
- data/cookbooks/build_node/recipes/default.rb +5 -2
- data/cookbooks/build_node/test/integration/default/build-node_spec.rb +3 -2
- data/cookbooks/chef_server/.kitchen.ec2.yml +8 -0
- data/cookbooks/chef_server/.kitchen.yml +0 -1
- data/cookbooks/chef_server/metadata.rb +0 -2
- data/cookbooks/chef_server/recipes/{cheffish.rb → bootstrap_users.rb} +1 -1
- data/cookbooks/chef_server/recipes/default.rb +30 -14
- data/cookbooks/chef_server/test/integration/default/chef_server_spec.rb +7 -4
- data/cookbooks/compliance/.kitchen.ec2.yml +8 -0
- data/cookbooks/compliance/metadata.rb +0 -1
- data/cookbooks/compliance/recipes/default.rb +5 -7
- data/cookbooks/compliance/test/integration/default/compliance.rb +3 -2
- data/cookbooks/infranodes/.kitchen.ec2.yml +23 -2
- data/cookbooks/infranodes/recipes/default.rb +25 -9
- data/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/recipes/default.rb +9 -3
- data/cookbooks/infranodes/test/integration/default/infranodes_spec.rb +11 -9
- data/cookbooks/wombat/attributes/default.rb +2 -0
- data/cookbooks/wombat/metadata.rb +2 -0
- data/cookbooks/wombat/recipes/authorized-keys.rb +10 -0
- data/cookbooks/workstation/recipes/certs-keys.rb +2 -1
- data/cookbooks/workstation/templates/default/ssh_config.erb +2 -2
- data/lib/wombat/build.rb +138 -120
- data/lib/wombat/cli.rb +8 -0
- data/lib/wombat/common.rb +27 -12
- data/lib/wombat/deploy.rb +33 -26
- data/lib/wombat/version.rb +1 -1
- data/packer/automate.json +7 -5
- data/packer/build-node.json +6 -4
- data/packer/chef-server.json +11 -6
- data/packer/compliance.json +6 -5
- data/packer/infranodes-windows.json +100 -0
- data/packer/infranodes.json +6 -5
- data/packer/workstation.json +5 -4
- data/stacks/.gitkeep +0 -0
- data/templates/bootstrap-aws.erb +2 -2
- data/templates/cfn.json.erb +16 -15
- data/wombat.example.yml +45 -35
- metadata +5 -15
- data/packer/mock-data/.gitignore +0 -16
- data/packer/mock-data/.kitchen.yml +0 -21
- data/packer/mock-data/Berksfile +0 -3
- data/packer/mock-data/README.md +0 -4
- data/packer/mock-data/chefignore +0 -102
- data/packer/mock-data/metadata.rb +0 -7
- data/packer/mock-data/recipes/default.rb +0 -69
- data/packer/mock-data/spec/spec_helper.rb +0 -2
- data/packer/mock-data/spec/unit/recipes/default_spec.rb +0 -20
- data/packer/mock-data/test/integration/default/serverspec/default_spec.rb +0 -9
- data/packer/mock-data/test/integration/helpers/serverspec/spec_helper.rb +0 -8
@@ -1,20 +1,22 @@
|
|
1
1
|
# automate tests
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
unless os.windows?
|
4
|
+
describe file("/home/#{os.name}/.ssh/authorized_keys") do
|
5
|
+
its('content') { should include file("/tmp/public.pub").content }
|
6
|
+
it { should exist }
|
7
|
+
end
|
6
8
|
|
7
|
-
describe package('push-jobs-client') do
|
8
|
-
|
9
|
+
describe package('push-jobs-client') do
|
10
|
+
it { should be_installed }
|
11
|
+
end
|
9
12
|
end
|
10
13
|
|
11
|
-
|
14
|
+
etc_hosts = os.windows? ? 'C:\Windows\System32\Drivers\etc\hosts' : '/etc/hosts'
|
15
|
+
|
16
|
+
describe file(etc_hosts) do
|
12
17
|
its('content') { should match /172.31.54.10\s.*chef.animals.biz chef/ }
|
13
18
|
its('content') { should match /172.31.54.11\s.*automate.animals.biz automate/ }
|
14
19
|
its('content') { should match /172.31.54.12\s.*compliance.animals.biz compliance/ }
|
15
20
|
its('content') { should match /172.31.54.51\s.*build-node-1.animals.biz build-node-1/ }
|
16
21
|
its('content') { should match /172.31.54.201\s.*workstation-1.animals.biz workstation-1/ }
|
17
22
|
end
|
18
|
-
|
19
|
-
# add tests to verify users and passwords
|
20
|
-
# delivery-ctl list-users doesn't work
|
@@ -12,6 +12,8 @@ default['demo']['versions'].tap do |pkg|
|
|
12
12
|
pkg['chef-server'] = 'stable-latest'
|
13
13
|
pkg['automate'] = 'stable-latest'
|
14
14
|
pkg['compliance'] = 'stable-latest'
|
15
|
+
pkg['push-jobs-server'] = 'stable-latest'
|
16
|
+
pkg['manage'] = 'stable-latest'
|
15
17
|
end
|
16
18
|
|
17
19
|
default['demo']['hosts'] = {
|
@@ -7,4 +7,14 @@
|
|
7
7
|
append_if_no_line "Add certificate to authorized_keys" do
|
8
8
|
path "/home/#{node['demo']['admin-user']}/.ssh/authorized_keys"
|
9
9
|
line lazy { IO.read('/tmp/public.pub') }
|
10
|
+
not_if { node['platform'] == 'windows' }
|
11
|
+
end
|
12
|
+
|
13
|
+
node.default['authorization']['sudo']['include_sudoers_d'] = true
|
14
|
+
|
15
|
+
sudo 'centos' do
|
16
|
+
user 'centos'
|
17
|
+
nopasswd true
|
18
|
+
defaults ['!requiretty']
|
19
|
+
only_if { node['platform'] == 'centos' }
|
10
20
|
end
|
@@ -14,7 +14,8 @@ template "#{home}/.ssh/config" do
|
|
14
14
|
home: home,
|
15
15
|
server: "#{node['demo']['domain_prefix']}automate.#{node['demo']['domain']}",
|
16
16
|
ent: node['demo']['enterprise'],
|
17
|
-
|
17
|
+
automate_user: "workstation-#{node['demo']['workstation-number']}",
|
18
|
+
ssh_user: node['demo']['admin-user']
|
18
19
|
)
|
19
20
|
end
|
20
21
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Host <%= @server %>
|
2
2
|
HostName <%= @server %>
|
3
3
|
Port 8989
|
4
|
-
User <%= @
|
4
|
+
User <%= @automate_user -%>@<%= @ent %>
|
5
5
|
IdentityFile <%= @home -%>/.ssh/id_rsa
|
6
6
|
IdentitiesOnly yes
|
7
7
|
KexAlgorithms +diffie-hellman-group1-sha1
|
@@ -9,7 +9,7 @@ Host <%= @server %>
|
|
9
9
|
|
10
10
|
Host *
|
11
11
|
Port 22
|
12
|
-
User
|
12
|
+
User <%= @ssh_user %>
|
13
13
|
IdentityFile <%= @home -%>/.ssh/id_rsa
|
14
14
|
IdentitiesOnly yes
|
15
15
|
KexAlgorithms +diffie-hellman-group1-sha1
|
data/lib/wombat/build.rb
CHANGED
@@ -17,145 +17,56 @@ class BuildRunner
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def start
|
20
|
-
banner("Generating
|
20
|
+
banner("Generating certs (if necessary)")
|
21
21
|
wombat['certs'].each do |hostname|
|
22
22
|
gen_x509_cert(hostname)
|
23
23
|
end
|
24
|
-
|
24
|
+
banner("Generating SSH keypair (if necessary)")
|
25
25
|
gen_ssh_key
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
time = Benchmark.measure do
|
28
|
+
banner("Starting build for templates: #{templates}")
|
29
|
+
aws_region_check if builder == 'amazon-ebs'
|
30
|
+
templates.each do |t|
|
31
|
+
vendor_cookbooks(t)
|
31
32
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
options = {}
|
37
|
-
# TODO: this needs to be abstracted badly
|
38
|
-
case template
|
39
|
-
when 'build-node', 'build-nodes'
|
40
|
-
vendor_cookbooks('build-node')
|
41
|
-
build_nodes.each do |name, num|
|
42
|
-
template = 'build-node'
|
43
|
-
options = {'node-number' => num}
|
44
|
-
packer_cmd = Mixlib::ShellOut.new(packer_build(template, builder, options), :timeout => 3600, live_stream: STDOUT)
|
45
|
-
packer_cmd.run_command
|
46
|
-
end
|
47
|
-
when 'workstation', 'workstations'
|
48
|
-
bootstrap_aws
|
49
|
-
vendor_cookbooks('workstation')
|
50
|
-
workstations.each do |name, num|
|
51
|
-
template = 'workstation'
|
52
|
-
options = {'workstation-number' => num}
|
53
|
-
packer_cmd = Mixlib::ShellOut.new(packer_build(template, builder, options), :timeout => 3600, live_stream: STDOUT)
|
54
|
-
packer_cmd.run_command
|
55
|
-
end
|
56
|
-
when 'infranode', 'infranodes'
|
57
|
-
vendor_cookbooks('infranodes')
|
58
|
-
infranodes.each do |name, num|
|
59
|
-
template = 'infranodes'
|
60
|
-
options = {'node-name' => name}
|
61
|
-
packer_cmd = Mixlib::ShellOut.new(packer_build(template, builder, options), :timeout => 3600, live_stream: STDOUT)
|
62
|
-
packer_cmd.run_command
|
63
|
-
end
|
64
|
-
else
|
65
|
-
vendor_cookbooks(template)
|
66
|
-
packer_cmd = Mixlib::ShellOut.new(packer_build(template, builder, options), :timeout => 3600, live_stream: STDOUT)
|
67
|
-
packer_cmd.run_command
|
68
|
-
puts packer_cmd
|
69
|
-
puts packer_cmd.stdout
|
70
|
-
puts packer_cmd.stderr unless packer_cmd.stderr.empty?
|
71
|
-
end
|
33
|
+
|
34
|
+
if parallel.nil?
|
35
|
+
build_hash.each do |k, v|
|
36
|
+
build(v['template'], v['options'])
|
72
37
|
end
|
38
|
+
else
|
39
|
+
build_parallel(templates)
|
73
40
|
end
|
74
41
|
end
|
42
|
+
shell_out_command("say -v fred \"Wombat has made an #{build_hash.keys.to_s}\" for you") if audio?
|
75
43
|
banner("Build finished in #{duration(time.real)}.")
|
76
44
|
end
|
77
45
|
|
78
46
|
private
|
79
47
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
rm.run_command
|
84
|
-
puts "Vendoring cookbooks for #{template}"
|
85
|
-
vendor = Mixlib::ShellOut.new("berks vendor -q -b cookbooks/#{base}/Berksfile vendored-cookbooks/#{base}", live_stream: STDOUT)
|
86
|
-
vendor.run_command
|
48
|
+
def build(template, options)
|
49
|
+
bootstrap_aws if options['os'] == 'windows'
|
50
|
+
shell_out_command(packer_build_cmd(template, builder, options))
|
87
51
|
end
|
88
52
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
case template
|
93
|
-
when 'build-node'
|
94
|
-
log_name = "build-node-#{options['node-number']}"
|
95
|
-
when 'workstation'
|
96
|
-
log_name = "workstation-#{options['workstation-number']}"
|
97
|
-
when 'infranodes'
|
98
|
-
log_name = "infranodes-#{options['node-name']}"
|
99
|
-
else
|
100
|
-
log_name = template
|
53
|
+
def build_parallel(templates)
|
54
|
+
Parallel.map(build_hash.keys, in_threads: build_hash.count) do |name|
|
55
|
+
build(build_hash[name]['template'], build_hash[name]['options'])
|
101
56
|
end
|
102
|
-
|
103
|
-
case builder
|
104
|
-
when 'amazon-ebs'
|
105
|
-
if template == 'workstation'
|
106
|
-
source_ami = wombat['aws']['source_ami']['windows']
|
107
|
-
else
|
108
|
-
source_ami = wombat['aws']['source_ami']['ubuntu']
|
109
|
-
end
|
110
|
-
if ENV['AWS_REGION']
|
111
|
-
puts "Region set by environment: #{ENV['AWS_REGION']}"
|
112
|
-
else
|
113
|
-
banner("$AWS_REGION not set, setting to #{wombat['aws']['region']}")
|
114
|
-
ENV['AWS_REGION'] = wombat['aws']['region']
|
115
|
-
end
|
116
|
-
log_prefix = "aws"
|
117
|
-
when 'googlecompute'
|
118
|
-
if template == 'workstation'
|
119
|
-
source_image = wombat['gce']['source_image']['windows']
|
120
|
-
else
|
121
|
-
source_image = wombat['gce']['source_image']['ubuntu']
|
122
|
-
end
|
123
|
-
log_prefix = "gce"
|
124
|
-
end
|
125
|
-
# TODO: fail if packer isn't found in a graceful way
|
126
|
-
cmd = %W(packer build #{packer_dir}/#{template}.json | tee #{log_dir}/#{log_prefix}-#{log_name}.log)
|
127
|
-
cmd.insert(2, "--only #{builder}")
|
128
|
-
cmd.insert(2, "--var org=#{wombat['org']}")
|
129
|
-
cmd.insert(2, "--var domain=#{wombat['domain']}")
|
130
|
-
cmd.insert(2, "--var domain_prefix=#{wombat['domain_prefix']}")
|
131
|
-
cmd.insert(2, "--var enterprise=#{wombat['enterprise']}")
|
132
|
-
cmd.insert(2, "--var chefdk=#{wombat['products']['chefdk']}")
|
133
|
-
cmd.insert(2, "--var chef_ver=#{wombat['products']['chef'].split('-')[1]}")
|
134
|
-
cmd.insert(2, "--var chef_channel=#{wombat['products']['chef'].split('-')[0]}")
|
135
|
-
cmd.insert(2, "--var automate=#{wombat['products']['automate']}")
|
136
|
-
cmd.insert(2, "--var compliance=#{wombat['products']['compliance']}")
|
137
|
-
cmd.insert(2, "--var chef-server=#{wombat['products']['chef-server']}")
|
138
|
-
cmd.insert(2, "--var node-name=#{options['node-name']}") if template =~ /infranodes/
|
139
|
-
cmd.insert(2, "--var node-number=#{options['node-number']}") if template =~ /build-node/
|
140
|
-
cmd.insert(2, "--var build-nodes=#{wombat['build-nodes']}")
|
141
|
-
cmd.insert(2, "--var winrm_password=#{wombat['workstation-passwd']}") if template =~ /workstation/
|
142
|
-
cmd.insert(2, "--var workstation-number=#{options['workstation-number']}") if template =~ /workstation/
|
143
|
-
cmd.insert(2, "--var workstations=#{wombat['workstations']}")
|
144
|
-
cmd.insert(2, "--var aws_source_ami=#{source_ami}")
|
145
|
-
cmd.insert(2, "--var gce_source_image=#{source_image}")
|
146
|
-
cmd.join(' ')
|
147
57
|
end
|
148
58
|
|
149
|
-
def
|
59
|
+
def build_hash
|
150
60
|
proc_hash = {}
|
151
61
|
templates.each do |template_name|
|
152
|
-
if template_name
|
62
|
+
if template_name =~ /infranodes/
|
153
63
|
infranodes.each do |name, _rl|
|
154
64
|
next if name.empty?
|
155
65
|
proc_hash[name] = {
|
156
|
-
'template' =>
|
66
|
+
'template' => template_name,
|
157
67
|
'options' => {
|
158
|
-
'node-name' => name
|
68
|
+
'node-name' => name,
|
69
|
+
'os' => wombat['infranodes'][name]['platform']
|
159
70
|
}
|
160
71
|
}
|
161
72
|
end
|
@@ -173,6 +84,7 @@ class BuildRunner
|
|
173
84
|
proc_hash[name] = {
|
174
85
|
'template' => 'workstation',
|
175
86
|
'options' => {
|
87
|
+
'os' => wombat['workstations']['platform'],
|
176
88
|
'workstation-number' => num
|
177
89
|
}
|
178
90
|
}
|
@@ -183,13 +95,119 @@ class BuildRunner
|
|
183
95
|
'options' => {}
|
184
96
|
}
|
185
97
|
end
|
186
|
-
vendor_cookbooks(template_name)
|
187
98
|
end
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
99
|
+
proc_hash
|
100
|
+
end
|
101
|
+
|
102
|
+
def a_to_s(*args)
|
103
|
+
clean_array(*args).join(" ")
|
104
|
+
end
|
105
|
+
|
106
|
+
def clean_array(*args)
|
107
|
+
args.flatten.reject { |i| i.nil? || i == "" }.map(&:to_s)
|
108
|
+
end
|
109
|
+
|
110
|
+
def b_to_c(builder)
|
111
|
+
case builder
|
112
|
+
when 'amazon-ebs'
|
113
|
+
cloud = 'aws'
|
114
|
+
when 'googlecompute'
|
115
|
+
cloud = 'gce'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def shell_out_command(command)
|
120
|
+
cmd = Mixlib::ShellOut.new(a_to_s(command), :timeout => timeout, live_stream: STDOUT)
|
121
|
+
cmd.run_command
|
122
|
+
cmd
|
123
|
+
end
|
124
|
+
|
125
|
+
def aws_region_check
|
126
|
+
if ENV['AWS_REGION']
|
127
|
+
banner("Region set by environment: #{ENV['AWS_REGION']}")
|
128
|
+
else
|
129
|
+
banner("$AWS_REGION not set, setting to #{wombat['aws']['region']}")
|
130
|
+
ENV['AWS_REGION'] = wombat['aws']['region']
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def vendor_cookbooks(template)
|
135
|
+
banner "Vendoring cookbooks for #{template}"
|
136
|
+
|
137
|
+
if template =~ /.*-windows/
|
138
|
+
base = template.split('-')[0]
|
139
|
+
else
|
140
|
+
base = template.split('.json')[0].tr('-', '_')
|
141
|
+
end
|
142
|
+
rm_cmd = "rm -rf #{cookbook_dir}/#{base}/Berksfile.lock vendored-cookbooks/#{base}"
|
143
|
+
shell_out_command(rm_cmd)
|
144
|
+
vendor_cmd = "berks vendor -q -b #{cookbook_dir}/#{base}/Berksfile vendored-cookbooks/#{base}"
|
145
|
+
shell_out_command(vendor_cmd)
|
146
|
+
end
|
147
|
+
|
148
|
+
def log(template, builder, options)
|
149
|
+
cloud = b_to_c(builder)
|
150
|
+
case template
|
151
|
+
when 'build-node'
|
152
|
+
log_name = "#{cloud}-build-node-#{options['node-number']}-#{linux}"
|
153
|
+
when 'workstation'
|
154
|
+
log_name = "#{cloud}-workstation-#{options['workstation-number']}-#{linux}"
|
155
|
+
when /infranodes/
|
156
|
+
if options['os'] =~ /windows/
|
157
|
+
log_name = "#{cloud}-infranodes-#{options['node-name']}-windows"
|
158
|
+
else
|
159
|
+
log_name = "#{cloud}-infranodes-#{options['node-name']}-#{linux}"
|
160
|
+
end
|
161
|
+
else
|
162
|
+
log_name = "#{cloud}-#{template}-#{linux}"
|
163
|
+
end
|
164
|
+
log_file = "#{log_dir}/#{log_name}.log"
|
165
|
+
end
|
166
|
+
|
167
|
+
def packer_build_cmd(template, builder, options)
|
168
|
+
create_infranodes_json
|
169
|
+
|
170
|
+
if template == 'workstation'
|
171
|
+
source_ami = wombat['aws']['source_ami']['windows']
|
172
|
+
source_image = wombat['gce']['source_image']['windows']
|
173
|
+
elsif template =~ /infranodes/
|
174
|
+
if options['os'] == 'windows'
|
175
|
+
source_ami = wombat['aws']['source_ami']['windows']
|
176
|
+
source_image = wombat['gce']['source_image']['windows']
|
177
|
+
else
|
178
|
+
source_ami = wombat['aws']['source_ami'][linux]
|
179
|
+
source_image = wombat['gce']['source_image'][linux]
|
180
|
+
end
|
181
|
+
else
|
182
|
+
source_ami = wombat['aws']['source_ami'][linux]
|
183
|
+
source_image = wombat['gce']['source_image'][linux]
|
193
184
|
end
|
185
|
+
|
186
|
+
# TODO: fail if packer isn't found in a graceful way
|
187
|
+
cmd = %W(packer build #{packer_dir}/#{template}.json | tee #{log(template, builder, options)})
|
188
|
+
cmd.insert(2, "--only #{builder}")
|
189
|
+
cmd.insert(2, "--var org=#{wombat['org']}")
|
190
|
+
cmd.insert(2, "--var domain=#{wombat['domain']}")
|
191
|
+
cmd.insert(2, "--var domain_prefix=#{wombat['domain_prefix']}")
|
192
|
+
cmd.insert(2, "--var enterprise=#{wombat['enterprise']}")
|
193
|
+
cmd.insert(2, "--var chefdk=#{wombat['products']['chefdk']}")
|
194
|
+
cmd.insert(2, "--var chef_ver=#{wombat['products']['chef'].split('-')[1]}")
|
195
|
+
cmd.insert(2, "--var chef_channel=#{wombat['products']['chef'].split('-')[0]}")
|
196
|
+
cmd.insert(2, "--var automate=#{wombat['products']['automate']}")
|
197
|
+
cmd.insert(2, "--var compliance=#{wombat['products']['compliance']}")
|
198
|
+
cmd.insert(2, "--var chef-server=#{wombat['products']['chef-server']}")
|
199
|
+
cmd.insert(2, "--var push-jobs-server=#{wombat['products']['push-jobs-server']}")
|
200
|
+
cmd.insert(2, "--var manage=#{wombat['products']['manage']}")
|
201
|
+
cmd.insert(2, "--var node-name=#{options['node-name']}") if template =~ /infranodes/
|
202
|
+
cmd.insert(2, "--var node-number=#{options['node-number']}") if template =~ /build-node/
|
203
|
+
cmd.insert(2, "--var build-nodes=#{wombat['build-nodes']['count']}")
|
204
|
+
cmd.insert(2, "--var winrm_password=#{wombat['workstations']['password']}")
|
205
|
+
cmd.insert(2, "--var winrm_username=Administrator")
|
206
|
+
cmd.insert(2, "--var workstation-number=#{options['workstation-number']}") if template =~ /workstation/
|
207
|
+
cmd.insert(2, "--var workstations=#{wombat['workstations']['count']}")
|
208
|
+
cmd.insert(2, "--var aws_source_ami=#{source_ami}")
|
209
|
+
cmd.insert(2, "--var gce_source_image=#{source_image}")
|
210
|
+
cmd.insert(2, "--var ssh_username=#{linux}")
|
211
|
+
cmd.join(' ')
|
194
212
|
end
|
195
213
|
end
|
data/lib/wombat/cli.rb
CHANGED
@@ -99,6 +99,14 @@ class Options
|
|
99
99
|
opts.on("-c CLOUD", "--cloud CLOUD", "Select cloud") do |opt|
|
100
100
|
options.cloud = opt
|
101
101
|
end
|
102
|
+
|
103
|
+
opts.on("--update-lock", "Update lockfile") do |opt|
|
104
|
+
options.update_lock = opt
|
105
|
+
end
|
106
|
+
|
107
|
+
opts.on("--create-template", "Create template") do |opt|
|
108
|
+
options.create_template = opt
|
109
|
+
end
|
102
110
|
},
|
103
111
|
argv: stack_argv_proc
|
104
112
|
},
|
data/lib/wombat/common.rb
CHANGED
@@ -40,11 +40,10 @@ module Common
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def bootstrap_aws
|
43
|
-
|
44
|
-
@workstation_passwd = wombat['workstation-passwd']
|
43
|
+
@workstation_passwd = wombat['workstations']['password']
|
45
44
|
rendered = ERB.new(File.read('templates/bootstrap-aws.erb'), nil, '-').result(binding)
|
46
45
|
File.open("#{packer_dir}/scripts/bootstrap-aws.txt", 'w') { |file| file.puts rendered }
|
47
|
-
|
46
|
+
banner("Generated: #{packer_dir}/scripts/bootstrap-aws.txt")
|
48
47
|
end
|
49
48
|
|
50
49
|
def gen_x509_cert(hostname)
|
@@ -100,13 +99,9 @@ module Common
|
|
100
99
|
end
|
101
100
|
end
|
102
101
|
|
103
|
-
def parse_log(
|
104
|
-
|
105
|
-
|
106
|
-
File.read("#{log_dir}/aws-#{instance}.log").split("\n").grep(/#{wombat['aws']['region']}:/) {|x| x.split[1]}.last
|
107
|
-
when "gce", "gcp", "google", "gdm"
|
108
|
-
File.read("#{log_dir}/gce-#{instance}.log").split("\n").grep(/A disk image was created:/) {|x| x.split[1]}.last
|
109
|
-
end
|
102
|
+
def parse_log(log, cloud)
|
103
|
+
regex = cloud == 'gcp' ? "A disk image was created:" : "#{wombat['aws']['region']}:"
|
104
|
+
File.read(log).split("\n").grep(/#{regex}/) {|x| x.split[1]}.last
|
110
105
|
end
|
111
106
|
|
112
107
|
def infranodes
|
@@ -119,7 +114,7 @@ module Common
|
|
119
114
|
|
120
115
|
def build_nodes
|
121
116
|
build_nodes = {}
|
122
|
-
1.upto(wombat['build-nodes'].to_i) do |i|
|
117
|
+
1.upto(wombat['build-nodes']['count'].to_i) do |i|
|
123
118
|
build_nodes["build-node-#{i}"] = i
|
124
119
|
end
|
125
120
|
build_nodes
|
@@ -127,7 +122,7 @@ module Common
|
|
127
122
|
|
128
123
|
def workstations
|
129
124
|
workstations = {}
|
130
|
-
1.upto(wombat['workstations'].to_i) do |i|
|
125
|
+
1.upto(wombat['workstations']['count'].to_i) do |i|
|
131
126
|
workstations["workstation-#{i}"] = i
|
132
127
|
end
|
133
128
|
workstations
|
@@ -145,6 +140,10 @@ module Common
|
|
145
140
|
end
|
146
141
|
end
|
147
142
|
|
143
|
+
def linux
|
144
|
+
wombat['linux'].nil? ? 'ubuntu' : wombat['linux']
|
145
|
+
end
|
146
|
+
|
148
147
|
def key_dir
|
149
148
|
wombat['conf'].nil? ? 'keys' : wombat['conf']['key_dir']
|
150
149
|
end
|
@@ -160,4 +159,20 @@ module Common
|
|
160
159
|
def log_dir
|
161
160
|
wombat['conf'].nil? ? 'logs' : wombat['conf']['log_dir']
|
162
161
|
end
|
162
|
+
|
163
|
+
def stack_dir
|
164
|
+
wombat['conf'].nil? ? 'stacks' : wombat['conf']['stack_dir']
|
165
|
+
end
|
166
|
+
|
167
|
+
def timeout
|
168
|
+
wombat['conf']['timeout'] ||= 7200
|
169
|
+
end
|
170
|
+
|
171
|
+
def is_mac?
|
172
|
+
(/darwin/ =~ RUBY_PLATFORM) != nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def audio?
|
176
|
+
is_mac? && wombat['conf']['audio']
|
177
|
+
end
|
163
178
|
end
|
data/lib/wombat/deploy.rb
CHANGED
@@ -4,18 +4,20 @@ require 'aws-sdk'
|
|
4
4
|
class DeployRunner
|
5
5
|
include Common
|
6
6
|
|
7
|
-
attr_reader :stack, :cloud
|
7
|
+
attr_reader :stack, :cloud, :lock_opt, :template_opt
|
8
8
|
|
9
9
|
def initialize(opts)
|
10
10
|
@stack = opts.stack
|
11
11
|
@cloud = opts.cloud.nil? ? "aws" : opts.cloud
|
12
|
+
@lock_opt = opts.update_lock
|
13
|
+
@template_opt = opts.create_template
|
12
14
|
end
|
13
15
|
|
14
16
|
def start
|
15
17
|
case cloud
|
16
18
|
when 'aws'
|
17
|
-
update_lock(cloud)
|
18
|
-
create_template
|
19
|
+
update_lock(cloud) if lock_opt
|
20
|
+
create_template if template_opt
|
19
21
|
create_stack(stack)
|
20
22
|
end
|
21
23
|
end
|
@@ -23,7 +25,7 @@ class DeployRunner
|
|
23
25
|
private
|
24
26
|
|
25
27
|
def create_stack(stack)
|
26
|
-
template_file = File.read("#{
|
28
|
+
template_file = File.read("#{stack_dir}/#{@demo}.json")
|
27
29
|
cfn = Aws::CloudFormation::Client.new(region: lock['aws']['region'])
|
28
30
|
|
29
31
|
banner("Creating CloudFormation stack")
|
@@ -43,11 +45,12 @@ class DeployRunner
|
|
43
45
|
end
|
44
46
|
|
45
47
|
def create_template
|
48
|
+
banner('Creating template...')
|
46
49
|
region = lock['aws']['region']
|
47
50
|
@chef_server_ami = lock['amis'][region]['chef-server']
|
48
51
|
@automate_ami = lock['amis'][region]['automate']
|
49
52
|
@compliance_ami = lock['amis'][region]['compliance']
|
50
|
-
@build_nodes = lock['build-nodes'].to_i
|
53
|
+
@build_nodes = lock['build-nodes']['count'].to_i
|
51
54
|
@build_node_ami = {}
|
52
55
|
1.upto(@build_nodes) do |i|
|
53
56
|
@build_node_ami[i] = lock['amis'][region]['build-node'][i.to_s]
|
@@ -56,7 +59,7 @@ class DeployRunner
|
|
56
59
|
infranodes.each do |name, _rl|
|
57
60
|
@infra[name] = lock['amis'][region]['infranodes'][name]
|
58
61
|
end
|
59
|
-
@workstations = lock['workstations'].to_i
|
62
|
+
@workstations = lock['workstations']['count'].to_i
|
60
63
|
@workstation_ami = {}
|
61
64
|
1.upto(@workstations) do |i|
|
62
65
|
@workstation_ami[i] = lock['amis'][region]['workstation'][i.to_s]
|
@@ -66,35 +69,39 @@ class DeployRunner
|
|
66
69
|
@version = lock['version']
|
67
70
|
@ttl = lock['ttl']
|
68
71
|
rendered_cfn = ERB.new(File.read('templates/cfn.json.erb'), nil, '-').result(binding)
|
69
|
-
File.open("#{@demo}.json", 'w') { |file| file.puts rendered_cfn }
|
72
|
+
File.open("#{stack_dir}/#{@demo}.json", 'w') { |file| file.puts rendered_cfn }
|
70
73
|
banner("Generate CloudFormation JSON: #{@demo}.json")
|
71
74
|
end
|
72
75
|
|
76
|
+
def logs
|
77
|
+
Dir.glob("#{log_dir}/#{cloud}*.log").reject { |l| !l.match(wombat['linux']) }
|
78
|
+
end
|
79
|
+
|
73
80
|
def update_lock(cloud)
|
81
|
+
banner('Updating wombat.lock')
|
82
|
+
|
74
83
|
copy = {}
|
75
84
|
copy = wombat
|
76
85
|
region = copy[cloud]['region']
|
77
|
-
|
86
|
+
linux = copy['linux']
|
78
87
|
copy['amis'] = { region => {} }
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
copy['amis'][region]
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
copy['amis'][region].store(
|
93
|
-
infranodes.each do |name, _rl|
|
94
|
-
copy['amis'][region]['infranodes'].store(name, parse_log("infranodes-#{name}", "aws"))
|
95
|
-
end
|
88
|
+
logs.each do |log|
|
89
|
+
case log
|
90
|
+
when /build-node/
|
91
|
+
copy['amis'][region]['build-node'] ||= {}
|
92
|
+
num = log.split('-')[3]
|
93
|
+
copy['amis'][region]['build-node'].store(num, parse_log(log, cloud))
|
94
|
+
when /workstation/
|
95
|
+
copy['amis'][region]['workstation'] ||= {}
|
96
|
+
num = log.split('-')[2]
|
97
|
+
copy['amis'][region]['workstation'].store(num, parse_log(log, cloud))
|
98
|
+
when /infranodes/
|
99
|
+
copy['amis'][region]['infranodes'] ||= {}
|
100
|
+
name = log.split('-')[2]
|
101
|
+
copy['amis'][region]['infranodes'].store(name, parse_log(log, cloud))
|
96
102
|
else
|
97
|
-
|
103
|
+
instance = log.match("#{cloud}-(.*)-(.*)\.log")[1]
|
104
|
+
copy['amis'][region].store(instance, parse_log(log, cloud))
|
98
105
|
end
|
99
106
|
end
|
100
107
|
copy['last_updated'] = Time.now.gmtime.strftime('%Y%m%d%H%M%S')
|
data/lib/wombat/version.rb
CHANGED
data/packer/automate.json
CHANGED
@@ -24,7 +24,8 @@
|
|
24
24
|
"domain_prefix": "",
|
25
25
|
"enterprise": "mammals",
|
26
26
|
"org": "marsupials",
|
27
|
-
"workstations": "1"
|
27
|
+
"workstations": "1",
|
28
|
+
"ssh_username": "ubuntu"
|
28
29
|
},
|
29
30
|
|
30
31
|
"builders": [
|
@@ -33,11 +34,11 @@
|
|
33
34
|
"secret_key": "{{user `aws_secret_key`}}",
|
34
35
|
"region": "{{user `aws_region`}}",
|
35
36
|
"source_ami": "{{user `aws_source_ami`}}",
|
36
|
-
"instance_type": "
|
37
|
+
"instance_type": "t2.medium",
|
37
38
|
"communicator": "ssh",
|
38
39
|
"associate_public_ip_address": true,
|
39
40
|
"ssh_private_ip": false,
|
40
|
-
"ssh_username": "
|
41
|
+
"ssh_username": "{{user `ssh_username`}}",
|
41
42
|
"ssh_pty" : true,
|
42
43
|
"ami_name": "automate-{{timestamp}}"
|
43
44
|
},
|
@@ -68,7 +69,7 @@
|
|
68
69
|
"disk_size": "80",
|
69
70
|
"image_name": "automate-{{timestamp}}",
|
70
71
|
"machine_type": "n1-standard-2",
|
71
|
-
"ssh_username": "
|
72
|
+
"ssh_username": "{{user `ssh_username`}}",
|
72
73
|
"ssh_pty" : true
|
73
74
|
}
|
74
75
|
],
|
@@ -88,9 +89,10 @@
|
|
88
89
|
"type": "chef-solo",
|
89
90
|
"install_command": "{{user `chef_install_url`}} | sudo bash -s -- -c {{user `chef_channel`}} -v {{user `chef_ver`}}",
|
90
91
|
"cookbook_paths": [ "{{pwd}}/vendored-cookbooks/automate" ],
|
91
|
-
"run_list": [ "
|
92
|
+
"run_list": [ "automate", "wombat::authorized-keys", "wombat::etc-hosts" ],
|
92
93
|
"json": {
|
93
94
|
"demo": {
|
95
|
+
"admin-user": "{{user `ssh_username`}}",
|
94
96
|
"domain_prefix": "{{user `domain_prefix`}}",
|
95
97
|
"domain": "{{user `domain`}}",
|
96
98
|
"enterprise": "{{user `enterprise`}}",
|