Class: Bosh::Director::DeploymentPlan::Instance

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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, #invalid_dns, #reverse_domain, #reverse_host, #update_dns_a_record, #update_dns_ptr_record

Constructor Details

#initialize(job, index) ⇒ Instance

Creates a new instance specification based on the job and index.

Parameters:



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/bosh/director/deployment_plan/instance.rb', line 48

def initialize(job, index)
  @job = job
  @index = index
  @model = nil
  @configuration_hash = nil
  @template_hashes = nil
  @idle_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_hashString

Returns Checksum all of the configuration templates.

Returns:

  • (String)

    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_stateHash

Returns current state as provided by the BOSH Agent.

Returns:

  • (Hash)

    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

#idle_vmDeploymentPlan::IdleVm (readonly)

Returns Associated resource pool VM.

Returns:



35
36
37
# File 'lib/bosh/director/deployment_plan/instance.rb', line 35

def idle_vm
  @idle_vm
end

#indexInteger (readonly)

Returns Instance index.

Returns:

  • (Integer)

    Instance index



11
12
13
# File 'lib/bosh/director/deployment_plan/instance.rb', line 11

def index
  @index
end

#jobDeploymentPlan::Job (readonly)

Returns Associated job.

Returns:



8
9
10
# File 'lib/bosh/director/deployment_plan/instance.rb', line 8

def job
  @job
end

#modelModels::Instance (readonly)

Returns Instance model.

Returns:



14
15
16
# File 'lib/bosh/director/deployment_plan/instance.rb', line 14

def model
  @model
end

#network_reservationsHash<String, NetworkReservation>

Returns network reservations.

Returns:



26
27
28
# File 'lib/bosh/director/deployment_plan/instance.rb', line 26

def network_reservations
  @network_reservations
end

#recreateBoolean

Returns true if this instance needs to be recreated.

Returns:

  • (Boolean)

    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_archiveBosh::Director::Core::Templates::RenderedTemplatesArchive

Returns:

  • (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

#restartBoolean

Returns true if this instance needs to be restarted.

Returns:

  • (Boolean)

    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

#stateString

Returns job state.

Returns:

  • (String)

    job state



29
30
31
# File 'lib/bosh/director/deployment_plan/instance.rb', line 29

def state
  @state
end

#template_hashesHash

Returns A hash of template SHA1 hashes.

Returns:

  • (Hash)

    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

Instance Method Details

#add_network_reservation(name, reservation) ⇒ Object

Adds a new network to this instance

Parameters:



130
131
132
133
134
135
136
137
138
139
# File 'lib/bosh/director/deployment_plan/instance.rb', line 130

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_idle_vmvoid

This method returns an undefined value.

Allocates an idle VM in this job resource pool and binds current instance to that idle VM.



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/bosh/director/deployment_plan/instance.rb', line 405

def allocate_idle_vm
  resource_pool = @job.resource_pool
  idle_vm = resource_pool.allocate_vm
  network = resource_pool.network

  if idle_vm.vm
    # 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(idle_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
    idle_vm.bound_instance = self
    # this also means we no longer need previous VM network reservation
    # (instance has its own)
    idle_vm.release_reservation
  end

  @idle_vm = idle_vm
end

#bind_modelvoid

This method returns an undefined value.

Looks up a DB model for this instance, creates one if doesn’t exist yet.



87
88
89
# File 'lib/bosh/director/deployment_plan/instance.rb', line 87

def bind_model
  @model ||= find_or_create_model
end

#bind_unallocated_vmvoid

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 idle VM is allocated if instance DB record doesn’t reference one.



95
96
97
98
99
100
# File 'lib/bosh/director/deployment_plan/instance.rb', line 95

def bind_unallocated_vm
  bind_model
  if @model.vm.nil?
    allocate_idle_vm
  end
end

#changed?Boolean

Returns true if the any of the expected specifications differ from the ones provided by the VM

Returns:

  • (Boolean)

    returns true if the any of the expected specifications differ from the ones provided by the VM



328
329
330
# File 'lib/bosh/director/deployment_plan/instance.rb', line 328

def changed?
  !changes.empty?
end

#changesSet<Symbol>

Returns a set of all of the specification differences

Returns:

  • (Set<Symbol>)

    returns a set of all of the specification differences



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/bosh/director/deployment_plan/instance.rb', line 335

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

Returns:

  • (Boolean)

    returns true if the expected configuration hash differs from the one provided by the VM



265
266
267
# File 'lib/bosh/director/deployment_plan/instance.rb', line 265

def configuration_changed?
  configuration_hash != @current_state['configuration_hash']
end

#disk_currently_attached?Boolean

Returns true if the persistent disk is attached to the VM

Returns:

  • (Boolean)

    returns true if the persistent disk is attached to the VM



225
226
227
# File 'lib/bosh/director/deployment_plan/instance.rb', line 225

def disk_currently_attached?
  current_state['persistent_disk'].to_i > 0
end

#disk_sizeInteger

Returns persistent disk size.

Returns:

  • (Integer)

    persistent disk size



195
196
197
198
199
200
201
202
203
# File 'lib/bosh/director/deployment_plan/instance.rb', line 195

def disk_size
  if @model.nil?
    current_state['persistent_disk'].to_i
  elsif @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

Returns:

  • (Boolean)

    returns true if the DNS records configured for the instance differ from the ones configured on the DNS server



300
301
302
303
304
305
306
307
308
309
# File 'lib/bosh/director/deployment_plan/instance.rb', line 300

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_infoHash<String, String>

Returns dns record hash of dns name and IP.

Returns:

  • (Hash<String, String>)

    dns record hash of dns name and IP



207
208
209
210
211
212
213
214
# File 'lib/bosh/director/deployment_plan/instance.rb', line 207

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.

Returns:

  • (String)

    dns record name



218
219
220
# File 'lib/bosh/director/deployment_plan/instance.rb', line 218

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_modelModels::Instance

Looks up instance model in DB

Returns:



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/bosh/director/deployment_plan/instance.rb', line 386

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

Returns:

  • (Boolean)

    returns true if the expected job configuration differs from the one provided by the VM



272
273
274
275
276
277
278
279
280
281
# File 'lib/bosh/director/deployment_plan/instance.rb', line 272

def job_changed?
  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_settingsHash

Returns BOSH network settings used for Agent apply call.

Returns:

  • (Hash)

    BOSH network settings used for Agent apply call



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/bosh/director/deployment_plan/instance.rb', line 155

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

Returns:

  • (Boolean)

    returns true if the network configuration changed



231
232
233
# File 'lib/bosh/director/deployment_plan/instance.rb', line 231

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

Returns:

  • (Boolean)

    returns true if the expected packaged of the running instance differ from the ones provided by the VM



286
287
288
# File 'lib/bosh/director/deployment_plan/instance.rb', line 286

def packages_changed?
  @job.package_spec != @current_state['packages']
end

#persistent_disk_changed?Boolean

Returns true if the expected persistent disk differs from the one currently configured on the VM

Returns:

  • (Boolean)

    returns true if the expected persistent disk differs from the one currently configured on the VM



293
294
295
# File 'lib/bosh/director/deployment_plan/instance.rb', line 293

def persistent_disk_changed?
  @job.persistent_disk != disk_size
end

#resource_pool_changed?Boolean

Returns true if the expected resource pool differs from the one provided by the VM

Returns:

  • (Boolean)

    returns true if the expected resource pool differs from the one provided by the VM



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/bosh/director/deployment_plan/instance.rb', line 238

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

#specHash<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.

Returns:



356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/bosh/director/deployment_plan/instance.rb', line 356

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,
    'persistent_disk' => job.persistent_disk,
    'configuration_hash' => configuration_hash,
    'properties' => job.properties,
    'dns_domain_name' => dns_domain_name
  }

  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.

Returns:

  • (Boolean)

    returns true if the expected job state differs from the one provided by the VM



319
320
321
322
323
# File 'lib/bosh/director/deployment_plan/instance.rb', line 319

def state_changed?
  @state == 'detached' ||
    @state == 'started' && @current_state['job_state'] != 'running' ||
    @state == 'stopped' && @current_state['job_state'] == 'running'
end

#sync_state_with_dbvoid

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).



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/bosh/director/deployment_plan/instance.rb', line 107

def sync_state_with_db
  if @model.nil?
    raise DirectorError, "Instance `#{self}' model is not bound"
  end

  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

#take_network_reservations(reservations) ⇒ void

This method returns an undefined value.

Take any existing valid network reservations

Parameters:



146
147
148
149
150
151
# File 'lib/bosh/director/deployment_plan/instance.rb', line 146

def take_network_reservations(reservations)
  reservations.each do |name, provided_reservation|
    reservation = @network_reservations[name]
    reservation.take(provided_reservation) if reservation
  end
end

#to_sObject



71
72
73
# File 'lib/bosh/director/deployment_plan/instance.rb', line 71

def to_s
  "#{@job.name}/#{@index}"
end

#use_model(model) ⇒ void

This method returns an undefined value.

Parameters:



77
78
79
80
81
82
# File 'lib/bosh/director/deployment_plan/instance.rb', line 77

def use_model(model)
  if @model
    raise DirectorError, 'Instance model is already bound'
  end
  @model = model
end