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.
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`}}",