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
@@ -8,112 +8,14 @@ module Bosh::Director
8
8
  # (network & storage) required for the VM to match the instance
9
9
  # requirements.
10
10
  class Vm
11
- # @return [DeploymentPlan::ResourcePool] Associated resource pool
12
- attr_reader :resource_pool
13
-
14
- # @return [NetworkReservation] VM network reservation
15
- attr_accessor :network_reservation
16
-
17
11
  # @return [Models::Vm] Associated DB model
18
12
  attr_accessor :model
19
13
 
20
- # @return [Hash] Current state as provided by the BOSH Agent
21
- attr_writer :current_state
22
-
23
14
  # @return [DeploymentPlan::Instance, nil] Instance that reserved this VM
24
15
  attr_accessor :bound_instance
25
16
 
26
- def current_state
27
- if @current_state
28
- @current_state.delete('release')
29
- end
30
- @current_state
31
- end
32
-
33
- ##
34
- # Creates a new idle VM reference for the specific resource pool
35
- # @param [DeploymentPlan::ResourcePool] resource_pool Resource pool
36
- def initialize(resource_pool)
37
- @resource_pool = resource_pool
38
- @current_state = nil
39
- @bound_instance = nil
40
- @network_reservation = nil
41
- @model = nil
42
- end
43
-
44
- #
45
- # @return [Boolean] Does this VM have a network reservation?
46
- def has_network_reservation?
47
- !@network_reservation.nil?
48
- end
49
-
50
- #
51
- # Uses provided network reservation
52
- # @param [NetworkReservation] reservation Network reservation
53
- def use_reservation(reservation)
54
- @network_reservation = reservation
55
- end
56
-
57
- #
58
- # Releases current network reservation (if any)
59
- # @return [void]
60
- def release_reservation
61
- if has_network_reservation?
62
- @resource_pool.network.release(@network_reservation)
63
- @network_reservation = nil
64
- end
65
- end
66
-
67
- ##
68
- # @return [Hash] BOSH network settings used for Agent apply call
69
- def network_settings
70
- # use the instance network settings if bound, otherwise use the one
71
- # provided by the resource pool
72
- if @bound_instance
73
- @bound_instance.network_settings
74
- else
75
- unless @network_reservation
76
- raise NetworkReservationMissing,
77
- 'Missing network reservation for resource pool VM'
78
- end
79
-
80
- network_settings = {}
81
- network = @resource_pool.network
82
- network_settings[network.name] = network.network_settings(
83
- @network_reservation)
84
- network_settings
85
- end
86
- end
87
-
88
- ##
89
- # @return [Boolean] returns true if the expected network configuration
90
- # differs from the one provided by the VM
91
- def networks_changed?
92
- network_settings != @current_state['networks']
93
- end
94
-
95
- ##
96
- # @return [Boolean] returns true if the expected resource pool
97
- # specification differs from the one provided by the VM
98
- def resource_pool_changed?
99
- return true if resource_pool.spec != @current_state['resource_pool']
100
- return true if resource_pool.deployment_plan.recreate
101
- return true if @model && @model.env != resource_pool.env
102
-
103
- false
104
- end
105
-
106
- ##
107
- # @return [Boolean] returns true if the any of the expected specifications
108
- # differ from the ones provided by the VM
109
- def changed?
110
- resource_pool_changed? || networks_changed?
111
- end
112
-
113
- #TODO: rename 'clean'
114
- def clean_vm
17
+ def clean
115
18
  self.model = nil
116
- self.current_state = nil
117
19
  end
118
20
  end
119
21
  end
@@ -0,0 +1,27 @@
1
+ module Bosh::Director
2
+ module DeploymentPlan
3
+ class VmType
4
+ include ValidationHelper
5
+
6
+ attr_reader :name
7
+
8
+ attr_reader :cloud_properties
9
+
10
+ def initialize(spec)
11
+
12
+ @name = safe_property(spec, "name", class: String)
13
+
14
+ @cloud_properties =
15
+ safe_property(spec, "cloud_properties", class: Hash, default: {})
16
+
17
+ end
18
+
19
+ def spec
20
+ {
21
+ "name" => @name,
22
+ "cloud_properties" => @cloud_properties,
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,268 @@
1
+ module Bosh::Director
2
+ class DiskManager
3
+
4
+ def initialize(cloud, logger)
5
+ @cloud = cloud
6
+ @logger = logger
7
+ @transactor = Transactor.new
8
+ end
9
+
10
+ def update_persistent_disk(instance_plan, vm_recreator)
11
+ @logger.info('Updating persistent disk')
12
+ check_persistent_disk(instance_plan)
13
+
14
+ return unless instance_plan.persistent_disk_changed?
15
+
16
+ instance = instance_plan.instance
17
+ old_disk = instance.model.persistent_disk
18
+
19
+ disk = nil
20
+ if instance_plan.needs_disk?
21
+ disk = create_and_attach_disk(instance_plan, vm_recreator)
22
+ mount_and_migrate_disk(instance, disk, old_disk)
23
+ end
24
+
25
+ @transactor.retryable_transaction(Bosh::Director::Config.db) do
26
+ old_disk.update(:active => false) if old_disk
27
+ disk.update(:active => true) if disk
28
+ end
29
+
30
+ delete_mounted_persistent_disk(instance, old_disk) if old_disk
31
+ end
32
+
33
+ def attach_disks_if_needed(instance_plan)
34
+ unless instance_plan.needs_disk?
35
+ @logger.warn('Skipping disk attachment, instance no longer needs disk')
36
+ return
37
+ end
38
+
39
+ instance = instance_plan.instance
40
+ disk_cid = instance.model.persistent_disk_cid
41
+ return @logger.info('Skipping disk attaching') if disk_cid.nil?
42
+ vm_model = instance.vm.model
43
+ begin
44
+ @cloud.attach_disk(vm_model.cid, disk_cid)
45
+ AgentClient.with_vm(vm_model).mount_disk(disk_cid)
46
+ rescue => e
47
+ @logger.warn("Failed to attach disk to new VM: #{e.inspect}")
48
+ raise e
49
+ end
50
+ end
51
+
52
+ def delete_persistent_disks(instance_model)
53
+ instance_model.persistent_disks.each do |disk|
54
+ orphan_disk(disk)
55
+ end
56
+ end
57
+
58
+ def orphan_disk(disk)
59
+ @transactor.retryable_transaction(Bosh::Director::Config.db) do
60
+ orphan_disk = Models::OrphanDisk.create(
61
+ disk_cid: disk.disk_cid,
62
+ size: disk.size,
63
+ availability_zone: disk.instance.availability_zone,
64
+ deployment_name: disk.instance.deployment.name,
65
+ instance_name: "#{disk.instance.job}/#{disk.instance.uuid}",
66
+ cloud_properties: disk.cloud_properties
67
+ )
68
+
69
+ orphan_snapshots(disk.snapshots, orphan_disk)
70
+ @logger.info("Orphaning disk: '#{disk.disk_cid}', " +
71
+ "#{disk.active ? "active" : "inactive"}")
72
+
73
+ disk.destroy
74
+ end
75
+ end
76
+
77
+ def list_orphan_disks
78
+ Models::OrphanDisk.all.map do |disk|
79
+ {
80
+ 'disk_cid' => disk.disk_cid,
81
+ 'size' => disk.size,
82
+ 'az' => disk.availability_zone,
83
+ 'deployment_name' => disk.deployment_name,
84
+ 'instance_name' => disk.instance_name,
85
+ 'cloud_properties' => disk.cloud_properties,
86
+ 'orphaned_at' => disk.created_at.to_s
87
+ }
88
+ end
89
+ end
90
+
91
+ def delete_orphan_disk_by_disk_cid(disk_cid)
92
+ @logger.info("Deleting orphan disk: #{disk_cid}")
93
+ orphan_disk = Bosh::Director::Models::OrphanDisk.where(disk_cid: disk_cid).first
94
+ if orphan_disk
95
+ delete_orphan_disk(orphan_disk)
96
+ else
97
+ @logger.debug("Disk not found: #{disk_cid}")
98
+ end
99
+ end
100
+
101
+ def unmount_disk_for(instance_plan)
102
+ disk = instance_plan.instance.model.persistent_disk
103
+ return if disk.nil?
104
+ unmount(instance_plan.instance, disk)
105
+ end
106
+
107
+ def delete_orphan_disk(orphan_disk)
108
+ begin
109
+ orphan_disk.orphan_snapshots.each do |orphan_snapshot|
110
+ delete_orphan_snapshot(orphan_snapshot)
111
+ end
112
+ @logger.info("Deleting orphan orphan disk: #{orphan_disk.disk_cid}")
113
+ @cloud.delete_disk(orphan_disk.disk_cid)
114
+ orphan_disk.destroy
115
+ rescue Bosh::Clouds::DiskNotFound
116
+ @logger.debug("Disk not found in IaaS: #{orphan_disk.disk_cid}")
117
+ orphan_disk.destroy
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ def delete_orphan_snapshot(orphan_snapshot)
124
+ begin
125
+ snapshot_cid = orphan_snapshot.snapshot_cid
126
+ @logger.info("Deleting orphan snapshot: #{snapshot_cid}")
127
+ @cloud.delete_snapshot(snapshot_cid)
128
+ orphan_snapshot.destroy
129
+ rescue Bosh::Clouds::DiskNotFound
130
+ @logger.debug("Disk not found in IaaS: #{snapshot_cid}")
131
+ orphan_snapshot.destroy
132
+ end
133
+ end
134
+
135
+ def orphan_snapshots(snapshots, orphan_disk)
136
+ snapshots.each do |snapshot|
137
+ @logger.info("Orphaning snapshot: '#{snapshot.snapshot_cid}'")
138
+ Models::OrphanSnapshot.create(
139
+ orphan_disk: orphan_disk,
140
+ snapshot_cid: snapshot.snapshot_cid,
141
+ clean: snapshot.clean,
142
+ snapshot_created_at: snapshot.created_at
143
+ )
144
+ snapshot.delete
145
+ end
146
+ end
147
+
148
+ def delete_mounted_persistent_disk(instance, disk)
149
+ unmount(instance, disk)
150
+
151
+ disk_cid = disk.disk_cid
152
+ if disk_cid.nil?
153
+ @logger.info('Skipping disk detaching, instance does not have a disk')
154
+ return
155
+ end
156
+
157
+ begin
158
+ @logger.info("Detaching disk #{disk_cid}")
159
+ @cloud.detach_disk(instance.model.vm.cid, disk_cid)
160
+ rescue Bosh::Clouds::DiskNotAttached
161
+ if disk.active
162
+ raise CloudDiskNotAttached,
163
+ "`#{instance}' VM should have persistent disk attached " +
164
+ "but it doesn't (according to CPI)"
165
+ end
166
+ end
167
+
168
+ orphan_disk(disk)
169
+ end
170
+
171
+ def unmount(instance, disk)
172
+ disk_cid = disk.disk_cid
173
+ if disk_cid.nil?
174
+ @logger.info('Skipping disk unmounting, instance does not have a disk')
175
+ return
176
+ end
177
+
178
+ if disks(instance).include?(disk_cid)
179
+ @logger.info("Stopping instance '#{instance}' before unmount")
180
+ agent(instance).stop
181
+ @logger.info("Unmounting disk '#{disk_cid}'")
182
+ agent(instance).unmount_disk(disk_cid)
183
+ end
184
+ end
185
+
186
+ # Synchronizes persistent_disks with the agent.
187
+ # (Currently assumes that we only have 1 persistent disk.)
188
+ # @return [void]
189
+ def check_persistent_disk(instance_plan)
190
+ instance = instance_plan.instance
191
+ return if instance.model.persistent_disks.empty?
192
+ agent_disk_cid = disks(instance).first
193
+
194
+ if agent_disk_cid.nil? && !instance_plan.needs_disk?
195
+ @logger.debug('Disk is already detached')
196
+ elsif agent_disk_cid != instance.model.persistent_disk_cid
197
+ raise AgentDiskOutOfSync,
198
+ "`#{instance}' has invalid disks: agent reports " +
199
+ "`#{agent_disk_cid}' while director record shows " +
200
+ "`#{instance.model.persistent_disk_cid}'"
201
+ end
202
+
203
+ instance.model.persistent_disks.each do |disk|
204
+ unless disk.active
205
+ @logger.warn("`#{instance}' has inactive disk #{disk.disk_cid}")
206
+ end
207
+ end
208
+ end
209
+
210
+ def disks(instance)
211
+ agent(instance).list_disk
212
+ end
213
+
214
+ def agent(instance)
215
+ AgentClient.with_vm(instance.vm.model)
216
+ end
217
+
218
+ def create_and_attach_disk(instance_plan, vm_recreator)
219
+ instance = instance_plan.instance
220
+ disk = create_disk(instance_plan)
221
+ @cloud.attach_disk(instance.model.vm.cid, disk.disk_cid)
222
+ return disk
223
+ rescue Bosh::Clouds::NoDiskSpace => e
224
+ if e.ok_to_retry
225
+ @logger.warn('Retrying attach disk operation after persistent disk update failed')
226
+ # Re-creating the vm may cause it to be re-created in a place with more storage
227
+ unmount_disk_for(instance_plan)
228
+ vm_recreator.recreate_vm(instance_plan, disk.disk_cid)
229
+ begin
230
+ @cloud.attach_disk(instance.model.vm.cid, disk.disk_cid)
231
+ rescue
232
+ orphan_disk(disk)
233
+ raise
234
+ end
235
+ else
236
+ orphan_disk(disk)
237
+ raise
238
+ end
239
+ return disk
240
+ end
241
+
242
+ def mount_and_migrate_disk(instance, new_disk, old_disk)
243
+ agent(instance).mount_disk(new_disk.disk_cid)
244
+ agent(instance).migrate_disk(old_disk.disk_cid, new_disk.disk_cid) if old_disk
245
+ rescue => e
246
+ @logger.debug("Failed to migrate disk, deleting new disk. #{e.inspect}")
247
+ delete_mounted_persistent_disk(instance, new_disk)
248
+ raise e
249
+ end
250
+
251
+ def create_disk(instance_plan)
252
+ job = instance_plan.desired_instance.job
253
+ instance_model = instance_plan.instance.model
254
+
255
+ disk_size = job.persistent_disk_type.disk_size
256
+ cloud_properties = job.persistent_disk_type.cloud_properties
257
+
258
+ disk_cid = @cloud.create_disk(disk_size, cloud_properties, instance_model.vm.cid)
259
+ Models::PersistentDisk.create(
260
+ disk_cid: disk_cid,
261
+ active: false,
262
+ instance_id: instance_model.id,
263
+ size: disk_size,
264
+ cloud_properties: cloud_properties,
265
+ )
266
+ end
267
+ end
268
+ end
@@ -0,0 +1,28 @@
1
+ module Bosh::Director
2
+ class Canonicalizer
3
+
4
+ def self.canonicalize(string, opts = {})
5
+ # a-z, 0-9, -, case insensitive, and must start with a letter
6
+ string = string.downcase.gsub(/_/, "-")
7
+ if opts[:allow_dots]
8
+ string = string.gsub(/[^a-z0-9\-\.]/, "")
9
+ else
10
+ string = string.gsub(/[^a-z0-9\-]/, "")
11
+ end
12
+
13
+ validate_dns_name(string)
14
+ end
15
+
16
+ def self.validate_dns_name(string)
17
+ if string =~ /^(\d|-)/
18
+ raise DnsInvalidCanonicalName,
19
+ "Invalid DNS canonical name `#{string}', must begin with a letter"
20
+ end
21
+ if string =~ /-$/
22
+ raise DnsInvalidCanonicalName,
23
+ "Invalid DNS canonical name `#{string}', can't end with a hyphen"
24
+ end
25
+ string
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,163 @@
1
+ module Bosh::Director
2
+ class DnsManager
3
+ attr_reader :dns_domain_name
4
+
5
+ def self.create
6
+ dns_config = Config.dns || {}
7
+ dns_enabled = !!Config.dns_db # to be consistent with current behavior
8
+ logger = Config.logger
9
+ local_dns_repo = LocalDnsRepo.new(logger)
10
+ dns_domain_name = Canonicalizer.canonicalize(dns_config.fetch('domain_name', 'bosh'), :allow_dots => true)
11
+ dns_provider = PowerDns.new(dns_domain_name, logger)
12
+
13
+ new(dns_domain_name, dns_config, dns_enabled, dns_provider, local_dns_repo, logger)
14
+ end
15
+
16
+ def initialize(dns_domain_name, dns_config, dns_enabled, dns_provider, local_dns_repo, logger)
17
+ @dns_domain_name = dns_domain_name
18
+ @dns_provider = dns_provider
19
+ @dns_enabled = dns_enabled
20
+ @default_server = dns_config['server']
21
+ @flush_command = dns_config['flush_command']
22
+ @ip_address = dns_config['address']
23
+ @local_dns_repo = local_dns_repo
24
+ @logger = logger
25
+ end
26
+
27
+ def dns_enabled?
28
+ @dns_enabled
29
+ end
30
+
31
+ def configure_nameserver
32
+ return unless dns_enabled?
33
+
34
+ @dns_provider.create_or_update_nameserver(@ip_address)
35
+ end
36
+
37
+ def find_dns_record(dns_record_name, ip_address)
38
+ @dns_provider.find_dns_record(dns_record_name, ip_address)
39
+ end
40
+
41
+ def find_dns_record_names_by_instance(instance_model)
42
+ instance_model.nil? ? [] : instance_model.dns_record_names.to_a.compact
43
+ end
44
+
45
+ def update_dns_record_for_instance(instance_model, dns_names_to_ip)
46
+ current_dns_records = @local_dns_repo.find(instance_model)
47
+ new_dns_records = []
48
+ dns_names_to_ip.each do |record_name, ip_address|
49
+ new_dns_records << record_name
50
+ @logger.info("Updating DNS for: #{record_name} to #{ip_address}")
51
+ @dns_provider.create_or_update_dns_records(record_name, ip_address)
52
+ end
53
+ dns_records = (current_dns_records + new_dns_records).uniq
54
+ @local_dns_repo.create_or_update(instance_model, dns_records)
55
+ end
56
+
57
+ def migrate_legacy_records(instance_model)
58
+ return unless dns_enabled?
59
+
60
+ return if @local_dns_repo.find(instance_model).any?
61
+
62
+ index_pattern_for_all_networks = dns_record_name(
63
+ instance_model.index,
64
+ instance_model.job,
65
+ '%',
66
+ instance_model.deployment.name
67
+ )
68
+ uuid_pattern_for_all_networks = dns_record_name(
69
+ instance_model.uuid,
70
+ instance_model.job,
71
+ '%',
72
+ instance_model.deployment.name
73
+ )
74
+
75
+ legacy_record_names = [index_pattern_for_all_networks, uuid_pattern_for_all_networks]
76
+ .map { |pattern| @dns_provider.find_dns_records_by_pattern(pattern) }
77
+ .flatten
78
+ .map(&:name)
79
+
80
+ @local_dns_repo.create_or_update(instance_model, legacy_record_names)
81
+ end
82
+
83
+ def delete_dns_for_instance(instance_model)
84
+ return unless dns_enabled?
85
+
86
+ current_dns_records = @local_dns_repo.find(instance_model)
87
+ if current_dns_records.empty?
88
+ # for backwards compatibility when old instances
89
+ # did not have records in local repo
90
+ # we cannot migrate them because powerdns can be different database
91
+ # those instance only had index-based dns records (before global-net)
92
+ index_record_pattern = dns_record_name(instance_model.index, instance_model.job, '%', instance_model.deployment.name)
93
+ @dns_provider.delete(index_record_pattern)
94
+ return
95
+ end
96
+
97
+ current_dns_records.each do |record_name|
98
+ @logger.info("Removing DNS for: #{record_name}")
99
+ @dns_provider.delete(record_name)
100
+ end
101
+
102
+ @local_dns_repo.delete(instance_model)
103
+ end
104
+
105
+ # build a list of dns servers to use
106
+ def dns_servers(network, dns_spec, add_default_dns = true)
107
+ servers = nil
108
+
109
+ if dns_spec
110
+ servers = []
111
+ dns_spec.each do |dns|
112
+ dns = NetAddr::CIDR.create(dns)
113
+ unless dns.size == 1
114
+ raise NetworkInvalidDns,
115
+ "Invalid DNS for network `#{network}': must be a single IP"
116
+ end
117
+
118
+ servers << dns.ip
119
+ end
120
+ end
121
+
122
+ return servers unless add_default_dns
123
+ add_default_dns_server(servers)
124
+ end
125
+
126
+ # Purge cached DNS records
127
+ def flush_dns_cache
128
+ if @flush_command && !@flush_command.empty?
129
+ stdout, stderr, status = Open3.capture3(@flush_command)
130
+ if status == 0
131
+ @logger.debug("Flushed #{stdout.chomp} records from DNS cache")
132
+ else
133
+ @logger.warn("Failed to flush DNS cache: #{stderr.chomp}")
134
+ end
135
+ end
136
+ end
137
+
138
+ def dns_record_name(hostname, job_name, network_name, deployment_name)
139
+ network_name = Canonicalizer.canonicalize(network_name) unless network_name == '%'
140
+
141
+ [ hostname,
142
+ Canonicalizer.canonicalize(job_name),
143
+ network_name,
144
+ Canonicalizer.canonicalize(deployment_name),
145
+ @dns_domain_name
146
+ ].join('.')
147
+ end
148
+
149
+ private
150
+
151
+ # add default dns server to an array of dns servers
152
+ def add_default_dns_server(servers)
153
+ return servers unless dns_enabled?
154
+
155
+ unless @default_server.to_s.empty? || @default_server == '127.0.0.1'
156
+ (servers ||= []) << @default_server
157
+ servers.uniq!
158
+ end
159
+
160
+ servers
161
+ end
162
+ end
163
+ end