Class: Bosh::Director::DeploymentPlan::Assembler
- Includes:
- IpUtil, LockHelper
- Defined in:
- lib/bosh/director/deployment_plan/assembler.rb
Overview
DeploymentPlan::Assembler is used to populate deployment plan with information about existing deployment and information from director DB
Instance Method Summary collapse
- #bind_dns ⇒ Object
-
#bind_existing_deployment ⇒ void
Binds information about existing deployment to a plan.
-
#bind_existing_vm(vm_model, lock) ⇒ Object
Queries agent for VM state and updates deployment plan accordingly.
-
#bind_idle_vm(vm_model, resource_pool, state, reservations) ⇒ Object
Binds idle VM to a resource pool with a proper network reservation.
- #bind_instance(instance_model, state, reservations) ⇒ Object
- #bind_instance_networks ⇒ Object
-
#bind_properties ⇒ void
Binds properties for all templates in the deployment.
-
#bind_releases ⇒ void
Binds release DB record(s) to a plan.
-
#bind_resource_pools ⇒ void
Takes a look at the current state of all resource pools in the deployment and schedules adding any new VMs if needed.
-
#bind_stemcells ⇒ void
Binds stemcell model for each stemcell spec in each resource pool in the deployment plan.
-
#bind_templates ⇒ void
Binds template models for each release spec in the deployment plan.
-
#bind_unallocated_vms ⇒ void
Looks at every job instance in the deployment plan and binds it to the instance database model (idle VM is also created in the appropriate resource pool if necessary).
- #get_network_reservations(state) ⇒ Object
- #get_state(vm_model) ⇒ Object
-
#initialize(deployment_plan, stemcell_manager, cloud, blobstore, logger, event_log) ⇒ Assembler
constructor
A new instance of Assembler.
- #migrate_legacy_state(vm_model, state) ⇒ Object
- #verify_state(vm_model, state) ⇒ Object
Methods included from IpUtil
#each_ip, #format_ip, #ip_to_i, #ip_to_netaddr, #process_range
Methods included from LockHelper
#with_compile_lock, #with_deployment_lock, #with_release_lock, #with_release_locks, #with_stemcell_lock
Constructor Details
#initialize(deployment_plan, stemcell_manager, cloud, blobstore, logger, event_log) ⇒ Assembler
Returns a new instance of Assembler.
8 9 10 11 12 13 14 15 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 8 def initialize(deployment_plan, stemcell_manager, cloud, blobstore, logger, event_log) @deployment_plan = deployment_plan @cloud = cloud @logger = logger @event_log = event_log @stemcell_manager = stemcell_manager @blobstore = blobstore end |
Instance Method Details
#bind_dns ⇒ Object
315 316 317 318 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 315 def bind_dns binder = DeploymentPlan::DnsBinder.new(@deployment_plan) binder.bind_deployment end |
#bind_existing_deployment ⇒ void
This method returns an undefined value.
Binds information about existing deployment to a plan
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 30 def bind_existing_deployment lock = Mutex.new ThreadPool.new(:max_threads => Config.max_threads).wrap do |pool| @deployment_plan.vms.each do |vm_model| pool.process do with_thread_name("bind_existing_deployment(#{vm_model.agent_id})") do bind_existing_vm(vm_model, lock) end end end end end |
#bind_existing_vm(vm_model, lock) ⇒ Object
Queries agent for VM state and updates deployment plan accordingly
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 46 def bind_existing_vm(vm_model, lock) state = get_state(vm_model) lock.synchronize do @logger.debug('Processing VM network reservations') reservations = get_network_reservations(state) instance = vm_model.instance if instance bind_instance(instance, state, reservations) else resource_pool_name = state['resource_pool']['name'] resource_pool = @deployment_plan.resource_pool(resource_pool_name) if resource_pool @logger.debug("Binding VM to resource pool '#{resource_pool_name}'") bind_idle_vm(vm_model, resource_pool, state, reservations) else @logger.debug("Resource pool '#{resource_pool_name}' does not exist, marking VM for deletion") @deployment_plan.delete_vm(vm_model) end end @logger.debug('Finished processing VM network reservations') end end |
#bind_idle_vm(vm_model, resource_pool, state, reservations) ⇒ Object
Binds idle VM to a resource pool with a proper network reservation
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 75 def bind_idle_vm(vm_model, resource_pool, state, reservations) if reservations.any? { |network_name, reservation| reservation.static? } @logger.debug("Releasing all network reservations for VM `#{vm_model.cid}'") reservations.each do |network_name, reservation| @logger.debug("Releasing #{reservation.type} network reservation `#{network_name}' for VM `#{vm_model.cid}'") @deployment_plan.network(network_name).release(reservation) end @logger.debug("Deleting VM `#{vm_model.cid}' with static network reservation") @deployment_plan.delete_vm(vm_model) return end @logger.debug("Adding VM `#{vm_model.cid}' to resource pool `#{resource_pool.name}'") idle_vm = resource_pool.add_idle_vm idle_vm.model = vm_model idle_vm.current_state = state network_name = resource_pool.network.name reservation = reservations[network_name] if reservation @logger.debug("Using existing `#{reservation.type}' " + "network reservation of `#{reservation.ip}' for VM `#{vm_model.cid}'") idle_vm.use_reservation(reservation) else @logger.debug("No network reservation for VM `#{vm_model.cid}'") end end |
#bind_instance(instance_model, state, reservations) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 107 def bind_instance(instance_model, state, reservations) @logger.debug('Binding instance VM') # Update instance, if we are renaming a job. if @deployment_plan.rename_in_progress? old_name = @deployment_plan.job_rename['old_name'] new_name = @deployment_plan.job_rename['new_name'] if instance_model.job == old_name @logger.info("Renaming `#{old_name}' to `#{new_name}'") instance_model.update(:job => new_name) end end instance_name = "#{instance_model.job}/#{instance_model.index}" job = @deployment_plan.job(instance_model.job) unless job @logger.debug("Job `#{instance_model.job}' not found, marking for deletion") @deployment_plan.delete_instance(instance_model) return end instance = job.instance(instance_model.index) unless instance @logger.debug("Job instance `#{instance_name}' not found, marking for deletion") @deployment_plan.delete_instance(instance_model) return end @logger.debug("Found existing job instance `#{instance_name}'") instance.bind_existing_instance(instance_model, state, reservations) end |
#bind_instance_networks ⇒ Object
275 276 277 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 275 def bind_instance_networks @deployment_plan.jobs_starting_on_deploy.each(&:bind_instance_networks) end |
#bind_properties ⇒ void
This method returns an undefined value.
Binds properties for all templates in the deployment
293 294 295 296 297 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 293 def bind_properties @deployment_plan.jobs.each do |job| job.bind_properties end end |
#bind_releases ⇒ void
This method returns an undefined value.
Binds release DB record(s) to a plan
19 20 21 22 23 24 25 26 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 19 def bind_releases releases = @deployment_plan.releases with_release_locks(releases.map(&:name)) do releases.each do |release| release.bind_model end end end |
#bind_resource_pools ⇒ void
This method returns an undefined value.
Takes a look at the current state of all resource pools in the deployment and schedules adding any new VMs if needed. VMs are NOT created at this stage, only data structures are being allocated. ResourcePoolUpdater will later perform actual changes based on this data.
261 262 263 264 265 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 261 def bind_resource_pools @deployment_plan.resource_pools.each do |resource_pool| resource_pool.process_idle_vms end end |
#bind_stemcells ⇒ void
This method returns an undefined value.
Binds stemcell model for each stemcell spec in each resource pool in the deployment plan
302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 302 def bind_stemcells @deployment_plan.resource_pools.each do |resource_pool| stemcell = resource_pool.stemcell if stemcell.nil? raise DirectorError, "Stemcell not bound for resource pool `#{resource_pool.name}'" end stemcell.bind_model end end |
#bind_templates ⇒ void
This method returns an undefined value.
Binds template models for each release spec in the deployment plan
281 282 283 284 285 286 287 288 289 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 281 def bind_templates @deployment_plan.releases.each do |release| release.bind_templates end @deployment_plan.jobs.each do |job| job.validate_package_names_do_not_collide! end end |
#bind_unallocated_vms ⇒ void
This method returns an undefined value.
Looks at every job instance in the deployment plan and binds it to the instance database model (idle VM is also created in the appropriate resource pool if necessary)
271 272 273 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 271 def bind_unallocated_vms @deployment_plan.jobs_starting_on_deploy.each(&:bind_unallocated_vms) end |
#get_network_reservations(state) ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 141 def get_network_reservations(state) reservations = {} state['networks'].each do |name, network_config| network = @deployment_plan.network(name) if network reservation = NetworkReservation.new(:ip => network_config['ip']) network.reserve(reservation) reservations[name] = reservation if reservation.reserved? end end reservations end |
#get_state(vm_model) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 154 def get_state(vm_model) @logger.debug("Requesting current VM state for: #{vm_model.agent_id}") agent = AgentClient.with_defaults(vm_model.agent_id) state = agent.get_state @logger.debug("Received VM state: #{state.pretty_inspect}") verify_state(vm_model, state) @logger.debug('Verified VM state') migrate_legacy_state(vm_model, state) state.delete('release') if state.include?('job') state['job'].delete('release') end state end |
#migrate_legacy_state(vm_model, state) ⇒ Object
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 235 def migrate_legacy_state(vm_model, state) # Persisting apply spec for VMs that were introduced before we started # persisting it on apply itself (this is for cloudcheck purposes only) if vm_model.apply_spec.nil? # The assumption is that apply_spec <=> VM state vm_model.update(:apply_spec => state) end instance = vm_model.instance if instance disk_size = state['persistent_disk'].to_i persistent_disk = instance.persistent_disk # This is to support legacy deployments where we did not have # the disk_size specified. if disk_size != 0 && persistent_disk && persistent_disk.size == 0 persistent_disk.update(:size => disk_size) end end end |
#verify_state(vm_model, state) ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/bosh/director/deployment_plan/assembler.rb', line 171 def verify_state(vm_model, state) instance = vm_model.instance if instance && instance.deployment_id != vm_model.deployment_id # Both VM and instance should reference same deployment raise VmInstanceOutOfSync, "VM `#{vm_model.cid}' and instance " + "`#{instance.job}/#{instance.index}' " + "don't belong to the same deployment" end unless state.kind_of?(Hash) @logger.error("Invalid state for `#{vm_model.cid}': #{state.pretty_inspect}") raise AgentInvalidStateFormat, "VM `#{vm_model.cid}' returns invalid state: " + "expected Hash, got #{state.class}" end actual_deployment_name = state['deployment'] expected_deployment_name = @deployment_plan.name if actual_deployment_name != expected_deployment_name raise AgentWrongDeployment, "VM `#{vm_model.cid}' is out of sync: " + 'expected to be a part of deployment ' + "`#{expected_deployment_name}' " + 'but is actually a part of deployment ' + "`#{actual_deployment_name}'" end actual_job = state['job'].is_a?(Hash) ? state['job']['name'] : nil actual_index = state['index'] if instance.nil? && !actual_job.nil? raise AgentUnexpectedJob, "VM `#{vm_model.cid}' is out of sync: " + "it reports itself as `#{actual_job}/#{actual_index}' but " + 'there is no instance reference in DB' end if instance && (instance.job != actual_job || instance.index != actual_index) # Check if we are resuming a previously unfinished rename if actual_job == @deployment_plan.job_rename['old_name'] && instance.job == @deployment_plan.job_rename['new_name'] && instance.index == actual_index # Rename already happened in the DB but then something happened # and agent has never been updated. unless @deployment_plan.job_rename['force'] raise AgentRenameInProgress, "Found a job `#{actual_job}' that seems to be " + "in the middle of a rename to `#{instance.job}'. " + "Run 'rename' again with '--force' to proceed." end else raise AgentJobMismatch, "VM `#{vm_model.cid}' is out of sync: " + "it reports itself as `#{actual_job}/#{actual_index}' but " + "according to DB it is `#{instance.job}/#{instance.index}'" end end end |