bosh-director 1.3202.0 → 1.3213.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/db/migrations/director/20151223172000_rename_requires_json.rb +7 -0
  3. data/db/migrations/director/20160106162749_runtime_configs.rb +19 -0
  4. data/db/migrations/director/20160106163433_add_runtime_configs_to_deployments.rb +7 -0
  5. data/db/migrations/director/20160202162216_add_post_start_completed_to_instance.rb +7 -0
  6. data/db/migrations/director/20160210201838_denormalize_compiled_package_stemcell_id_to_stemcell_name_and_version.rb +57 -0
  7. data/db/migrations/director/20160219175840_add_column_teams_to_deployments.rb +8 -0
  8. data/db/migrations/director/20160224222508_add_deployment_name_to_task.rb +7 -0
  9. data/db/migrations/director/20160225182206_rename_post_start_completed.rb +8 -0
  10. data/lib/bosh/director.rb +9 -0
  11. data/lib/bosh/director/api.rb +1 -1
  12. data/lib/bosh/director/api/api_helper.rb +27 -0
  13. data/lib/bosh/director/api/controllers/base_controller.rb +28 -5
  14. data/lib/bosh/director/api/controllers/cloud_configs_controller.rb +4 -3
  15. data/lib/bosh/director/api/controllers/deployments_controller.rb +165 -81
  16. data/lib/bosh/director/api/controllers/locks_controller.rb +1 -1
  17. data/lib/bosh/director/api/controllers/packages_controller.rb +4 -35
  18. data/lib/bosh/director/api/controllers/releases_controller.rb +6 -4
  19. data/lib/bosh/director/api/controllers/runtime_configs_controller.rb +41 -0
  20. data/lib/bosh/director/api/controllers/stemcells_controller.rb +1 -1
  21. data/lib/bosh/director/api/controllers/tasks_controller.rb +72 -5
  22. data/lib/bosh/director/api/deployment_manager.rb +10 -42
  23. data/lib/bosh/director/api/extensions/scoping.rb +11 -24
  24. data/lib/bosh/director/api/instance_lookup.rb +10 -22
  25. data/lib/bosh/director/api/instance_manager.rb +27 -15
  26. data/lib/bosh/director/api/local_identity_provider.rb +0 -8
  27. data/lib/bosh/director/api/problem_manager.rb +7 -19
  28. data/lib/bosh/director/api/property_manager.rb +12 -21
  29. data/lib/bosh/director/api/resurrector_manager.rb +4 -4
  30. data/lib/bosh/director/api/route_configuration.rb +1 -0
  31. data/lib/bosh/director/api/runtime_config_manager.rb +35 -0
  32. data/lib/bosh/director/api/snapshot_manager.rb +2 -2
  33. data/lib/bosh/director/api/task_helper.rb +2 -1
  34. data/lib/bosh/director/api/task_manager.rb +2 -8
  35. data/lib/bosh/director/api/uaa_identity_provider.rb +0 -16
  36. data/lib/bosh/director/blob_util.rb +3 -2
  37. data/lib/bosh/director/cloudcheck_helper.rb +17 -3
  38. data/lib/bosh/director/compile_task.rb +53 -24
  39. data/lib/bosh/director/compile_task_generator.rb +6 -6
  40. data/lib/bosh/director/compiled_package_group.rb +4 -3
  41. data/lib/bosh/director/compiled_release.rb +6 -0
  42. data/lib/bosh/director/compiled_release/manifest.rb +30 -0
  43. data/lib/bosh/director/compiled_release_manifest.rb +3 -3
  44. data/lib/bosh/director/config.rb +11 -1
  45. data/lib/bosh/director/deployment_plan.rb +1 -0
  46. data/lib/bosh/director/deployment_plan/assembler.rb +6 -2
  47. data/lib/bosh/director/deployment_plan/cloud_manifest_parser.rb +26 -10
  48. data/lib/bosh/director/deployment_plan/compilation_config.rb +43 -7
  49. data/lib/bosh/director/deployment_plan/compilation_instance_pool.rb +10 -3
  50. data/lib/bosh/director/deployment_plan/deployment_repo.rb +4 -10
  51. data/lib/bosh/director/deployment_plan/dynamic_network.rb +1 -1
  52. data/lib/bosh/director/deployment_plan/instance.rb +36 -17
  53. data/lib/bosh/director/deployment_plan/instance_plan.rb +13 -2
  54. data/lib/bosh/director/deployment_plan/instance_spec.rb +12 -4
  55. data/lib/bosh/director/deployment_plan/job.rb +73 -39
  56. data/lib/bosh/director/deployment_plan/job_availability_zone_parser.rb +4 -4
  57. data/lib/bosh/director/deployment_plan/job_migrator.rb +7 -7
  58. data/lib/bosh/director/deployment_plan/job_network_parser.rb +6 -6
  59. data/lib/bosh/director/deployment_plan/job_spec_parser.rb +91 -33
  60. data/lib/bosh/director/deployment_plan/links/link.rb +9 -4
  61. data/lib/bosh/director/deployment_plan/links/link_lookup.rb +23 -15
  62. data/lib/bosh/director/deployment_plan/links/link_path.rb +168 -15
  63. data/lib/bosh/director/deployment_plan/links/links_resolver.rb +34 -32
  64. data/lib/bosh/director/deployment_plan/links/template_link.rb +28 -8
  65. data/lib/bosh/director/deployment_plan/manifest_validator.rb +1 -1
  66. data/lib/bosh/director/deployment_plan/network_settings.rb +27 -13
  67. data/lib/bosh/director/deployment_plan/package_validator.rb +9 -5
  68. data/lib/bosh/director/deployment_plan/placement_planner/networks_to_static_ips.rb +4 -4
  69. data/lib/bosh/director/deployment_plan/planner.rb +31 -7
  70. data/lib/bosh/director/deployment_plan/planner_factory.rb +147 -6
  71. data/lib/bosh/director/deployment_plan/runtime_manifest_parser.rb +142 -0
  72. data/lib/bosh/director/deployment_plan/stemcell.rb +2 -2
  73. data/lib/bosh/director/deployment_plan/steps/package_compile_step.rb +3 -2
  74. data/lib/bosh/director/deployment_plan/template.rb +93 -8
  75. data/lib/bosh/director/deployment_plan/update_config.rb +10 -0
  76. data/lib/bosh/director/deployment_plan/vm_extension.rb +27 -0
  77. data/lib/bosh/director/errand/runner.rb +1 -1
  78. data/lib/bosh/director/errors.rb +11 -1
  79. data/lib/bosh/director/instance_updater.rb +46 -57
  80. data/lib/bosh/director/instance_updater/instance_state.rb +9 -0
  81. data/lib/bosh/director/instance_updater/state_applier.rb +18 -5
  82. data/lib/bosh/director/job_queue.rb +2 -2
  83. data/lib/bosh/director/job_renderer.rb +2 -2
  84. data/lib/bosh/director/job_updater.rb +7 -1
  85. data/lib/bosh/director/jobs/attach_disk.rb +2 -2
  86. data/lib/bosh/director/jobs/cloud_check/apply_resolutions.rb +6 -1
  87. data/lib/bosh/director/jobs/cloud_check/scan_and_fix.rb +14 -3
  88. data/lib/bosh/director/jobs/export_release.rb +1 -1
  89. data/lib/bosh/director/jobs/fetch_logs.rb +1 -4
  90. data/lib/bosh/director/jobs/helpers/compiled_package_deleter.rb +1 -2
  91. data/lib/bosh/director/jobs/helpers/stemcell_deleter.rb +0 -16
  92. data/lib/bosh/director/jobs/release/release_job.rb +7 -7
  93. data/lib/bosh/director/jobs/run_errand.rb +5 -5
  94. data/lib/bosh/director/jobs/ssh.rb +3 -3
  95. data/lib/bosh/director/jobs/update_deployment.rb +41 -5
  96. data/lib/bosh/director/jobs/update_release.rb +78 -82
  97. data/lib/bosh/director/jobs/update_stemcell.rb +1 -1
  98. data/lib/bosh/director/jobs/vm_state.rb +34 -21
  99. data/lib/bosh/director/key_generator.rb +54 -0
  100. data/lib/bosh/director/lock.rb +2 -2
  101. data/lib/bosh/director/log_bundles_cleaner.rb +1 -0
  102. data/lib/bosh/director/manifest/changeset.rb +39 -22
  103. data/lib/bosh/director/manifest/diff_lines.rb +1 -27
  104. data/lib/bosh/director/manifest/manifest.rb +22 -7
  105. data/lib/bosh/director/manifest/redactor.rb +44 -0
  106. data/lib/bosh/director/models.rb +1 -0
  107. data/lib/bosh/director/models/compiled_package.rb +21 -15
  108. data/lib/bosh/director/models/deployment.rb +10 -0
  109. data/lib/bosh/director/models/instance.rb +2 -1
  110. data/lib/bosh/director/models/release_version.rb +0 -16
  111. data/lib/bosh/director/models/runtime_config.rb +19 -0
  112. data/lib/bosh/director/models/template.rb +4 -4
  113. data/lib/bosh/director/package_dependencies_manager.rb +22 -0
  114. data/lib/bosh/director/password_helper.rb +18 -0
  115. data/lib/bosh/director/permission_authorizer.rb +50 -30
  116. data/lib/bosh/director/post_deployment_script_runner.rb +40 -0
  117. data/lib/bosh/director/problem_handlers/missing_disk.rb +2 -2
  118. data/lib/bosh/director/problem_resolver.rb +8 -2
  119. data/lib/bosh/director/problem_scanner/scanner.rb +1 -1
  120. data/lib/bosh/director/problem_scanner/vm_scan_stage.rb +1 -1
  121. data/lib/bosh/director/validation_helper.rb +5 -5
  122. data/lib/bosh/director/version.rb +1 -1
  123. data/lib/bosh/director/vm_creator.rb +8 -0
  124. data/lib/cloud/dummy.rb +1 -0
  125. metadata +51 -19
  126. data/lib/bosh/director/api/vm_state_manager.rb +0 -9
  127. data/lib/bosh/director/compiled_package/blob_sha_mismatch_error.rb +0 -5
  128. data/lib/bosh/director/compiled_package/compiled_package.rb +0 -30
@@ -15,7 +15,7 @@ module Bosh
15
15
  manifest['jobs'].each do |job|
16
16
  if job.has_key?('migrated_from')
17
17
  raise Bosh::Director::DeploymentInvalidProperty,
18
- "Deployment manifest jobs contain 'migrated_from', but it can only be used with cloud-config."
18
+ "Deployment manifest instance groups contain 'migrated_from', but it can only be used with cloud-config."
19
19
  end
20
20
  end
21
21
  end
@@ -1,15 +1,15 @@
1
1
  module Bosh::Director::DeploymentPlan
2
2
  class NetworkSettings
3
- def initialize(job_name, deployment_name, default_network, desired_reservations, state, availability_zone, instance_index, instance_id, dns_manager)
3
+ def initialize(job_name, deployment_name, default_network, desired_reservations, current_networks, availability_zone, instance_index, instance_id, dns_manager)
4
4
  @job_name = job_name
5
5
  @desired_reservations = desired_reservations
6
6
  @default_network = default_network
7
7
  @deployment_name = deployment_name
8
- @state = state
9
8
  @availability_zone = availability_zone
10
9
  @instance_index = instance_index
11
10
  @instance_id = instance_id
12
11
  @dns_manager = dns_manager
12
+ @current_networks = current_networks
13
13
  end
14
14
 
15
15
  def to_hash
@@ -22,16 +22,12 @@ module Bosh::Director::DeploymentPlan
22
22
  @desired_reservations.each do |reservation|
23
23
  network_name = reservation.network.name
24
24
  network_settings[network_name] = reservation.network.network_settings(reservation, default_properties[network_name], @availability_zone)
25
-
26
25
  # Somewhat of a hack: for dynamic networks we might know IP address, Netmask & Gateway
27
26
  # if they're featured in agent state, in that case we put them into network spec to satisfy
28
27
  # ConfigurationHasher in both agent and director.
29
- if @state.is_a?(Hash) &&
30
- @state['networks'].is_a?(Hash) &&
31
- @state['networks'][network_name].is_a?(Hash) &&
32
- network_settings[network_name]['type'] == 'dynamic'
28
+ if @current_networks.is_a?(Hash) && @current_networks[network_name].is_a?(Hash) && network_settings[network_name]['type'] == 'dynamic'
33
29
  %w(ip netmask gateway).each do |key|
34
- network_settings[network_name][key] = @state['networks'][network_name][key]
30
+ network_settings[network_name][key] = @current_networks[network_name][key] unless @current_networks[network_name][key].nil?
35
31
  end
36
32
  end
37
33
  end
@@ -50,16 +46,34 @@ module Bosh::Director::DeploymentPlan
50
46
  dns_record_info
51
47
  end
52
48
 
49
+ def network_address(preferred_network_name = nil)
50
+ network_name = preferred_network_name || @default_network['gateway']
51
+ network_hash = to_hash
52
+
53
+ if network_hash[network_name]['type'] == 'dynamic'
54
+ address = @dns_manager.dns_record_name(@instance_id, @job_name, network_name, @deployment_name)
55
+ else
56
+ address = network_hash[network_name]['ip']
57
+ end
58
+
59
+ address
60
+ end
61
+
53
62
  def network_addresses
54
63
  network_addresses = {}
64
+
55
65
  to_hash.each do |network_name, network|
56
- network_addresses[network_name] = {
57
- 'address' => network['type'] == 'dynamic' ?
58
- @dns_manager.dns_record_name(@instance_id, @job_name, network_name, @deployment_name) :
59
- network['ip']
60
- }
66
+ if network['type'] == 'dynamic'
67
+ address = @dns_manager.dns_record_name(@instance_id, @job_name, network_name, @deployment_name)
68
+ else
69
+ address = network['ip']
70
+ end
71
+
72
+ network_addresses[network_name] = address
61
73
  end
74
+
62
75
  network_addresses
63
76
  end
77
+
64
78
  end
65
79
  end
@@ -6,19 +6,23 @@ module Bosh::Director
6
6
  @logger = logger
7
7
  end
8
8
 
9
- def validate(release_version_model, stemcel_model)
9
+ def validate(release_version_model, stemcell_model)
10
10
  release_desc = "#{release_version_model.release.name}/#{release_version_model.version}"
11
11
 
12
12
  @logger.debug("Validating packages for release '#{release_desc}'")
13
13
  release_version_model.packages.each do |package|
14
- packages_list = release_version_model.transitive_dependencies(package)
14
+ packages_list = Bosh::Director::PackageDependenciesManager.new(release_version_model).transitive_dependencies(package)
15
15
  packages_list << package
16
16
  packages_list.each do |needed_package|
17
17
  if needed_package.sha1.nil? || needed_package.blobstore_id.nil?
18
- compiled_packages_list = Bosh::Director::Models::CompiledPackage[:package_id => needed_package.id, :stemcell_id => stemcel_model.id]
19
- if compiled_packages_list.nil?
18
+ compiled_packages_list = Bosh::Director::Models::CompiledPackage.where(:package_id => needed_package.id,
19
+ :stemcell_os => stemcell_model.operating_system).all
20
+ compiled_packages_list = compiled_packages_list.select do |compiled_package|
21
+ Bosh::Common::Version::StemcellVersion.match(compiled_package.stemcell_version, stemcell_model.version)
22
+ end
23
+ if compiled_packages_list.empty?
20
24
  @faults[release_desc] ||= Set.new
21
- @faults[release_desc] << Fault.new(needed_package, stemcel_model)
25
+ @faults[release_desc] << Fault.new(needed_package, stemcell_model)
22
26
  end
23
27
  end
24
28
  end
@@ -19,7 +19,7 @@ module Bosh
19
19
  subnet_for_ip = subnets.find { |subnet| subnet.static_ips.include?(static_ip) }
20
20
  if subnet_for_ip.nil?
21
21
  raise JobNetworkInstanceIpMismatch,
22
- "Job '#{job_name}' with network '#{job_network.name}' declares static ip '#{format_ip(static_ip)}', " +
22
+ "Instance group '#{job_name}' with network '#{job_network.name}' declares static ip '#{format_ip(static_ip)}', " +
23
23
  "which belongs to no subnet"
24
24
  end
25
25
  az_names = subnet_for_ip.availability_zone_names.nil? ? [nil] : subnet_for_ip.availability_zone_names
@@ -44,7 +44,7 @@ module Bosh
44
44
  end
45
45
 
46
46
  raise JobInvalidAvailabilityZone,
47
- "Job '#{@job_name}' subnets declare availability zones and the job does not"
47
+ "Instance group '#{@job_name}' subnets declare availability zones and the instance group does not"
48
48
  end
49
49
  end
50
50
 
@@ -59,7 +59,7 @@ module Bosh
59
59
 
60
60
  if non_desired_ip_to_az
61
61
  raise JobStaticIpsFromInvalidAvailabilityZone,
62
- "Job '#{@job_name}' declares static ip '#{format_ip(non_desired_ip_to_az.ip)}' which does not belong to any of the job's availability zones."
62
+ "Instance group '#{@job_name}' declares static ip '#{format_ip(non_desired_ip_to_az.ip)}' which does not belong to any of the instance group's availability zones."
63
63
  end
64
64
  end
65
65
  end
@@ -79,7 +79,7 @@ module Bosh
79
79
  def distribute_evenly_per_zone
80
80
  best_combination = BruteForceIpAllocation.new(@networks_to_static_ips).find_best_combination
81
81
  if best_combination.nil?
82
- raise JobNetworkInstanceIpMismatch, "Failed to evenly distribute static IPs between zones for job '#{@job_name}'"
82
+ raise JobNetworkInstanceIpMismatch, "Failed to evenly distribute static IPs between zones for instance group '#{@job_name}'"
83
83
  end
84
84
  @networks_to_static_ips = best_combination
85
85
  end
@@ -1,5 +1,6 @@
1
1
  require 'bosh/director/deployment_plan/deployment_spec_parser'
2
2
  require 'bosh/director/deployment_plan/cloud_manifest_parser'
3
+ require 'bosh/director/deployment_plan/runtime_manifest_parser'
3
4
  require 'bosh/director/deployment_plan/disk_type'
4
5
  require 'forwardable'
5
6
  require 'common/deep_copy'
@@ -51,15 +52,14 @@ module Bosh::Director
51
52
  # @return [Boolean] Indicates whether VMs should be drained
52
53
  attr_reader :skip_drain
53
54
 
54
- def initialize(attrs, manifest_text, cloud_config, deployment_model, options = {})
55
- @cloud_config = cloud_config
56
-
55
+ def initialize(attrs, manifest_text, cloud_config, runtime_config, deployment_model, options = {})
57
56
  @name = attrs.fetch(:name)
58
57
  @properties = attrs.fetch(:properties)
59
58
  @releases = {}
60
59
 
61
60
  @manifest_text = Bosh::Common::DeepCopy.copy(manifest_text)
62
61
  @cloud_config = cloud_config
62
+ @runtime_config = runtime_config
63
63
  @model = deployment_model
64
64
 
65
65
  @stemcells = {}
@@ -88,6 +88,8 @@ module Bosh::Director
88
88
  :resource_pool,
89
89
  :vm_types,
90
90
  :vm_type,
91
+ :vm_extensions,
92
+ :vm_extension,
91
93
  :add_resource_pool,
92
94
  :disk_types,
93
95
  :disk_type,
@@ -98,7 +100,7 @@ module Bosh::Director
98
100
  Canonicalizer.canonicalize(@name)
99
101
  end
100
102
 
101
- def bind_models
103
+ def bind_models(skip_links_binding = false)
102
104
  stemcell_manager = Api::StemcellManager.new
103
105
  dns_manager = DnsManagerProvider.create
104
106
  assembler = DeploymentPlan::Assembler.new(
@@ -109,7 +111,7 @@ module Bosh::Director
109
111
  @logger
110
112
  )
111
113
 
112
- assembler.bind_models
114
+ assembler.bind_models(skip_links_binding)
113
115
  end
114
116
 
115
117
  def compile_packages
@@ -209,7 +211,7 @@ module Bosh::Director
209
211
  def add_job(job)
210
212
  if @jobs_canonical_name_index.include?(job.canonical_name)
211
213
  raise DeploymentCanonicalJobNameTaken,
212
- "Invalid job name `#{job.name}', canonical name already taken"
214
+ "Invalid instance group name '#{job.name}', canonical name already taken"
213
215
  end
214
216
 
215
217
  @jobs << job
@@ -225,7 +227,19 @@ module Bosh::Director
225
227
  end
226
228
 
227
229
  def jobs_starting_on_deploy
228
- @jobs.select(&:starts_on_deploy?)
230
+ jobs = []
231
+
232
+ @jobs.each do |job|
233
+ if job.is_service?
234
+ jobs << job
235
+ elsif job.is_errand?
236
+ if job.instances.any? { |i| nil != i.model && !i.model.vm_cid.to_s.empty? }
237
+ jobs << job
238
+ end
239
+ end
240
+ end
241
+
242
+ jobs
229
243
  end
230
244
 
231
245
  def persist_updates!
@@ -241,6 +255,7 @@ module Bosh::Director
241
255
 
242
256
  model.manifest = Psych.dump(@manifest_text)
243
257
  model.cloud_config = @cloud_config
258
+ model.runtime_config = @runtime_config
244
259
  model.link_spec = @link_spec
245
260
  model.save
246
261
  end
@@ -284,6 +299,7 @@ module Bosh::Director
284
299
  @global_network_resolver = options.fetch(:global_network_resolver)
285
300
  @resource_pools = self.class.index_by_name(options.fetch(:resource_pools))
286
301
  @vm_types = self.class.index_by_name(options.fetch(:vm_types, {}))
302
+ @vm_extensions = self.class.index_by_name(options.fetch(:vm_extensions, {}))
287
303
  @disk_types = self.class.index_by_name(options.fetch(:disk_types))
288
304
  @availability_zones = options.fetch(:availability_zones_list)
289
305
  @compilation = options.fetch(:compilation)
@@ -332,6 +348,14 @@ module Bosh::Director
332
348
  @vm_types[name]
333
349
  end
334
350
 
351
+ def vm_extensions
352
+ @vm_extensions.values
353
+ end
354
+
355
+ def vm_extension(name)
356
+ @vm_extensions[name]
357
+ end
358
+
335
359
  def add_resource_pool(resource_pool)
336
360
  @resource_pools[resource_pool.name] = resource_pool
337
361
  end
@@ -33,17 +33,17 @@ module Bosh
33
33
  end
34
34
 
35
35
  def create_from_model(deployment_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)
36
+ manifest = Manifest.load_from_text(deployment_model.manifest, deployment_model.cloud_config, deployment_model.runtime_config)
37
+ create_from_manifest(manifest, deployment_model.cloud_config, deployment_model.runtime_config, options)
38
38
  end
39
39
 
40
- def create_from_manifest(manifest, cloud_config, options)
41
- parse_from_manifest(manifest, cloud_config, options)
40
+ def create_from_manifest(manifest, cloud_config, runtime_config, options)
41
+ parse_from_manifest(manifest, cloud_config, runtime_config, options)
42
42
  end
43
43
 
44
44
  private
45
45
 
46
- def parse_from_manifest(manifest, cloud_config, options)
46
+ def parse_from_manifest(manifest, cloud_config, runtime_config, options)
47
47
  manifest.resolve_aliases
48
48
  @manifest_validator.validate(manifest.manifest_hash, manifest.cloud_config_hash)
49
49
  deployment_manifest, cloud_manifest = @deployment_manifest_migrator.migrate(manifest.manifest_hash, manifest.cloud_config_hash)
@@ -67,15 +67,156 @@ module Bosh
67
67
  @logger.info('Creating deployment plan')
68
68
  @logger.info("Deployment plan options: #{plan_options}")
69
69
 
70
- deployment = Planner.new(attrs, deployment_manifest, cloud_config, deployment_model, plan_options)
70
+ deployment = Planner.new(attrs, deployment_manifest, cloud_config, runtime_config, deployment_model, plan_options)
71
71
  global_network_resolver = GlobalNetworkResolver.new(deployment)
72
72
 
73
73
  ip_provider_factory = IpProviderFactory.new(deployment.using_global_networking?, @logger)
74
74
  deployment.cloud_planner = CloudManifestParser.new(@logger).parse(cloud_manifest, global_network_resolver, ip_provider_factory)
75
75
  DeploymentSpecParser.new(deployment, Config.event_log, @logger).parse(deployment_manifest, plan_options)
76
+
77
+ if runtime_config
78
+ RuntimeManifestParser.new(@logger, deployment).parse(runtime_config.manifest)
79
+ end
80
+
81
+ process_links(deployment)
82
+
76
83
  DeploymentValidator.new.validate(deployment)
77
84
  deployment
78
85
  end
86
+
87
+ def process_links(deployment)
88
+ errors = []
89
+
90
+ deployment.jobs.each do |current_job|
91
+ current_job.templates.each do |template|
92
+ if template.link_infos.has_key?(current_job.name) && template.link_infos[current_job.name].has_key?('consumes')
93
+ template.link_infos[current_job.name]['consumes'].each do |name, source|
94
+ link_path = LinkPath.new(deployment, current_job.name, template.name)
95
+
96
+ begin
97
+ link_path.parse(source)
98
+ rescue Exception => e
99
+ errors.push e
100
+ end
101
+
102
+ if !link_path.skip
103
+ current_job.add_link_path(template.name, name, link_path)
104
+ end
105
+ end
106
+ end
107
+
108
+ ## Choose between using template-scoped and other props.
109
+ ## if job manifest had a "properties key" in the template block
110
+ if template.template_scoped_properties.has_key?(current_job.name)
111
+ scoped_properties = template.template_scoped_properties[current_job.name]
112
+ else
113
+ scoped_properties = current_job.all_properties || {}
114
+ end
115
+
116
+ if template.link_infos.has_key?(current_job.name) && template.link_infos[current_job.name].has_key?('provides')
117
+ template.link_infos[current_job.name]['provides'].each do |link_name, provided_link|
118
+ if provided_link['properties']
119
+ ## Get default values for this job
120
+ default_properties = get_default_properties(deployment, template)
121
+
122
+ provided_link['mapped_properties'] = process_link_properties(scoped_properties, default_properties, provided_link['properties'], errors)
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ if errors.length > 0
130
+ message = 'Unable to process links for deployment. Errors are:'
131
+
132
+ errors.each do |e|
133
+ message = "#{message}\n - \"#{e.message.gsub(/\n/, "\n ")}\""
134
+ end
135
+
136
+ raise message
137
+ end
138
+ end
139
+
140
+ def get_default_properties(deployment, template)
141
+ release_manager = Api::ReleaseManager.new
142
+
143
+ release_versions_templates_models_hash = {}
144
+
145
+ template_name = template.name
146
+ release_name = template.release.name
147
+
148
+ release = deployment.release(release_name)
149
+
150
+ if !release_versions_templates_models_hash.has_key?(release_name)
151
+ release_model = release_manager.find_by_name(release_name)
152
+ current_release_version = release_manager.find_version(release_model, release.version)
153
+ release_versions_templates_models_hash[release_name] = current_release_version.templates
154
+ end
155
+
156
+ templates_models_list = release_versions_templates_models_hash[release_name]
157
+ current_template_model = templates_models_list.find {|target| target.name == template_name }
158
+
159
+ if current_template_model.properties != nil
160
+ default_prop = {}
161
+ default_prop['properties'] = current_template_model.properties
162
+ default_prop["template_name"] = template.name
163
+ return default_prop
164
+ end
165
+
166
+ return {"template_name" => template.name}
167
+ end
168
+
169
+ def process_link_properties(scoped_properties, default_properties, link_property_list, errors)
170
+ mapped_properties = {}
171
+
172
+ link_property_list.each do |link_property| #list of properties
173
+ previous_property_in_loop = {}
174
+ current_property_in_loop = scoped_properties
175
+ mapped_properties_in_loop = mapped_properties
176
+
177
+ use_defaults = false
178
+ property_path = link_property.split(".")
179
+ property_path.each do |key|
180
+ if !current_property_in_loop || !current_property_in_loop.has_key?(key)
181
+ use_defaults = true
182
+ else
183
+ current_property_in_loop = current_property_in_loop[key]
184
+ end
185
+
186
+ if !mapped_properties_in_loop.has_key?(key)
187
+ mapped_properties_in_loop[key] = {}
188
+ end
189
+ previous_property_in_loop = mapped_properties_in_loop
190
+ mapped_properties_in_loop = mapped_properties_in_loop[key]
191
+ end
192
+
193
+ if use_defaults
194
+ if default_properties.has_key?('properties') && default_properties['properties'].has_key?(link_property)
195
+ if default_properties['properties'][link_property].has_key?('default')
196
+ previous_property_in_loop[property_path.last()] = default_properties['properties'][link_property]['default']
197
+ else
198
+ e = Exception.new("Link property #{link_property} in template #{default_properties['template_name']} has no default value or value supplied by the deployment manifest")
199
+ errors.push(e)
200
+ end
201
+ else
202
+ e = Exception.new("Link property #{link_property} in template #{default_properties['template_name']} is not defined in release spec")
203
+ errors.push(e)
204
+ end
205
+ else
206
+ previous_property_in_loop[property_path.last()] = current_property_in_loop
207
+ end
208
+
209
+ # if use_defaults && !default_properties.has_key?("properties") && !default_properties['properties'][link_property].has_key?('default')
210
+ # e = Exception.new("Property #{link_property} in template #{default_properties['template_name']} has no default value or value supplied by the deployment manifest")
211
+ # errors.push(e)
212
+ # elsif use_defaults
213
+ # previous_property_in_loop[property_path.last()] = default_properties['properties'][link_property]['default']
214
+ # else
215
+ # previous_property_in_loop[property_path.last()] = current_property_in_loop
216
+ # end
217
+ end
218
+ return mapped_properties
219
+ end
79
220
  end
80
221
  end
81
222
  end
@@ -0,0 +1,142 @@
1
+ module Bosh::Director
2
+ module DeploymentPlan
3
+ class RuntimeManifestParser
4
+ include ValidationHelper
5
+
6
+ def initialize(logger, deployment=nil)
7
+ @deployment = deployment
8
+ @logger = logger
9
+ end
10
+
11
+ def parse(runtime_manifest)
12
+ parse_releases(runtime_manifest)
13
+ parse_addons(runtime_manifest)
14
+ end
15
+
16
+ private
17
+
18
+ def parse_releases(runtime_manifest)
19
+ @release_specs = []
20
+
21
+ if runtime_manifest['release']
22
+ if runtime_manifest['releases']
23
+ raise RuntimeAmbiguousReleaseSpec,
24
+ "Runtime manifest contains both `release' and `releases' " +
25
+ 'sections, please use one of the two.'
26
+ end
27
+ @release_specs << runtime_manifest['release']
28
+ else
29
+ safe_property(runtime_manifest, 'releases', :class => Array).each do |release|
30
+ @release_specs << release
31
+ end
32
+ end
33
+
34
+ @release_specs.each do |release_spec|
35
+ if release_spec['version'] == 'latest'
36
+ raise RuntimeInvalidReleaseVersion,
37
+ "Runtime manifest contains the release `#{release_spec['name']}' with version as `latest'. " +
38
+ "Please specify the actual version string."
39
+ end
40
+
41
+ if @deployment
42
+ deployment_release = @deployment.release(release_spec["name"])
43
+ if deployment_release
44
+ if deployment_release.version != release_spec["version"]
45
+ raise RuntimeInvalidDeploymentRelease, "Runtime manifest specifies release `#{release_spec["name"]}' with version as `#{release_spec["version"]}'. " +
46
+ "This conflicts with version `#{deployment_release.version}' specified in the deployment manifest."
47
+ else
48
+ next
49
+ end
50
+ end
51
+
52
+ release_version = DeploymentPlan::ReleaseVersion.new(@deployment.model, release_spec)
53
+ release_version.bind_model
54
+
55
+ @deployment.add_release(release_version)
56
+ end
57
+ end
58
+ end
59
+
60
+ def parse_addons(runtime_manifest)
61
+ addons = safe_property(runtime_manifest, 'addons', :class => Array, :default => [])
62
+ addons.each do |addon_spec|
63
+ deployment_plan_templates = []
64
+
65
+ addon_jobs = safe_property(addon_spec, 'jobs', :class => Array, :default => [])
66
+
67
+ addon_jobs.each do |job|
68
+ if !@release_specs.find { |release_spec| release_spec['name'] == job['release'] }
69
+ raise RuntimeReleaseNotListedInReleases,
70
+ "Runtime manifest specifies job `#{job['name']}' which is defined in `#{job['release']}', but `#{job['release']}' is not listed in the releases section."
71
+ end
72
+
73
+ if @deployment
74
+ valid_release_versions = @deployment.releases.map {|r| r.name }
75
+ deployment_release_ids = Models::Release.where(:name => valid_release_versions).map {|r| r.id}
76
+ deployment_jobs = @deployment.jobs
77
+
78
+ templates_from_model = Models::Template.where(:name => job['name'], :release_id => deployment_release_ids)
79
+ if templates_from_model == nil
80
+ raise "Job '#{job['name']}' not found in Template table"
81
+ end
82
+
83
+ release = @deployment.release(job['release'])
84
+ release.bind_model
85
+
86
+ template = DeploymentPlan::Template.new(release, job['name'])
87
+
88
+ deployment_jobs.each do |j|
89
+ templates_from_model.each do |template_from_model|
90
+ if template_from_model.consumes != nil
91
+ template_from_model.consumes.each do |consumes|
92
+ template.add_link_info(j.name, 'consumes', consumes["name"], consumes)
93
+ end
94
+ end
95
+ if template_from_model.provides != nil
96
+ template_from_model.provides.each do |provides|
97
+ template.add_link_info(j.name, 'provides', provides["name"], provides)
98
+ end
99
+ end
100
+ end
101
+
102
+ provides_links = safe_property(job, 'provides', class: Hash, optional: true)
103
+ provides_links.to_a.each do |link_name, source|
104
+ template.add_link_info(j.name, "provides", link_name, source)
105
+ end
106
+
107
+ consumes_links = safe_property(job, 'consumes', class: Hash, optional: true)
108
+ consumes_links.to_a.each do |link_name, source|
109
+ template.add_link_info(j.name, 'consumes', link_name, source)
110
+ end
111
+ end
112
+
113
+ template.bind_models
114
+ deployment_plan_templates.push(template)
115
+
116
+ deployment_jobs.each do |job|
117
+ merge_addon(job, deployment_plan_templates, addon_spec['properties'])
118
+ end
119
+
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ def merge_addon(job, templates, properties)
126
+ if job.templates
127
+ job.templates.concat(templates)
128
+ else
129
+ job.templates = templates
130
+ end
131
+
132
+ if properties
133
+ if job.all_properties
134
+ job.all_properties.merge!(properties)
135
+ else
136
+ job.all_properties = properties
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end