wombat-cli 0.2.0 → 0.2.1
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 +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`}}",
|