wombat-cli 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +27 -0
  4. data/CHANGELOG.md +15 -1
  5. data/Gemfile +3 -0
  6. data/README.md +2 -2
  7. data/Rakefile +25 -0
  8. data/bin/wombat +1 -1
  9. data/generator_files/cookbooks/automate/metadata.rb +1 -1
  10. data/generator_files/cookbooks/automate/recipes/update-users.rb +1 -1
  11. data/generator_files/cookbooks/chef_server/recipes/default.rb +24 -11
  12. data/generator_files/cookbooks/workstation/.kitchen.ec2.yml +2 -1
  13. data/generator_files/cookbooks/workstation/metadata.rb +1 -1
  14. data/generator_files/cookbooks/workstation/recipes/default.rb +1 -2
  15. data/generator_files/cookbooks/workstation/templates/default/ise_profile.ps1.erb +2 -2
  16. data/generator_files/cookbooks/workstation/test/integration/default/workstation_spec.rb +4 -4
  17. data/generator_files/packer/automate.json +129 -107
  18. data/generator_files/packer/build-node.json +134 -112
  19. data/generator_files/packer/chef-server.json +130 -108
  20. data/generator_files/packer/compliance.json +126 -104
  21. data/generator_files/packer/infranodes-windows.json +136 -97
  22. data/generator_files/packer/infranodes.json +127 -106
  23. data/generator_files/packer/workstation.json +134 -95
  24. data/generator_files/templates/arm.json.erb +576 -0
  25. data/generator_files/wombat.yml +6 -2
  26. data/lib/wombat/aws.rb +67 -0
  27. data/lib/wombat/build.rb +273 -184
  28. data/lib/wombat/cli.rb +182 -147
  29. data/lib/wombat/common.rb +228 -220
  30. data/lib/wombat/crypto.rb +65 -0
  31. data/lib/wombat/delete.rb +48 -18
  32. data/lib/wombat/deploy.rb +147 -34
  33. data/lib/wombat/init.rb +21 -19
  34. data/lib/wombat/latest.rb +27 -0
  35. data/lib/wombat/output.rb +31 -30
  36. data/lib/wombat/update.rb +13 -10
  37. data/lib/wombat/version.rb +1 -1
  38. data/spec/functional/common_spec.rb +26 -0
  39. data/spec/spec_helper.rb +103 -0
  40. data/spec/unit/common_spec.rb +116 -0
  41. data/wombat-cli.gemspec +2 -1
  42. metadata +36 -11
  43. /data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/{delivery.crt → automate.crt} +0 -0
  44. /data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/{delivery.key → automate.key} +0 -0
  45. /data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/{chef-server.crt → chef.crt} +0 -0
  46. /data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/{chef-server.key → chef.key} +0 -0
data/lib/wombat/common.rb CHANGED
@@ -1,266 +1,274 @@
1
1
  require 'yaml'
2
2
  require 'json'
3
3
  require 'erb'
4
- require 'openssl'
5
- require 'net/ssh'
6
4
  require 'benchmark'
7
5
  require 'fileutils'
8
6
 
9
- module Common
7
+ module Wombat
8
+ module Common
10
9
 
11
- def banner(msg)
12
- puts "==> #{msg}"
13
- end
14
-
15
- def info(msg)
16
- puts " #{msg}"
17
- end
10
+ def banner(msg)
11
+ puts "==> #{msg}"
12
+ end
18
13
 
19
- def warn(msg)
20
- puts ">>> #{msg}"
21
- end
14
+ def info(msg)
15
+ puts " #{msg}"
16
+ end
22
17
 
23
- def duration(total)
24
- total = 0 if total.nil?
25
- minutes = (total / 60).to_i
26
- seconds = (total - (minutes * 60))
27
- format("%dm%.2fs", minutes, seconds)
28
- end
18
+ def warn(msg)
19
+ puts ">>> #{msg}"
20
+ end
29
21
 
30
- def wombat
31
- if !File.exists?('wombat.yml')
32
- warn('No wombat.yml found, copying example')
33
- gen_dir = "#{File.expand_path("../..", File.dirname(__FILE__))}/generator_files"
34
- FileUtils.cp_r "#{gen_dir}/wombat.yml", Dir.pwd
22
+ def duration(total)
23
+ total = 0 if total.nil?
24
+ minutes = (total / 60).to_i
25
+ seconds = (total - (minutes * 60))
26
+ format("%dm%.2fs", minutes, seconds)
35
27
  end
36
- YAML.load(File.read('wombat.yml'))
37
- end
38
28
 
39
- def lock
40
- if !File.exists?('wombat.lock')
41
- warn('No wombat.lock found')
42
- return 1
43
- else
44
- JSON.parse(File.read('wombat.lock'))
29
+ def wombat
30
+ @wombat_yml ||= ENV['WOMBAT_YML'] unless ENV['WOMBAT_YML'].nil?
31
+ @wombat_yml ||= 'wombat.yml'
32
+ if !File.exist?(@wombat_yml)
33
+ warn('No wombat.yml found, copying example')
34
+ gen_dir = "#{File.expand_path("../..", File.dirname(__FILE__))}/generator_files"
35
+ FileUtils.cp_r "#{gen_dir}/wombat.yml", Dir.pwd
36
+ end
37
+ YAML.load(File.read(@wombat_yml))
45
38
  end
46
- end
47
39
 
48
- def bootstrap_aws
49
- @workstation_passwd = wombat['workstations']['password']
50
- rendered = ERB.new(File.read("#{conf['template_dir']}/bootstrap-aws.erb"), nil, '-').result(binding)
51
- Dir.mkdir("#{conf['packer_dir']}/scripts", 0755) unless File.exist?("#{conf['packer_dir']}/scripts")
52
- File.open("#{conf['packer_dir']}/scripts/bootstrap-aws.txt", 'w') { |file| file.puts rendered }
53
- banner("Generated: #{conf['packer_dir']}/scripts/bootstrap-aws.txt")
54
- end
40
+ def lock
41
+ if !File.exist?('wombat.lock')
42
+ warn('No wombat.lock found')
43
+ return 1
44
+ else
45
+ JSON.parse(File.read('wombat.lock'))
46
+ end
47
+ end
55
48
 
56
- def gen_x509_cert(hostname)
57
- rsa_key = OpenSSL::PKey::RSA.new(2048)
58
- public_key = rsa_key.public_key
59
-
60
- subject = "/C=AU/ST=New South Wales/L=Sydney/O=#{wombat['org']}/OU=wombats/CN=#{wombat['domain_prefix']}#{hostname}.#{wombat['domain']}"
61
-
62
- cert = OpenSSL::X509::Certificate.new
63
- cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
64
- cert.not_before = Time.now
65
- cert.not_after = Time.now + 365 * 24 * 60 * 60
66
- cert.public_key = public_key
67
- cert.serial = 0x0
68
- cert.version = 2
69
-
70
- ef = OpenSSL::X509::ExtensionFactory.new
71
- ef.subject_certificate = cert
72
- ef.issuer_certificate = cert
73
- cert.extensions = [
74
- ef.create_extension('basicConstraints', 'CA:TRUE', true),
75
- ef.create_extension('subjectKeyIdentifier', 'hash'),
76
- # ef.create_extension("keyUsage", "cRLSign,keyCertSign", true),
77
- ]
78
- cert.add_extension ef.create_extension('authorityKeyIdentifier',
79
- 'keyid:always,issuer:always')
80
-
81
- cert.sign(rsa_key, OpenSSL::Digest::SHA256.new)
82
-
83
- Dir.mkdir(conf['key_dir'], 0755) unless File.exist?(conf['key_dir'])
84
-
85
- if File.exist?("#{conf['key_dir']}/#{hostname}.crt") && File.exist?("#{conf['key_dir']}/#{hostname}.key")
86
- puts "An x509 certificate already exists for #{hostname}"
87
- else
88
- File.open("#{conf['key_dir']}/#{hostname}.crt", 'w') { |file| file.puts cert.to_pem }
89
- File.open("#{conf['key_dir']}/#{hostname}.key", 'w') { |file| file.puts rsa_key.to_pem }
90
- puts "Certificate created for #{wombat['domain_prefix']}#{hostname}.#{wombat['domain']}"
49
+ def bootstrap_aws
50
+ @workstation_passwd = wombat['workstations']['password']
51
+ rendered = ERB.new(File.read("#{conf['template_dir']}/bootstrap-aws.erb"), nil, '-').result(binding)
52
+ Dir.mkdir("#{conf['packer_dir']}/scripts", 0755) unless File.exist?("#{conf['packer_dir']}/scripts")
53
+ File.open("#{conf['packer_dir']}/scripts/bootstrap-aws.txt", 'w') { |file| file.puts rendered }
54
+ banner("Generated: #{conf['packer_dir']}/scripts/bootstrap-aws.txt")
91
55
  end
92
- end
93
56
 
94
- def gen_ssh_key
95
- rsa_key = OpenSSL::PKey::RSA.new 2048
57
+ def parse_log(log, cloud)
58
+ regex = case cloud
59
+ when 'gcp'
60
+ 'A disk image was created:'
61
+ when 'azure'
62
+ 'OSDiskUri:'
63
+ else
64
+ "#{wombat['aws']['region']}:"
65
+ end
66
+
67
+ File.read(log).split("\n").grep(/#{regex}/) {|x| x.split[1]}.last
68
+ end
96
69
 
97
- type = rsa_key.ssh_type
98
- data = [rsa_key.to_blob].pack('m0')
70
+ def infranodes
71
+ unless wombat['infranodes'].nil?
72
+ wombat['infranodes'].sort
73
+ else
74
+ puts 'No infranodes listed in wombat.yml'
75
+ {}
76
+ end
77
+ end
99
78
 
100
- openssh_format = "#{type} #{data}"
79
+ def build_nodes
80
+ build_nodes = {}
81
+ 1.upto(wombat['build-nodes']['count'].to_i) do |i|
82
+ build_nodes["build-node-#{i}"] = i
83
+ end
84
+ build_nodes
85
+ end
101
86
 
102
- Dir.mkdir(conf['key_dir'], 0755) unless File.exist?(conf['key_dir'])
87
+ def workstations
88
+ workstations = {}
89
+ 1.upto(wombat['workstations']['count'].to_i) do |i|
90
+ workstations["workstation-#{i}"] = i
91
+ end
92
+ workstations
93
+ end
103
94
 
104
- if File.exist?("#{conf['key_dir']}/public.pub") && File.exist?("#{conf['key_dir']}/private.pem")
105
- puts 'An SSH keypair already exists'
106
- else
107
- File.open("#{conf['key_dir']}/public.pub", 'w') { |file| file.puts openssh_format }
108
- File.open("#{conf['key_dir']}/private.pem", 'w') { |file| file.puts rsa_key.to_pem }
109
- puts 'SSH Keypair created'
95
+ def create_infranodes_json
96
+ infranodes_file_path = File.join(conf['files_dir'], 'infranodes-info.json')
97
+ if File.exists?(infranodes_file_path) && is_valid_json?(infranodes_file_path)
98
+ current_state = JSON(File.read(infranodes_file_path))
99
+ else
100
+ current_state = nil
101
+ end
102
+ return if current_state == infranodes # yay idempotence
103
+ File.open(infranodes_file_path, 'w') do |f|
104
+ f.puts JSON.pretty_generate(infranodes)
105
+ end
110
106
  end
111
- end
112
107
 
113
- def parse_log(log, cloud)
114
- regex = cloud == 'gcp' ? "A disk image was created:" : "#{wombat['aws']['region']}:"
115
- File.read(log).split("\n").grep(/#{regex}/) {|x| x.split[1]}.last
116
- end
108
+ def linux
109
+ wombat['linux'].nil? ? 'ubuntu' : wombat['linux']
110
+ end
117
111
 
118
- def infranodes
119
- unless wombat['infranodes'].nil?
120
- wombat['infranodes'].sort
121
- else
122
- puts 'No infranodes listed in wombat.yml'
112
+ def conf
113
+ conf = wombat['conf']
114
+ conf ||= {}
115
+ conf['files_dir'] ||= 'files'
116
+ conf['key_dir'] ||= 'keys'
117
+ conf['cookbook_dir'] ||= 'cookbooks'
118
+ conf['packer_dir'] ||= 'packer'
119
+ conf['log_dir'] ||= 'logs'
120
+ conf['stack_dir'] ||= 'stacks'
121
+ conf['template_dir'] ||= 'templates'
122
+ conf['timeout'] ||= 7200
123
+ conf['audio'] ||= false
124
+ conf
123
125
  end
124
- end
125
126
 
126
- def build_nodes
127
- build_nodes = {}
128
- 1.upto(wombat['build-nodes']['count'].to_i) do |i|
129
- build_nodes["build-node-#{i}"] = i
127
+ def is_mac?
128
+ (/darwin/ =~ RUBY_PLATFORM) != nil
130
129
  end
131
- build_nodes
132
- end
133
130
 
134
- def workstations
135
- workstations = {}
136
- 1.upto(wombat['workstations']['count'].to_i) do |i|
137
- workstations["workstation-#{i}"] = i
131
+ def audio?
132
+ is_mac? && conf['audio']
138
133
  end
139
- workstations
140
- end
141
134
 
142
- def create_infranodes_json
143
- if File.exists?("#{conf['packer_dir']}/file/infranodes-info.json")
144
- current_state = JSON(File.read('files/infranodes-info.json'))
145
- else
146
- current_state = nil
135
+ def logs
136
+ path = "#{conf['log_dir']}/#{cloud}*.log"
137
+ Dir.glob(path).reject { |l| !l.match(wombat['linux']) }
147
138
  end
148
- return if current_state == infranodes # yay idempotence
149
- File.open("#{conf['packer_dir']}/files/infranodes-info.json", 'w') do |f|
150
- f.puts JSON.pretty_generate(infranodes)
139
+
140
+ def calculate_templates
141
+ globs = "*.json"
142
+ Dir.chdir(conf['packer_dir']) do
143
+ Array(globs).
144
+ map { |glob| result = Dir.glob("#{glob}"); result.empty? ? glob : result }.
145
+ flatten.
146
+ sort.
147
+ delete_if { |file| file =~ /\.variables\./ }.
148
+ map { |template| template.sub(/\.json$/, '') }
149
+ end
151
150
  end
152
- end
153
151
 
154
- def linux
155
- wombat['linux'].nil? ? 'ubuntu' : wombat['linux']
156
- end
152
+ def update_lock(cloud)
153
+ copy = {}
154
+ copy = wombat
157
155
 
158
- def conf
159
- conf = wombat['conf']
160
- conf ||= {}
161
- conf['key_dir'] ||= 'keys'
162
- conf['cookbook_dir'] ||= 'cookbooks'
163
- conf['packer_dir'] ||= 'packer'
164
- conf['log_dir'] ||= 'logs'
165
- conf['stack_dir'] ||= 'stacks'
166
- conf['template_dir'] ||= 'templates'
167
- conf['timeout'] ||= 7200
168
- conf['audio'] ||= false
169
- conf
170
- end
156
+ # Check that the copy contains a key for the named cloud
157
+ unless copy.key?(cloud)
158
+ throw "The Cloud '#{cloud}' is not specified in Wombat"
159
+ end
171
160
 
172
- def is_mac?
173
- (/darwin/ =~ RUBY_PLATFORM) != nil
174
- end
161
+ # Determine the region/location/zone for the specific cloud
162
+ case cloud
163
+ when 'aws'
164
+ region = copy['aws']['region']
165
+ when 'azure'
166
+ region = copy['azure']['location']
167
+ when 'gce'
168
+ region = copy['gce']['zone']
169
+ end
175
170
 
176
- def audio?
177
- is_mac? && conf['audio']
178
- end
171
+ linux = copy['linux']
172
+ copy['amis'] = { region => {} }
173
+
174
+ if logs.length == 0
175
+ warn('No logs found - skipping lock update')
176
+ else
177
+ logs.each do |log|
178
+ case log
179
+ when /build-node/
180
+ copy['amis'][region]['build-node'] ||= {}
181
+ num = log.split('-')[3]
182
+ copy['amis'][region]['build-node'].store(num, parse_log(log, cloud))
183
+ when /workstation/
184
+ copy['amis'][region]['workstation'] ||= {}
185
+ num = log.split('-')[2]
186
+ copy['amis'][region]['workstation'].store(num, parse_log(log, cloud))
187
+ when /infranodes/
188
+ copy['amis'][region]['infranodes'] ||= {}
189
+ name = log.split('-')[2]
190
+ copy['amis'][region]['infranodes'].store(name, parse_log(log, cloud))
191
+ else
192
+ instance = log.match("#{cloud}-(.*)-#{linux}\.log")[1]
193
+ copy['amis'][region].store(instance, parse_log(log, cloud))
194
+ end
195
+ end
196
+ copy['last_updated'] = Time.now.gmtime.strftime('%Y%m%d%H%M%S')
197
+ banner('Updating wombat.lock')
198
+ File.open('wombat.lock', 'w') do |f|
199
+ f.write(JSON.pretty_generate(copy))
200
+ end
201
+ end
202
+ end
179
203
 
180
- def logs
181
- Dir.glob("#{conf['log_dir']}/#{cloud}*.log").reject { |l| !l.match(wombat['linux']) }
182
- end
204
+ def update_template(cloud)
205
+ if lock == 1
206
+ warn('No lock - skipping template creation')
207
+ else
208
+
209
+ # Determine the region/location/zone for the specific cloud
210
+ case cloud
211
+ when 'aws'
212
+ region = lock['aws']['region']
213
+ template_file = "cfn.json.erb"
214
+ @chef_server_ami = lock['amis'][region]['chef-server']
215
+ @automate_ami = lock['amis'][region]['automate']
216
+ @compliance_ami = lock['amis'][region]['compliance']
217
+ @availability_zone = lock['aws']['az']
218
+ @iam_roles = lock['aws']['iam_roles']
219
+ when 'azure'
220
+ region = lock['azure']['location']
221
+ @storage_account = lock['azure']['storage_account']
222
+ template_file = "arm.json.erb"
223
+ @chef_server_uri = lock['amis'][region]['chef-server']
224
+ @automate_uri = lock['amis'][region]['automate']
225
+ @compliance_uri = lock['amis'][region]['compliance']
226
+
227
+ # set an admin password for the machines that are created
228
+ @password = "aAan0orxevCma4gG"
229
+ when 'gce'
230
+ region = lock['gce']['zone']
231
+ end
183
232
 
184
- def calculate_templates
185
- globs = "*.json"
186
- Dir.chdir(conf['packer_dir']) do
187
- Array(globs).
188
- map { |glob| result = Dir.glob("#{glob}"); result.empty? ? glob : result }.
189
- flatten.
190
- sort.
191
- delete_if { |file| file =~ /\.variables\./ }.
192
- map { |template| template.sub(/\.json$/, '') }
193
- end
194
- end
233
+ if lock['amis'][region].key?('build-node')
234
+ @build_nodes = lock['build-nodes']['count'].to_i
235
+ @build_node_ami = {}
236
+ 1.upto(@build_nodes) do |i|
237
+ @build_node_ami[i] = lock['amis'][region]['build-node'][i.to_s]
238
+ end
239
+ end
195
240
 
196
- def update_lock(cloud)
197
- copy = {}
198
- copy = wombat
199
- region = copy[cloud]['region']
200
- linux = copy['linux']
201
- copy['amis'] = { region => {} }
202
-
203
- if logs.length == 0
204
- warn('No logs found - skipping lock update')
205
- else
206
- logs.each do |log|
207
- case log
208
- when /build-node/
209
- copy['amis'][region]['build-node'] ||= {}
210
- num = log.split('-')[3]
211
- copy['amis'][region]['build-node'].store(num, parse_log(log, cloud))
212
- when /workstation/
213
- copy['amis'][region]['workstation'] ||= {}
214
- num = log.split('-')[2]
215
- copy['amis'][region]['workstation'].store(num, parse_log(log, cloud))
216
- when /infranodes/
217
- copy['amis'][region]['infranodes'] ||= {}
218
- name = log.split('-')[2]
219
- copy['amis'][region]['infranodes'].store(name, parse_log(log, cloud))
220
- else
221
- instance = log.match("#{cloud}-(.*)-#{linux}\.log")[1]
222
- copy['amis'][region].store(instance, parse_log(log, cloud))
241
+ @infra = {}
242
+ infranodes.each do |name, _rl|
243
+ @infra[name] = lock['amis'][region]['infranodes'][name]
223
244
  end
224
- end
225
- copy['last_updated'] = Time.now.gmtime.strftime('%Y%m%d%H%M%S')
226
- banner('Updating wombat.lock')
227
- File.open('wombat.lock', 'w') do |f|
228
- f.write(JSON.pretty_generate(copy))
245
+
246
+ if lock['amis'][region].key?('workstation')
247
+ @workstations = lock['workstations']['count'].to_i
248
+ @workstation_ami = {}
249
+ 1.upto(@workstations) do |i|
250
+ @workstation_ami[i] = lock['amis'][region]['workstation'][i.to_s]
251
+ end
252
+ end
253
+
254
+ @demo = lock['name']
255
+ @version = lock['version']
256
+ @ttl = lock['ttl']
257
+
258
+ rendered_cfn = ERB.new(File.read("#{conf['template_dir']}/#{template_file}"), nil, '-').result(binding)
259
+ Dir.mkdir(conf['stack_dir'], 0755) unless File.exist?(conf['stack_dir'])
260
+ File.open("#{conf['stack_dir']}/#{@demo}.json", 'w') { |file| file.puts rendered_cfn }
261
+ banner("Generated: #{conf['stack_dir']}/#{@demo}.json")
229
262
  end
230
263
  end
231
- end
232
264
 
233
- def update_template(cloud)
234
- if lock == 1
235
- warn('No lock - skipping template creation')
236
- else
237
- region = lock['aws']['region']
238
- @chef_server_ami = lock['amis'][region]['chef-server']
239
- @automate_ami = lock['amis'][region]['automate']
240
- @compliance_ami = lock['amis'][region]['compliance']
241
- @build_nodes = lock['build-nodes']['count'].to_i
242
- @build_node_ami = {}
243
- 1.upto(@build_nodes) do |i|
244
- @build_node_ami[i] = lock['amis'][region]['build-node'][i.to_s]
245
- end
246
- @infra = {}
247
- infranodes.each do |name, _rl|
248
- @infra[name] = lock['amis'][region]['infranodes'][name]
249
- end
250
- @workstations = lock['workstations']['count'].to_i
251
- @workstation_ami = {}
252
- 1.upto(@workstations) do |i|
253
- @workstation_ami[i] = lock['amis'][region]['workstation'][i.to_s]
265
+ def is_valid_json?(file)
266
+ begin
267
+ JSON.parse(file)
268
+ true
269
+ rescue JSON::ParserError => e
270
+ false
254
271
  end
255
- @availability_zone = lock['aws']['az']
256
- @iam_roles = lock['aws']['iam_roles']
257
- @demo = lock['name']
258
- @version = lock['version']
259
- @ttl = lock['ttl']
260
- rendered_cfn = ERB.new(File.read("#{conf['template_dir']}/cfn.json.erb"), nil, '-').result(binding)
261
- Dir.mkdir(conf['stack_dir'], 0755) unless File.exist?(conf['stack_dir'])
262
- File.open("#{conf['stack_dir']}/#{@demo}.json", 'w') { |file| file.puts rendered_cfn }
263
- banner("Generated: #{conf['stack_dir']}/#{@demo}.json")
264
272
  end
265
273
  end
266
- end
274
+ end
@@ -0,0 +1,65 @@
1
+ require 'openssl'
2
+ require 'net/ssh'
3
+
4
+ module Wombat
5
+ module Crypto
6
+ include Wombat::Common
7
+
8
+ def gen_x509_cert(hostname)
9
+ rsa_key = OpenSSL::PKey::RSA.new(2048)
10
+ public_key = rsa_key.public_key
11
+
12
+ subject = "/C=AU/ST=New South Wales/L=Sydney/O=#{wombat['org']}/OU=wombats/CN=#{wombat['domain_prefix']}#{hostname}.#{wombat['domain']}"
13
+
14
+ cert = OpenSSL::X509::Certificate.new
15
+ cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
16
+ cert.not_before = Time.now
17
+ cert.not_after = Time.now + 365 * 24 * 60 * 60
18
+ cert.public_key = public_key
19
+ cert.serial = 0x0
20
+ cert.version = 2
21
+
22
+ ef = OpenSSL::X509::ExtensionFactory.new
23
+ ef.subject_certificate = cert
24
+ ef.issuer_certificate = cert
25
+ cert.extensions = [
26
+ ef.create_extension('basicConstraints', 'CA:TRUE', true),
27
+ ef.create_extension('subjectKeyIdentifier', 'hash'),
28
+ # ef.create_extension("keyUsage", "cRLSign,keyCertSign", true),
29
+ ]
30
+ cert.add_extension ef.create_extension('authorityKeyIdentifier',
31
+ 'keyid:always,issuer:always')
32
+
33
+ cert.sign(rsa_key, OpenSSL::Digest::SHA256.new)
34
+
35
+ Dir.mkdir(conf['key_dir'], 0755) unless File.exist?(conf['key_dir'])
36
+
37
+ if File.exist?("#{conf['key_dir']}/#{hostname}.crt") && File.exist?("#{conf['key_dir']}/#{hostname}.key")
38
+ puts "An x509 certificate already exists for #{hostname}"
39
+ else
40
+ File.open("#{conf['key_dir']}/#{hostname}.crt", 'w') { |file| file.puts cert.to_pem }
41
+ File.open("#{conf['key_dir']}/#{hostname}.key", 'w') { |file| file.puts rsa_key.to_pem }
42
+ puts "Certificate created for #{wombat['domain_prefix']}#{hostname}.#{wombat['domain']}"
43
+ end
44
+ end
45
+
46
+ def gen_ssh_key
47
+ rsa_key = OpenSSL::PKey::RSA.new 2048
48
+
49
+ type = rsa_key.ssh_type
50
+ data = [rsa_key.to_blob].pack('m0')
51
+
52
+ openssh_format = "#{type} #{data}"
53
+
54
+ Dir.mkdir(conf['key_dir'], 0755) unless File.exist?(conf['key_dir'])
55
+
56
+ if File.exist?("#{conf['key_dir']}/public.pub") && File.exist?("#{conf['key_dir']}/private.pem")
57
+ puts 'An SSH keypair already exists'
58
+ else
59
+ File.open("#{conf['key_dir']}/public.pub", 'w') { |file| file.puts openssh_format }
60
+ File.open("#{conf['key_dir']}/private.pem", 'w') { |file| file.puts rsa_key.to_pem }
61
+ puts 'SSH Keypair created'
62
+ end
63
+ end
64
+ end
65
+ end
data/lib/wombat/delete.rb CHANGED
@@ -1,28 +1,58 @@
1
1
  require 'wombat/common'
2
2
  require 'aws-sdk'
3
+ require 'ms_rest_azure'
4
+ require 'azure_mgmt_resources'
3
5
 
4
- class DeleteRunner
5
- include Common
6
+ module Wombat
7
+ class DeleteRunner
8
+ include Wombat::Common
6
9
 
7
- attr_reader :stack, :cloud
10
+ attr_reader :stack, :cloud
8
11
 
9
- def initialize(opts)
10
- @stack = opts.stack
11
- @cloud = opts.cloud.nil? ? "aws" : opts.cloud
12
- end
12
+ def initialize(opts)
13
+ @stack = opts.stack
14
+ @cloud = opts.cloud.nil? ? "aws" : opts.cloud
15
+ end
13
16
 
14
- def start
15
- cfn_delete_stack(stack)
16
- end
17
+ def start
18
+ cfn_delete_stack(stack)
19
+ end
20
+
21
+ private
22
+
23
+ def cfn_delete_stack(stack)
24
+
25
+ # Delete the stack from the correct platform
26
+ case @cloud
27
+ when "aws"
28
+ cfn = Aws::CloudFormation::Client.new(region: lock['aws']['region'])
29
+
30
+ resp = cfn.delete_stack({
31
+ stack_name: stack,
32
+ })
33
+ banner("Deleted #{stack}")
34
+
35
+ when "azure"
36
+
37
+ # Create the connection to Azure using the information in the environment variables
38
+ subscription_id = ENV['AZURE_SUBSCRIPTION_ID']
39
+ tenant_id = ENV['AZURE_TENANT_ID']
40
+ client_id = ENV['AZURE_CLIENT_ID']
41
+ client_secret = ENV['AZURE_CLIENT_SECRET']
42
+
43
+ token_provider = MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret)
44
+ azure_conn = MsRest::TokenCredentials.new(token_provider)
45
+
46
+ # Create a resource client so that the resource group can be deleted
47
+ resource_management_client = Azure::ARM::Resources::ResourceManagementClient.new(azure_conn)
48
+ resource_management_client.subscription_id = subscription_id
17
49
 
18
- private
50
+ banner(format("Deleting resource group: %s", stack))
19
51
 
20
- def cfn_delete_stack(stack)
21
- cfn = Aws::CloudFormation::Client.new(region: lock['aws']['region'])
52
+ resource_management_client.resource_groups.begin_delete(stack)
22
53
 
23
- resp = cfn.delete_stack({
24
- stack_name: stack,
25
- })
26
- banner("Deleted #{stack}")
54
+ info "Destroy operation accepted and will continue in the background."
55
+ end
56
+ end
27
57
  end
28
- end
58
+ end