bosh-director 1.3160.0 → 1.3163.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bosh-director-worker +2 -14
  3. data/db/migrations/director/20150513225143_ip_addresses.rb +11 -0
  4. data/db/migrations/director/20150702004608_add_links.rb +8 -0
  5. data/db/migrations/director/20150708231924_add_link_spec.rb +7 -0
  6. data/db/migrations/director/20150724183256_add_debugging_to_ip_addresses.rb +8 -0
  7. data/db/migrations/director/20150730225029_add_uuid_to_instances.rb +16 -0
  8. data/db/migrations/director/20150803215805_add_availabililty_zone_and_cloud_properties_to_instances.rb +8 -0
  9. data/db/migrations/director/20150804211419_add_compilation_flag_to_instance.rb +7 -0
  10. data/db/migrations/director/20150918003455_add_bootstrap_node_to_instance.rb +7 -0
  11. data/db/migrations/director/20151008232214_add_dns_records.rb +7 -0
  12. data/db/migrations/director/20151015172551_add_orphan_disks_and_snapshots.rb +29 -0
  13. data/db/migrations/director/20151030222853_add_templates_to_instance.rb +10 -0
  14. data/db/migrations/director/20151031001039_add_spec_to_instance.rb +19 -0
  15. data/db/migrations/director/20151109190602_rename_orphan_columns.rb +13 -0
  16. data/lib/bosh/director.rb +19 -9
  17. data/lib/bosh/director/agent_client.rb +0 -17
  18. data/lib/bosh/director/api/cloud_config_manager.rb +7 -5
  19. data/lib/bosh/director/api/controllers/base_controller.rb +3 -2
  20. data/lib/bosh/director/api/controllers/cleanup_controller.rb +15 -0
  21. data/lib/bosh/director/api/controllers/deployments_controller.rb +38 -26
  22. data/lib/bosh/director/api/controllers/disks_controller.rb +20 -0
  23. data/lib/bosh/director/api/controllers/info_controller.rb +2 -2
  24. data/lib/bosh/director/api/controllers/releases_controller.rb +1 -16
  25. data/lib/bosh/director/api/controllers/stemcells_controller.rb +1 -9
  26. data/lib/bosh/director/api/deployment_manager.rb +2 -1
  27. data/lib/bosh/director/api/instance_lookup.rb +17 -0
  28. data/lib/bosh/director/api/instance_manager.rb +20 -10
  29. data/lib/bosh/director/api/release_manager.rb +28 -8
  30. data/lib/bosh/director/api/resurrector_manager.rb +9 -2
  31. data/lib/bosh/director/api/route_configuration.rb +2 -0
  32. data/lib/bosh/director/api/snapshot_manager.rb +9 -5
  33. data/lib/bosh/director/api/stemcell_manager.rb +50 -0
  34. data/lib/bosh/director/app.rb +1 -1
  35. data/lib/bosh/director/cloudcheck_helper.rb +119 -132
  36. data/lib/bosh/director/compile_task.rb +1 -1
  37. data/lib/bosh/director/compile_task_generator.rb +2 -2
  38. data/lib/bosh/director/config.rb +21 -12
  39. data/lib/bosh/director/deployment_deleter.rb +69 -0
  40. data/lib/bosh/director/deployment_plan.rb +35 -4
  41. data/lib/bosh/director/deployment_plan/agent_state_migrator.rb +47 -0
  42. data/lib/bosh/director/deployment_plan/assembler.rb +115 -241
  43. data/lib/bosh/director/deployment_plan/availability_zone.rb +27 -0
  44. data/lib/bosh/director/deployment_plan/cloud_manifest_parser.rb +144 -35
  45. data/lib/bosh/director/deployment_plan/compilation_config.rb +21 -19
  46. data/lib/bosh/director/deployment_plan/compilation_instance_pool.rb +169 -0
  47. data/lib/bosh/director/deployment_plan/deployment_repo.rb +4 -8
  48. data/lib/bosh/director/deployment_plan/deployment_spec_parser.rb +13 -1
  49. data/lib/bosh/director/deployment_plan/deployment_validator.rb +17 -0
  50. data/lib/bosh/director/deployment_plan/desired_instance.rb +15 -0
  51. data/lib/bosh/director/deployment_plan/{disk_pool.rb → disk_type.rb} +14 -19
  52. data/lib/bosh/director/deployment_plan/dynamic_network.rb +105 -53
  53. data/lib/bosh/director/deployment_plan/dynamic_network_subnet.rb +13 -0
  54. data/lib/bosh/director/deployment_plan/env.rb +18 -0
  55. data/lib/bosh/director/deployment_plan/global_network_resolver.rb +77 -0
  56. data/lib/bosh/director/deployment_plan/instance.rb +222 -390
  57. data/lib/bosh/director/deployment_plan/instance_network_reservations.rb +71 -0
  58. data/lib/bosh/director/deployment_plan/instance_plan.rb +336 -0
  59. data/lib/bosh/director/deployment_plan/instance_plan_factory.rb +54 -0
  60. data/lib/bosh/director/deployment_plan/instance_plan_sorter.rb +61 -0
  61. data/lib/bosh/director/deployment_plan/instance_planner.rb +101 -0
  62. data/lib/bosh/director/deployment_plan/instance_repository.rb +36 -0
  63. data/lib/bosh/director/deployment_plan/instance_spec.rb +154 -0
  64. data/lib/bosh/director/deployment_plan/ip_provider/database_ip_repo.rb +136 -0
  65. data/lib/bosh/director/deployment_plan/ip_provider/in_memory_ip_repo.rb +81 -0
  66. data/lib/bosh/director/deployment_plan/ip_provider/ip_provider.rb +153 -0
  67. data/lib/bosh/director/deployment_plan/ip_provider/ip_provider_factory.rb +22 -0
  68. data/lib/bosh/director/deployment_plan/job.rb +116 -53
  69. data/lib/bosh/director/deployment_plan/job_availability_zone_parser.rb +49 -0
  70. data/lib/bosh/director/deployment_plan/job_migrator.rb +90 -0
  71. data/lib/bosh/director/deployment_plan/job_network.rb +42 -0
  72. data/lib/bosh/director/deployment_plan/job_network_parser.rb +118 -0
  73. data/lib/bosh/director/deployment_plan/job_spec_parser.rb +123 -126
  74. data/lib/bosh/director/deployment_plan/links/link.rb +30 -0
  75. data/lib/bosh/director/deployment_plan/links/link_lookup.rb +66 -0
  76. data/lib/bosh/director/deployment_plan/links/link_path.rb +27 -0
  77. data/lib/bosh/director/deployment_plan/links/links_resolver.rb +70 -0
  78. data/lib/bosh/director/deployment_plan/links/template_link.rb +21 -0
  79. data/lib/bosh/director/deployment_plan/manifest_migrator.rb +3 -17
  80. data/lib/bosh/director/deployment_plan/manifest_validator.rb +46 -0
  81. data/lib/bosh/director/deployment_plan/manual_network.rb +70 -97
  82. data/lib/bosh/director/deployment_plan/manual_network_subnet.rb +148 -0
  83. data/lib/bosh/director/deployment_plan/network.rb +50 -39
  84. data/lib/bosh/director/deployment_plan/network_planner.rb +4 -0
  85. data/lib/bosh/director/deployment_plan/network_planner/plan.rb +26 -0
  86. data/lib/bosh/director/deployment_plan/network_planner/planner.rb +21 -0
  87. data/lib/bosh/director/deployment_plan/network_planner/reservation_reconciler.rb +81 -0
  88. data/lib/bosh/director/deployment_plan/network_planner/vip_static_ips_planner.rb +50 -0
  89. data/lib/bosh/director/deployment_plan/network_settings.rb +65 -0
  90. data/lib/bosh/director/deployment_plan/options/skip_drain.rb +7 -0
  91. data/lib/bosh/director/deployment_plan/package_validator.rb +79 -0
  92. data/lib/bosh/director/deployment_plan/placement_planner.rb +8 -0
  93. data/lib/bosh/director/deployment_plan/placement_planner/availability_zone_picker.rb +90 -0
  94. data/lib/bosh/director/deployment_plan/placement_planner/bruteforce_ip_allocation.rb +124 -0
  95. data/lib/bosh/director/deployment_plan/placement_planner/index_assigner.rb +32 -0
  96. data/lib/bosh/director/deployment_plan/placement_planner/networks_to_static_ips.rb +125 -0
  97. data/lib/bosh/director/deployment_plan/placement_planner/placed_desired_instances.rb +40 -0
  98. data/lib/bosh/director/deployment_plan/placement_planner/plan.rb +42 -0
  99. data/lib/bosh/director/deployment_plan/placement_planner/static_ips_availability_zone_picker.rb +237 -0
  100. data/lib/bosh/director/deployment_plan/placement_planner/unplaced_existing_instances.rb +53 -0
  101. data/lib/bosh/director/deployment_plan/planner.rb +186 -74
  102. data/lib/bosh/director/deployment_plan/planner_factory.rb +30 -147
  103. data/lib/bosh/director/deployment_plan/release_version.rb +3 -3
  104. data/lib/bosh/director/deployment_plan/resource_pool.rb +2 -174
  105. data/lib/bosh/director/deployment_plan/stemcell.rb +57 -14
  106. data/lib/bosh/director/deployment_plan/steps/package_compile_step.rb +28 -135
  107. data/lib/bosh/director/deployment_plan/steps/update_step.rb +23 -44
  108. data/lib/bosh/director/deployment_plan/template.rb +15 -4
  109. data/lib/bosh/director/deployment_plan/vip_network.rb +14 -42
  110. data/lib/bosh/director/deployment_plan/vm.rb +1 -99
  111. data/lib/bosh/director/deployment_plan/vm_type.rb +27 -0
  112. data/lib/bosh/director/disk_manager.rb +268 -0
  113. data/lib/bosh/director/dns/canonicalizer.rb +28 -0
  114. data/lib/bosh/director/dns/dns_manager.rb +163 -0
  115. data/lib/bosh/director/dns/local_dns_repo.rb +20 -0
  116. data/lib/bosh/director/dns/powerdns.rb +170 -0
  117. data/lib/bosh/director/errand/job_manager.rb +18 -29
  118. data/lib/bosh/director/error_ignorer.rb +16 -0
  119. data/lib/bosh/director/errors.rb +51 -20
  120. data/lib/bosh/director/event_log.rb +6 -0
  121. data/lib/bosh/director/instance_deleter.rb +53 -81
  122. data/lib/bosh/director/instance_reuser.rb +89 -0
  123. data/lib/bosh/director/instance_updater.rb +139 -281
  124. data/lib/bosh/director/instance_updater/preparer.rb +8 -5
  125. data/lib/bosh/director/instance_updater/state_applier.rb +21 -0
  126. data/lib/bosh/director/ip_util.rb +46 -26
  127. data/lib/bosh/director/job_renderer.rb +22 -10
  128. data/lib/bosh/director/job_runner.rb +1 -4
  129. data/lib/bosh/director/job_updater.rb +47 -35
  130. data/lib/bosh/director/job_updater_factory.rb +5 -4
  131. data/lib/bosh/director/jobs/base_job.rb +8 -0
  132. data/lib/bosh/director/jobs/cleanup_artifacts.rb +93 -0
  133. data/lib/bosh/director/jobs/delete_deployment.rb +10 -154
  134. data/lib/bosh/director/jobs/delete_deployment_snapshots.rb +1 -1
  135. data/lib/bosh/director/jobs/delete_orphan_disks.rb +44 -0
  136. data/lib/bosh/director/jobs/delete_release.rb +19 -196
  137. data/lib/bosh/director/jobs/delete_stemcell.rb +10 -76
  138. data/lib/bosh/director/jobs/export_release.rb +41 -121
  139. data/lib/bosh/director/jobs/fetch_logs.rb +0 -6
  140. data/lib/bosh/director/jobs/helpers.rb +10 -0
  141. data/lib/bosh/director/jobs/helpers/blob_deleter.rb +24 -0
  142. data/lib/bosh/director/jobs/helpers/compiled_package_deleter.rb +24 -0
  143. data/lib/bosh/director/jobs/helpers/name_version_release_deleter.rb +48 -0
  144. data/lib/bosh/director/jobs/helpers/package_deleter.rb +33 -0
  145. data/lib/bosh/director/jobs/helpers/release_deleter.rb +52 -0
  146. data/lib/bosh/director/jobs/helpers/release_version_deleter.rb +115 -0
  147. data/lib/bosh/director/jobs/helpers/releases_to_delete_picker.rb +31 -0
  148. data/lib/bosh/director/jobs/helpers/stemcell_deleter.rb +61 -0
  149. data/lib/bosh/director/jobs/helpers/stemcells_to_delete_picker.rb +30 -0
  150. data/lib/bosh/director/jobs/helpers/template_deleter.rb +20 -0
  151. data/lib/bosh/director/jobs/release/release_job.rb +18 -7
  152. data/lib/bosh/director/jobs/run_errand.rb +57 -36
  153. data/lib/bosh/director/jobs/scheduled_orphan_cleanup.rb +46 -0
  154. data/lib/bosh/director/jobs/ssh.rb +50 -17
  155. data/lib/bosh/director/jobs/update_deployment.rb +29 -11
  156. data/lib/bosh/director/jobs/update_release.rb +25 -4
  157. data/lib/bosh/director/jobs/vm_state.rb +23 -32
  158. data/lib/bosh/director/lock.rb +13 -8
  159. data/lib/bosh/director/logs_fetcher.rb +1 -1
  160. data/lib/bosh/director/models.rb +3 -0
  161. data/lib/bosh/director/models/compiled_package.rb +3 -3
  162. data/lib/bosh/director/models/deployment.rb +10 -0
  163. data/lib/bosh/director/models/instance.rb +77 -1
  164. data/lib/bosh/director/models/ip_address.rb +26 -0
  165. data/lib/bosh/director/models/orphan_disk.rb +23 -0
  166. data/lib/bosh/director/models/orphan_snapshot.rb +14 -0
  167. data/lib/bosh/director/models/template.rb +32 -9
  168. data/lib/bosh/director/models/vm.rb +5 -8
  169. data/lib/bosh/director/network_reservation.rb +69 -99
  170. data/lib/bosh/director/problem_handlers/inactive_disk.rb +5 -20
  171. data/lib/bosh/director/problem_handlers/missing_disk.rb +2 -13
  172. data/lib/bosh/director/problem_resolver.rb +2 -2
  173. data/lib/bosh/director/problem_scanner/vm_scan_stage.rb +2 -21
  174. data/lib/bosh/director/scheduler.rb +23 -6
  175. data/lib/bosh/director/{instance_updater/stopper.rb → stopper.rb} +24 -18
  176. data/lib/bosh/director/tagged_logger.rb +30 -0
  177. data/lib/bosh/director/transactor.rb +9 -0
  178. data/lib/bosh/director/version.rb +1 -1
  179. data/lib/bosh/director/vm_creator.rb +91 -19
  180. data/lib/bosh/director/vm_deleter.rb +25 -0
  181. data/lib/bosh/director/vm_recreator.rb +15 -0
  182. data/lib/cloud/dummy.rb +381 -94
  183. metadata +110 -30
  184. data/lib/bosh/director/deployment_plan/dns_binder.rb +0 -45
  185. data/lib/bosh/director/deployment_plan/instance_vm_binder.rb +0 -37
  186. data/lib/bosh/director/deployment_plan/network_subnet.rb +0 -166
  187. data/lib/bosh/director/deployment_plan/resource_pools.rb +0 -68
  188. data/lib/bosh/director/dns_helper.rb +0 -223
  189. data/lib/bosh/director/instance_updater/network_updater.rb +0 -110
  190. data/lib/bosh/director/instance_updater/vm_updater.rb +0 -189
  191. data/lib/bosh/director/problem_handlers/out_of_sync_vm.rb +0 -64
  192. data/lib/bosh/director/problem_handlers/unbound_instance_vm.rb +0 -85
  193. data/lib/bosh/director/resource_pool_updater.rb +0 -174
  194. data/lib/bosh/director/vm_data.rb +0 -63
  195. data/lib/bosh/director/vm_reuser.rb +0 -63
@@ -0,0 +1,49 @@
1
+ module Bosh::Director
2
+ module DeploymentPlan
3
+ class JobAvailabilityZoneParser
4
+ include ValidationHelper
5
+
6
+ def parse(job_spec, job, deployment, networks)
7
+ az_names = safe_property(job_spec, 'azs', class: Array, optional: true)
8
+ check_contains(az_names, networks, job)
9
+
10
+ return nil if az_names.nil?
11
+ check_validity_of(az_names, job.name)
12
+ look_up_from_deployment(az_names, deployment, job.name)
13
+ end
14
+
15
+ def check_contains(az_names, networks, job)
16
+ networks.each do |network|
17
+ unless network.has_azs?(az_names)
18
+ raise JobNetworkMissingRequiredAvailabilityZone,
19
+ "Job '#{job.name}' must specify availability zone that matches availability zones of network '#{network.name}'"
20
+ end
21
+ end
22
+ end
23
+
24
+ def check_validity_of(az_names, job_name)
25
+ if az_names.empty?
26
+ raise JobMissingAvailabilityZones, "Job '#{job_name}' has empty availability zones"
27
+ end
28
+
29
+ az_names.each do |name|
30
+ unless name.is_a?(String)
31
+ raise JobInvalidAvailabilityZone, "Job '#{job_name}' has invalid availability zone '#{name}', string expected"
32
+ end
33
+ end
34
+ end
35
+
36
+ def look_up_from_deployment(az_names, deployment, job_name)
37
+ az_names.map do |name|
38
+ az = deployment.availability_zone(name)
39
+ if az.nil?
40
+ raise JobUnknownAvailabilityZone, "Job '#{job_name}' references unknown availability zone '#{name}'"
41
+ end
42
+ az
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+
@@ -0,0 +1,90 @@
1
+ module Bosh::Director
2
+ class DeploymentPlan::MigratedFromJob < Struct.new(:name, :availability_zone); end
3
+
4
+ class DeploymentPlan::JobMigrator
5
+ def initialize(deployment_plan, logger)
6
+ @deployment_plan = deployment_plan
7
+ @logger = logger
8
+ end
9
+
10
+ def find_existing_instances(desired_job)
11
+ instances = []
12
+ existing_instances = @deployment_plan.instance_models.select { |model| model.job == desired_job.name }
13
+ existing_instances.each do |existing_instance|
14
+ instances << existing_instance
15
+ end
16
+
17
+ unless desired_job.migrated_from.to_a.empty?
18
+ migrated_from_instances = all_migrated_from_instances(
19
+ desired_job.migrated_from,
20
+ desired_job
21
+ )
22
+
23
+ instances += migrated_from_instances
24
+ end
25
+
26
+ instances
27
+ end
28
+
29
+ private
30
+
31
+ def all_migrated_from_instances(migrated_from_jobs, desired_job)
32
+ desired_job_name = desired_job.name
33
+ migrated_from_instances = []
34
+
35
+ migrated_from_jobs.each do |migrated_from_job|
36
+ if @deployment_plan.job(migrated_from_job.name)
37
+ raise DeploymentInvalidMigratedFromJob,
38
+ "Failed to migrate job '#{migrated_from_job.name}' to '#{desired_job_name}'. " +
39
+ 'A deployment can not migrate a job and also specify it. ' +
40
+ "Please remove job '#{migrated_from_job.name}'."
41
+ end
42
+
43
+ other_jobs = @deployment_plan.jobs.reject { |job| job.name == desired_job_name }
44
+
45
+ migrate_to_multiple_jobs = other_jobs.any? do |job|
46
+ job.migrated_from.any? do |other_migrated_from_job|
47
+ other_migrated_from_job.name == migrated_from_job.name
48
+ end
49
+ end
50
+
51
+ if migrate_to_multiple_jobs
52
+ raise DeploymentInvalidMigratedFromJob,
53
+ "Failed to migrate job '#{migrated_from_job.name}' to '#{desired_job_name}'. A job may be migrated to only one job."
54
+ end
55
+
56
+ migrated_from_job_instances = []
57
+
58
+ @deployment_plan.existing_instances.each do |instance|
59
+ if instance.job == migrated_from_job.name
60
+ if instance.availability_zone.nil? &&
61
+ migrated_from_job.availability_zone.nil? &&
62
+ desired_job.availability_zones.to_a.compact.any?
63
+ raise DeploymentInvalidMigratedFromJob,
64
+ "Failed to migrate job '#{migrated_from_job.name}' to '#{desired_job_name}', availability zone of '#{migrated_from_job.name}' is not specified"
65
+ end
66
+
67
+ if !migrated_from_job.availability_zone.nil? && !instance.availability_zone.nil?
68
+ if migrated_from_job.availability_zone != instance.availability_zone
69
+ raise DeploymentInvalidMigratedFromJob,
70
+ "Failed to migrate job '#{migrated_from_job.name}' to '#{desired_job_name}', '#{migrated_from_job.name}' belongs to availability zone '#{instance.availability_zone}' and manifest specifies '#{migrated_from_job.availability_zone}'"
71
+ end
72
+ end
73
+
74
+ if instance.availability_zone.nil?
75
+ instance.update(availability_zone: migrated_from_job.availability_zone)
76
+ end
77
+
78
+ migrated_from_job_instances << instance
79
+
80
+ @logger.debug("Migrating job '#{migrated_from_job.name}/#{instance.uuid} (#{instance.index})' to '#{desired_job.name}/#{instance.uuid} (#{instance.index})'")
81
+ end
82
+ end
83
+
84
+ migrated_from_instances += migrated_from_job_instances
85
+ end
86
+
87
+ migrated_from_instances
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,42 @@
1
+ module Bosh::Director
2
+ module DeploymentPlan
3
+ class JobNetwork
4
+ attr_reader :name, :static_ips, :deployment_network
5
+
6
+ def initialize(name, static_ips, default_for, deployment_network)
7
+ @name = name
8
+ @static_ips = static_ips
9
+ @default_for = default_for
10
+ @deployment_network = deployment_network
11
+ end
12
+
13
+ def availability_zones
14
+ @deployment_network.availability_zones
15
+ end
16
+
17
+ def properties_for_which_the_network_is_the_default
18
+ @default_for
19
+ end
20
+
21
+ def static?
22
+ !!@static_ips
23
+ end
24
+
25
+ def vip?
26
+ deployment_network.kind_of?(VipNetwork)
27
+ end
28
+
29
+ def default_for?(property)
30
+ properties_for_which_the_network_is_the_default.include?(property)
31
+ end
32
+
33
+ def make_default_for(defaults)
34
+ @default_for = defaults
35
+ end
36
+
37
+ def has_azs?(az_names)
38
+ @deployment_network.has_azs?(az_names)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,118 @@
1
+ require 'bosh/director/deployment_plan/job_network'
2
+
3
+ module Bosh::Director
4
+ module DeploymentPlan
5
+ class JobNetworksParser
6
+ include ValidationHelper
7
+ include IpUtil
8
+
9
+ def initialize(properties_that_require_defaults)
10
+ @properties_that_require_defaults = properties_that_require_defaults
11
+ end
12
+
13
+ def parse(job_spec, job_name, manifest_networks)
14
+ networks = parse_networks(job_spec, job_name, manifest_networks)
15
+ networks.each do |network|
16
+ validate_default_properties(network, job_name)
17
+ end
18
+
19
+ validate_default_networks(networks, job_name)
20
+
21
+ networks
22
+ end
23
+
24
+ private
25
+
26
+ def parse_networks(job_spec, job_name, manifest_networks)
27
+ network_specs = safe_property(job_spec, "networks", :class => Array)
28
+ if network_specs.empty?
29
+ raise JobMissingNetwork, "Job `#{job_name}' must specify at least one network"
30
+ end
31
+ network_specs.map do |network_spec|
32
+ network_name = safe_property(network_spec, "name", :class => String)
33
+ default_for = safe_property(network_spec, "default", :class => Array, :default => [])
34
+ static_ips = parse_static_ips(network_spec['static_ips'], job_name)
35
+
36
+ deployment_network = look_up_deployment_network(manifest_networks, job_name, network_name)
37
+ deployment_network.validate_reference_from_job!(network_spec, job_name)
38
+
39
+ JobNetwork.new(network_name, static_ips, default_for, deployment_network)
40
+ end
41
+ end
42
+
43
+ def look_up_deployment_network(manifest_networks, job_name, network_name)
44
+ deployment_network = manifest_networks.find{ |network| network.name == network_name }
45
+ if deployment_network.nil?
46
+ raise JobUnknownNetwork, "Job '#{job_name}' references an unknown network '#{network_name}'"
47
+ end
48
+ deployment_network
49
+ end
50
+
51
+ def parse_static_ips(static_ips_raw, job_name)
52
+ static_ips = nil
53
+ if static_ips_raw
54
+ static_ips = []
55
+ each_ip(static_ips_raw) do |ip|
56
+ if static_ips.include?(ip)
57
+ raise JobInvalidStaticIPs, "Job '#{job_name}' specifies static IP '#{format_ip(ip)}' more than once"
58
+ end
59
+
60
+ static_ips.push(ip)
61
+ end
62
+ end
63
+ static_ips
64
+ end
65
+
66
+ def validate_default_properties(network, job_name)
67
+ network.properties_for_which_the_network_is_the_default.each do |property|
68
+ unless @properties_that_require_defaults.include?(property)
69
+ raise JobNetworkInvalidDefault,
70
+ "Job `#{job_name}' specified an invalid default network property `#{property}', " +
71
+ "valid properties are: " + @properties_that_require_defaults.join(", ")
72
+ end
73
+ end
74
+ end
75
+
76
+ def validate_default_networks(networks, job_name)
77
+ networks.first.make_default_for(@properties_that_require_defaults) if networks.count == 1
78
+
79
+ default_networks_for_properties = default_networks_for_properties(networks)
80
+ validate_only_one_default_network(default_networks_for_properties, job_name)
81
+ validate_default_network_for_each_property(default_networks_for_properties, job_name)
82
+ end
83
+
84
+ def validate_default_network_for_each_property(default_networks_for_properties, job_name)
85
+ missing_default_properties = default_networks_for_properties.select { |_, networks|
86
+ networks.empty?
87
+ }.map { |property, _|
88
+ property
89
+ }
90
+ unless missing_default_properties.empty?
91
+ raise JobNetworkMissingDefault,
92
+ "Job `#{job_name}' must specify which network is default for " +
93
+ missing_default_properties.sort.join(", ") + ", since it has more than one network configured"
94
+ end
95
+ end
96
+
97
+ def validate_only_one_default_network(default_networks_for_properties, job_name)
98
+ multiple_defaults = default_networks_for_properties.select { |_, networks|
99
+ networks.count > 1
100
+ }
101
+ unless multiple_defaults.empty?
102
+ message_for_each_property = multiple_defaults.map do |property, networks|
103
+ quoted_network_names = networks.map { |network| "'#{network.name}'" }.join(', ')
104
+ "'#{property}' has default networks: #{quoted_network_names}."
105
+ end
106
+ raise JobNetworkMultipleDefaults,
107
+ "Job `#{job_name}' specified more than one network to contain default. #{message_for_each_property.join(' ')}"
108
+ end
109
+ end
110
+
111
+ def default_networks_for_properties(networks)
112
+ @properties_that_require_defaults.inject({}) do |defaults, property|
113
+ defaults.merge(property => networks.select { |network| network.default_for?(property) })
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -3,7 +3,6 @@ require 'bosh/template/property_helper'
3
3
  module Bosh::Director
4
4
  module DeploymentPlan
5
5
  class JobSpecParser
6
- include DnsHelper
7
6
  include ValidationHelper
8
7
  include Bosh::Template::PropertyHelper
9
8
  include IpUtil
@@ -19,24 +18,34 @@ module Bosh::Director
19
18
  # @return [DeploymentPlan::Job] Job as build from job_spec
20
19
  def parse(job_spec)
21
20
  @job_spec = job_spec
22
- @job = Job.new(@deployment)
21
+ @job = Job.new(@logger)
23
22
 
24
23
  parse_name
25
24
  parse_lifecycle
26
25
 
27
26
  parse_release
27
+ validate_templates
28
+
28
29
  parse_template
29
30
  parse_templates
30
31
 
31
- validate_templates
32
-
33
32
  check_template_uniqueness
34
33
  parse_disk
35
34
  parse_properties
36
35
  parse_resource_pool
37
36
  parse_update_config
38
- parse_instances
39
- parse_networks
37
+
38
+ networks = JobNetworksParser.new(Network::VALID_DEFAULTS).parse(@job_spec, @job.name, @deployment.networks)
39
+ @job.networks = networks
40
+ assign_default_networks(networks)
41
+
42
+ availability_zones = JobAvailabilityZoneParser.new.parse(@job_spec, @job, @deployment, networks)
43
+ @job.availability_zones = availability_zones
44
+
45
+ parse_migrated_from
46
+
47
+ desired_instances = parse_desired_instances(availability_zones, networks)
48
+ @job.desired_instances = desired_instances
40
49
 
41
50
  @job
42
51
  end
@@ -45,7 +54,7 @@ module Bosh::Director
45
54
 
46
55
  def parse_name
47
56
  @job.name = safe_property(@job_spec, "name", :class => String)
48
- @job.canonical_name = canonical(@job.name)
57
+ @job.canonical_name = Canonicalizer.canonicalize(@job.name)
49
58
  end
50
59
 
51
60
  def parse_lifecycle
@@ -100,7 +109,7 @@ module Bosh::Director
100
109
  end
101
110
 
102
111
  Array(template_names).each do |template_name|
103
- @job.templates << @job.release.use_template_named(template_name)
112
+ @job.templates << @job.release.get_or_create_template(template_name)
104
113
  end
105
114
  end
106
115
  end
@@ -109,11 +118,9 @@ module Bosh::Director
109
118
  templates = safe_property(@job_spec, 'templates', class: Array, optional: true)
110
119
 
111
120
  if templates
112
- templates.each do |template|
113
- template_name = safe_property(template, 'name', class: String)
114
- release_name = safe_property(template, 'release', class: String, optional: true)
115
-
116
- release = nil
121
+ templates.each do |template_spec|
122
+ template_name = safe_property(template_spec, 'name', class: String)
123
+ release_name = safe_property(template_spec, 'release', class: String, optional: true)
117
124
 
118
125
  if release_name
119
126
  release = @deployment.release(release_name)
@@ -128,7 +135,15 @@ module Bosh::Director
128
135
  end
129
136
  end
130
137
 
131
- @job.templates << release.use_template_named(template_name)
138
+ @job.templates << release.get_or_create_template(template_name)
139
+
140
+ links = safe_property(template_spec, 'links', class: Hash, optional: true)
141
+ @logger.debug("Parsing template links: #{links.inspect}")
142
+
143
+ links.to_a.each do |name, path|
144
+ link_path = LinkPath.parse(@deployment.name, path, @logger)
145
+ @job.add_link_path(template_name, name, link_path)
146
+ end
132
147
  end
133
148
  end
134
149
  end
@@ -146,30 +161,45 @@ module Bosh::Director
146
161
 
147
162
  def parse_disk
148
163
  disk_size = safe_property(@job_spec, 'persistent_disk', :class => Integer, :optional => true)
164
+ disk_type_name = safe_property(@job_spec, 'persistent_disk_type', :class => String, :optional => true)
149
165
  disk_pool_name = safe_property(@job_spec, 'persistent_disk_pool', :class => String, :optional => true)
150
166
 
151
- if disk_size && disk_pool_name
167
+ if disk_type_name && disk_pool_name
152
168
  raise JobInvalidPersistentDisk,
153
- "Job `#{@job.name}' references both a peristent disk size `#{disk_size}' " +
154
- "and a peristent disk pool `#{disk_pool_name}'"
169
+ "Job `#{@job.name}' specifies both 'disk_types' and 'disk_pools', only one key is allowed. " +
170
+ "'disk_pools' key will be DEPRECATED in the future."
171
+ end
172
+
173
+ if disk_type_name
174
+ disk_name = disk_type_name
175
+ disk_source = 'type'
176
+ else
177
+ disk_name = disk_pool_name
178
+ disk_source = 'pool'
179
+ end
180
+
181
+ if disk_size && disk_name
182
+ raise JobInvalidPersistentDisk,
183
+ "Job `#{@job.name}' references both a persistent disk size `#{disk_size}' " +
184
+ "and a persistent disk #{disk_source} `#{disk_name}'"
155
185
  end
156
186
 
157
187
  if disk_size
158
188
  if disk_size < 0
159
189
  raise JobInvalidPersistentDisk,
160
- "Job `#{@job.name}' references an invalid peristent disk size `#{disk_size}'"
190
+ "Job `#{@job.name}' references an invalid persistent disk size `#{disk_size}'"
161
191
  else
162
192
  @job.persistent_disk = disk_size
163
193
  end
164
194
  end
165
195
 
166
- if disk_pool_name
167
- disk_pool = @deployment.disk_pool(disk_pool_name)
168
- if disk_pool.nil?
169
- raise JobUnknownDiskPool,
170
- "Job `#{@job.name}' references an unknown disk pool `#{disk_pool_name}'"
196
+ if disk_name
197
+ disk_type = @deployment.disk_type(disk_name)
198
+ if disk_type.nil?
199
+ raise JobUnknownDiskType,
200
+ "Job `#{@job.name}' references an unknown disk #{disk_source} `#{disk_name}'"
171
201
  else
172
- @job.persistent_disk_pool = disk_pool
202
+ @job.persistent_disk_type = disk_type
173
203
  end
174
204
  end
175
205
  end
@@ -195,11 +225,46 @@ module Bosh::Director
195
225
  end
196
226
 
197
227
  def parse_resource_pool
198
- resource_pool_name = safe_property(@job_spec, "resource_pool", class: String)
199
- @job.resource_pool = @deployment.resource_pool(resource_pool_name)
200
- if @job.resource_pool.nil?
201
- raise JobUnknownResourcePool,
202
- "Job `#{@job.name}' references an unknown resource pool `#{resource_pool_name}'"
228
+ job_env_hash = safe_property(@job_spec, 'env', class: Hash, :default => {})
229
+ @job.env = Env.new(job_env_hash)
230
+
231
+ resource_pool_name = safe_property(@job_spec, "resource_pool", class: String, optional: true)
232
+ if resource_pool_name
233
+ resource_pool = @deployment.resource_pool(resource_pool_name)
234
+ if resource_pool.nil?
235
+ raise JobUnknownResourcePool,
236
+ "Job `#{@job.name}' references an unknown resource pool `#{resource_pool_name}'"
237
+ end
238
+
239
+ @job.vm_type = VmType.new({
240
+ 'name' => resource_pool.name,
241
+ 'cloud_properties' => resource_pool.cloud_properties
242
+ })
243
+
244
+ @job.stemcell = resource_pool.stemcell
245
+
246
+ if !job_env_hash.empty? && !resource_pool.env.empty?
247
+ raise JobAmbiguousEnv,
248
+ "Job '#{@job.name}' and resource pool: '#{resource_pool_name}' both declare env properties"
249
+ end
250
+
251
+ @job.env = Env.new(resource_pool.env)
252
+
253
+ return
254
+ end
255
+
256
+ vm_type_name = safe_property(@job_spec, 'vm_type', class: String)
257
+ @job.vm_type = @deployment.vm_type(vm_type_name)
258
+ if @job.vm_type.nil?
259
+ raise JobUnknownVmType,
260
+ "Job `#{@job.name}' references an unknown vm type `#{vm_type_name}'"
261
+ end
262
+
263
+ stemcell_name = safe_property(@job_spec, 'stemcell', class: String)
264
+ @job.stemcell = @deployment.stemcell(stemcell_name)
265
+ if @job.stemcell.nil?
266
+ raise JobUnknownStemcell,
267
+ "Job `#{@job.name}' references an unknown stemcell `#{stemcell_name}'"
203
268
  end
204
269
  end
205
270
 
@@ -208,30 +273,26 @@ module Bosh::Director
208
273
  @job.update = UpdateConfig.new(update_spec, @deployment.update)
209
274
  end
210
275
 
211
- def parse_instances
276
+ def parse_desired_instances(availability_zones, networks)
212
277
  @job.state = safe_property(@job_spec, "state", class: String, optional: true)
213
278
  job_size = safe_property(@job_spec, "instances", class: Integer)
214
279
  instance_states = safe_property(@job_spec, "instance_states", class: Hash, default: {})
215
280
 
216
- instance_states.each_pair do |index, state|
217
- begin
218
- index = Integer(index)
219
- rescue ArgumentError
220
- raise JobInvalidInstanceIndex,
221
- "Invalid job index `#{index}', integer expected"
222
- end
223
-
224
- unless (0...job_size).include?(index)
225
- raise JobInvalidInstanceIndex,
226
- "`#{@job.name}/#{index}' is outside of (0..#{job_size-1}) range"
281
+ networks.each do |network|
282
+ static_ips = network.static_ips
283
+ if static_ips && static_ips.size != job_size
284
+ raise JobNetworkInstanceIpMismatch,
285
+ "Job `#{@job.name}' has #{job_size} instances but was allocated #{static_ips.size} static IPs"
227
286
  end
287
+ end
228
288
 
289
+ instance_states.each_pair do |index_or_id, state|
229
290
  unless Job::VALID_JOB_STATES.include?(state)
230
291
  raise JobInvalidInstanceState,
231
- "Invalid state `#{state}' for `#{@job.name}/#{index}', valid states are: #{Job::VALID_JOB_STATES.join(", ")}"
292
+ "Invalid state `#{state}' for `#{@job.name}/#{index_or_id}', valid states are: #{Job::VALID_JOB_STATES.join(", ")}"
232
293
  end
233
294
 
234
- @job.instance_states[index] = state
295
+ @job.instance_states[index_or_id] = state
235
296
  end
236
297
 
237
298
  if @job.state && !Job::VALID_JOB_STATES.include?(@job.state)
@@ -239,93 +300,22 @@ module Bosh::Director
239
300
  "Invalid state `#{@job.state}' for `#{@job.name}', valid states are: #{Job::VALID_JOB_STATES.join(", ")}"
240
301
  end
241
302
 
242
- if @job.lifecycle == 'errand'
243
- @job.resource_pool.reserve_errand_capacity(job_size)
244
- else
245
- @job.resource_pool.reserve_capacity(job_size)
246
- end
247
- job_size.times do |index|
248
- @job.instances[index] = Instance.new(@job, index, @logger)
249
- end
303
+ job_size.times.map { DesiredInstance.new(@job, @deployment) }
250
304
  end
251
305
 
252
- def parse_networks
253
- @job.default_network = {}
254
-
255
- network_specs = safe_property(@job_spec, "networks", :class => Array)
256
- if network_specs.empty?
257
- raise JobMissingNetwork,
258
- "Job `#{@job.name}' must specify at least one network"
259
- end
260
-
261
- network_specs.each do |network_spec|
262
- network_name = safe_property(network_spec, "name", :class => String)
263
- network = @deployment.network(network_name)
264
- if network.nil?
265
- raise JobUnknownNetwork,
266
- "Job `#{@job.name}' references an unknown network `#{network_name}'"
267
- end
268
-
269
- static_ips = nil
270
- if network_spec["static_ips"]
271
- static_ips = []
272
- each_ip(network_spec["static_ips"]) do |ip|
273
- static_ips << ip
274
- end
275
- if static_ips.size != @job.instances.size
276
- raise JobNetworkInstanceIpMismatch,
277
- "Job `#{@job.name}' has #{@job.instances.size} instances but was allocated #{static_ips.size} static IPs"
278
- end
279
- end
280
-
281
- default_network = safe_property(network_spec, "default", :class => Array, :optional => true)
282
- if default_network
283
- default_network.each do |property|
284
- unless Network::VALID_DEFAULTS.include?(property)
285
- raise JobNetworkInvalidDefault,
286
- "Job `#{@job.name}' specified an invalid default network property `#{property}', " +
287
- "valid properties are: " + Network::VALID_DEFAULTS.join(", ")
288
- end
289
-
290
- if @job.default_network[property]
291
- raise JobNetworkMultipleDefaults,
292
- "Job `#{@job.name}' specified more than one network to contain default #{property}"
293
- else
294
- @job.default_network[property] = network_name
295
- end
296
- end
297
- end
298
-
299
- @job.instances.each_with_index do |instance, index|
300
- reservation = NetworkReservation.new
301
- if static_ips
302
- reservation.ip = static_ips[index]
303
- reservation.type = NetworkReservation::STATIC
304
- else
305
- reservation.type = NetworkReservation::DYNAMIC
306
+ def parse_migrated_from
307
+ migrated_from = safe_property(@job_spec, 'migrated_from', class: Array, optional: true, :default => [])
308
+ migrated_from.each do |migrated_from_job_spec|
309
+ name = safe_property(migrated_from_job_spec, 'name', class: String)
310
+ az = safe_property(migrated_from_job_spec, 'az', class: String, optional: true)
311
+ unless az.nil?
312
+ unless @job.availability_zones.to_a.map(&:name).include?(az)
313
+ raise DeploymentInvalidMigratedFromJob,
314
+ "Job '#{name}' specified for migration to job '#{@job.name}' refers to availability zone '#{az}'. " +
315
+ "Az '#{az}' is not in the list of availability zones of job '#{@job.name}'."
306
316
  end
307
- instance.add_network_reservation(network_name, reservation)
308
- end
309
- end
310
-
311
- if network_specs.size > 1
312
- missing_default_properties = Network::VALID_DEFAULTS.dup
313
- @job.default_network.each_key do |key|
314
- missing_default_properties.delete(key)
315
- end
316
-
317
- unless missing_default_properties.empty?
318
- raise JobNetworkMissingDefault,
319
- "Job `#{@job.name}' must specify which network is default for " +
320
- missing_default_properties.sort.join(", ") + ", since it has more than one network configured"
321
- end
322
- else
323
- # Set the default network to the one and only available network
324
- # (if not specified already)
325
- network = safe_property(network_specs[0], "name", :class => String)
326
- Network::VALID_DEFAULTS.each do |property|
327
- @job.default_network[property] ||= network
328
317
  end
318
+ @job.migrated_from << MigratedFromJob.new(name, az)
329
319
  end
330
320
  end
331
321
 
@@ -343,6 +333,13 @@ module Bosh::Director
343
333
  "Job `#{@job.name}' does not specify template or templates keys, one is required"
344
334
  end
345
335
  end
336
+
337
+ def assign_default_networks(networks)
338
+ Network::VALID_DEFAULTS.each do |property|
339
+ network = networks.find { |network| network.default_for?(property) }
340
+ @job.default_network[property] = network.name if network
341
+ end
342
+ end
346
343
  end
347
344
  end
348
345
  end