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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/DESIGN.md +2 -1
  4. data/README.md +10 -32
  5. data/Rakefile +1 -52
  6. data/cookbooks/automate/.kitchen.ec2.yml +8 -1
  7. data/cookbooks/automate/.kitchen.yml +0 -1
  8. data/cookbooks/automate/metadata.rb +0 -2
  9. data/cookbooks/automate/recipes/default.rb +4 -3
  10. data/cookbooks/automate/test/integration/default/automate_spec.rb +3 -2
  11. data/cookbooks/build_node/.kitchen.ec2.yml +8 -1
  12. data/cookbooks/build_node/metadata.rb +0 -3
  13. data/cookbooks/build_node/recipes/default.rb +5 -2
  14. data/cookbooks/build_node/test/integration/default/build-node_spec.rb +3 -2
  15. data/cookbooks/chef_server/.kitchen.ec2.yml +8 -0
  16. data/cookbooks/chef_server/.kitchen.yml +0 -1
  17. data/cookbooks/chef_server/metadata.rb +0 -2
  18. data/cookbooks/chef_server/recipes/{cheffish.rb → bootstrap_users.rb} +1 -1
  19. data/cookbooks/chef_server/recipes/default.rb +30 -14
  20. data/cookbooks/chef_server/test/integration/default/chef_server_spec.rb +7 -4
  21. data/cookbooks/compliance/.kitchen.ec2.yml +8 -0
  22. data/cookbooks/compliance/metadata.rb +0 -1
  23. data/cookbooks/compliance/recipes/default.rb +5 -7
  24. data/cookbooks/compliance/test/integration/default/compliance.rb +3 -2
  25. data/cookbooks/infranodes/.kitchen.ec2.yml +23 -2
  26. data/cookbooks/infranodes/recipes/default.rb +25 -9
  27. data/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/recipes/default.rb +9 -3
  28. data/cookbooks/infranodes/test/integration/default/infranodes_spec.rb +11 -9
  29. data/cookbooks/wombat/attributes/default.rb +2 -0
  30. data/cookbooks/wombat/metadata.rb +2 -0
  31. data/cookbooks/wombat/recipes/authorized-keys.rb +10 -0
  32. data/cookbooks/workstation/recipes/certs-keys.rb +2 -1
  33. data/cookbooks/workstation/templates/default/ssh_config.erb +2 -2
  34. data/lib/wombat/build.rb +138 -120
  35. data/lib/wombat/cli.rb +8 -0
  36. data/lib/wombat/common.rb +27 -12
  37. data/lib/wombat/deploy.rb +33 -26
  38. data/lib/wombat/version.rb +1 -1
  39. data/packer/automate.json +7 -5
  40. data/packer/build-node.json +6 -4
  41. data/packer/chef-server.json +11 -6
  42. data/packer/compliance.json +6 -5
  43. data/packer/infranodes-windows.json +100 -0
  44. data/packer/infranodes.json +6 -5
  45. data/packer/workstation.json +5 -4
  46. data/stacks/.gitkeep +0 -0
  47. data/templates/bootstrap-aws.erb +2 -2
  48. data/templates/cfn.json.erb +16 -15
  49. data/wombat.example.yml +45 -35
  50. metadata +5 -15
  51. data/packer/mock-data/.gitignore +0 -16
  52. data/packer/mock-data/.kitchen.yml +0 -21
  53. data/packer/mock-data/Berksfile +0 -3
  54. data/packer/mock-data/README.md +0 -4
  55. data/packer/mock-data/chefignore +0 -102
  56. data/packer/mock-data/metadata.rb +0 -7
  57. data/packer/mock-data/recipes/default.rb +0 -69
  58. data/packer/mock-data/spec/spec_helper.rb +0 -2
  59. data/packer/mock-data/spec/unit/recipes/default_spec.rb +0 -20
  60. data/packer/mock-data/test/integration/default/serverspec/default_spec.rb +0 -9
  61. data/packer/mock-data/test/integration/helpers/serverspec/spec_helper.rb +0 -8
@@ -1,20 +1,22 @@
1
1
  # automate tests
2
2
 
3
- describe file('/home/ubuntu/.ssh/authorized_keys') do
4
- its('content') { file("/tmp/public.pub").content }
5
- end
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
- it { should be_installed }
9
+ describe package('push-jobs-client') do
10
+ it { should be_installed }
11
+ end
9
12
  end
10
13
 
11
- describe file('/etc/hosts') do
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'] = {
@@ -9,3 +9,5 @@ version '0.2.0'
9
9
  depends 'hostsfile'
10
10
  depends 'apt'
11
11
  depends 'chef-ingredient'
12
+ depends 'sudo'
13
+ depends 'line'
@@ -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
- user: "workstation-#{node['demo']['workstation-number']}"
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 <%= @user -%>@<%= @ent %>
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 ubuntu
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 keys (if necessary)")
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
- if parallel
28
- time = Benchmark.measure do
29
- banner("Starting parallel build for templates: #{templates}")
30
- parallel_pack(templates, builder)
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
- else
33
- time = Benchmark.measure do
34
- banner("Starting sequential build for templates: #{templates}")
35
- templates.each do |template|
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 vendor_cookbooks(template)
81
- base = template.split('.json')[0].tr('-', '_')
82
- rm = Mixlib::ShellOut.new("rm -rf vendored-cookbooks/#{base} cookbooks/#{base}/Berksfile.lock", live_stream: STDOUT)
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 packer_build(template, builder, options={})
90
- # TODO: this is gross and feels gross so maybe we should do it more better
91
- create_infranodes_json
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 parallel_pack(templates, builder)
59
+ def build_hash
150
60
  proc_hash = {}
151
61
  templates.each do |template_name|
152
- if template_name == 'infranodes'
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' => 'infranodes',
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
- puts proc_hash
189
- Parallel.map(proc_hash.keys, in_threads: proc_hash.count) do |name|
190
- cmd = packer_build(proc_hash[name]['template'], builder, proc_hash[name]['options'])
191
- packer_cmd = Mixlib::ShellOut.new(cmd, :timeout => 3600, live_stream: STDOUT)
192
- packer_cmd.run_command
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
- puts 'Generating bootstrap script from template'
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
- puts "#{packer_dir}/scripts/bootstrap-aws.txt"
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(instance, cloud)
104
- case cloud
105
- when "aws", "amazon", "jeffbezosband", "cfn"
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("#{stack}.json")
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
- banner('Updating wombat.lock')
86
+ linux = copy['linux']
78
87
  copy['amis'] = { region => {} }
79
- Dir.glob("#{log_dir}/#{cloud}*.log") do |log|
80
- instance = log.match('aws-(.*)\.log')[1]
81
- if instance =~ /build-node/
82
- copy['amis'][region].store('build-node', {})
83
- 1.upto(wombat['build-nodes'].to_i) do |i|
84
- copy['amis'][region]['build-node'].store(i.to_s, parse_log("build-node-#{i}", "aws"))
85
- end
86
- elsif instance =~ /workstation/
87
- copy['amis'][region].store('workstation', {})
88
- 1.upto(wombat['workstations'].to_i) do |i|
89
- copy['amis'][region]['workstation'].store(i.to_s, parse_log("workstation-#{i}", "aws"))
90
- end
91
- elsif instance =~ /infranodes/
92
- copy['amis'][region].store('infranodes', {})
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
- copy['amis'][region].store(instance, parse_log(instance, "aws"))
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')
@@ -1,3 +1,3 @@
1
1
  module Wombat
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
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": "c3.xlarge",
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": "ubuntu",
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": "ubuntu",
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": [ "apt", "automate" ],
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`}}",