bosh_cli 1.0.3 → 1.5.0.pre.1113
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/bosh +0 -9
- data/lib/cli.rb +69 -64
- data/lib/cli/backup_destination_path.rb +33 -0
- data/lib/cli/base_command.rb +57 -56
- data/lib/cli/blob_manager.rb +12 -12
- data/lib/cli/changeset_helper.rb +6 -7
- data/lib/cli/client/director.rb +724 -0
- data/lib/cli/command_handler.rb +6 -7
- data/lib/cli/commands/backup.rb +39 -0
- data/lib/cli/commands/biff.rb +42 -21
- data/lib/cli/commands/blob_management.rb +1 -1
- data/lib/cli/commands/cloudcheck.rb +11 -13
- data/lib/cli/commands/deployment.rb +53 -37
- data/lib/cli/commands/help.rb +3 -2
- data/lib/cli/commands/job_management.rb +67 -103
- data/lib/cli/commands/job_rename.rb +6 -8
- data/lib/cli/commands/log_management.rb +78 -55
- data/lib/cli/commands/maintenance.rb +36 -30
- data/lib/cli/commands/misc.rb +72 -51
- data/lib/cli/commands/package.rb +2 -2
- data/lib/cli/commands/property_management.rb +10 -12
- data/lib/cli/commands/release.rb +236 -133
- data/lib/cli/commands/snapshot.rb +93 -0
- data/lib/cli/commands/ssh.rb +216 -213
- data/lib/cli/commands/stemcell.rb +46 -34
- data/lib/cli/commands/task.rb +2 -2
- data/lib/cli/commands/user.rb +27 -3
- data/lib/cli/commands/vm.rb +28 -0
- data/lib/cli/commands/vms.rb +81 -23
- data/lib/cli/config.rb +6 -2
- data/lib/cli/core_ext.rb +31 -30
- data/lib/cli/deployment_helper.rb +134 -159
- data/lib/cli/deployment_manifest.rb +66 -0
- data/lib/cli/deployment_manifest_compiler.rb +0 -3
- data/lib/cli/event_log_renderer.rb +10 -10
- data/lib/cli/file_with_progress_bar.rb +52 -0
- data/lib/cli/job_builder.rb +1 -1
- data/lib/cli/job_command_args.rb +23 -0
- data/lib/cli/job_property_collection.rb +4 -7
- data/lib/cli/job_property_validator.rb +22 -12
- data/lib/cli/job_state.rb +54 -0
- data/lib/cli/line_wrap.rb +54 -0
- data/lib/cli/packaging_helper.rb +10 -10
- data/lib/cli/release.rb +18 -15
- data/lib/cli/release_builder.rb +9 -4
- data/lib/cli/release_compiler.rb +9 -9
- data/lib/cli/release_tarball.rb +3 -6
- data/lib/cli/resurrection.rb +31 -0
- data/lib/cli/runner.rb +56 -30
- data/lib/cli/stemcell.rb +25 -10
- data/lib/cli/task_log_renderer.rb +1 -1
- data/lib/cli/task_tracker.rb +10 -9
- data/lib/cli/validation.rb +3 -1
- data/lib/cli/version.rb +1 -1
- data/lib/cli/version_calc.rb +5 -18
- data/lib/cli/versions_index.rb +1 -1
- data/lib/cli/vm_state.rb +43 -0
- data/lib/cli/yaml_helper.rb +26 -35
- metadata +75 -208
- data/Rakefile +0 -56
- data/lib/cli/director.rb +0 -628
- data/spec/assets/biff/bad_gateway_config.yml +0 -28
- data/spec/assets/biff/good_simple_config.yml +0 -63
- data/spec/assets/biff/good_simple_golden_config.yml +0 -63
- data/spec/assets/biff/good_simple_template.erb +0 -69
- data/spec/assets/biff/ip_out_of_range.yml +0 -63
- data/spec/assets/biff/multiple_subnets_config.yml +0 -40
- data/spec/assets/biff/network_only_template.erb +0 -34
- data/spec/assets/biff/no_cc_config.yml +0 -27
- data/spec/assets/biff/no_range_config.yml +0 -27
- data/spec/assets/biff/no_subnet_config.yml +0 -16
- data/spec/assets/biff/ok_network_config.yml +0 -30
- data/spec/assets/biff/properties_template.erb +0 -6
- data/spec/assets/config/atmos/config/final.yml +0 -6
- data/spec/assets/config/atmos/config/private.yml +0 -4
- data/spec/assets/config/bad-providers/config/final.yml +0 -5
- data/spec/assets/config/bad-providers/config/private.yml +0 -4
- data/spec/assets/config/deprecation/config/final.yml +0 -5
- data/spec/assets/config/deprecation/config/private.yml +0 -2
- data/spec/assets/config/local/config/final.yml +0 -5
- data/spec/assets/config/local/config/private.yml +0 -1
- data/spec/assets/config/s3/config/final.yml +0 -5
- data/spec/assets/config/s3/config/private.yml +0 -5
- data/spec/assets/config/swift-hp/config/final.yml +0 -6
- data/spec/assets/config/swift-hp/config/private.yml +0 -7
- data/spec/assets/config/swift-rackspace/config/final.yml +0 -6
- data/spec/assets/config/swift-rackspace/config/private.yml +0 -6
- data/spec/assets/deployment.MF +0 -0
- data/spec/assets/plugins/bosh/cli/commands/echo.rb +0 -43
- data/spec/assets/plugins/bosh/cli/commands/ruby.rb +0 -24
- data/spec/assets/release/jobs/cacher.tgz +0 -0
- data/spec/assets/release/jobs/cacher/config/file1.conf +0 -0
- data/spec/assets/release/jobs/cacher/config/file2.conf +0 -0
- data/spec/assets/release/jobs/cacher/job.MF +0 -6
- data/spec/assets/release/jobs/cacher/monit +0 -1
- data/spec/assets/release/jobs/cleaner.tgz +0 -0
- data/spec/assets/release/jobs/cleaner/job.MF +0 -4
- data/spec/assets/release/jobs/cleaner/monit +0 -1
- data/spec/assets/release/jobs/sweeper.tgz +0 -0
- data/spec/assets/release/jobs/sweeper/config/test.conf +0 -1
- data/spec/assets/release/jobs/sweeper/job.MF +0 -5
- data/spec/assets/release/jobs/sweeper/monit +0 -1
- data/spec/assets/release/packages/mutator.tar.gz +0 -0
- data/spec/assets/release/packages/stuff.tgz +0 -0
- data/spec/assets/release/release.MF +0 -17
- data/spec/assets/release_invalid_checksum.tgz +0 -0
- data/spec/assets/release_invalid_jobs.tgz +0 -0
- data/spec/assets/release_no_name.tgz +0 -0
- data/spec/assets/release_no_version.tgz +0 -0
- data/spec/assets/stemcell/image +0 -1
- data/spec/assets/stemcell/stemcell.MF +0 -6
- data/spec/assets/stemcell_invalid_mf.tgz +0 -0
- data/spec/assets/stemcell_no_image.tgz +0 -0
- data/spec/assets/valid_release.tgz +0 -0
- data/spec/assets/valid_stemcell.tgz +0 -0
- data/spec/spec_helper.rb +0 -28
- data/spec/unit/base_command_spec.rb +0 -87
- data/spec/unit/biff_spec.rb +0 -172
- data/spec/unit/blob_manager_spec.rb +0 -288
- data/spec/unit/cache_spec.rb +0 -36
- data/spec/unit/cli_commands_spec.rb +0 -356
- data/spec/unit/config_spec.rb +0 -125
- data/spec/unit/core_ext_spec.rb +0 -81
- data/spec/unit/dependency_helper_spec.rb +0 -52
- data/spec/unit/deployment_manifest_compiler_spec.rb +0 -63
- data/spec/unit/deployment_manifest_spec.rb +0 -153
- data/spec/unit/director_spec.rb +0 -471
- data/spec/unit/director_task_spec.rb +0 -48
- data/spec/unit/event_log_renderer_spec.rb +0 -171
- data/spec/unit/hash_changeset_spec.rb +0 -73
- data/spec/unit/job_builder_spec.rb +0 -455
- data/spec/unit/job_property_collection_spec.rb +0 -111
- data/spec/unit/job_property_validator_spec.rb +0 -7
- data/spec/unit/job_rename_spec.rb +0 -200
- data/spec/unit/package_builder_spec.rb +0 -593
- data/spec/unit/release_builder_spec.rb +0 -120
- data/spec/unit/release_spec.rb +0 -173
- data/spec/unit/release_tarball_spec.rb +0 -29
- data/spec/unit/runner_spec.rb +0 -7
- data/spec/unit/ssh_spec.rb +0 -84
- data/spec/unit/stemcell_spec.rb +0 -17
- data/spec/unit/task_tracker_spec.rb +0 -131
- data/spec/unit/version_calc_spec.rb +0 -27
- data/spec/unit/versions_index_spec.rb +0 -144
@@ -5,7 +5,6 @@ module Bosh::Cli
|
|
5
5
|
include VersionCalc
|
6
6
|
|
7
7
|
def prepare_deployment_manifest(options = {})
|
8
|
-
# TODO: extract to helper class
|
9
8
|
deployment_required
|
10
9
|
manifest_filename = deployment
|
11
10
|
|
@@ -16,11 +15,11 @@ module Bosh::Cli
|
|
16
15
|
manifest = load_yaml_file(manifest_filename)
|
17
16
|
manifest_yaml = File.read(manifest_filename)
|
18
17
|
|
19
|
-
if manifest[
|
20
|
-
err(
|
18
|
+
if manifest['name'].blank?
|
19
|
+
err('Deployment name not found in the deployment manifest')
|
21
20
|
end
|
22
21
|
|
23
|
-
if manifest[
|
22
|
+
if manifest['target']
|
24
23
|
err(manifest_target_upgrade_notice)
|
25
24
|
end
|
26
25
|
|
@@ -29,40 +28,40 @@ module Bosh::Cli
|
|
29
28
|
properties = {}
|
30
29
|
|
31
30
|
begin
|
32
|
-
say(
|
33
|
-
properties = director.list_properties(manifest[
|
31
|
+
say('Getting deployment properties from director...')
|
32
|
+
properties = director.list_properties(manifest['name'])
|
34
33
|
rescue Bosh::Cli::DirectorError
|
35
|
-
say(
|
36
|
-
|
34
|
+
say('Unable to get properties list from director, ' +
|
35
|
+
'trying without it...')
|
37
36
|
end
|
38
37
|
|
39
|
-
say(
|
38
|
+
say('Compiling deployment manifest...')
|
40
39
|
compiler.properties = properties.inject({}) do |hash, property|
|
41
|
-
hash[property[
|
40
|
+
hash[property['name']] = property['value']
|
42
41
|
hash
|
43
42
|
end
|
44
43
|
|
45
|
-
manifest =
|
44
|
+
manifest = Psych.load(compiler.result)
|
46
45
|
end
|
47
46
|
|
48
|
-
if manifest[
|
47
|
+
if manifest['name'].blank? || manifest['director_uuid'].blank?
|
49
48
|
err("Invalid manifest `#{File.basename(deployment)}': " +
|
50
|
-
|
49
|
+
'name and director UUID are required')
|
51
50
|
end
|
52
51
|
|
53
|
-
if director.uuid != manifest[
|
52
|
+
if director.uuid != manifest['director_uuid']
|
54
53
|
err("Target director UUID doesn't match UUID from deployment manifest")
|
55
54
|
end
|
56
55
|
|
57
|
-
if manifest[
|
56
|
+
if manifest['release'].blank? && manifest['releases'].blank?
|
58
57
|
err("Deployment manifest doesn't have release information: '" +
|
59
|
-
|
58
|
+
"please add 'release' or 'releases' section")
|
60
59
|
end
|
61
60
|
|
62
61
|
resolve_release_aliases(manifest)
|
63
62
|
resolve_stemcell_aliases(manifest)
|
64
63
|
|
65
|
-
options[:yaml] ?
|
64
|
+
options[:yaml] ? Psych.dump(manifest) : manifest
|
66
65
|
end
|
67
66
|
|
68
67
|
# Check if the 2 deployments are different.
|
@@ -91,7 +90,7 @@ module Bosh::Cli
|
|
91
90
|
# if something goes wrong, so it doesn't need to have
|
92
91
|
# a meaningful return value.
|
93
92
|
# @return Boolean Were there any changes in deployment manifest?
|
94
|
-
def inspect_deployment_changes(manifest, options = {
|
93
|
+
def inspect_deployment_changes(manifest, options = {})
|
95
94
|
show_empty_changeset = true
|
96
95
|
|
97
96
|
if options.has_key?(:show_empty_changeset)
|
@@ -99,27 +98,26 @@ module Bosh::Cli
|
|
99
98
|
end
|
100
99
|
|
101
100
|
manifest = manifest.dup
|
102
|
-
current_deployment = director.get_deployment(manifest[
|
101
|
+
current_deployment = director.get_deployment(manifest['name'])
|
103
102
|
|
104
103
|
# We cannot retrieve current manifest until there was at least one
|
105
104
|
# successful deployment. There used to be a warning about that
|
106
105
|
# but it turned out to be confusing to many users and thus has
|
107
106
|
# been removed.
|
108
|
-
return if current_deployment[
|
109
|
-
current_manifest =
|
107
|
+
return if current_deployment['manifest'].nil?
|
108
|
+
current_manifest = Psych.load(current_deployment['manifest'])
|
110
109
|
|
111
110
|
unless current_manifest.is_a?(Hash)
|
112
|
-
err(
|
113
|
-
|
111
|
+
err('Current deployment manifest format is invalid, ' +
|
112
|
+
'check if director works properly')
|
114
113
|
end
|
115
114
|
|
116
|
-
# TODO: validate new deployment manifest
|
117
115
|
diff = Bosh::Cli::HashChangeset.new
|
118
116
|
diff.add_hash(normalize_deployment_manifest(manifest), :new)
|
119
117
|
diff.add_hash(normalize_deployment_manifest(current_manifest), :old)
|
120
|
-
@_diff_key_visited = {
|
118
|
+
@_diff_key_visited = { 'name' => 1, 'director_uuid' => 1 }
|
121
119
|
|
122
|
-
say(
|
120
|
+
say('Detecting changes in deployment...'.make_green)
|
123
121
|
nl
|
124
122
|
|
125
123
|
if !diff.changed? && !show_empty_changeset
|
@@ -163,16 +161,16 @@ module Bosh::Cli
|
|
163
161
|
end
|
164
162
|
|
165
163
|
if old_stemcells != new_stemcells
|
166
|
-
unless confirmed?(
|
167
|
-
|
164
|
+
unless confirmed?('Stemcell update has been detected. ' +
|
165
|
+
'Are you sure you want to update stemcells?')
|
168
166
|
cancel_deployment
|
169
167
|
end
|
170
168
|
end
|
171
169
|
|
172
170
|
if old_stemcells.size != new_stemcells.size
|
173
|
-
say(
|
174
|
-
|
175
|
-
unless confirmed?(
|
171
|
+
say('Stemcell update seems to be inconsistent with current '.make_red +
|
172
|
+
'deployment. Please carefully review changes above.'.make_red)
|
173
|
+
unless confirmed?('Are you sure this configuration is correct?')
|
176
174
|
cancel_deployment
|
177
175
|
end
|
178
176
|
end
|
@@ -194,31 +192,102 @@ module Bosh::Cli
|
|
194
192
|
|
195
193
|
diff.changed?
|
196
194
|
rescue Bosh::Cli::ResourceNotFound
|
197
|
-
say(
|
198
|
-
|
195
|
+
say('Cannot get current deployment information from director, ' +
|
196
|
+
'possibly a new deployment'.make_red)
|
199
197
|
true
|
200
198
|
end
|
201
199
|
|
202
|
-
|
200
|
+
def latest_release_versions
|
201
|
+
@_latest_release_versions ||= begin
|
202
|
+
director.list_releases.inject({}) do |hash, release|
|
203
|
+
name = release['name']
|
204
|
+
versions = release['versions'] || release['release_versions'].map { |release_version| release_version['version'] }
|
205
|
+
latest_version = versions.map { |v| Bosh::Common::VersionNumber.new(v) }.max
|
206
|
+
hash[name] = latest_version.to_s
|
207
|
+
hash
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
203
211
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
212
|
+
# @param [Hash] manifest Deployment manifest (will be modified)
|
213
|
+
# @return [void]
|
214
|
+
def resolve_release_aliases(manifest)
|
215
|
+
releases = manifest['releases'] || [manifest['release']]
|
216
|
+
|
217
|
+
releases.each do |release|
|
218
|
+
if release['version'] == 'latest'
|
219
|
+
latest_release_version = latest_release_versions[release['name']]
|
220
|
+
unless latest_release_version
|
221
|
+
err("Release '#{release['name']}' not found on director. Unable to resolve 'latest' alias in manifest.")
|
222
|
+
end
|
223
|
+
release['version'] = latest_release_version
|
224
|
+
end
|
225
|
+
|
226
|
+
if release['version'].to_i.to_s == release['version']
|
227
|
+
release['version'] = release['version'].to_i
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def job_unique_in_deployment?(job_name)
|
233
|
+
job = find_job(job_name)
|
234
|
+
job.fetch('instances') == 1 if job
|
235
|
+
end
|
236
|
+
|
237
|
+
def job_exists_in_deployment?(job_name)
|
238
|
+
!!find_job(job_name)
|
239
|
+
end
|
240
|
+
|
241
|
+
def job_must_exist_in_deployment(job)
|
242
|
+
err("Job `#{job}' doesn't exist") unless job_exists_in_deployment?(job)
|
243
|
+
end
|
244
|
+
|
245
|
+
def prompt_for_job_and_index
|
246
|
+
jobs_list = jobs_and_indexes
|
247
|
+
|
248
|
+
return jobs_list.first if jobs_list.size == 1
|
249
|
+
|
250
|
+
choose do |menu|
|
251
|
+
menu.prompt = 'Choose an instance: '
|
252
|
+
jobs_list.each do |job_name, index|
|
253
|
+
menu.choice("#{job_name}/#{index}") { [job_name, index] }
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def jobs_and_indexes
|
259
|
+
jobs = prepare_deployment_manifest.fetch('jobs')
|
260
|
+
|
261
|
+
jobs.inject([]) do |jobs_and_indexes, job|
|
262
|
+
job_name = job.fetch('name')
|
263
|
+
0.upto(job.fetch('instances').to_i - 1) do |index|
|
264
|
+
jobs_and_indexes << [job_name, index]
|
265
|
+
end
|
266
|
+
jobs_and_indexes
|
209
267
|
end
|
210
268
|
end
|
211
269
|
|
212
270
|
def cancel_deployment
|
213
|
-
quit(
|
271
|
+
quit('Deployment canceled'.make_red)
|
272
|
+
end
|
273
|
+
|
274
|
+
private
|
275
|
+
|
276
|
+
def find_job(job_name)
|
277
|
+
jobs = prepare_deployment_manifest.fetch('jobs')
|
278
|
+
jobs.find { |job| job.fetch('name') == job_name }
|
214
279
|
end
|
215
280
|
|
216
|
-
def
|
217
|
-
|
281
|
+
def find_deployment(name)
|
282
|
+
if File.exists?(name)
|
283
|
+
File.expand_path(name)
|
284
|
+
else
|
285
|
+
File.expand_path(File.join(work_dir, 'deployments', "#{name}.yml"))
|
286
|
+
end
|
218
287
|
end
|
219
288
|
|
220
289
|
def manifest_target_upgrade_notice
|
221
|
-
<<-EOS.gsub(/^\s*/,
|
290
|
+
<<-EOS.gsub(/^\s*/, '').gsub(/\n$/, '')
|
222
291
|
Please upgrade your deployment manifest to use director UUID instead
|
223
292
|
of target. Just replace 'target' key with 'director_uuid' key in your
|
224
293
|
manifest. You can get your director UUID by targeting your director
|
@@ -227,130 +296,53 @@ module Bosh::Cli
|
|
227
296
|
end
|
228
297
|
|
229
298
|
def print_summary(diff, key, title = nil)
|
230
|
-
title ||= key.to_s.gsub(/[-_]/,
|
299
|
+
title ||= key.to_s.gsub(/[-_]/, ' ').capitalize
|
231
300
|
|
232
|
-
say(title.
|
301
|
+
say(title.make_green)
|
233
302
|
summary = diff[key].summary
|
234
303
|
if summary.empty?
|
235
|
-
say(
|
304
|
+
say('No changes')
|
236
305
|
else
|
237
306
|
say(summary.join("\n"))
|
238
307
|
end
|
239
308
|
@_diff_key_visited[key.to_s] = 1
|
240
309
|
end
|
241
310
|
|
242
|
-
def normalize_deployment_manifest(
|
243
|
-
|
244
|
-
|
245
|
-
%w(releases networks jobs resource_pools).each do |section|
|
246
|
-
normalized[section] ||= []
|
247
|
-
|
248
|
-
unless normalized[section].kind_of?(Array)
|
249
|
-
manifest_error("#{section} is expected to be an array")
|
250
|
-
end
|
251
|
-
|
252
|
-
normalized[section] = normalized[section].inject({}) do |acc, e|
|
253
|
-
if e["name"].blank?
|
254
|
-
manifest_error("missing name for one of entries in '#{section}'")
|
255
|
-
end
|
256
|
-
if acc.has_key?(e["name"])
|
257
|
-
manifest_error("duplicate entry '#{e['name']}' in '#{section}'")
|
258
|
-
end
|
259
|
-
acc[e["name"]] = e
|
260
|
-
acc
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
normalized["networks"].each do |network_name, network|
|
265
|
-
# VIP and dynamic networks do not require subnet,
|
266
|
-
# but if it's there we can run some sanity checks
|
267
|
-
next unless network.has_key?("subnets")
|
268
|
-
|
269
|
-
unless network["subnets"].kind_of?(Array)
|
270
|
-
manifest_error("network subnets is expected to be an array")
|
271
|
-
end
|
272
|
-
|
273
|
-
subnets = network["subnets"].inject({}) do |acc, e|
|
274
|
-
if e["range"].blank?
|
275
|
-
manifest_error("missing range for one of subnets " +
|
276
|
-
"in '#{network_name}'")
|
277
|
-
end
|
278
|
-
if acc.has_key?(e["range"])
|
279
|
-
manifest_error("duplicate network range '#{e['range']}' " +
|
280
|
-
"in '#{network}'")
|
281
|
-
end
|
282
|
-
acc[e["range"]] = e
|
283
|
-
acc
|
284
|
-
end
|
285
|
-
|
286
|
-
normalized["networks"][network_name]["subnets"] = subnets
|
287
|
-
end
|
288
|
-
|
289
|
-
normalized
|
311
|
+
def normalize_deployment_manifest(manifest_hash)
|
312
|
+
DeploymentManifest.new(manifest_hash).normalize
|
290
313
|
end
|
291
314
|
|
292
315
|
def warn_about_release_changes(release_diff)
|
293
316
|
if release_diff[:name].changed?
|
294
|
-
say(
|
317
|
+
say('Release name has changed: %s -> %s'.make_red % [
|
295
318
|
release_diff[:name].old, release_diff[:name].new])
|
296
|
-
unless confirmed?(
|
297
|
-
|
319
|
+
unless confirmed?('This is very serious and potentially destructive ' +
|
320
|
+
'change. ARE YOU SURE YOU WANT TO DO IT?')
|
298
321
|
cancel_deployment
|
299
322
|
end
|
300
323
|
elsif release_diff[:version].changed?
|
301
|
-
say(
|
324
|
+
say('Release version has changed: %s -> %s'.make_yellow % [
|
302
325
|
release_diff[:version].old, release_diff[:version].new])
|
303
|
-
unless confirmed?(
|
326
|
+
unless confirmed?('Are you sure you want to deploy this version?')
|
304
327
|
cancel_deployment
|
305
328
|
end
|
306
329
|
end
|
307
330
|
end
|
308
331
|
|
309
|
-
# @param [Hash] manifest Deployment manifest (will be modified)
|
310
|
-
# @return [void]
|
311
|
-
def resolve_release_aliases(manifest)
|
312
|
-
if manifest["release"]
|
313
|
-
if manifest["releases"]
|
314
|
-
err("Manifest has both `release' and `releases', please fix it")
|
315
|
-
end
|
316
|
-
releases = [manifest["release"]]
|
317
|
-
else
|
318
|
-
releases = manifest["releases"]
|
319
|
-
end
|
320
|
-
|
321
|
-
unless releases.is_a?(Array)
|
322
|
-
err("Invalid release spec in the deployment manifest")
|
323
|
-
end
|
324
|
-
|
325
|
-
releases.each do |release|
|
326
|
-
if release["version"] == "latest"
|
327
|
-
latest_version = latest_releases[release["name"]]
|
328
|
-
if latest_version.nil?
|
329
|
-
err("Latest version for release `#{release["name"]}' is unknown")
|
330
|
-
end
|
331
|
-
# Avoiding Fixnum -> String noise in diff
|
332
|
-
if latest_version.to_s == latest_version.to_i.to_s
|
333
|
-
latest_version = latest_version.to_i
|
334
|
-
end
|
335
|
-
release["version"] = latest_version
|
336
|
-
end
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
332
|
# @param [Hash] manifest Deployment manifest (will be modified)
|
341
333
|
# @return [void]
|
342
334
|
def resolve_stemcell_aliases(manifest)
|
343
|
-
return if manifest[
|
335
|
+
return if manifest['resource_pools'].nil?
|
344
336
|
|
345
|
-
manifest[
|
346
|
-
stemcell = rp[
|
337
|
+
manifest['resource_pools'].each do |rp|
|
338
|
+
stemcell = rp['stemcell']
|
347
339
|
unless stemcell.is_a?(Hash)
|
348
|
-
err(
|
340
|
+
err('Invalid stemcell spec in the deployment manifest')
|
349
341
|
end
|
350
|
-
if stemcell[
|
351
|
-
latest_version = latest_stemcells[stemcell[
|
342
|
+
if stemcell['version'] == 'latest'
|
343
|
+
latest_version = latest_stemcells[stemcell['name']]
|
352
344
|
if latest_version.nil?
|
353
|
-
err("Latest version for stemcell `#{stemcell[
|
345
|
+
err("Latest version for stemcell `#{stemcell['name']}' is unknown")
|
354
346
|
end
|
355
347
|
# Avoiding {Float,Fixnum} -> String noise in diff
|
356
348
|
if latest_version.to_s == latest_version.to_f.to_s
|
@@ -358,7 +350,7 @@ module Bosh::Cli
|
|
358
350
|
elsif latest_version.to_s == latest_version.to_i.to_s
|
359
351
|
latest_version = latest_version.to_i
|
360
352
|
end
|
361
|
-
stemcell[
|
353
|
+
stemcell['version'] = latest_version
|
362
354
|
end
|
363
355
|
end
|
364
356
|
end
|
@@ -367,11 +359,11 @@ module Bosh::Cli
|
|
367
359
|
def latest_stemcells
|
368
360
|
@_latest_stemcells ||= begin
|
369
361
|
stemcells = director.list_stemcells.inject({}) do |hash, stemcell|
|
370
|
-
unless stemcell.is_a?(Hash) && stemcell[
|
371
|
-
err(
|
362
|
+
unless stemcell.is_a?(Hash) && stemcell['name'] && stemcell['version']
|
363
|
+
err('Invalid director stemcell list format')
|
372
364
|
end
|
373
|
-
hash[stemcell[
|
374
|
-
hash[stemcell[
|
365
|
+
hash[stemcell['name']] ||= []
|
366
|
+
hash[stemcell['name']] << stemcell['version']
|
375
367
|
hash
|
376
368
|
end
|
377
369
|
|
@@ -381,22 +373,5 @@ module Bosh::Cli
|
|
381
373
|
end
|
382
374
|
end
|
383
375
|
end
|
384
|
-
|
385
|
-
# @return [Array]
|
386
|
-
def latest_releases
|
387
|
-
@_latest_releases ||= begin
|
388
|
-
director.list_releases.inject({}) do |hash, release|
|
389
|
-
unless release["name"].is_a?(String) &&
|
390
|
-
release["versions"].is_a?(Array)
|
391
|
-
err("Invalid director release list format")
|
392
|
-
end
|
393
|
-
hash[release["name"]] = release["versions"].sort { |v1, v2|
|
394
|
-
version_cmp(v2, v1)
|
395
|
-
}.first
|
396
|
-
hash
|
397
|
-
end
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
376
|
end
|
402
377
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'common/deep_copy'
|
2
|
+
|
3
|
+
module Bosh::Cli
|
4
|
+
class DeploymentManifest
|
5
|
+
def initialize(manifest_hash)
|
6
|
+
@manifest_hash = manifest_hash
|
7
|
+
end
|
8
|
+
|
9
|
+
def normalize
|
10
|
+
normalized = Bosh::Common::DeepCopy.copy(manifest_hash)
|
11
|
+
|
12
|
+
%w(releases networks jobs resource_pools).each do |section|
|
13
|
+
normalized[section] ||= []
|
14
|
+
|
15
|
+
unless normalized[section].kind_of?(Array)
|
16
|
+
manifest_error("#{section} is expected to be an array")
|
17
|
+
end
|
18
|
+
|
19
|
+
normalized[section] = normalized[section].inject({}) do |acc, e|
|
20
|
+
if e["name"].blank?
|
21
|
+
manifest_error("missing name for one of entries in '#{section}'")
|
22
|
+
end
|
23
|
+
if acc.has_key?(e["name"])
|
24
|
+
manifest_error("duplicate entry '#{e['name']}' in '#{section}'")
|
25
|
+
end
|
26
|
+
acc[e["name"]] = e
|
27
|
+
acc
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
normalized["networks"].each do |network_name, network|
|
32
|
+
# VIP and dynamic networks do not require subnet,
|
33
|
+
# but if it's there we can run some sanity checks
|
34
|
+
next unless network.has_key?("subnets")
|
35
|
+
|
36
|
+
unless network["subnets"].kind_of?(Array)
|
37
|
+
manifest_error("network subnets is expected to be an array")
|
38
|
+
end
|
39
|
+
|
40
|
+
subnets = network["subnets"].inject({}) do |acc, e|
|
41
|
+
if e["range"].blank?
|
42
|
+
manifest_error("missing range for one of subnets " +
|
43
|
+
"in '#{network_name}'")
|
44
|
+
end
|
45
|
+
if acc.has_key?(e["range"])
|
46
|
+
manifest_error("duplicate network range '#{e['range']}' " +
|
47
|
+
"in '#{network}'")
|
48
|
+
end
|
49
|
+
acc[e["range"]] = e
|
50
|
+
acc
|
51
|
+
end
|
52
|
+
|
53
|
+
normalized["networks"][network_name]["subnets"] = subnets
|
54
|
+
end
|
55
|
+
|
56
|
+
normalized
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
attr_reader :manifest_hash
|
61
|
+
|
62
|
+
def manifest_error(err)
|
63
|
+
err("Deployment manifest error: #{err}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|