wombat-cli 0.3.4 → 0.4.0
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 +4 -0
- data/.travis.yml +27 -0
- data/CHANGELOG.md +15 -1
- data/Gemfile +3 -0
- data/README.md +2 -2
- data/Rakefile +25 -0
- data/bin/wombat +1 -1
- data/generator_files/cookbooks/automate/metadata.rb +1 -1
- data/generator_files/cookbooks/automate/recipes/update-users.rb +1 -1
- data/generator_files/cookbooks/chef_server/recipes/default.rb +24 -11
- data/generator_files/cookbooks/workstation/.kitchen.ec2.yml +2 -1
- data/generator_files/cookbooks/workstation/metadata.rb +1 -1
- data/generator_files/cookbooks/workstation/recipes/default.rb +1 -2
- data/generator_files/cookbooks/workstation/templates/default/ise_profile.ps1.erb +2 -2
- data/generator_files/cookbooks/workstation/test/integration/default/workstation_spec.rb +4 -4
- data/generator_files/packer/automate.json +129 -107
- data/generator_files/packer/build-node.json +134 -112
- data/generator_files/packer/chef-server.json +130 -108
- data/generator_files/packer/compliance.json +126 -104
- data/generator_files/packer/infranodes-windows.json +136 -97
- data/generator_files/packer/infranodes.json +127 -106
- data/generator_files/packer/workstation.json +134 -95
- data/generator_files/templates/arm.json.erb +576 -0
- data/generator_files/wombat.yml +6 -2
- data/lib/wombat/aws.rb +67 -0
- data/lib/wombat/build.rb +273 -184
- data/lib/wombat/cli.rb +182 -147
- data/lib/wombat/common.rb +228 -220
- data/lib/wombat/crypto.rb +65 -0
- data/lib/wombat/delete.rb +48 -18
- data/lib/wombat/deploy.rb +147 -34
- data/lib/wombat/init.rb +21 -19
- data/lib/wombat/latest.rb +27 -0
- data/lib/wombat/output.rb +31 -30
- data/lib/wombat/update.rb +13 -10
- data/lib/wombat/version.rb +1 -1
- data/spec/functional/common_spec.rb +26 -0
- data/spec/spec_helper.rb +103 -0
- data/spec/unit/common_spec.rb +116 -0
- data/wombat-cli.gemspec +2 -1
- metadata +36 -11
- /data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/{delivery.crt → automate.crt} +0 -0
- /data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/{delivery.key → automate.key} +0 -0
- /data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/{chef-server.crt → chef.crt} +0 -0
- /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
|
7
|
+
module Wombat
|
8
|
+
module Common
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def info(msg)
|
16
|
-
puts " #{msg}"
|
17
|
-
end
|
10
|
+
def banner(msg)
|
11
|
+
puts "==> #{msg}"
|
12
|
+
end
|
18
13
|
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
def info(msg)
|
15
|
+
puts " #{msg}"
|
16
|
+
end
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
95
|
-
|
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
|
-
|
98
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
108
|
+
def linux
|
109
|
+
wombat['linux'].nil? ? 'ubuntu' : wombat['linux']
|
110
|
+
end
|
117
111
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
-
|
127
|
-
|
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
|
-
|
135
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
152
|
+
def update_lock(cloud)
|
153
|
+
copy = {}
|
154
|
+
copy = wombat
|
157
155
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
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
|
-
|
177
|
-
|
178
|
-
|
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
|
-
|
181
|
-
|
182
|
-
|
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
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
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
|
-
|
5
|
-
|
6
|
+
module Wombat
|
7
|
+
class DeleteRunner
|
8
|
+
include Wombat::Common
|
6
9
|
|
7
|
-
|
10
|
+
attr_reader :stack, :cloud
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
def initialize(opts)
|
13
|
+
@stack = opts.stack
|
14
|
+
@cloud = opts.cloud.nil? ? "aws" : opts.cloud
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
50
|
+
banner(format("Deleting resource group: %s", stack))
|
19
51
|
|
20
|
-
|
21
|
-
cfn = Aws::CloudFormation::Client.new(region: lock['aws']['region'])
|
52
|
+
resource_management_client.resource_groups.begin_delete(stack)
|
22
53
|
|
23
|
-
|
24
|
-
|
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
|