Class: Bosh::Director::DeploymentPlan::Instance
- Includes:
- Bosh::Director::DnsHelper
- Defined in:
- lib/bosh/director/deployment_plan/instance.rb
Overview
Represents a single job instance.
Constant Summary
Constants included from Bosh::Director::DnsHelper
Bosh::Director::DnsHelper::SOA, Bosh::Director::DnsHelper::TTL_4H, Bosh::Director::DnsHelper::TTL_5M
Instance Attribute Summary collapse
-
#configuration_hash ⇒ String
Checksum all of the configuration templates.
-
#current_state ⇒ Hash
readonly
Current state as provided by the BOSH Agent.
-
#index ⇒ Integer
readonly
Instance index.
-
#job ⇒ DeploymentPlan::Job
readonly
Associated job.
-
#model ⇒ Models::Instance
readonly
Instance model.
-
#network_reservations ⇒ Hash<String, NetworkReservation>
Network reservations.
-
#recreate ⇒ Boolean
True if this instance needs to be recreated.
- #rendered_templates_archive ⇒ Bosh::Director::Core::Templates::RenderedTemplatesArchive
-
#restart ⇒ Boolean
True if this instance needs to be restarted.
-
#state ⇒ String
Job state.
-
#template_hashes ⇒ Hash
A hash of template SHA1 hashes.
-
#vm ⇒ DeploymentPlan::Vm
readonly
Associated resource pool VM.
Instance Method Summary collapse
-
#add_network_reservation(name, reservation) ⇒ Object
Adds a new network to this instance.
-
#allocate_vm ⇒ void
Allocates an VM in this job resource pool and binds current instance to that VM.
- #apply_partial_vm_state ⇒ Object
- #apply_vm_state ⇒ Object
-
#bind_existing_instance(instance_model, state, reservations) ⇒ Object
Updates this domain object to reflect an existing instance running on an existing vm.
- #bind_to_vm_model(vm_model) ⇒ Object
-
#bind_unallocated_vm ⇒ void
Looks up instance model in DB and binds it to this instance spec.
-
#changed? ⇒ Boolean
Returns true if the any of the expected specifications differ from the ones provided by the VM.
-
#changes ⇒ Set<Symbol>
Returns a set of all of the specification differences.
-
#configuration_changed? ⇒ Boolean
Returns true if the expected configuration hash differs from the one provided by the VM.
-
#disk_cloud_properties ⇒ Hash
Persistent disk cloud properties.
-
#disk_currently_attached? ⇒ Boolean
Returns true if the persistent disk is attached to the VM.
-
#disk_size ⇒ Integer
Persistent disk size.
-
#dns_changed? ⇒ Boolean
Returns true if the DNS records configured for the instance differ from the ones configured on the DNS server.
-
#dns_record_info ⇒ Hash<String, String>
Dns record hash of dns name and IP.
-
#dns_record_name(network_name) ⇒ String
Dns record name.
-
#find_or_create_model ⇒ Models::Instance
Looks up instance model in DB.
-
#initialize(job, index, logger) ⇒ Instance
constructor
Creates a new instance specification based on the job and index.
-
#job_changed? ⇒ Boolean
Returns true if the expected job configuration differs from the one provided by the VM.
-
#network_settings ⇒ Hash
BOSH network settings used for Agent apply call.
-
#networks_changed? ⇒ Boolean
Returns true if the network configuration changed.
-
#packages_changed? ⇒ Boolean
Returns true if the expected packaged of the running instance differ from the ones provided by the VM.
-
#persistent_disk_changed? ⇒ Boolean
Returns true if the expected persistent disk or cloud_properties differs from the state currently configured on the VM.
-
#resource_pool_changed? ⇒ Boolean
Returns true if the expected resource pool differs from the one provided by the VM.
-
#spec ⇒ Hash<String, Object>
Instance spec that’s passed to the VM during the BOSH Agent apply call.
-
#state_changed? ⇒ Boolean
Checks if agent view of the instance state is consistent with target instance state.
-
#sync_state_with_db ⇒ void
Syncs instance state with instance model in DB.
- #to_s ⇒ Object
Methods included from Bosh::Director::DnsHelper
#add_default_dns_server, #canonical, #default_dns_server, #delete_dns_records, #delete_empty_domain, #dns_domain_name, #dns_ns_record, #dns_servers, #flush_dns_cache, #invalid_dns, #reverse_domain, #reverse_host, #update_dns_a_record, #update_dns_ptr_record
Constructor Details
#initialize(job, index, logger) ⇒ Instance
Creates a new instance specification based on the job and index.
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/instance.rb', line 46 def initialize(job, index, logger) @job = job @index = index @logger = logger @configuration_hash = nil @template_hashes = nil @vm = nil @current_state = nil @network_reservations = {} @state = job.instance_state(@index) # Expanding virtual states case @state when 'recreate' @recreate = true @state = 'started' when 'restart' @restart = true @state = 'started' end end |
Instance Attribute Details
#configuration_hash ⇒ String
Returns Checksum all of the configuration templates.
17 18 19 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 17 def configuration_hash @configuration_hash end |
#current_state ⇒ Hash (readonly)
Returns current state as provided by the BOSH Agent.
32 33 34 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 32 def current_state @current_state end |
#index ⇒ Integer (readonly)
Returns Instance index.
11 12 13 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 11 def index @index end |
#job ⇒ DeploymentPlan::Job (readonly)
Returns Associated job.
8 9 10 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 8 def job @job end |
#model ⇒ Models::Instance (readonly)
Returns Instance model.
14 15 16 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 14 def model @model end |
#network_reservations ⇒ Hash<String, NetworkReservation>
Returns network reservations.
26 27 28 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 26 def network_reservations @network_reservations end |
#recreate ⇒ Boolean
Returns true if this instance needs to be recreated.
38 39 40 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 38 def recreate @recreate end |
#rendered_templates_archive ⇒ Bosh::Director::Core::Templates::RenderedTemplatesArchive
23 24 25 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 23 def rendered_templates_archive @rendered_templates_archive end |
#restart ⇒ Boolean
Returns true if this instance needs to be restarted.
41 42 43 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 41 def restart @restart end |
#state ⇒ String
Returns job state.
29 30 31 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 29 def state @state end |
#template_hashes ⇒ Hash
Returns A hash of template SHA1 hashes.
20 21 22 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 20 def template_hashes @template_hashes end |
#vm ⇒ DeploymentPlan::Vm (readonly)
Returns Associated resource pool VM.
35 36 37 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 35 def vm @vm end |
Instance Method Details
#add_network_reservation(name, reservation) ⇒ Object
Adds a new network to this instance
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 173 def add_network_reservation(name, reservation) old_reservation = @network_reservations[name] if old_reservation raise NetworkReservationAlreadyExists, "`#{self}' already has reservation " + "for network `#{name}', IP #{old_reservation.ip}" end @network_reservations[name] = reservation end |
#allocate_vm ⇒ void
This method returns an undefined value.
Allocates an VM in this job resource pool and binds current instance to that VM.
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 462 def allocate_vm resource_pool = @job.resource_pool vm = resource_pool.allocate_vm network = resource_pool.network if vm.model # There's already a resource pool VM that can become our instance, # so we can try to reuse its reservation instance_reservation = @network_reservations[network.name] if instance_reservation instance_reservation.take(vm.network_reservation) end else # VM is not created yet: let's just make it reference this instance # so later it knows what it needs to become vm.bound_instance = self # this also means we no longer need previous VM network reservation # (instance has its own) vm.release_reservation end @vm = vm end |
#apply_partial_vm_state ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 97 def apply_partial_vm_state @logger.info('Applying partial VM state') state = @vm.current_state state['job'] = job.spec state['index'] = index # Apply the assignment to the VM agent = AgentClient.with_defaults(@vm.model.agent_id) agent.apply(state) # Our assumption here is that director database access # is much less likely to fail than VM agent communication # so we only update database after we see a successful agent apply. # If database update fails subsequent deploy will try to # assign a new VM to this instance which is ok. @vm.model.db.transaction do @vm.model.update(:apply_spec => state) @model.update(:vm => @vm.model) end @current_state = state end |
#apply_vm_state ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 121 def apply_vm_state @logger.info('Applying VM state') state = { 'deployment' => @job.deployment.name, 'networks' => network_settings, 'resource_pool' => @job.resource_pool.spec, 'job' => @job.spec, 'index' => @index, } if disk_size > 0 state['persistent_disk'] = disk_size end @model.vm.update(:apply_spec => state) agent = AgentClient.with_defaults(@model.vm.agent_id) agent.apply(state) # Agent will potentially return modified version of state # with resolved dynamic networks information @current_state = agent.get_state end |
#bind_existing_instance(instance_model, state, reservations) ⇒ Object
Updates this domain object to reflect an existing instance running on an existing vm
87 88 89 90 91 92 93 94 95 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 87 def bind_existing_instance(instance_model, state, reservations) check_model_not_bound @model = instance_model @current_state = state take_network_reservations(reservations) add_allocated_vm(instance_model.vm, state) end |
#bind_to_vm_model(vm_model) ⇒ Object
436 437 438 439 440 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 436 def bind_to_vm_model(vm_model) @model.update(vm: vm_model) @vm.model = vm_model @vm.bound_instance = self end |
#bind_unallocated_vm ⇒ void
This method returns an undefined value.
Looks up instance model in DB and binds it to this instance spec. Instance model is created if it’s not found in DB. New VM is allocated if instance DB record doesn’t reference one.
78 79 80 81 82 83 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 78 def bind_unallocated_vm @model ||= find_or_create_model if @model.vm.nil? allocate_vm end end |
#changed? ⇒ Boolean
Returns true if the any of the expected specifications differ from the ones provided by the VM
374 375 376 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 374 def changed? !changes.empty? end |
#changes ⇒ Set<Symbol>
Returns a set of all of the specification differences
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 380 def changes changes = Set.new unless @state == 'detached' && @current_state.nil? changes << :restart if @restart changes << :resource_pool if resource_pool_changed? changes << :network if networks_changed? changes << :packages if packages_changed? changes << :persistent_disk if persistent_disk_changed? changes << :configuration if configuration_changed? changes << :job if job_changed? changes << :state if state_changed? changes << :dns if dns_changed? end changes end |
#configuration_changed? ⇒ Boolean
Returns true if the expected configuration hash differs from the one provided by the VM
305 306 307 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 305 def configuration_changed? configuration_hash != @current_state['configuration_hash'] end |
#disk_cloud_properties ⇒ Hash
Returns persistent disk cloud properties.
238 239 240 241 242 243 244 245 246 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 238 def disk_cloud_properties check_model_bound if @model.persistent_disk @model.persistent_disk.cloud_properties else {} end end |
#disk_currently_attached? ⇒ Boolean
Returns true if the persistent disk is attached to the VM
267 268 269 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 267 def disk_currently_attached? current_state['persistent_disk'].to_i > 0 end |
#disk_size ⇒ Integer
Returns persistent disk size.
226 227 228 229 230 231 232 233 234 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 226 def disk_size check_model_bound if @model.persistent_disk @model.persistent_disk.size else 0 end end |
#dns_changed? ⇒ Boolean
Returns true if the DNS records configured for the instance differ from the ones configured on the DNS server
346 347 348 349 350 351 352 353 354 355 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 346 def dns_changed? if Config.dns_enabled? dns_record_info.any? do |name, ip| Models::Dns::Record.find(:name => name, :type => 'A', :content => ip).nil? end else false end end |
#dns_record_info ⇒ Hash<String, String>
Returns dns record hash of dns name and IP.
250 251 252 253 254 255 256 257 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 250 def dns_record_info dns_record_info = {} network_settings.each do |network_name, network| name = dns_record_name(network_name) dns_record_info[name] = network['ip'] end dns_record_info end |
#dns_record_name(network_name) ⇒ String
Returns dns record name.
261 262 263 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 261 def dns_record_name(network_name) [index, job.canonical_name, canonical(network_name), job.deployment.canonical_name, dns_domain_name].join('.') end |
#find_or_create_model ⇒ Models::Instance
Looks up instance model in DB
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 444 def find_or_create_model if @job.deployment.model.nil? raise DirectorError, 'Deployment model is not bound' end conditions = { deployment_id: @job.deployment.model.id, job: @job.name, index: @index } Models::Instance.find_or_create(conditions) do |model| model.state = 'started' end end |
#job_changed? ⇒ Boolean
Returns true if the expected job configuration differs from the one provided by the VM
312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 312 def job_changed? return true if @current_state.nil? job_spec = @job.spec if job_spec != @current_state['job'] # The agent job spec could be in legacy form. job_spec cannot be, # though, because we got it from the spec function in job.rb which # automatically makes it non-legacy. return job_spec != Job.convert_from_legacy_spec(@current_state['job']) end return false end |
#network_settings ⇒ Hash
Returns BOSH network settings used for Agent apply call.
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 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 186 def network_settings default_properties = {} @job.default_network.each do |key, value| (default_properties[value] ||= []) << key end network_settings = {} @network_reservations.each do |name, reservation| network = @job.deployment.network(name) network_settings[name] = network.network_settings(reservation, default_properties[name]) # Temporary hack for running errands. # We need to avoid RunErrand task thinking that # network configuration for errand VM differs # from network configuration for its Instance. # # Obviously this does not account for other changes # in network configuration that errand job might need. # (e.g. errand job desires static ip) if @job.starts_on_deploy? network_settings[name]['dns_record_name'] = dns_record_name(name) end # Somewhat of a hack: for dynamic networks we might know IP address, Netmask & Gateway # if they're featured in agent state, in that case we put them into network spec to satisfy # ConfigurationHasher in both agent and director. if @current_state.is_a?(Hash) && @current_state['networks'].is_a?(Hash) && @current_state['networks'][name].is_a?(Hash) && network_settings[name]['type'] == 'dynamic' %w(ip netmask gateway).each do |key| network_settings[name][key] = @current_state['networks'][name][key] end end end network_settings end |
#networks_changed? ⇒ Boolean
Returns true if the network configuration changed
273 274 275 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 273 def networks_changed? network_settings != @current_state['networks'] end |
#packages_changed? ⇒ Boolean
Returns true if the expected packaged of the running instance differ from the ones provided by the VM
328 329 330 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 328 def packages_changed? @job.package_spec != @current_state['packages'] end |
#persistent_disk_changed? ⇒ Boolean
Returns true if the expected persistent disk or cloud_properties differs from the state currently configured on the VM
335 336 337 338 339 340 341 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 335 def persistent_disk_changed? new_disk_size = @job.persistent_disk_pool ? @job.persistent_disk_pool.disk_size : 0 new_disk_cloud_properties = @job.persistent_disk_pool ? @job.persistent_disk_pool.cloud_properties : {} return true if new_disk_size != disk_size new_disk_size != 0 && new_disk_cloud_properties != disk_cloud_properties end |
#resource_pool_changed? ⇒ Boolean
Returns true if the expected resource pool differs from the one provided by the VM
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 279 def resource_pool_changed? if @recreate || @job.deployment.recreate return true end if @job.resource_pool.spec != @current_state['resource_pool'] return true end # env is not a part of a resource pool spec but rather gets persisted # in director DB, hence the check below # NOTE: we only update VMs that have env persisted to avoid recreating # everything, so if the director gets updated from the version that # doesn't persist VM env to the version that does, there needs to # be at least one deployment that recreates all VMs before the following # code path gets exercised. if @model && @model.vm && @model.vm.env && @job.resource_pool.env != @model.vm.env return true end false end |
#spec ⇒ Hash<String, Object>
Instance spec that’s passed to the VM during the BOSH Agent apply call. It’s what’s used for comparing the expected vs the actual state.
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 400 def spec spec = { 'deployment' => @job.deployment.name, 'job' => job.spec, 'index' => index, 'networks' => network_settings, 'resource_pool' => job.resource_pool.spec, 'packages' => job.package_spec, 'configuration_hash' => configuration_hash, 'properties' => job.properties, 'dns_domain_name' => dns_domain_name } if job.persistent_disk_pool # supply both for reverse compatibility with old agent spec['persistent_disk'] = job.persistent_disk_pool.disk_size # old agents will ignore this pool spec['persistent_disk_pool'] = job.persistent_disk_pool.spec else spec['persistent_disk'] = 0 end if template_hashes spec['template_hashes'] = template_hashes end # Ruby BOSH Agent does not look at 'rendered_templates_archive' # since it renders job templates and then compares template hashes. # Go BOSH Agent has no ability to render ERB so pre-rendered templates are provided. if rendered_templates_archive spec['rendered_templates_archive'] = rendered_templates_archive.spec end spec end |
#state_changed? ⇒ Boolean
Checks if agent view of the instance state is consistent with target instance state.
In case the instance current state is ‘detached’ we should never get to this method call.
365 366 367 368 369 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 365 def state_changed? @state == 'detached' || @state == 'started' && @current_state['job_state'] != 'running' || @state == 'stopped' && @current_state['job_state'] == 'running' end |
#sync_state_with_db ⇒ void
This method returns an undefined value.
Syncs instance state with instance model in DB. This is needed because not all instance states are available in the deployment manifest and we we cannot really persist this data in the agent state (as VM might be stopped or detached).
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 152 def sync_state_with_db check_model_bound if @state # Deployment plan explicitly sets state for this instance @model.update(:state => @state) elsif @model.state # Instance has its state persisted from the previous deployment @state = @model.state else # Target instance state should either be persisted in DB or provided # via deployment plan, otherwise something is really wrong raise InstanceTargetStateUndefined, "Instance `#{self}' target state cannot be determined" end end |
#to_s ⇒ Object
70 71 72 |
# File 'lib/bosh/director/deployment_plan/instance.rb', line 70 def to_s "#{@job.name}/#{@index}" end |