wombat-cli 0.4.1 → 0.4.2

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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +23 -23
  3. data/.travis.yml +27 -27
  4. data/CHANGELOG.md +77 -70
  5. data/DESIGN.md +49 -49
  6. data/Gemfile +5 -5
  7. data/README.md +146 -146
  8. data/Rakefile +26 -26
  9. data/bin/wombat +24 -24
  10. data/generator_files/Vagrantfile +120 -120
  11. data/generator_files/cookbooks/automate/.gitignore +16 -16
  12. data/generator_files/cookbooks/automate/.kitchen.ec2.yml +34 -34
  13. data/generator_files/cookbooks/automate/.kitchen.yml +24 -24
  14. data/generator_files/cookbooks/automate/Berksfile +6 -6
  15. data/generator_files/cookbooks/automate/README.md +4 -4
  16. data/generator_files/cookbooks/automate/chefignore +102 -102
  17. data/generator_files/cookbooks/automate/libraries/_helper.rb +52 -52
  18. data/generator_files/cookbooks/automate/libraries/delivery_api.rb +204 -204
  19. data/generator_files/cookbooks/automate/libraries/delivery_project.rb +31 -31
  20. data/generator_files/cookbooks/automate/libraries/dsl.rb +4 -4
  21. data/generator_files/cookbooks/automate/metadata.rb +11 -11
  22. data/generator_files/cookbooks/automate/recipes/default.rb +112 -112
  23. data/generator_files/cookbooks/automate/recipes/update-users.rb +48 -48
  24. data/generator_files/cookbooks/automate/templates/delivery.erb +6 -6
  25. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/automate.crt +26 -26
  26. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/automate.key +27 -27
  27. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/chef.crt +25 -25
  28. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/chef.key +27 -27
  29. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/compliance.crt +26 -26
  30. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/compliance.key +27 -27
  31. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/private.pem +27 -27
  32. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/files/public.pub +1 -1
  33. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/metadata.rb +3 -3
  34. data/generator_files/cookbooks/automate/test/fixtures/cookbooks/mock_data/recipes/default.rb +27 -27
  35. data/generator_files/cookbooks/automate/test/integration/default/automate_spec.rb +56 -56
  36. data/generator_files/cookbooks/build_node/.gitignore +16 -16
  37. data/generator_files/cookbooks/build_node/.kitchen.ec2.yml +37 -37
  38. data/generator_files/cookbooks/build_node/.kitchen.yml +23 -23
  39. data/generator_files/cookbooks/build_node/Berksfile +8 -8
  40. data/generator_files/cookbooks/build_node/README.md +4 -4
  41. data/generator_files/cookbooks/build_node/chefignore +102 -102
  42. data/generator_files/cookbooks/build_node/metadata.rb +12 -12
  43. data/generator_files/cookbooks/build_node/recipes/default.rb +38 -38
  44. data/generator_files/cookbooks/build_node/templates/client.erb +2 -2
  45. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/automate.crt +26 -26
  46. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/automate.key +27 -27
  47. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/chef.crt +25 -25
  48. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/chef.key +27 -27
  49. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/compliance.crt +26 -26
  50. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/compliance.key +27 -27
  51. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/private.pem +27 -27
  52. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/files/public.pub +1 -1
  53. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/metadata.rb +2 -2
  54. data/generator_files/cookbooks/build_node/test/fixtures/cookbooks/mock_data/recipes/default.rb +18 -18
  55. data/generator_files/cookbooks/build_node/test/integration/default/build-node_spec.rb +40 -40
  56. data/generator_files/cookbooks/chef_server/.gitignore +16 -16
  57. data/generator_files/cookbooks/chef_server/.kitchen.ec2.yml +34 -34
  58. data/generator_files/cookbooks/chef_server/.kitchen.yml +24 -24
  59. data/generator_files/cookbooks/chef_server/Berksfile +6 -6
  60. data/generator_files/cookbooks/chef_server/README.md +4 -4
  61. data/generator_files/cookbooks/chef_server/chefignore +102 -102
  62. data/generator_files/cookbooks/chef_server/metadata.rb +11 -11
  63. data/generator_files/cookbooks/chef_server/recipes/bootstrap_users.rb +91 -91
  64. data/generator_files/cookbooks/chef_server/recipes/default.rb +113 -113
  65. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/automate.crt +26 -26
  66. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/automate.key +27 -27
  67. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/chef.crt +25 -25
  68. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/chef.key +27 -27
  69. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/compliance.crt +26 -26
  70. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/compliance.key +27 -27
  71. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/private.pem +27 -27
  72. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/files/public.pub +1 -1
  73. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/metadata.rb +2 -2
  74. data/generator_files/cookbooks/chef_server/test/fixtures/cookbooks/mock_data/recipes/default.rb +23 -23
  75. data/generator_files/cookbooks/chef_server/test/integration/default/chef_server_spec.rb +50 -50
  76. data/generator_files/cookbooks/compliance/.gitignore +16 -16
  77. data/generator_files/cookbooks/compliance/.kitchen.ec2.yml +34 -34
  78. data/generator_files/cookbooks/compliance/.kitchen.yml +24 -24
  79. data/generator_files/cookbooks/compliance/Berksfile +7 -7
  80. data/generator_files/cookbooks/compliance/README.md +4 -4
  81. data/generator_files/cookbooks/compliance/chefignore +102 -102
  82. data/generator_files/cookbooks/compliance/metadata.rb +11 -11
  83. data/generator_files/cookbooks/compliance/recipes/default.rb +57 -57
  84. data/generator_files/cookbooks/compliance/spec/spec_helper.rb +2 -2
  85. data/generator_files/cookbooks/compliance/spec/unit/recipes/default_spec.rb +20 -20
  86. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/automate.crt +26 -26
  87. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/automate.key +27 -27
  88. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/chef.crt +25 -25
  89. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/chef.key +27 -27
  90. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/compliance.crt +26 -26
  91. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/compliance.key +27 -27
  92. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/private.pem +27 -27
  93. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/files/public.pub +1 -1
  94. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/metadata.rb +4 -4
  95. data/generator_files/cookbooks/compliance/test/fixtures/cookbooks/mock_data/recipes/default.rb +21 -21
  96. data/generator_files/cookbooks/compliance/test/integration/default/compliance.rb +28 -28
  97. data/generator_files/cookbooks/infranodes/.gitignore +16 -16
  98. data/generator_files/cookbooks/infranodes/.kitchen.ec2.yml +48 -48
  99. data/generator_files/cookbooks/infranodes/.kitchen.yml +21 -21
  100. data/generator_files/cookbooks/infranodes/Berksfile +6 -6
  101. data/generator_files/cookbooks/infranodes/README.md +4 -4
  102. data/generator_files/cookbooks/infranodes/attributes/default.rb +2 -2
  103. data/generator_files/cookbooks/infranodes/chefignore +102 -102
  104. data/generator_files/cookbooks/infranodes/metadata.rb +13 -13
  105. data/generator_files/cookbooks/infranodes/recipes/default.rb +57 -57
  106. data/generator_files/cookbooks/infranodes/spec/spec_helper.rb +2 -2
  107. data/generator_files/cookbooks/infranodes/spec/unit/recipes/default_spec.rb +20 -20
  108. data/generator_files/cookbooks/infranodes/templates/default/client.rb.erb +5 -5
  109. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/automate.crt +26 -26
  110. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/automate.key +27 -27
  111. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/chef.crt +25 -25
  112. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/chef.key +27 -27
  113. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/compliance.crt +26 -26
  114. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/compliance.key +27 -27
  115. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/private.pem +27 -27
  116. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/files/public.pub +1 -1
  117. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/metadata.rb +3 -3
  118. data/generator_files/cookbooks/infranodes/test/fixtures/cookbooks/mock_data/recipes/default.rb +27 -27
  119. data/generator_files/cookbooks/infranodes/test/integration/default/infranodes_spec.rb +22 -22
  120. data/generator_files/cookbooks/infranodes/test/integration/helpers/serverspec/spec_helper.rb +8 -8
  121. data/generator_files/cookbooks/wombat/.gitignore +16 -16
  122. data/generator_files/cookbooks/wombat/.kitchen.yml +43 -43
  123. data/generator_files/cookbooks/wombat/Berksfile +5 -5
  124. data/generator_files/cookbooks/wombat/README.md +4 -4
  125. data/generator_files/cookbooks/wombat/attributes/default.rb +74 -74
  126. data/generator_files/cookbooks/wombat/attributes/packer.rb +18 -18
  127. data/generator_files/cookbooks/wombat/chefignore +102 -102
  128. data/generator_files/cookbooks/wombat/metadata.rb +13 -13
  129. data/generator_files/cookbooks/wombat/recipes/authorized-keys.rb +20 -20
  130. data/generator_files/cookbooks/wombat/recipes/default.rb +111 -111
  131. data/generator_files/cookbooks/wombat/recipes/etc-hosts.rb +51 -51
  132. data/generator_files/cookbooks/workstation/.gitignore +16 -16
  133. data/generator_files/cookbooks/workstation/.kitchen.ec2.yml +30 -30
  134. data/generator_files/cookbooks/workstation/.kitchen.yml +22 -22
  135. data/generator_files/cookbooks/workstation/Berksfile +7 -7
  136. data/generator_files/cookbooks/workstation/README.md +3 -3
  137. data/generator_files/cookbooks/workstation/chefignore +102 -102
  138. data/generator_files/cookbooks/workstation/files/atom.apm.list +7 -7
  139. data/generator_files/cookbooks/workstation/files/atom.config.cson +3 -3
  140. data/generator_files/cookbooks/workstation/metadata.rb +14 -14
  141. data/generator_files/cookbooks/workstation/recipes/browser.rb +59 -59
  142. data/generator_files/cookbooks/workstation/recipes/certs-keys.rb +45 -45
  143. data/generator_files/cookbooks/workstation/recipes/chef.rb +29 -29
  144. data/generator_files/cookbooks/workstation/recipes/default.rb +20 -20
  145. data/generator_files/cookbooks/workstation/recipes/dotnet.rb +17 -17
  146. data/generator_files/cookbooks/workstation/recipes/editor.rb +19 -19
  147. data/generator_files/cookbooks/workstation/recipes/profile.rb +42 -42
  148. data/generator_files/cookbooks/workstation/recipes/terminal.rb +13 -13
  149. data/generator_files/cookbooks/workstation/templates/default/bookmarks.html.erb +23 -23
  150. data/generator_files/cookbooks/workstation/templates/default/data_collector.rb.erb +2 -2
  151. data/generator_files/cookbooks/workstation/templates/default/ise_profile.ps1.erb +11 -11
  152. data/generator_files/cookbooks/workstation/templates/default/knife.rb.erb +10 -10
  153. data/generator_files/cookbooks/workstation/templates/default/master_preferences.json.erb +28 -28
  154. data/generator_files/cookbooks/workstation/templates/default/ssh_config.erb +16 -16
  155. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/automate.crt +26 -26
  156. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/automate.key +27 -27
  157. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/chef.crt +26 -26
  158. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/chef.key +27 -27
  159. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/compliance.crt +26 -26
  160. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/compliance.key +27 -27
  161. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/private.pem +27 -27
  162. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/public.pub +1 -1
  163. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/metadata.rb +2 -2
  164. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/recipes/default.rb +21 -21
  165. data/generator_files/cookbooks/workstation/test/integration/default/workstation_spec.rb +37 -37
  166. data/generator_files/packer/automate.json +131 -131
  167. data/generator_files/packer/build-node.json +137 -137
  168. data/generator_files/packer/chef-server.json +132 -132
  169. data/generator_files/packer/compliance.json +128 -128
  170. data/generator_files/packer/infranodes-windows.json +138 -138
  171. data/generator_files/packer/infranodes.json +129 -129
  172. data/generator_files/packer/workstation.json +136 -136
  173. data/generator_files/templates/arm.json.erb +575 -575
  174. data/generator_files/templates/arm.tidy.json.erb +31 -31
  175. data/generator_files/templates/bootstrap-aws.erb +36 -36
  176. data/generator_files/templates/cfn.json.erb +674 -674
  177. data/generator_files/wombat.yml +71 -71
  178. data/lib/wombat/aws.rb +67 -67
  179. data/lib/wombat/build.rb +338 -338
  180. data/lib/wombat/cli.rb +238 -238
  181. data/lib/wombat/common.rb +347 -347
  182. data/lib/wombat/crypto.rb +64 -64
  183. data/lib/wombat/delete.rb +94 -94
  184. data/lib/wombat/deploy.rb +101 -101
  185. data/lib/wombat/init.rb +32 -32
  186. data/lib/wombat/latest.rb +27 -27
  187. data/lib/wombat/output.rb +86 -86
  188. data/lib/wombat/update.rb +20 -20
  189. data/lib/wombat/version.rb +3 -3
  190. data/lib/wombat.rb +8 -8
  191. data/spec/functional/common_spec.rb +26 -26
  192. data/spec/spec_helper.rb +103 -103
  193. data/spec/unit/common_spec.rb +116 -116
  194. data/terraform/README.md +13 -13
  195. data/terraform/templates/terraform.tfvars.erb +12 -12
  196. data/terraform/wombat.tf +328 -328
  197. data/wombat-cli.gemspec +34 -34
  198. metadata +2 -2
data/lib/wombat/common.rb CHANGED
@@ -1,348 +1,348 @@
1
- require 'yaml'
2
- require 'json'
3
- require 'erb'
4
- require 'benchmark'
5
- require 'fileutils'
6
- require 'ms_rest_azure'
7
-
8
- module Wombat
9
- module Common
10
-
11
- def banner(msg)
12
- puts "==> #{msg}"
13
- end
14
-
15
- def info(msg)
16
- puts " #{msg}"
17
- end
18
-
19
- def warn(msg)
20
- puts ">>> #{msg}"
21
- end
22
-
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
29
-
30
- def wombat
31
- @wombat_yml ||= ENV['WOMBAT_YML'] unless ENV['WOMBAT_YML'].nil?
32
- @wombat_yml ||= 'wombat.yml'
33
- if !File.exist?(@wombat_yml)
34
- warn('No wombat.yml found, copying example')
35
- gen_dir = "#{File.expand_path("../..", File.dirname(__FILE__))}/generator_files"
36
- FileUtils.cp_r "#{gen_dir}/wombat.yml", Dir.pwd
37
- end
38
- YAML.load(File.read(@wombat_yml))
39
- end
40
-
41
- def lock
42
- if !File.exist?('wombat.lock')
43
- warn('No wombat.lock found')
44
- return 1
45
- else
46
- JSON.parse(File.read('wombat.lock'))
47
- end
48
- end
49
-
50
- def bootstrap_aws
51
- @workstation_passwd = wombat['workstations']['password']
52
- rendered = ERB.new(File.read("#{conf['template_dir']}/bootstrap-aws.erb"), nil, '-').result(binding)
53
- Dir.mkdir("#{conf['packer_dir']}/scripts", 0755) unless File.exist?("#{conf['packer_dir']}/scripts")
54
- File.open("#{conf['packer_dir']}/scripts/bootstrap-aws.txt", 'w') { |file| file.puts rendered }
55
- banner("Generated: #{conf['packer_dir']}/scripts/bootstrap-aws.txt")
56
- end
57
-
58
- def parse_log(log, cloud)
59
- regex = case cloud
60
- when 'gcp'
61
- 'A disk image was created:'
62
- when 'azure'
63
- 'OSDiskUri:'
64
- else
65
- "#{wombat['aws']['region']}:"
66
- end
67
-
68
- File.read(log).split("\n").grep(/#{regex}/) {|x| x.split[1]}.last
69
- end
70
-
71
- def infranodes
72
- unless wombat['infranodes'].nil?
73
- wombat['infranodes'].sort
74
- else
75
- puts 'No infranodes listed in wombat.yml'
76
- {}
77
- end
78
- end
79
-
80
- def build_nodes
81
- build_nodes = {}
82
- 1.upto(wombat['build-nodes']['count'].to_i) do |i|
83
- build_nodes["build-node-#{i}"] = i
84
- end
85
- build_nodes
86
- end
87
-
88
- def workstations
89
- workstations = {}
90
- 1.upto(wombat['workstations']['count'].to_i) do |i|
91
- workstations["workstation-#{i}"] = i
92
- end
93
- workstations
94
- end
95
-
96
- def create_infranodes_json
97
- infranodes_file_path = File.join(conf['files_dir'], 'infranodes-info.json')
98
- if File.exists?(infranodes_file_path) && is_valid_json?(infranodes_file_path)
99
- current_state = JSON(File.read(infranodes_file_path))
100
- else
101
- current_state = nil
102
- end
103
- return if current_state == infranodes # yay idempotence
104
- File.open(infranodes_file_path, 'w') do |f|
105
- f.puts JSON.pretty_generate(infranodes)
106
- end
107
- end
108
-
109
- def linux
110
- wombat['linux'].nil? ? 'ubuntu' : wombat['linux']
111
- end
112
-
113
- def conf
114
- conf = wombat['conf']
115
- conf ||= {}
116
- conf['files_dir'] ||= 'files'
117
- conf['key_dir'] ||= 'keys'
118
- conf['cookbook_dir'] ||= 'cookbooks'
119
- conf['packer_dir'] ||= 'packer'
120
- conf['log_dir'] ||= 'logs'
121
- conf['stack_dir'] ||= 'stacks'
122
- conf['template_dir'] ||= 'templates'
123
- conf['timeout'] ||= 7200
124
- conf['audio'] ||= false
125
- conf
126
- end
127
-
128
- def is_mac?
129
- (/darwin/ =~ RUBY_PLATFORM) != nil
130
- end
131
-
132
- def audio?
133
- is_mac? && conf['audio']
134
- end
135
-
136
- def logs
137
- path = "#{conf['log_dir']}/#{cloud}*.log"
138
- Dir.glob(path).reject { |l| !l.match(wombat['linux']) }
139
- end
140
-
141
- def calculate_templates
142
- globs = "*.json"
143
- Dir.chdir(conf['packer_dir']) do
144
- Array(globs).
145
- map { |glob| result = Dir.glob("#{glob}"); result.empty? ? glob : result }.
146
- flatten.
147
- sort.
148
- delete_if { |file| file =~ /\.variables\./ }.
149
- map { |template| template.sub(/\.json$/, '') }
150
- end
151
- end
152
-
153
- def update_lock(cloud)
154
- copy = {}
155
- copy = wombat
156
-
157
- # Check that the copy contains a key for the named cloud
158
- unless copy.key?(cloud)
159
- throw "The Cloud '#{cloud}' is not specified in Wombat"
160
- end
161
-
162
- # Determine the region/location/zone for the specific cloud
163
- case cloud
164
- when 'aws'
165
- region = copy['aws']['region']
166
- when 'azure'
167
- region = copy['azure']['location']
168
- when 'gce'
169
- region = copy['gce']['zone']
170
- end
171
-
172
- linux = copy['linux']
173
- copy['amis'] = { region => {} }
174
-
175
- if logs.length == 0
176
- warn('No logs found - skipping lock update')
177
- else
178
- logs.each do |log|
179
- case log
180
- when /build-node/
181
- copy['amis'][region]['build-node'] ||= {}
182
- num = log.split('-')[3]
183
- copy['amis'][region]['build-node'].store(num, parse_log(log, cloud))
184
- when /workstation/
185
- copy['amis'][region]['workstation'] ||= {}
186
- num = log.split('-')[2]
187
- copy['amis'][region]['workstation'].store(num, parse_log(log, cloud))
188
- when /infranodes/
189
- copy['amis'][region]['infranodes'] ||= {}
190
- name = log.split('-')[2]
191
- copy['amis'][region]['infranodes'].store(name, parse_log(log, cloud))
192
- else
193
- instance = log.match("#{cloud}-(.*)-#{linux}\.log")[1]
194
- copy['amis'][region].store(instance, parse_log(log, cloud))
195
- end
196
- end
197
- copy['last_updated'] = Time.now.gmtime.strftime('%Y%m%d%H%M%S')
198
- banner('Updating wombat.lock')
199
- File.open('wombat.lock', 'w') do |f|
200
- f.write(JSON.pretty_generate(copy))
201
- end
202
- end
203
- end
204
-
205
- def update_template(cloud)
206
- if lock == 1
207
- warn('No lock - skipping template creation')
208
- else
209
-
210
- @demo = lock['name']
211
- @version = lock['version']
212
- @ttl = lock['ttl']
213
-
214
- # Determine the region/location/zone for the specific cloud
215
- case cloud
216
- when 'aws'
217
- region = lock['aws']['region']
218
- template_files = {
219
- "cfn.json.erb": "#{conf['stack_dir']}/#{@demo}.json"
220
- }
221
- @chef_server_ami = lock['amis'][region]['chef-server']
222
- @automate_ami = lock['amis'][region]['automate']
223
- @compliance_ami = lock['amis'][region]['compliance']
224
- @availability_zone = lock['aws']['az']
225
- @iam_roles = lock['aws']['iam_roles']
226
- when 'azure'
227
- region = lock['azure']['location']
228
- @storage_account = lock['azure']['storage_account']
229
- template_files = {
230
- "arm.json.erb": "#{conf['stack_dir']}/#{@demo}.json",
231
- "arm.tidy.json.erb": "#{conf['stack_dir']}/#{@demo}.tidy.json"
232
- }
233
- @chef_server_uri = lock['amis'][region]['chef-server']
234
- @automate_uri = lock['amis'][region]['automate']
235
- @compliance_uri = lock['amis'][region]['compliance']
236
- @password = lock['workstations']['password']
237
- when 'gce'
238
- region = lock['gce']['zone']
239
- end
240
-
241
- if lock['amis'][region].key?('build-node')
242
- @build_nodes = lock['build-nodes']['count'].to_i
243
- @build_node_ami = {}
244
- 1.upto(@build_nodes) do |i|
245
- @build_node_ami[i] = lock['amis'][region]['build-node'][i.to_s]
246
- end
247
- end
248
-
249
- @infra = {}
250
- infranodes.each do |name, _rl|
251
- @infra[name] = lock['amis'][region]['infranodes'][name]
252
- end
253
-
254
- if lock['amis'][region].key?('workstation')
255
- @workstations = lock['workstations']['count'].to_i
256
- @workstation_ami = {}
257
- 1.upto(@workstations) do |i|
258
- @workstation_ami[i] = lock['amis'][region]['workstation'][i.to_s]
259
- end
260
- end
261
-
262
- # Iterate around each of the template files that have been defined and render it
263
- template_files.each do |template_file, destination|
264
- rendered_cfn = ERB.new(File.read("#{conf['template_dir']}/#{template_file}"), nil, '-').result(binding)
265
- Dir.mkdir(conf['stack_dir'], 0755) unless File.exist?(conf['stack_dir'])
266
- File.open("#{destination}", 'w') { |file| file.puts rendered_cfn }
267
- banner("Generated: #{destination}")
268
- end
269
- end
270
- end
271
-
272
- def is_valid_json?(file)
273
- begin
274
- JSON.parse(file)
275
- true
276
- rescue JSON::ParserError => e
277
- false
278
- end
279
- end
280
-
281
- # Connect to Azure using environment variables
282
- #
283
- #
284
- def connect_azure
285
-
286
- # Create the connection to Azure using the information in the environment variables
287
- tenant_id = ENV['AZURE_TENANT_ID']
288
- client_id = ENV['AZURE_CLIENT_ID']
289
- client_secret = ENV['AZURE_CLIENT_SECRET']
290
-
291
- token_provider = MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret)
292
- MsRest::TokenCredentials.new(token_provider)
293
- end
294
-
295
- # Track the progress of the deployment in Azure
296
- #
297
- # ===== Attributes
298
- #
299
- # * +rg_name+ - Name of the resource group being deployed to
300
- # * +deployment_name+ - Name of the deployment that is currently being processed
301
- def follow_azure_deployment(rg_name, deployment_name)
302
-
303
- end_provisioning_states = 'Canceled,Failed,Deleted,Succeeded'
304
- end_provisioning_state_reached = false
305
-
306
- until end_provisioning_state_reached
307
- list_outstanding_deployment_operations(rg_name, deployment_name)
308
- sleep 10
309
- deployment_provisioning_state = deployment_state(rg_name, deployment_name)
310
- end_provisioning_state_reached = end_provisioning_states.split(',').include?(deployment_provisioning_state)
311
- end
312
- info format("Resource Template deployment reached end state of %s", deployment_provisioning_state)
313
- end
314
-
315
- # Get a list of the outstanding deployment operations
316
- #
317
- # ===== Attributes
318
- #
319
- # * +rg_name+ - Name of the resource group being deployed to
320
- # * +deployment_name+ - Name of the deployment that is currently being processed
321
- def list_outstanding_deployment_operations(rg_name, deployment_name)
322
- end_operation_states = 'Failed,Succeeded'
323
- deployment_operations = resource_management_client.deployment_operations.list(rg_name, deployment_name)
324
- deployment_operations.each do |val|
325
- resource_provisioning_state = val.properties.provisioning_state
326
- unless val.properties.target_resource.nil?
327
- resource_name = val.properties.target_resource.resource_name
328
- resource_type = val.properties.target_resource.resource_type
329
- end
330
- end_operation_state_reached = end_operation_states.split(',').include?(resource_provisioning_state)
331
- unless end_operation_state_reached
332
- info format("resource %s '%s' provisioning status is %s", resource_type, resource_name, resource_provisioning_state)
333
- end
334
- end
335
- end
336
-
337
- # Get the state of the specified deployment
338
- #
339
- # ===== Attributes
340
- #
341
- # * +rg_name+ - Name of the resource group being deployed to
342
- # * +deployment_name+ - Name of the deployment that is currently being processed
343
- def deployment_state(rg_name, deployment_name)
344
- deployments = resource_management_client.deployments.get(rg_name, deployment_name)
345
- deployments.properties.provisioning_state
346
- end
347
- end
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'erb'
4
+ require 'benchmark'
5
+ require 'fileutils'
6
+ require 'ms_rest_azure'
7
+
8
+ module Wombat
9
+ module Common
10
+
11
+ def banner(msg)
12
+ puts "==> #{msg}"
13
+ end
14
+
15
+ def info(msg)
16
+ puts " #{msg}"
17
+ end
18
+
19
+ def warn(msg)
20
+ puts ">>> #{msg}"
21
+ end
22
+
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
29
+
30
+ def wombat
31
+ @wombat_yml ||= ENV['WOMBAT_YML'] unless ENV['WOMBAT_YML'].nil?
32
+ @wombat_yml ||= 'wombat.yml'
33
+ if !File.exist?(@wombat_yml)
34
+ warn('No wombat.yml found, copying example')
35
+ gen_dir = "#{File.expand_path("../..", File.dirname(__FILE__))}/generator_files"
36
+ FileUtils.cp_r "#{gen_dir}/wombat.yml", Dir.pwd
37
+ end
38
+ YAML.load(File.read(@wombat_yml))
39
+ end
40
+
41
+ def lock
42
+ if !File.exist?('wombat.lock')
43
+ warn('No wombat.lock found')
44
+ return 1
45
+ else
46
+ JSON.parse(File.read('wombat.lock'))
47
+ end
48
+ end
49
+
50
+ def bootstrap_aws
51
+ @workstation_passwd = wombat['workstations']['password']
52
+ rendered = ERB.new(File.read("#{conf['template_dir']}/bootstrap-aws.erb"), nil, '-').result(binding)
53
+ Dir.mkdir("#{conf['packer_dir']}/scripts", 0755) unless File.exist?("#{conf['packer_dir']}/scripts")
54
+ File.open("#{conf['packer_dir']}/scripts/bootstrap-aws.txt", 'w') { |file| file.puts rendered }
55
+ banner("Generated: #{conf['packer_dir']}/scripts/bootstrap-aws.txt")
56
+ end
57
+
58
+ def parse_log(log, cloud)
59
+ regex = case cloud
60
+ when 'gcp'
61
+ 'A disk image was created:'
62
+ when 'azure'
63
+ 'OSDiskUri:'
64
+ else
65
+ "#{wombat['aws']['region']}:"
66
+ end
67
+
68
+ File.read(log).split("\n").grep(/#{regex}/) {|x| x.split[1]}.last
69
+ end
70
+
71
+ def infranodes
72
+ unless wombat['infranodes'].nil?
73
+ wombat['infranodes'].sort
74
+ else
75
+ puts 'No infranodes listed in wombat.yml'
76
+ {}
77
+ end
78
+ end
79
+
80
+ def build_nodes
81
+ build_nodes = {}
82
+ 1.upto(wombat['build-nodes']['count'].to_i) do |i|
83
+ build_nodes["build-node-#{i}"] = i
84
+ end
85
+ build_nodes
86
+ end
87
+
88
+ def workstations
89
+ workstations = {}
90
+ 1.upto(wombat['workstations']['count'].to_i) do |i|
91
+ workstations["workstation-#{i}"] = i
92
+ end
93
+ workstations
94
+ end
95
+
96
+ def create_infranodes_json
97
+ infranodes_file_path = File.join(conf['files_dir'], 'infranodes-info.json')
98
+ if File.exists?(infranodes_file_path) && is_valid_json?(infranodes_file_path)
99
+ current_state = JSON(File.read(infranodes_file_path))
100
+ else
101
+ current_state = nil
102
+ end
103
+ return if current_state == infranodes # yay idempotence
104
+ File.open(infranodes_file_path, 'w') do |f|
105
+ f.puts JSON.pretty_generate(infranodes)
106
+ end
107
+ end
108
+
109
+ def linux
110
+ wombat['linux'].nil? ? 'ubuntu' : wombat['linux']
111
+ end
112
+
113
+ def conf
114
+ conf = wombat['conf']
115
+ conf ||= {}
116
+ conf['files_dir'] ||= 'files'
117
+ conf['key_dir'] ||= 'keys'
118
+ conf['cookbook_dir'] ||= 'cookbooks'
119
+ conf['packer_dir'] ||= 'packer'
120
+ conf['log_dir'] ||= 'logs'
121
+ conf['stack_dir'] ||= 'stacks'
122
+ conf['template_dir'] ||= 'templates'
123
+ conf['timeout'] ||= 7200
124
+ conf['audio'] ||= false
125
+ conf
126
+ end
127
+
128
+ def is_mac?
129
+ (/darwin/ =~ RUBY_PLATFORM) != nil
130
+ end
131
+
132
+ def audio?
133
+ is_mac? && conf['audio']
134
+ end
135
+
136
+ def logs
137
+ path = "#{conf['log_dir']}/#{cloud}*.log"
138
+ Dir.glob(path).reject { |l| !l.match(wombat['linux']) }
139
+ end
140
+
141
+ def calculate_templates
142
+ globs = "*.json"
143
+ Dir.chdir(conf['packer_dir']) do
144
+ Array(globs).
145
+ map { |glob| result = Dir.glob("#{glob}"); result.empty? ? glob : result }.
146
+ flatten.
147
+ sort.
148
+ delete_if { |file| file =~ /\.variables\./ }.
149
+ map { |template| template.sub(/\.json$/, '') }
150
+ end
151
+ end
152
+
153
+ def update_lock(cloud)
154
+ copy = {}
155
+ copy = wombat
156
+
157
+ # Check that the copy contains a key for the named cloud
158
+ unless copy.key?(cloud)
159
+ throw "The Cloud '#{cloud}' is not specified in Wombat"
160
+ end
161
+
162
+ # Determine the region/location/zone for the specific cloud
163
+ case cloud
164
+ when 'aws'
165
+ region = copy['aws']['region']
166
+ when 'azure'
167
+ region = copy['azure']['location']
168
+ when 'gce'
169
+ region = copy['gce']['zone']
170
+ end
171
+
172
+ linux = copy['linux']
173
+ copy['amis'] = { region => {} }
174
+
175
+ if logs.length == 0
176
+ warn('No logs found - skipping lock update')
177
+ else
178
+ logs.each do |log|
179
+ case log
180
+ when /build-node/
181
+ copy['amis'][region]['build-node'] ||= {}
182
+ num = log.split('-')[3]
183
+ copy['amis'][region]['build-node'].store(num, parse_log(log, cloud))
184
+ when /workstation/
185
+ copy['amis'][region]['workstation'] ||= {}
186
+ num = log.split('-')[2]
187
+ copy['amis'][region]['workstation'].store(num, parse_log(log, cloud))
188
+ when /infranodes/
189
+ copy['amis'][region]['infranodes'] ||= {}
190
+ name = log.split('-')[2]
191
+ copy['amis'][region]['infranodes'].store(name, parse_log(log, cloud))
192
+ else
193
+ instance = log.match("#{cloud}-(.*)-#{linux}\.log")[1]
194
+ copy['amis'][region].store(instance, parse_log(log, cloud))
195
+ end
196
+ end
197
+ copy['last_updated'] = Time.now.gmtime.strftime('%Y%m%d%H%M%S')
198
+ banner('Updating wombat.lock')
199
+ File.open('wombat.lock', 'w') do |f|
200
+ f.write(JSON.pretty_generate(copy))
201
+ end
202
+ end
203
+ end
204
+
205
+ def update_template(cloud)
206
+ if lock == 1
207
+ warn('No lock - skipping template creation')
208
+ else
209
+
210
+ @demo = lock['name']
211
+ @version = lock['version']
212
+ @ttl = lock['ttl']
213
+
214
+ # Determine the region/location/zone for the specific cloud
215
+ case cloud
216
+ when 'aws'
217
+ region = lock['aws']['region']
218
+ template_files = {
219
+ "cfn.json.erb": "#{conf['stack_dir']}/#{@demo}.json"
220
+ }
221
+ @chef_server_ami = lock['amis'][region]['chef-server']
222
+ @automate_ami = lock['amis'][region]['automate']
223
+ @compliance_ami = lock['amis'][region]['compliance']
224
+ @availability_zone = lock['aws']['az']
225
+ @iam_roles = lock['aws']['iam_roles']
226
+ when 'azure'
227
+ region = lock['azure']['location']
228
+ @storage_account = lock['azure']['storage_account']
229
+ template_files = {
230
+ "arm.json.erb": "#{conf['stack_dir']}/#{@demo}.json",
231
+ "arm.tidy.json.erb": "#{conf['stack_dir']}/#{@demo}.tidy.json"
232
+ }
233
+ @chef_server_uri = lock['amis'][region]['chef-server']
234
+ @automate_uri = lock['amis'][region]['automate']
235
+ @compliance_uri = lock['amis'][region]['compliance']
236
+ @password = lock['workstations']['password']
237
+ when 'gce'
238
+ region = lock['gce']['zone']
239
+ end
240
+
241
+ if lock['amis'][region].key?('build-node')
242
+ @build_nodes = lock['build-nodes']['count'].to_i
243
+ @build_node_ami = {}
244
+ 1.upto(@build_nodes) do |i|
245
+ @build_node_ami[i] = lock['amis'][region]['build-node'][i.to_s]
246
+ end
247
+ end
248
+
249
+ @infra = {}
250
+ infranodes.each do |name, _rl|
251
+ @infra[name] = lock['amis'][region]['infranodes'][name]
252
+ end
253
+
254
+ if lock['amis'][region].key?('workstation')
255
+ @workstations = lock['workstations']['count'].to_i
256
+ @workstation_ami = {}
257
+ 1.upto(@workstations) do |i|
258
+ @workstation_ami[i] = lock['amis'][region]['workstation'][i.to_s]
259
+ end
260
+ end
261
+
262
+ # Iterate around each of the template files that have been defined and render it
263
+ template_files.each do |template_file, destination|
264
+ rendered_cfn = ERB.new(File.read("#{conf['template_dir']}/#{template_file}"), nil, '-').result(binding)
265
+ Dir.mkdir(conf['stack_dir'], 0755) unless File.exist?(conf['stack_dir'])
266
+ File.open("#{destination}", 'w') { |file| file.puts rendered_cfn }
267
+ banner("Generated: #{destination}")
268
+ end
269
+ end
270
+ end
271
+
272
+ def is_valid_json?(file)
273
+ begin
274
+ JSON.parse(file)
275
+ true
276
+ rescue JSON::ParserError => e
277
+ false
278
+ end
279
+ end
280
+
281
+ # Connect to Azure using environment variables
282
+ #
283
+ #
284
+ def connect_azure
285
+
286
+ # Create the connection to Azure using the information in the environment variables
287
+ tenant_id = ENV['AZURE_TENANT_ID']
288
+ client_id = ENV['AZURE_CLIENT_ID']
289
+ client_secret = ENV['AZURE_CLIENT_SECRET']
290
+
291
+ token_provider = MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret)
292
+ MsRest::TokenCredentials.new(token_provider)
293
+ end
294
+
295
+ # Track the progress of the deployment in Azure
296
+ #
297
+ # ===== Attributes
298
+ #
299
+ # * +rg_name+ - Name of the resource group being deployed to
300
+ # * +deployment_name+ - Name of the deployment that is currently being processed
301
+ def follow_azure_deployment(rg_name, deployment_name)
302
+
303
+ end_provisioning_states = 'Canceled,Failed,Deleted,Succeeded'
304
+ end_provisioning_state_reached = false
305
+
306
+ until end_provisioning_state_reached
307
+ list_outstanding_deployment_operations(rg_name, deployment_name)
308
+ sleep 10
309
+ deployment_provisioning_state = deployment_state(rg_name, deployment_name)
310
+ end_provisioning_state_reached = end_provisioning_states.split(',').include?(deployment_provisioning_state)
311
+ end
312
+ info format("Resource Template deployment reached end state of %s", deployment_provisioning_state)
313
+ end
314
+
315
+ # Get a list of the outstanding deployment operations
316
+ #
317
+ # ===== Attributes
318
+ #
319
+ # * +rg_name+ - Name of the resource group being deployed to
320
+ # * +deployment_name+ - Name of the deployment that is currently being processed
321
+ def list_outstanding_deployment_operations(rg_name, deployment_name)
322
+ end_operation_states = 'Failed,Succeeded'
323
+ deployment_operations = resource_management_client.deployment_operations.list(rg_name, deployment_name)
324
+ deployment_operations.each do |val|
325
+ resource_provisioning_state = val.properties.provisioning_state
326
+ unless val.properties.target_resource.nil?
327
+ resource_name = val.properties.target_resource.resource_name
328
+ resource_type = val.properties.target_resource.resource_type
329
+ end
330
+ end_operation_state_reached = end_operation_states.split(',').include?(resource_provisioning_state)
331
+ unless end_operation_state_reached
332
+ info format("resource %s '%s' provisioning status is %s", resource_type, resource_name, resource_provisioning_state)
333
+ end
334
+ end
335
+ end
336
+
337
+ # Get the state of the specified deployment
338
+ #
339
+ # ===== Attributes
340
+ #
341
+ # * +rg_name+ - Name of the resource group being deployed to
342
+ # * +deployment_name+ - Name of the deployment that is currently being processed
343
+ def deployment_state(rg_name, deployment_name)
344
+ deployments = resource_management_client.deployments.get(rg_name, deployment_name)
345
+ deployments.properties.provisioning_state
346
+ end
347
+ end
348
348
  end