bosh-director 1.3178.0 → 1.3181.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bosh/director.rb +4 -0
- data/lib/bosh/director/api/cloud_config_manager.rb +4 -0
- data/lib/bosh/director/api/controllers/deployments_controller.rb +35 -3
- data/lib/bosh/director/api/release_manager.rb +22 -17
- data/lib/bosh/director/config.rb +19 -0
- data/lib/bosh/director/deployment_plan/compilation_instance_pool.rb +14 -2
- data/lib/bosh/director/deployment_plan/ip_provider/in_memory_ip_repo.rb +4 -7
- data/lib/bosh/director/deployment_plan/planner_factory.rb +8 -9
- data/lib/bosh/director/deployment_plan/stemcell.rb +3 -11
- data/lib/bosh/director/jobs/run_errand.rb +3 -5
- data/lib/bosh/director/jobs/update_deployment.rb +3 -4
- data/lib/bosh/director/manifest/changeset.rb +115 -0
- data/lib/bosh/director/manifest/diff_lines.rb +83 -0
- data/lib/bosh/director/manifest/manifest.rb +72 -0
- data/lib/bosh/director/version.rb +1 -1
- metadata +19 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c97780b3dff8eed73c5d5be903e89db7379d5783
|
4
|
+
data.tar.gz: b44b5e4a56222f11ebbd158edd38a4ee12d931c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9906d59e3d0f2b08d4dad7c5bc3de47fb01dc528506a7b8d662cb0b0c4e6724dbb2c5a90871d893bef2f8cbbd8c560545c9b6149e69753b7510a4a6ee9b846d2
|
7
|
+
data.tar.gz: 6c32ef7e74cb561aec71c44bd28ddb66bb178bca559cf9c092417bc18bece0d008b62c3bb67f49bb523cb01efa34d345fb35be0fcced1e753cf48fc10d280c02
|
data/lib/bosh/director.rb
CHANGED
@@ -92,6 +92,10 @@ require 'bosh/director/transactor'
|
|
92
92
|
require 'bosh/director/sequel'
|
93
93
|
require 'common/thread_pool'
|
94
94
|
|
95
|
+
require 'bosh/director/manifest/manifest'
|
96
|
+
require 'bosh/director/manifest/changeset'
|
97
|
+
require 'bosh/director/manifest/diff_lines'
|
98
|
+
|
95
99
|
require 'bosh/director/log_bundles_cleaner'
|
96
100
|
require 'bosh/director/logs_fetcher'
|
97
101
|
|
@@ -205,7 +205,7 @@ module Bosh::Director
|
|
205
205
|
|
206
206
|
post '/:deployment/properties', :consumes => [:json] do
|
207
207
|
payload = json_decode(request.body)
|
208
|
-
@property_manager.create_property(params[:deployment], payload['name'], payload['value'])
|
208
|
+
@property_manager.create_property(params[:deployment], payload['name'], payload['value'] )
|
209
209
|
status(204)
|
210
210
|
end
|
211
211
|
|
@@ -267,12 +267,44 @@ module Bosh::Director
|
|
267
267
|
options = {}
|
268
268
|
options['recreate'] = true if params['recreate'] == 'true'
|
269
269
|
options['skip_drain'] = params['skip_drain'] if params['skip_drain']
|
270
|
-
|
270
|
+
if params['context']
|
271
|
+
@logger.debug("Deploying with context #{params['context']}")
|
272
|
+
context = JSON.parse(params['context'])
|
273
|
+
cloud_config = Api::CloudConfigManager.new.find_by_id(context['cloud_config_id'])
|
274
|
+
else
|
275
|
+
cloud_config =Api::CloudConfigManager.new.latest
|
276
|
+
end
|
271
277
|
|
272
|
-
task = @deployment_manager.create_deployment(current_user, request.body,
|
278
|
+
task = @deployment_manager.create_deployment(current_user, request.body, cloud_config, options)
|
273
279
|
redirect "/tasks/#{task.id}"
|
274
280
|
end
|
275
281
|
|
282
|
+
post '/:deployment/diff', :consumes => :yaml do
|
283
|
+
deployment = Models::Deployment[name: params[:deployment]]
|
284
|
+
if deployment
|
285
|
+
before_manifest = Manifest.load_from_text(deployment.manifest, deployment.cloud_config)
|
286
|
+
before_manifest.resolve_aliases
|
287
|
+
else
|
288
|
+
before_manifest = Manifest.load_from_text(nil, nil)
|
289
|
+
end
|
290
|
+
|
291
|
+
after_cloud_config = Bosh::Director::Api::CloudConfigManager.new.latest
|
292
|
+
after_manifest = Manifest.load_from_text(
|
293
|
+
request.body,
|
294
|
+
after_cloud_config
|
295
|
+
)
|
296
|
+
after_manifest.resolve_aliases
|
297
|
+
|
298
|
+
diff = before_manifest.diff(after_manifest)
|
299
|
+
|
300
|
+
json_encode({
|
301
|
+
'context' => {
|
302
|
+
'cloud_config_id' => after_cloud_config ? after_cloud_config.id : nil,
|
303
|
+
},
|
304
|
+
'diff' => diff.map { |l| [l.to_s, l.status] }
|
305
|
+
})
|
306
|
+
end
|
307
|
+
|
276
308
|
post '/:deployment_name/errands/:errand_name/runs' do
|
277
309
|
deployment_name = params[:deployment_name]
|
278
310
|
errand_name = params[:errand_name]
|
@@ -5,23 +5,7 @@ module Bosh::Director
|
|
5
5
|
|
6
6
|
def get_all_releases
|
7
7
|
releases = Models::Release.order_by(:name.asc).map do |release|
|
8
|
-
|
9
|
-
{
|
10
|
-
provided: version,
|
11
|
-
parsed: Bosh::Common::Version::ReleaseVersion.parse(version.values[:version])
|
12
|
-
}
|
13
|
-
end.sort_by { |rv| rv[:parsed] }
|
14
|
-
release_versions = sorted_version_tuples.map do |version|
|
15
|
-
provided = version[:provided]
|
16
|
-
{
|
17
|
-
'version' => provided.version.to_s,
|
18
|
-
'commit_hash' => provided.commit_hash,
|
19
|
-
'uncommitted_changes' => provided.uncommitted_changes,
|
20
|
-
'currently_deployed' => !provided.deployments.empty?,
|
21
|
-
'job_names' => provided.templates.map(&:name),
|
22
|
-
}
|
23
|
-
end
|
24
|
-
|
8
|
+
release_versions = sorted_release_versions(release)
|
25
9
|
{
|
26
10
|
'name' => release.name,
|
27
11
|
'release_versions' => release_versions
|
@@ -31,6 +15,27 @@ module Bosh::Director
|
|
31
15
|
releases
|
32
16
|
end
|
33
17
|
|
18
|
+
def sorted_release_versions(release)
|
19
|
+
sorted_version_tuples = release.versions_dataset.all.map do |version|
|
20
|
+
{
|
21
|
+
provided: version,
|
22
|
+
parsed: Bosh::Common::Version::ReleaseVersion.parse(version.values[:version])
|
23
|
+
}
|
24
|
+
end.sort_by { |rv| rv[:parsed] }
|
25
|
+
release_versions = sorted_version_tuples.map do |version|
|
26
|
+
provided = version[:provided]
|
27
|
+
{
|
28
|
+
'version' => provided.version.to_s,
|
29
|
+
'commit_hash' => provided.commit_hash,
|
30
|
+
'uncommitted_changes' => provided.uncommitted_changes,
|
31
|
+
'currently_deployed' => !provided.deployments.empty?,
|
32
|
+
'job_names' => provided.templates.map(&:name),
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
release_versions
|
37
|
+
end
|
38
|
+
|
34
39
|
def find_by_name(name)
|
35
40
|
release = Models::Release[:name => name]
|
36
41
|
if release.nil?
|
data/lib/bosh/director/config.rb
CHANGED
@@ -303,6 +303,25 @@ module Bosh::Director
|
|
303
303
|
Thread.current[:bosh] ||= {}
|
304
304
|
end
|
305
305
|
|
306
|
+
def generate_temp_dir
|
307
|
+
temp_dir = Dir.mktmpdir
|
308
|
+
ENV["TMPDIR"] = temp_dir
|
309
|
+
FileUtils.mkdir_p(temp_dir)
|
310
|
+
at_exit do
|
311
|
+
begin
|
312
|
+
if $!
|
313
|
+
status = $!.is_a?(::SystemExit) ? $!.status : 1
|
314
|
+
else
|
315
|
+
status = 0
|
316
|
+
end
|
317
|
+
FileUtils.rm_rf(temp_dir)
|
318
|
+
ensure
|
319
|
+
exit status
|
320
|
+
end
|
321
|
+
end
|
322
|
+
temp_dir
|
323
|
+
end
|
324
|
+
|
306
325
|
def patch_sqlite
|
307
326
|
return if @patched_sqlite
|
308
327
|
@patched_sqlite = true
|
@@ -26,7 +26,12 @@ module Bosh::Director
|
|
26
26
|
rescue => e
|
27
27
|
unless instance.nil? || instance_plan.nil?
|
28
28
|
@instance_reuser.remove_instance(instance)
|
29
|
-
|
29
|
+
|
30
|
+
if Config.keep_unreachable_vms
|
31
|
+
@logger.info('Keeping reused compilation VM for debugging')
|
32
|
+
else
|
33
|
+
delete_instance(instance_plan)
|
34
|
+
end
|
30
35
|
end
|
31
36
|
raise e
|
32
37
|
end
|
@@ -34,11 +39,18 @@ module Bosh::Director
|
|
34
39
|
|
35
40
|
def with_single_use_vm(stemcell)
|
36
41
|
begin
|
42
|
+
keep_failing_vm = false
|
37
43
|
instance_plan, instance = create_instance_plan(stemcell)
|
38
44
|
configure_instance_plan(instance_plan)
|
39
45
|
yield instance
|
46
|
+
rescue => e
|
47
|
+
@logger.info('Keeping single-use compilation VM for debugging')
|
48
|
+
keep_failing_vm = Config.keep_unreachable_vms
|
49
|
+
raise e
|
40
50
|
ensure
|
41
|
-
|
51
|
+
unless instance.nil? || keep_failing_vm
|
52
|
+
delete_instance(instance_plan)
|
53
|
+
end
|
42
54
|
end
|
43
55
|
end
|
44
56
|
|
@@ -29,9 +29,9 @@ module Bosh::Director::DeploymentPlan
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def allocate_dynamic_ip(reservation, subnet)
|
32
|
-
item = (0...subnet.range.size).find { |i| available_for_dynamic?(subnet.range[i], subnet) }
|
33
|
-
|
34
32
|
@mutex.synchronize do
|
33
|
+
item = (0...subnet.range.size).find { |i| available_for_dynamic?(subnet.range[i], subnet) }
|
34
|
+
|
35
35
|
if item.nil?
|
36
36
|
entry = @recently_released_ips.find do |entry|
|
37
37
|
entry[:network_name] == subnet.network_name && subnet.range.contains?(entry[:ip])
|
@@ -72,11 +72,8 @@ module Bosh::Director::DeploymentPlan
|
|
72
72
|
return false unless subnet.range.contains?(ip)
|
73
73
|
return false if subnet.static_ips.include?(ip.to_i)
|
74
74
|
return false if subnet.restricted_ips.include?(ip.to_i)
|
75
|
-
|
76
|
-
@
|
77
|
-
return false if @recently_released_ips.include?({ip: ip.to_i, network_name: subnet.network_name})
|
78
|
-
return false if @ips.include?({ip: ip.to_i, network_name: subnet.network_name})
|
79
|
-
end
|
75
|
+
return false if @recently_released_ips.include?({ip: ip.to_i, network_name: subnet.network_name})
|
76
|
+
return false if @ips.include?({ip: ip.to_i, network_name: subnet.network_name})
|
80
77
|
|
81
78
|
true
|
82
79
|
end
|
@@ -33,21 +33,20 @@ module Bosh
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def create_from_model(deployment_model, options={})
|
36
|
-
|
37
|
-
|
38
|
-
create_from_manifest(manifest_hash, cloud_config_model, options)
|
36
|
+
manifest = Manifest.load_from_text(deployment_model.manifest, deployment_model.cloud_config)
|
37
|
+
create_from_manifest(manifest, deployment_model.cloud_config, options)
|
39
38
|
end
|
40
39
|
|
41
|
-
def create_from_manifest(
|
42
|
-
parse_from_manifest(
|
40
|
+
def create_from_manifest(manifest, cloud_config, options)
|
41
|
+
parse_from_manifest(manifest, cloud_config, options)
|
43
42
|
end
|
44
43
|
|
45
44
|
private
|
46
45
|
|
47
|
-
def parse_from_manifest(
|
48
|
-
|
49
|
-
@manifest_validator.validate(manifest_hash, cloud_config_hash)
|
50
|
-
deployment_manifest, cloud_manifest = @deployment_manifest_migrator.migrate(manifest_hash, cloud_config_hash)
|
46
|
+
def parse_from_manifest(manifest, cloud_config, options)
|
47
|
+
manifest.resolve_aliases
|
48
|
+
@manifest_validator.validate(manifest.manifest_hash, manifest.cloud_config_hash)
|
49
|
+
deployment_manifest, cloud_manifest = @deployment_manifest_migrator.migrate(manifest.manifest_hash, manifest.cloud_config_hash)
|
51
50
|
@logger.debug("Migrated deployment manifest:\n#{deployment_manifest}")
|
52
51
|
@logger.debug("Migrated cloud config manifest:\n#{cloud_manifest}")
|
53
52
|
name = deployment_manifest['name']
|
@@ -38,10 +38,6 @@ module Bosh::Director
|
|
38
38
|
@model = nil
|
39
39
|
end
|
40
40
|
|
41
|
-
def is_using_latest_version?
|
42
|
-
@version == 'latest'
|
43
|
-
end
|
44
|
-
|
45
41
|
def is_using_os?
|
46
42
|
!@os.nil? && @name.nil?
|
47
43
|
end
|
@@ -62,13 +58,9 @@ module Bosh::Director
|
|
62
58
|
end
|
63
59
|
|
64
60
|
def add_stemcell_model
|
65
|
-
|
66
|
-
@
|
67
|
-
|
68
|
-
@model = is_using_os? ?
|
69
|
-
@manager.find_by_os_and_version(@os, @version) :
|
70
|
-
@manager.find_by_name_and_version(@name, @version)
|
71
|
-
end
|
61
|
+
@model = is_using_os? ?
|
62
|
+
@manager.find_by_os_and_version(@os, @version) :
|
63
|
+
@manager.find_by_name_and_version(@name, @version)
|
72
64
|
|
73
65
|
@name = @model.name
|
74
66
|
@os = @model.operating_system
|
@@ -23,18 +23,16 @@ module Bosh::Director
|
|
23
23
|
|
24
24
|
def perform
|
25
25
|
deployment_model = @deployment_manager.find_by_name(@deployment_name)
|
26
|
-
|
27
|
-
deployment_name =
|
26
|
+
deployment_manifest = Manifest.load_from_text(deployment_model.manifest, deployment_model.cloud_config)
|
27
|
+
deployment_name = deployment_manifest.to_hash['name']
|
28
28
|
with_deployment_lock(deployment_name) do
|
29
|
-
cloud_config_model = deployment_model.cloud_config
|
30
|
-
|
31
29
|
deployment = nil
|
32
30
|
job = nil
|
33
31
|
|
34
32
|
event_log.begin_stage('Preparing deployment', 1)
|
35
33
|
event_log.track('Preparing deployment') do
|
36
34
|
planner_factory = DeploymentPlan::PlannerFactory.create(logger)
|
37
|
-
deployment = planner_factory.create_from_manifest(
|
35
|
+
deployment = planner_factory.create_from_manifest(deployment_manifest, deployment_model.cloud_config, {})
|
38
36
|
deployment.bind_models
|
39
37
|
job = deployment.job(@errand_name)
|
40
38
|
|
@@ -21,8 +21,6 @@ module Bosh::Director
|
|
21
21
|
|
22
22
|
manifest_text = File.read(@manifest_file_path)
|
23
23
|
logger.debug("Manifest:\n#{manifest_text}")
|
24
|
-
deployment_manifest_hash = Psych.load(manifest_text)
|
25
|
-
|
26
24
|
cloud_config_model = Bosh::Director::Models::CloudConfig[@cloud_config_id]
|
27
25
|
if cloud_config_model.nil?
|
28
26
|
logger.debug("No cloud config uploaded yet.")
|
@@ -30,7 +28,8 @@ module Bosh::Director
|
|
30
28
|
logger.debug("Cloud config:\n#{cloud_config_model.manifest}")
|
31
29
|
end
|
32
30
|
|
33
|
-
|
31
|
+
deployment_manifest = Manifest.load_from_text(manifest_text, cloud_config_model)
|
32
|
+
deployment_name = deployment_manifest.to_hash['name']
|
34
33
|
with_deployment_lock(deployment_name) do
|
35
34
|
@notifier = DeploymentPlan::Notifier.new(deployment_name, Config.nats_rpc, logger)
|
36
35
|
@notifier.send_start_event
|
@@ -40,7 +39,7 @@ module Bosh::Director
|
|
40
39
|
event_log.begin_stage('Preparing deployment', 1)
|
41
40
|
event_log.track('Preparing deployment') do
|
42
41
|
planner_factory = DeploymentPlan::PlannerFactory.create(logger)
|
43
|
-
deployment_plan = planner_factory.create_from_manifest(
|
42
|
+
deployment_plan = planner_factory.create_from_manifest(deployment_manifest, cloud_config_model, @options)
|
44
43
|
deployment_plan.bind_models
|
45
44
|
end
|
46
45
|
|
@@ -0,0 +1,115 @@
|
|
1
|
+
class ::Hash
|
2
|
+
def deep_merge(second)
|
3
|
+
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
4
|
+
self.merge(second, &merger)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Bosh::Director
|
9
|
+
class Changeset
|
10
|
+
KEY_NAME = 'name'
|
11
|
+
|
12
|
+
def initialize(before, after)
|
13
|
+
@before = before
|
14
|
+
@after = after
|
15
|
+
if @before && @after
|
16
|
+
@merged = @before.deep_merge(@after)
|
17
|
+
elsif @before
|
18
|
+
@merged = @before
|
19
|
+
else
|
20
|
+
@merged = @after
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def diff(indent = 0)
|
25
|
+
lines = DiffLines.new
|
26
|
+
|
27
|
+
@merged.each_pair do |key, value|
|
28
|
+
if @before.nil? || @before[key].nil?
|
29
|
+
lines.concat(yaml_lines({key => value}, indent, 'added'))
|
30
|
+
|
31
|
+
elsif @after.nil? || @after[key].nil?
|
32
|
+
lines.concat(yaml_lines({key => value}, indent, 'removed'))
|
33
|
+
|
34
|
+
elsif @before[key].is_a?(Array) && @after[key].is_a?(Array)
|
35
|
+
lines.concat(compare_arrays(@before[key], @after[key], key, indent))
|
36
|
+
|
37
|
+
elsif value.is_a?(Hash)
|
38
|
+
changeset = Changeset.new(@before[key], @after[key])
|
39
|
+
diff_lines = changeset.diff(indent+1)
|
40
|
+
unless diff_lines.empty?
|
41
|
+
lines << Line.new(indent, "#{key}:", nil)
|
42
|
+
lines.concat(diff_lines)
|
43
|
+
end
|
44
|
+
|
45
|
+
elsif @before[key] != @after[key]
|
46
|
+
lines << Line.new(indent, "#{key}: #{@before[key]}", 'removed')
|
47
|
+
lines << Line.new(indent, "#{key}: #{@after[key]}", 'added')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
lines
|
51
|
+
end
|
52
|
+
|
53
|
+
def yaml_lines(value, indent, state)
|
54
|
+
lines = DiffLines.new
|
55
|
+
value.to_yaml(indent: Line::INDENT).gsub("---\n", '').split("\n").each do |line|
|
56
|
+
lines << Line.new(indent, line, state)
|
57
|
+
end
|
58
|
+
lines
|
59
|
+
end
|
60
|
+
|
61
|
+
def compare_arrays(old_value, new_value, parent_name, indent)
|
62
|
+
added = new_value - old_value
|
63
|
+
removed = old_value - new_value
|
64
|
+
|
65
|
+
lines = DiffLines.new
|
66
|
+
|
67
|
+
added.each do |elem|
|
68
|
+
if elem.is_a?(Hash)
|
69
|
+
using_names = (added+removed).all? { |e| e['name'] }
|
70
|
+
using_ranges = (added+removed).all? { |e| e['range'] }
|
71
|
+
if using_names || using_ranges
|
72
|
+
if using_names
|
73
|
+
removed_same_name_element = removed.find { |e| e['name'] == elem['name'] }
|
74
|
+
elsif using_ranges
|
75
|
+
removed_same_name_element = removed.find { |e| e['range'] == elem['range'] }
|
76
|
+
end
|
77
|
+
removed.delete(removed_same_name_element)
|
78
|
+
|
79
|
+
if removed_same_name_element
|
80
|
+
changeset = Changeset.new(removed_same_name_element, elem)
|
81
|
+
diff_lines = changeset.diff(indent+1)
|
82
|
+
|
83
|
+
unless diff_lines.empty?
|
84
|
+
# write name if elem has been changed
|
85
|
+
if using_names
|
86
|
+
lines.concat(yaml_lines([{'name' => elem['name']}], indent, nil))
|
87
|
+
elsif using_ranges
|
88
|
+
lines.concat(yaml_lines([{'range' => elem['range']}], indent, nil))
|
89
|
+
end
|
90
|
+
lines.concat(diff_lines)
|
91
|
+
end
|
92
|
+
else
|
93
|
+
lines.concat(yaml_lines([elem], indent, 'added'))
|
94
|
+
end
|
95
|
+
|
96
|
+
else
|
97
|
+
lines.concat(yaml_lines([elem], indent, 'added'))
|
98
|
+
end
|
99
|
+
else
|
100
|
+
lines.concat(yaml_lines([elem], indent, 'added'))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
unless removed.empty?
|
105
|
+
lines.concat(yaml_lines(removed, indent, 'removed'))
|
106
|
+
end
|
107
|
+
|
108
|
+
unless lines.empty?
|
109
|
+
lines.unshift(Line.new(indent, "#{parent_name}:", nil))
|
110
|
+
end
|
111
|
+
|
112
|
+
lines
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Bosh::Director
|
2
|
+
class Line < Struct.new(:indent, :text, :status)
|
3
|
+
INDENT = 2
|
4
|
+
|
5
|
+
def to_s
|
6
|
+
"#{' ' * INDENT * indent}#{text}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def full_indent
|
10
|
+
indent + text[/^ */].size / INDENT
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class DiffLines < Array
|
15
|
+
MANIFEST_KEYS_ORDER = %w(
|
16
|
+
azs
|
17
|
+
vm_types
|
18
|
+
resource_pools
|
19
|
+
compilation
|
20
|
+
networks
|
21
|
+
disk_types
|
22
|
+
disk_pools
|
23
|
+
name
|
24
|
+
director_uuid
|
25
|
+
stemcells
|
26
|
+
releases
|
27
|
+
update
|
28
|
+
jobs
|
29
|
+
)
|
30
|
+
|
31
|
+
def order
|
32
|
+
sections = {}
|
33
|
+
key = nil
|
34
|
+
|
35
|
+
self.each do |line|
|
36
|
+
if line.indent == 0 && line.text !~ /^[ -]/
|
37
|
+
key = line.text
|
38
|
+
sections[key] = []
|
39
|
+
end
|
40
|
+
|
41
|
+
sections[key] << line
|
42
|
+
end
|
43
|
+
|
44
|
+
ordered_lines = []
|
45
|
+
MANIFEST_KEYS_ORDER.each do |manifest_key|
|
46
|
+
section_name = manifest_key + ':'
|
47
|
+
lines = sections[section_name]
|
48
|
+
ordered_lines += lines.to_a
|
49
|
+
sections.delete(section_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
sections.each do |_, section_lines|
|
53
|
+
section_lines.each do |line|
|
54
|
+
ordered_lines << line
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
self.replace(ordered_lines)
|
59
|
+
end
|
60
|
+
|
61
|
+
def redact_properties
|
62
|
+
i = 0
|
63
|
+
while i < self.size
|
64
|
+
line = self[i]
|
65
|
+
|
66
|
+
if line.text =~ /\bproperties:/
|
67
|
+
properties_indent = line.full_indent
|
68
|
+
i += 1
|
69
|
+
line = self[i]
|
70
|
+
|
71
|
+
while line && line.full_indent > properties_indent
|
72
|
+
line.text.gsub!(/: .+/, ': <redacted>') # readact hash values
|
73
|
+
line.text.gsub!(/- [^:]+$/, '- <redacted>') # redact array values
|
74
|
+
i += 1
|
75
|
+
line = self[i]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
i += 1
|
79
|
+
end
|
80
|
+
self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Bosh::Director
|
2
|
+
class Manifest
|
3
|
+
def self.load_from_text(manifest_text, cloud_config)
|
4
|
+
cloud_config_hash = cloud_config.nil? ? nil : cloud_config.manifest
|
5
|
+
manifest_hash = manifest_text.nil? ? {} : Psych.load(manifest_text)
|
6
|
+
new(manifest_hash, cloud_config_hash)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :manifest_hash, :cloud_config_hash
|
10
|
+
|
11
|
+
def initialize(manifest_hash, cloud_config_hash)
|
12
|
+
@manifest_hash = manifest_hash
|
13
|
+
@cloud_config_hash = cloud_config_hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def resolve_aliases
|
17
|
+
hashed = to_hash
|
18
|
+
hashed['resource_pools'].to_a.each do |rp|
|
19
|
+
rp['stemcell']['version'] = resolve_stemcell_version(rp['stemcell'])
|
20
|
+
end
|
21
|
+
|
22
|
+
hashed['stemcells'].to_a.each do |stemcell|
|
23
|
+
stemcell['version'] = resolve_stemcell_version(stemcell)
|
24
|
+
end
|
25
|
+
|
26
|
+
hashed['releases'].to_a.each do |release|
|
27
|
+
release['version'] = resolve_release_version(release)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def diff(other_manifest)
|
32
|
+
Changeset.new(to_hash, other_manifest.to_hash).diff.order.redact_properties
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_hash
|
36
|
+
@manifest_hash.merge(@cloud_config_hash || {})
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def resolve_stemcell_version(stemcell)
|
42
|
+
stemcell_manager = Api::StemcellManager.new
|
43
|
+
|
44
|
+
unless stemcell.is_a?(Hash)
|
45
|
+
raise 'Invalid stemcell spec in the deployment manifest'
|
46
|
+
end
|
47
|
+
|
48
|
+
if stemcell['version'] == 'latest'
|
49
|
+
if stemcell['os']
|
50
|
+
latest_stemcell = stemcell_manager.latest_by_os(stemcell['os'])
|
51
|
+
elsif stemcell['name']
|
52
|
+
latest_stemcell = stemcell_manager.latest_by_name(stemcell['name'])
|
53
|
+
else
|
54
|
+
raise 'Stemcell definition must contain either name or os'
|
55
|
+
end
|
56
|
+
return latest_stemcell[:version].to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
stemcell['version'].to_s
|
60
|
+
end
|
61
|
+
|
62
|
+
def resolve_release_version(release_def)
|
63
|
+
release_manager = Api::ReleaseManager.new
|
64
|
+
if release_def['version'] == 'latest'
|
65
|
+
release = release_manager.find_by_name(release_def['name'])
|
66
|
+
return release_manager.sorted_release_versions(release).last['version']
|
67
|
+
end
|
68
|
+
|
69
|
+
release_def['version'].to_s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bosh-director
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3181.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- VMware
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bosh_common
|
@@ -16,98 +16,98 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.3181.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.3181.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bosh_cpi
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.
|
33
|
+
version: 1.3181.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1.
|
40
|
+
version: 1.3181.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bosh-registry
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.
|
47
|
+
version: 1.3181.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.
|
54
|
+
version: 1.3181.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: blobstore_client
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 1.
|
61
|
+
version: 1.3181.0
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 1.
|
68
|
+
version: 1.3181.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: bosh-core
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 1.
|
75
|
+
version: 1.3181.0
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1.
|
82
|
+
version: 1.3181.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: bosh-director-core
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 1.
|
89
|
+
version: 1.3181.0
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 1.
|
96
|
+
version: 1.3181.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: bosh-template
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 1.
|
103
|
+
version: 1.3181.0
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 1.
|
110
|
+
version: 1.3181.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: bosh_openstack_cpi
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -874,6 +874,9 @@ files:
|
|
874
874
|
- lib/bosh/director/lock_helper.rb
|
875
875
|
- lib/bosh/director/log_bundles_cleaner.rb
|
876
876
|
- lib/bosh/director/logs_fetcher.rb
|
877
|
+
- lib/bosh/director/manifest/changeset.rb
|
878
|
+
- lib/bosh/director/manifest/diff_lines.rb
|
879
|
+
- lib/bosh/director/manifest/manifest.rb
|
877
880
|
- lib/bosh/director/models.rb
|
878
881
|
- lib/bosh/director/models/cloud_config.rb
|
879
882
|
- lib/bosh/director/models/compiled_package.rb
|