wombat-cli 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +23 -23
  3. data/.travis.yml +22 -27
  4. data/CHANGELOG.md +438 -423
  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 +118 -124
  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 +79 -80
  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.azure.yml +45 -0
  134. data/generator_files/cookbooks/workstation/.kitchen.ec2.yml +46 -30
  135. data/generator_files/cookbooks/workstation/.kitchen.yml +42 -22
  136. data/generator_files/cookbooks/workstation/Berksfile +7 -7
  137. data/generator_files/cookbooks/workstation/README.md +3 -3
  138. data/generator_files/cookbooks/workstation/chefignore +106 -102
  139. data/generator_files/cookbooks/workstation/files/atom.apm.list +10 -7
  140. data/generator_files/cookbooks/workstation/files/atom.config.cson +6 -3
  141. data/generator_files/cookbooks/workstation/{templates/default/ise_profile.ps1.erb → files/ise_profile.ps1} +11 -11
  142. data/generator_files/cookbooks/workstation/libraries/home.rb +4 -4
  143. data/generator_files/cookbooks/workstation/metadata.rb +14 -14
  144. data/generator_files/cookbooks/workstation/recipes/browser.rb +53 -58
  145. data/generator_files/cookbooks/workstation/recipes/certs-keys.rb +41 -45
  146. data/generator_files/cookbooks/workstation/recipes/chef.rb +29 -28
  147. data/generator_files/cookbooks/workstation/recipes/default.rb +24 -21
  148. data/generator_files/cookbooks/workstation/recipes/dotnet.rb +19 -17
  149. data/generator_files/cookbooks/workstation/recipes/editor.rb +46 -18
  150. data/generator_files/cookbooks/workstation/recipes/profile.rb +14 -41
  151. data/generator_files/cookbooks/workstation/recipes/terminal.rb +11 -11
  152. data/generator_files/cookbooks/workstation/templates/default/bookmarks.html.erb +23 -23
  153. data/generator_files/cookbooks/workstation/templates/default/data_collector.rb.erb +2 -2
  154. data/generator_files/cookbooks/workstation/templates/default/knife.rb.erb +10 -10
  155. data/generator_files/cookbooks/workstation/templates/default/master_preferences.json.erb +28 -28
  156. data/generator_files/cookbooks/workstation/templates/default/ssh_config.erb +16 -16
  157. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/automate.crt +26 -26
  158. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/automate.key +27 -27
  159. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/chef.crt +26 -26
  160. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/chef.key +27 -27
  161. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/compliance.crt +26 -26
  162. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/compliance.key +27 -27
  163. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/private.pem +27 -27
  164. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/files/public.pub +1 -1
  165. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/metadata.rb +2 -2
  166. data/generator_files/cookbooks/workstation/test/fixtures/cookbooks/mock_data/recipes/default.rb +21 -21
  167. data/generator_files/cookbooks/workstation/test/integration/default/workstation_spec.rb +77 -37
  168. data/generator_files/packer/automate.json +136 -136
  169. data/generator_files/packer/build-node.json +142 -142
  170. data/generator_files/packer/chef-server.json +137 -137
  171. data/generator_files/packer/compliance.json +133 -133
  172. data/generator_files/packer/infranodes-windows.json +143 -143
  173. data/generator_files/packer/infranodes.json +134 -134
  174. data/generator_files/packer/scripts/PreSysprep.ps1 +9 -0
  175. data/generator_files/packer/workstation.json +160 -142
  176. data/generator_files/templates/arm.md.json.erb +754 -754
  177. data/generator_files/templates/arm.vhd.json.erb +630 -630
  178. data/generator_files/templates/bootstrap-aws.erb +39 -39
  179. data/generator_files/templates/cfn.json.erb +675 -674
  180. data/generator_files/wombat.yml +75 -74
  181. data/lib/wombat/aws.rb +67 -67
  182. data/lib/wombat/build.rb +392 -392
  183. data/lib/wombat/cli.rb +254 -254
  184. data/lib/wombat/common.rb +420 -420
  185. data/lib/wombat/crypto.rb +65 -65
  186. data/lib/wombat/delete.rb +67 -67
  187. data/lib/wombat/deploy.rb +128 -128
  188. data/lib/wombat/init.rb +32 -32
  189. data/lib/wombat/latest.rb +27 -27
  190. data/lib/wombat/output.rb +101 -101
  191. data/lib/wombat/update.rb +20 -20
  192. data/lib/wombat/version.rb +3 -3
  193. data/lib/wombat.rb +8 -8
  194. data/spec/functional/common_spec.rb +26 -26
  195. data/spec/spec_helper.rb +103 -103
  196. data/spec/unit/common_spec.rb +116 -116
  197. data/terraform/README.md +13 -13
  198. data/terraform/templates/terraform.tfvars.erb +12 -12
  199. data/terraform/wombat.tf +328 -328
  200. data/wombat-cli.gemspec +36 -36
  201. metadata +6 -4
data/lib/wombat/build.rb CHANGED
@@ -1,392 +1,392 @@
1
-
2
- require 'wombat/common'
3
- require 'wombat/crypto'
4
- require 'mixlib/shellout'
5
- require 'parallel'
6
- require 'ms_rest_azure'
7
- require 'azure_mgmt_resources'
8
- require 'azure_mgmt_storage'
9
- require 'azure/storage'
10
- require 'uri'
11
-
12
- module Wombat
13
- class BuildRunner
14
- include Wombat::Common
15
- include Wombat::Crypto
16
-
17
- attr_reader :templates, :builder, :parallel, :storage_access_key
18
-
19
- def initialize(opts)
20
- @templates = opts.templates.nil? ? calculate_templates : opts.templates
21
- @builder = opts.builder.nil? ? "amazon-ebs" : opts.builder
22
- @parallel = opts.parallel
23
- @wombat_yml = opts.wombat_yml unless opts.wombat_yml.nil?
24
- @debug = opts.debug
25
- @no_vendor = opts.vendor
26
- end
27
-
28
- def start
29
- if which('packer').nil?
30
- raise "packer binary not found in path, exiting..."
31
- end
32
- banner("Generating certs (if necessary)")
33
- wombat['certs'].each do |hostname|
34
- gen_x509_cert(hostname)
35
- end
36
- banner("Generating SSH keypair (if necessary)")
37
- gen_ssh_key
38
-
39
- # If running on azure ensure that the resource group and storage account exist
40
- prepare_azure if builder == "azure-arm"
41
-
42
- time = Benchmark.measure do
43
- banner("Starting build for templates: #{templates}")
44
- aws_region_check if builder == 'amazon-ebs'
45
- templates.each do |t|
46
- vendor_cookbooks(t) unless @no_vendor
47
- end
48
-
49
- if parallel.nil?
50
- build_hash.each do |k, v|
51
- build(v['template'], v['options'])
52
- end
53
- else
54
- build_parallel(templates)
55
- end
56
- end
57
-
58
- # Copy the images to the correct location if running Azure builder
59
- azure_copy_images if builder == "azure-arm"
60
-
61
- shell_out_command("say -v fred \"Wombat has made an #{build_hash.keys}\" for you") if audio?
62
- banner("Build finished in #{duration(time.real)}.")
63
- end
64
-
65
- private
66
-
67
- def prepare_azure()
68
-
69
- # Ensure that a storage acocunt has been specified, if it has not error
70
- if wombat['azure']['storage_account'].nil?
71
- puts "\nA storage account name must be specified in wombat.yml, e.g.\n openssl rand -base64 12\nEnsure all lowercase and no special characters"
72
- exit
73
- end
74
-
75
- # Using environment variables connect to azure
76
- subscription_id = ENV['AZURE_SUBSCRIPTION_ID']
77
- tenant_id = ENV['AZURE_TENANT_ID']
78
- client_id = ENV['AZURE_CLIENT_ID']
79
- client_secret = ENV['AZURE_CLIENT_SECRET']
80
-
81
- token_provider = MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret)
82
- azure_conn = MsRest::TokenCredentials.new(token_provider)
83
-
84
- # Create a resource to create the resource group if it does not exist
85
- resource_management_client = Azure::ARM::Resources::ResourceManagementClient.new(azure_conn)
86
- resource_management_client.subscription_id = subscription_id
87
-
88
- # Create a storage account client to create the stoarge account if it does not exist
89
- storage_management_client = Azure::ARM::Storage::StorageManagementClient.new(azure_conn)
90
- storage_management_client.subscription_id = subscription_id
91
-
92
- # Create the resource group
93
- create_resource_group(resource_management_client,
94
- wombat['name'],
95
- wombat['azure']['location'],
96
- wombat['owner'],
97
- wombat['azure']['tags'])
98
-
99
- # Check to see if the storage account already exists
100
- banner(format("Checking for storage account: %s", wombat['azure']['storage_account']))
101
-
102
- # Create the storage account in the resource group
103
- # NOTE: This should have a test to see if the storage account exists and it available however the
104
- # Azure Ruby SDK has an issue with the check_name_availability method and comes back with an error
105
- # This would normally be done through an ARM template, but in this case needs to exist before Packer can run
106
- storage_account = Azure::ARM::Storage::Models::StorageAccountCreateParameters.new
107
- storage_account.location = wombat['azure']['location']
108
- sku = Azure::ARM::Storage::Models::Sku.new
109
- sku.name = 'Standard_LRS'
110
- storage_account.sku = sku
111
- storage_account.kind = Azure::ARM::Storage::Models::Kind::Storage
112
-
113
- storage_management_client.storage_accounts.create(wombat['name'], wombat['azure']['storage_account'], storage_account)
114
-
115
- # Get the keys from the storage management client so that the container that the images will be moved into
116
- # can be checked for and created if required
117
- # Once Packer uses the MD features in the GO library this can be removed
118
- # ------------------------------------------------------------------------
119
- keys = storage_management_client.storage_accounts.list_keys(wombat['name'], wombat['azure']['storage_account'])
120
- @storage_access_key = keys.keys[0].value
121
-
122
- # Use the key to configure the storage library
123
- Azure::Storage.setup(:storage_account_name => wombat['azure']['storage_account'], :storage_access_key => storage_access_key)
124
- blobs = Azure::Storage::Blob::BlobService.new
125
-
126
- # Get all the containers to determine if the one that is required already exists
127
- container_names = []
128
- blobs.list_containers().each do |container|
129
- container_names.push(container.name)
130
- end
131
-
132
- # create the container if it does not exist
133
- container_name = "mdimages"
134
- if !container_names.include?(container_name)
135
- info("Creating storage container")
136
- container = blobs.create_container(container_name)
137
- end
138
- # ------------------------------------------------------------------------
139
-
140
- end
141
-
142
- # Packer does not put custom images into a location that is supported by Managed Disks
143
- # So to be able to use the MD feature of Azure, the images have to be copied to a location that
144
- # does work. This method is responsible for doing this work.
145
- #
146
- # @author Russell Seymour
147
- def azure_copy_images()
148
-
149
- container_name = "mdimages"
150
-
151
- Azure::Storage.setup(:storage_account_name => wombat['azure']['storage_account'], :storage_access_key => storage_access_key)
152
- blobs = Azure::Storage::Blob::BlobService.new
153
-
154
- # Read the logs for azure
155
- path = "#{wombat['conf']['log_dir']}/azure*.log"
156
- logs = Dir.glob(path).reject { |l| !l.match(wombat['linux']) }
157
-
158
- # iterate around the log files and get the image location
159
- time = Benchmark.measure do
160
- logs.each do |log|
161
-
162
- # get the image uri
163
- url = File.read(log).split("\n").grep(/OSDiskUri:/) {|x| x.split[1]}.last
164
-
165
- next if url.nil?
166
-
167
- # Use the storage library to copy the image from source to destination
168
- uri = URI(url)
169
-
170
- blob_name = uri.path.split(/\//).last
171
-
172
- info "Copying: #{blob_name}"
173
-
174
- status = blobs.copy_blob_from_uri(container_name, blob_name, url)
175
-
176
- # Append the new location for the image to the log file
177
- append_text = format("\nManagedDiskOSDiskUri: https://%s.blob.core.windows.net/%s/%s", wombat['azure']['storage_account'], container_name, blob_name)
178
- File.open(log, 'a') { |f| f.write(append_text) }
179
-
180
- end
181
- end
182
-
183
- info (format("Images copied in %s", duration(time.real)))
184
-
185
- end
186
-
187
- def build(template, options)
188
- bootstrap_aws if options['os'] == 'windows'
189
- shell_out_command(packer_build_cmd(template, builder, options))
190
- end
191
-
192
- def build_parallel(templates)
193
- Parallel.map(build_hash.keys, in_threads: build_hash.count) do |name|
194
- build(build_hash[name]['template'], build_hash[name]['options'])
195
- end
196
- end
197
-
198
- def build_hash
199
- proc_hash = {}
200
- templates.each do |template_name|
201
- if template_name =~ /infranodes/
202
- infranodes.each do |name, _rl|
203
- next if name.empty?
204
- proc_hash[name] = {
205
- 'template' => template_name,
206
- 'options' => {
207
- 'node-name' => name,
208
- 'os' => wombat['infranodes'][name]['platform']
209
- }
210
- }
211
- end
212
- elsif template_name =~ /build-node/
213
- build_nodes.each do |name, num|
214
- proc_hash[name] = {
215
- 'template' => template_name,
216
- 'options' => {
217
- 'node-number' => num
218
- }
219
- }
220
- end
221
- elsif template_name =~ /workstation/
222
- workstations.each do |name, num|
223
- proc_hash[name] = {
224
- 'template' => template_name,
225
- 'options' => {
226
- 'os' => wombat['workstations']['platform'],
227
- 'workstation-number' => num
228
- }
229
- }
230
- end
231
- else
232
- proc_hash[template_name] = {
233
- 'template' => template_name,
234
- 'options' => {}
235
- }
236
- end
237
- end
238
- proc_hash
239
- end
240
-
241
- def a_to_s(*args)
242
- clean_array(*args).join(" ")
243
- end
244
-
245
- def clean_array(*args)
246
- args.flatten.reject { |i| i.nil? || i == "" }.map(&:to_s)
247
- end
248
-
249
- def b_to_c(builder)
250
- case builder
251
- when 'amazon-ebs'
252
- 'aws'
253
- when 'googlecompute'
254
- 'gce'
255
- when 'azure-arm'
256
- 'azure'
257
- end
258
- end
259
-
260
- def shell_out_command(command)
261
- cmd = Mixlib::ShellOut.new(a_to_s(command), :timeout => conf['timeout'], live_stream: STDOUT)
262
- cmd.run_command
263
- cmd
264
- end
265
-
266
- def aws_region_check
267
- if ENV['AWS_REGION']
268
- banner("Region set by environment: #{ENV['AWS_REGION']}")
269
- else
270
- banner("$AWS_REGION not set, setting to #{wombat['aws']['region']}")
271
- ENV['AWS_REGION'] = wombat['aws']['region']
272
- end
273
- end
274
-
275
- def vendor_cookbooks(template)
276
- banner "Vendoring cookbooks for #{template}"
277
-
278
- if template =~ /.*-windows/
279
- base = template.split('-')[0]
280
- else
281
- base = template.split('.json')[0].tr('-', '_')
282
- end
283
- rm_cmd = "rm -rf #{conf['cookbook_dir']}/#{base}/Berksfile.lock vendored-cookbooks/#{base}"
284
- shell_out_command(rm_cmd)
285
- vendor_cmd = "berks vendor -q -b #{conf['cookbook_dir']}/#{base}/Berksfile vendored-cookbooks/#{base}"
286
- shell_out_command(vendor_cmd)
287
- end
288
-
289
- def log(template, builder, options)
290
- cloud = b_to_c(builder)
291
- case template
292
- when /automate/
293
- log_name = "#{cloud}-automate-#{linux}"
294
- when /chef-server/
295
- log_name = "#{cloud}-chef-server-#{linux}"
296
- when /compliance/
297
- log_name = "#{cloud}-compliance-#{linux}"
298
- when /build-node/
299
- log_name = "#{cloud}-build-node-#{options['node-number']}-#{linux}"
300
- when /workstation/
301
- log_name = "#{cloud}-workstation-#{options['workstation-number']}-#{linux}"
302
- when /infranodes/
303
- if options['os'] =~ /windows/
304
- log_name = "#{cloud}-infranodes-#{options['node-name']}-windows"
305
- else
306
- log_name = "#{cloud}-infranodes-#{options['node-name']}-#{linux}"
307
- end
308
- end
309
- log_file = "#{conf['log_dir']}/#{log_name}.log"
310
- end
311
-
312
- def which(cmd)
313
- exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
314
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
315
- exts.each { |ext|
316
- exe = File.join(path, "#{cmd}#{ext}")
317
- return exe if File.executable?(exe) && !File.directory?(exe)
318
- }
319
- end
320
- return nil
321
- end
322
-
323
- def base_image(template, builder, options)
324
- cloud = b_to_c(builder)
325
- if template =~ /workstation/
326
- wombat[cloud]['source_image']['windows']
327
- elsif template =~ /infranodes/
328
- if options['os'] == 'windows'
329
- wombat[cloud]['source_image']['windows']
330
- else
331
- wombat[cloud]['source_image'][linux]
332
- end
333
- else
334
- wombat[cloud]['source_image'][linux]
335
- end
336
- end
337
-
338
- def packer_build_cmd(template, builder, options)
339
- create_infranodes_json
340
- Dir.mkdir(conf['log_dir'], 0755) unless File.exist?(conf['log_dir'])
341
-
342
- cmd = %W(packer build #{conf['packer_dir']}/#{template}.json | tee #{log(template, builder, options)})
343
- cmd.insert(2, "--only #{builder}")
344
- cmd.insert(2, "--var org=#{wombat['org']}")
345
- cmd.insert(2, "--var domain=#{wombat['domain']}")
346
- cmd.insert(2, "--var domain_prefix=#{wombat['domain_prefix']}")
347
- cmd.insert(2, "--var enterprise=#{wombat['enterprise']}")
348
- cmd.insert(2, "--var chefdk=#{wombat['products']['chefdk']}")
349
- cmd.insert(2, "--var chef_ver=#{wombat['products']['chef'].split('-')[1]}")
350
- cmd.insert(2, "--var chef_channel=#{wombat['products']['chef'].split('-')[0]}")
351
- cmd.insert(2, "--var automate=#{wombat['products']['automate']}")
352
- cmd.insert(2, "--var compliance=#{wombat['products']['compliance']}")
353
- cmd.insert(2, "--var chef-server=#{wombat['products']['chef-server']}")
354
- cmd.insert(2, "--var push-jobs-server=#{wombat['products']['push-jobs-server']}")
355
- cmd.insert(2, "--var manage=#{wombat['products']['manage']}")
356
- cmd.insert(2, "--var node-name=#{options['node-name']}") if template =~ /infranodes/
357
- cmd.insert(2, "--var node-number=#{options['node-number']}") if template =~ /build-node/
358
- cmd.insert(2, "--var build-nodes=#{wombat['build-nodes']['count']}")
359
- cmd.insert(2, "--var winrm_password=#{wombat['workstations']['password']}")
360
- cmd.insert(2, "--var winrm_username=Administrator")
361
- cmd.insert(2, "--var workstation-number=#{options['workstation-number']}") if template =~ /workstation/
362
- cmd.insert(2, "--var workstations=#{wombat['workstations']['count']}")
363
- cmd.insert(2, "--var aws_source_ami=#{base_image(template, builder, options)}") if builder =~ /amazon-ebs/
364
- cmd.insert(2, "--var gce_source_image=#{base_image(template, builder, options)}") if builder =~ /googlecompute/
365
- cmd.insert(2, "--var azure_location=#{wombat['azure']['location']}")
366
- cmd.insert(2, "--var ssh_username=#{linux}")
367
- cmd.insert(2, "--debug") if @debug
368
-
369
- # If running with the azure-arm builder add the necessary arguments
370
- if builder =~ /azure-arm/
371
-
372
- # Get the information about the base image to use
373
- base_image = base_image(template, builder, options)
374
-
375
- if !base_image.nil?
376
- # This is a URN so it needs to be split out using : as delimiters
377
- base_image_parts = base_image.split(/:/)
378
-
379
- cmd.insert(2, "--var azure_image_publisher=#{base_image_parts[0]}")
380
- cmd.insert(2, "--var azure_image_offer=#{base_image_parts[1]}")
381
- cmd.insert(2, "--var azure_image_sku=#{base_image_parts[2]}")
382
- cmd.insert(2, "--var azure_image_version=#{base_image_parts[3]}") if base_image_parts.length == 4
383
- end
384
-
385
- cmd.insert(2, "--var azure_resource_group=#{wombat['name']}")
386
- cmd.insert(2, "--var azure_storage_account=#{wombat['azure']['storage_account']}")
387
- end
388
-
389
- cmd.join(' ')
390
- end
391
- end
392
- end
1
+
2
+ require 'wombat/common'
3
+ require 'wombat/crypto'
4
+ require 'mixlib/shellout'
5
+ require 'parallel'
6
+ require 'ms_rest_azure'
7
+ require 'azure_mgmt_resources'
8
+ require 'azure_mgmt_storage'
9
+ require 'azure/storage'
10
+ require 'uri'
11
+
12
+ module Wombat
13
+ class BuildRunner
14
+ include Wombat::Common
15
+ include Wombat::Crypto
16
+
17
+ attr_reader :templates, :builder, :parallel, :storage_access_key
18
+
19
+ def initialize(opts)
20
+ @templates = opts.templates.nil? ? calculate_templates : opts.templates
21
+ @builder = opts.builder.nil? ? "amazon-ebs" : opts.builder
22
+ @parallel = opts.parallel
23
+ @wombat_yml = opts.wombat_yml unless opts.wombat_yml.nil?
24
+ @debug = opts.debug
25
+ @no_vendor = opts.vendor
26
+ end
27
+
28
+ def start
29
+ if which('packer').nil?
30
+ raise "packer binary not found in path, exiting..."
31
+ end
32
+ banner("Generating certs (if necessary)")
33
+ wombat['certs'].each do |hostname|
34
+ gen_x509_cert(hostname)
35
+ end
36
+ banner("Generating SSH keypair (if necessary)")
37
+ gen_ssh_key
38
+
39
+ # If running on azure ensure that the resource group and storage account exist
40
+ prepare_azure if builder == "azure-arm"
41
+
42
+ time = Benchmark.measure do
43
+ banner("Starting build for templates: #{templates}")
44
+ aws_region_check if builder == 'amazon-ebs'
45
+ templates.each do |t|
46
+ vendor_cookbooks(t) unless @no_vendor
47
+ end
48
+
49
+ if parallel.nil?
50
+ build_hash.each do |k, v|
51
+ build(v['template'], v['options'])
52
+ end
53
+ else
54
+ build_parallel(templates)
55
+ end
56
+ end
57
+
58
+ # Copy the images to the correct location if running Azure builder
59
+ azure_copy_images if builder == "azure-arm"
60
+
61
+ shell_out_command("say -v fred \"Wombat has made an #{build_hash.keys}\" for you") if audio?
62
+ banner("Build finished in #{duration(time.real)}.")
63
+ end
64
+
65
+ private
66
+
67
+ def prepare_azure()
68
+
69
+ # Ensure that a storage acocunt has been specified, if it has not error
70
+ if wombat['azure']['storage_account'].nil?
71
+ puts "\nA storage account name must be specified in wombat.yml, e.g.\n openssl rand -base64 12\nEnsure all lowercase and no special characters"
72
+ exit
73
+ end
74
+
75
+ # Using environment variables connect to azure
76
+ subscription_id = ENV['AZURE_SUBSCRIPTION_ID']
77
+ tenant_id = ENV['AZURE_TENANT_ID']
78
+ client_id = ENV['AZURE_CLIENT_ID']
79
+ client_secret = ENV['AZURE_CLIENT_SECRET']
80
+
81
+ token_provider = MsRestAzure::ApplicationTokenProvider.new(tenant_id, client_id, client_secret)
82
+ azure_conn = MsRest::TokenCredentials.new(token_provider)
83
+
84
+ # Create a resource to create the resource group if it does not exist
85
+ resource_management_client = Azure::ARM::Resources::ResourceManagementClient.new(azure_conn)
86
+ resource_management_client.subscription_id = subscription_id
87
+
88
+ # Create a storage account client to create the stoarge account if it does not exist
89
+ storage_management_client = Azure::ARM::Storage::StorageManagementClient.new(azure_conn)
90
+ storage_management_client.subscription_id = subscription_id
91
+
92
+ # Create the resource group
93
+ create_resource_group(resource_management_client,
94
+ wombat['name'],
95
+ wombat['azure']['location'],
96
+ wombat['owner'],
97
+ wombat['azure']['tags'])
98
+
99
+ # Check to see if the storage account already exists
100
+ banner(format("Checking for storage account: %s", wombat['azure']['storage_account']))
101
+
102
+ # Create the storage account in the resource group
103
+ # NOTE: This should have a test to see if the storage account exists and it available however the
104
+ # Azure Ruby SDK has an issue with the check_name_availability method and comes back with an error
105
+ # This would normally be done through an ARM template, but in this case needs to exist before Packer can run
106
+ storage_account = Azure::ARM::Storage::Models::StorageAccountCreateParameters.new
107
+ storage_account.location = wombat['azure']['location']
108
+ sku = Azure::ARM::Storage::Models::Sku.new
109
+ sku.name = 'Standard_LRS'
110
+ storage_account.sku = sku
111
+ storage_account.kind = Azure::ARM::Storage::Models::Kind::Storage
112
+
113
+ storage_management_client.storage_accounts.create(wombat['name'], wombat['azure']['storage_account'], storage_account)
114
+
115
+ # Get the keys from the storage management client so that the container that the images will be moved into
116
+ # can be checked for and created if required
117
+ # Once Packer uses the MD features in the GO library this can be removed
118
+ # ------------------------------------------------------------------------
119
+ keys = storage_management_client.storage_accounts.list_keys(wombat['name'], wombat['azure']['storage_account'])
120
+ @storage_access_key = keys.keys[0].value
121
+
122
+ # Use the key to configure the storage library
123
+ Azure::Storage.setup(:storage_account_name => wombat['azure']['storage_account'], :storage_access_key => storage_access_key)
124
+ blobs = Azure::Storage::Blob::BlobService.new
125
+
126
+ # Get all the containers to determine if the one that is required already exists
127
+ container_names = []
128
+ blobs.list_containers().each do |container|
129
+ container_names.push(container.name)
130
+ end
131
+
132
+ # create the container if it does not exist
133
+ container_name = "mdimages"
134
+ if !container_names.include?(container_name)
135
+ info("Creating storage container")
136
+ container = blobs.create_container(container_name)
137
+ end
138
+ # ------------------------------------------------------------------------
139
+
140
+ end
141
+
142
+ # Packer does not put custom images into a location that is supported by Managed Disks
143
+ # So to be able to use the MD feature of Azure, the images have to be copied to a location that
144
+ # does work. This method is responsible for doing this work.
145
+ #
146
+ # @author Russell Seymour
147
+ def azure_copy_images()
148
+
149
+ container_name = "mdimages"
150
+
151
+ Azure::Storage.setup(:storage_account_name => wombat['azure']['storage_account'], :storage_access_key => storage_access_key)
152
+ blobs = Azure::Storage::Blob::BlobService.new
153
+
154
+ # Read the logs for azure
155
+ path = "#{wombat['conf']['log_dir']}/azure*.log"
156
+ logs = Dir.glob(path).reject { |l| !l.match(wombat['linux']) }
157
+
158
+ # iterate around the log files and get the image location
159
+ time = Benchmark.measure do
160
+ logs.each do |log|
161
+
162
+ # get the image uri
163
+ url = File.read(log).split("\n").grep(/OSDiskUri:/) {|x| x.split[1]}.last
164
+
165
+ next if url.nil?
166
+
167
+ # Use the storage library to copy the image from source to destination
168
+ uri = URI(url)
169
+
170
+ blob_name = uri.path.split(/\//).last
171
+
172
+ info "Copying: #{blob_name}"
173
+
174
+ status = blobs.copy_blob_from_uri(container_name, blob_name, url)
175
+
176
+ # Append the new location for the image to the log file
177
+ append_text = format("\nManagedDiskOSDiskUri: https://%s.blob.core.windows.net/%s/%s", wombat['azure']['storage_account'], container_name, blob_name)
178
+ File.open(log, 'a') { |f| f.write(append_text) }
179
+
180
+ end
181
+ end
182
+
183
+ info (format("Images copied in %s", duration(time.real)))
184
+
185
+ end
186
+
187
+ def build(template, options)
188
+ bootstrap_aws if options['os'] == 'windows'
189
+ shell_out_command(packer_build_cmd(template, builder, options))
190
+ end
191
+
192
+ def build_parallel(templates)
193
+ Parallel.map(build_hash.keys, in_threads: build_hash.count) do |name|
194
+ build(build_hash[name]['template'], build_hash[name]['options'])
195
+ end
196
+ end
197
+
198
+ def build_hash
199
+ proc_hash = {}
200
+ templates.each do |template_name|
201
+ if template_name =~ /infranodes/
202
+ infranodes.each do |name, _rl|
203
+ next if name.empty?
204
+ proc_hash[name] = {
205
+ 'template' => template_name,
206
+ 'options' => {
207
+ 'node-name' => name,
208
+ 'os' => wombat['infranodes'][name]['platform']
209
+ }
210
+ }
211
+ end
212
+ elsif template_name =~ /build-node/
213
+ build_nodes.each do |name, num|
214
+ proc_hash[name] = {
215
+ 'template' => template_name,
216
+ 'options' => {
217
+ 'node-number' => num
218
+ }
219
+ }
220
+ end
221
+ elsif template_name =~ /workstation/
222
+ workstations.each do |name, num|
223
+ proc_hash[name] = {
224
+ 'template' => template_name,
225
+ 'options' => {
226
+ 'os' => wombat['workstations']['platform'],
227
+ 'workstation-number' => num
228
+ }
229
+ }
230
+ end
231
+ else
232
+ proc_hash[template_name] = {
233
+ 'template' => template_name,
234
+ 'options' => {}
235
+ }
236
+ end
237
+ end
238
+ proc_hash
239
+ end
240
+
241
+ def a_to_s(*args)
242
+ clean_array(*args).join(" ")
243
+ end
244
+
245
+ def clean_array(*args)
246
+ args.flatten.reject { |i| i.nil? || i == "" }.map(&:to_s)
247
+ end
248
+
249
+ def b_to_c(builder)
250
+ case builder
251
+ when 'amazon-ebs'
252
+ 'aws'
253
+ when 'googlecompute'
254
+ 'gce'
255
+ when 'azure-arm'
256
+ 'azure'
257
+ end
258
+ end
259
+
260
+ def shell_out_command(command)
261
+ cmd = Mixlib::ShellOut.new(a_to_s(command), :timeout => conf['timeout'], live_stream: STDOUT)
262
+ cmd.run_command
263
+ cmd
264
+ end
265
+
266
+ def aws_region_check
267
+ if ENV['AWS_REGION']
268
+ banner("Region set by environment: #{ENV['AWS_REGION']}")
269
+ else
270
+ banner("$AWS_REGION not set, setting to #{wombat['aws']['region']}")
271
+ ENV['AWS_REGION'] = wombat['aws']['region']
272
+ end
273
+ end
274
+
275
+ def vendor_cookbooks(template)
276
+ banner "Vendoring cookbooks for #{template}"
277
+
278
+ if template =~ /.*-windows/
279
+ base = template.split('-')[0]
280
+ else
281
+ base = template.split('.json')[0].tr('-', '_')
282
+ end
283
+ rm_cmd = "rm -rf #{conf['cookbook_dir']}/#{base}/Berksfile.lock vendored-cookbooks/#{base}"
284
+ shell_out_command(rm_cmd)
285
+ vendor_cmd = "berks vendor -q -b #{conf['cookbook_dir']}/#{base}/Berksfile vendored-cookbooks/#{base}"
286
+ shell_out_command(vendor_cmd)
287
+ end
288
+
289
+ def log(template, builder, options)
290
+ cloud = b_to_c(builder)
291
+ case template
292
+ when /automate/
293
+ log_name = "#{cloud}-automate-#{linux}"
294
+ when /chef-server/
295
+ log_name = "#{cloud}-chef-server-#{linux}"
296
+ when /compliance/
297
+ log_name = "#{cloud}-compliance-#{linux}"
298
+ when /build-node/
299
+ log_name = "#{cloud}-build-node-#{options['node-number']}-#{linux}"
300
+ when /workstation/
301
+ log_name = "#{cloud}-workstation-#{options['workstation-number']}-#{linux}"
302
+ when /infranodes/
303
+ if options['os'] =~ /windows/
304
+ log_name = "#{cloud}-infranodes-#{options['node-name']}-windows"
305
+ else
306
+ log_name = "#{cloud}-infranodes-#{options['node-name']}-#{linux}"
307
+ end
308
+ end
309
+ log_file = "#{conf['log_dir']}/#{log_name}.log"
310
+ end
311
+
312
+ def which(cmd)
313
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
314
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
315
+ exts.each { |ext|
316
+ exe = File.join(path, "#{cmd}#{ext}")
317
+ return exe if File.executable?(exe) && !File.directory?(exe)
318
+ }
319
+ end
320
+ return nil
321
+ end
322
+
323
+ def base_image(template, builder, options)
324
+ cloud = b_to_c(builder)
325
+ if template =~ /workstation/
326
+ wombat[cloud]['source_image']['windows']
327
+ elsif template =~ /infranodes/
328
+ if options['os'] == 'windows'
329
+ wombat[cloud]['source_image']['windows']
330
+ else
331
+ wombat[cloud]['source_image'][linux]
332
+ end
333
+ else
334
+ wombat[cloud]['source_image'][linux]
335
+ end
336
+ end
337
+
338
+ def packer_build_cmd(template, builder, options)
339
+ create_infranodes_json
340
+ Dir.mkdir(conf['log_dir'], 0755) unless File.exist?(conf['log_dir'])
341
+
342
+ cmd = %W(packer build #{conf['packer_dir']}/#{template}.json | tee #{log(template, builder, options)})
343
+ cmd.insert(2, "--only #{builder}")
344
+ cmd.insert(2, "--var org=#{wombat['org']}")
345
+ cmd.insert(2, "--var domain=#{wombat['domain']}")
346
+ cmd.insert(2, "--var domain_prefix=#{wombat['domain_prefix']}")
347
+ cmd.insert(2, "--var enterprise=#{wombat['enterprise']}")
348
+ cmd.insert(2, "--var chefdk=#{wombat['products']['chefdk']}")
349
+ cmd.insert(2, "--var chef_ver=#{wombat['products']['chef'].split('-')[1]}")
350
+ cmd.insert(2, "--var chef_channel=#{wombat['products']['chef'].split('-')[0]}")
351
+ cmd.insert(2, "--var automate=#{wombat['products']['automate']}")
352
+ cmd.insert(2, "--var compliance=#{wombat['products']['compliance']}")
353
+ cmd.insert(2, "--var chef-server=#{wombat['products']['chef-server']}")
354
+ cmd.insert(2, "--var push-jobs-server=#{wombat['products']['push-jobs-server']}")
355
+ cmd.insert(2, "--var manage=#{wombat['products']['manage']}")
356
+ cmd.insert(2, "--var node-name=#{options['node-name']}") if template =~ /infranodes/
357
+ cmd.insert(2, "--var node-number=#{options['node-number']}") if template =~ /build-node/
358
+ cmd.insert(2, "--var build-nodes=#{wombat['build-nodes']['count']}")
359
+ cmd.insert(2, "--var winrm_password=#{wombat['workstations']['password']}")
360
+ cmd.insert(2, "--var winrm_username=Administrator")
361
+ cmd.insert(2, "--var workstation-number=#{options['workstation-number']}") if template =~ /workstation/
362
+ cmd.insert(2, "--var workstations=#{wombat['workstations']['count']}")
363
+ cmd.insert(2, "--var aws_source_ami=#{base_image(template, builder, options)}") if builder =~ /amazon-ebs/
364
+ cmd.insert(2, "--var gce_source_image=#{base_image(template, builder, options)}") if builder =~ /googlecompute/
365
+ cmd.insert(2, "--var azure_location=#{wombat['azure']['location']}")
366
+ cmd.insert(2, "--var ssh_username=#{linux}")
367
+ cmd.insert(2, "--debug") if @debug
368
+
369
+ # If running with the azure-arm builder add the necessary arguments
370
+ if builder =~ /azure-arm/
371
+
372
+ # Get the information about the base image to use
373
+ base_image = base_image(template, builder, options)
374
+
375
+ if !base_image.nil?
376
+ # This is a URN so it needs to be split out using : as delimiters
377
+ base_image_parts = base_image.split(/:/)
378
+
379
+ cmd.insert(2, "--var azure_image_publisher=#{base_image_parts[0]}")
380
+ cmd.insert(2, "--var azure_image_offer=#{base_image_parts[1]}")
381
+ cmd.insert(2, "--var azure_image_sku=#{base_image_parts[2]}")
382
+ cmd.insert(2, "--var azure_image_version=#{base_image_parts[3]}") if base_image_parts.length == 4
383
+ end
384
+
385
+ cmd.insert(2, "--var azure_resource_group=#{wombat['name']}")
386
+ cmd.insert(2, "--var azure_storage_account=#{wombat['azure']['storage_account']}")
387
+ end
388
+
389
+ cmd.join(' ')
390
+ end
391
+ end
392
+ end