Class: Bosh::Director::DeploymentPlan::InstanceGroup

Inherits:
Object
  • Object
show all
Includes:
Template::PropertyHelper
Defined in:
lib/bosh/director/deployment_plan/instance_group.rb

Constant Summary collapse

VALID_LIFECYCLE_PROFILES =
%w(service errand)
DEFAULT_LIFECYCLE_PROFILE =
'service'
VALID_JOB_STATES =

started, stopped and detached are real states (persisting in DB and reflecting target instance state) recreate and restart are two virtual states (both set target instance state to “started” and set appropriate instance spec modifiers)

%w(started stopped detached recreate restart)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger) ⇒ InstanceGroup

Returns a new instance of InstanceGroup.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 93

def initialize(logger)
  @logger = logger

  @release = nil
  @templates = []
  @all_properties = nil # All properties available to job
  @properties = nil # Actual job properties

  @instances = []
  @desired_instances = []
  @unneeded_instances = []
  @instance_states = {}
  @default_network = {}

  @packages = {}
  @link_paths = {}
  @resolved_links = {}
  @migrated_from = []
  @availability_zones = []

  @instance_plans = []

  @did_change = false
end

Instance Attribute Details

#all_propertiesObject

Returns the value of attribute all_properties.



76
77
78
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 76

def all_properties
  @all_properties
end

#availability_zonesObject

Returns the value of attribute availability_zones.



74
75
76
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 74

def availability_zones
  @availability_zones
end

#canonical_nameString

Returns Job canonical name (mostly for DNS).

Returns:

  • (String)

    Job canonical name (mostly for DNS)



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

def canonical_name
  @canonical_name
end

#default_networkObject

Returns the value of attribute default_network.



46
47
48
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 46

def default_network
  @default_network
end

#desired_instancesObject

Returns the value of attribute desired_instances.



82
83
84
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 82

def desired_instances
  @desired_instances
end

#did_changeObject

Returns the value of attribute did_change.



86
87
88
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 86

def did_change
  @did_change
end

#envDeploymentPlan::Env

Returns:



44
45
46
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 44

def env
  @env
end

#instance_statesHash<Integer, String>

Returns Individual instance expected states.

Returns:

  • (Hash<Integer, String>)

    Individual instance expected states



72
73
74
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 72

def instance_states
  @instance_states
end

#instancesObject

to preserve interface for UpdateStep – switch to instance_plans eventually



62
63
64
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 62

def instances
  @instances
end

#lifecycleString

Returns Lifecycle profile.

Returns:

  • (String)

    Lifecycle profile



23
24
25
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 23

def lifecycle
  @lifecycle
end

Returns the value of attribute link_paths.



84
85
86
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 84

def link_paths
  @link_paths
end

#migrated_fromObject

Returns the value of attribute migrated_from.



80
81
82
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 80

def migrated_from
  @migrated_from
end

#nameString

Returns Job name.

Returns:

  • (String)

    Job name



20
21
22
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 20

def name
  @name
end

#networksObject

Returns the value of attribute networks.



78
79
80
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 78

def networks
  @networks
end

#packagesHash<String, DeploymentPlan::Package] Packages included into this job

Returns Hash<String, DeploymentPlan::Package] Packages included into this job.

Returns:

  • (Hash<String, DeploymentPlan::Package] Packages included into this job)

    Hash<String, DeploymentPlan::Package] Packages included into this job



56
57
58
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 56

def packages
  @packages
end

#persistent_disk_typeDiskType

Returns Persistent disk type (or nil).

Returns:

  • (DiskType)

    Persistent disk type (or nil)



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

def persistent_disk_type
  @persistent_disk_type
end

#propertiesHash

Returns Job properties.

Returns:

  • (Hash)

    Job properties



52
53
54
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 52

def properties
  @properties
end

#releaseDeploymentPlan::ReleaseVersion

Returns Release this job belongs to.

Returns:



32
33
34
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 32

def release
  @release
end

#stateString

Returns Expected job state.

Returns:

  • (String)

    Expected job state



69
70
71
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 69

def state
  @state
end

#stemcellDeploymentPlan::Stemcell



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

def stemcell
  @stemcell
end

#templatesArray<DeploymentPlan::Template] Templates included into the job

Returns Array<DeploymentPlan::Template] Templates included into the job.

Returns:



49
50
51
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 49

def templates
  @templates
end

#unneeded_instancesArray<Models::Instance>

Returns List of excess instance models that are not needed for current deployment.

Returns:

  • (Array<Models::Instance>)

    List of excess instance models that are not needed for current deployment



66
67
68
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 66

def unneeded_instances
  @unneeded_instances
end

#updateDeploymentPlan::UpdateConfig

Returns Job update settings.

Returns:



59
60
61
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 59

def update
  @update
end

#vm_extensionsDeploymentPlan::VmExtension



41
42
43
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 41

def vm_extensions
  @vm_extensions
end

#vm_typeDeploymentPlan::VmType



38
39
40
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 38

def vm_type
  @vm_type
end

Class Method Details

.convert_from_legacy_spec(job_spec) ⇒ Object

Takes in a job spec and returns a job spec in the new format, if it needs to be modified. The new format has “templates” key, which is an array with each template’s data. This is used for job collocation, specifically for the agent’s current job spec when compared to the director’s. We only convert their template to a single array entry because it should be impossible for the agent to have a job spec with multiple templates in legacy form.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 138

def self.convert_from_legacy_spec(job_spec)
  return job_spec if !self.is_legacy_spec?(job_spec)
  template = {
    "name" => job_spec["template"],
    "version" => job_spec["version"],
    "sha1" => job_spec["sha1"],
    "blobstore_id" => job_spec["blobstore_id"]
  }

  # Supporting 'template_scoped_properties' for legacy spec is going to be messy.
  # So we will support this feature if a user want to use legacy spec. If they
  # want to use properties per template, let them use the regular way of defining
  # templates, i.e. by using the 'templates' key
  job_spec['templates'] = [template]
end

.is_legacy_spec?(job_spec) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 118

def self.is_legacy_spec?(job_spec)
  !job_spec.has_key?("templates")
end

.parse(plan, job_spec, event_log, logger, parse_options = {}) ⇒ Object



88
89
90
91
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 88

def self.parse(plan, job_spec, event_log, logger, parse_options = {})
  parser = InstanceGroupSpecParser.new(plan, event_log, logger)
  parser.parse(job_spec, parse_options)
end

Instance Method Details

#add_instance_plans(instance_plans) ⇒ Object



122
123
124
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 122

def add_instance_plans(instance_plans)
  @instance_plans = instance_plans
end


332
333
334
335
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 332

def add_link_path(template_name, link_name, link_path)
  @link_paths[template_name] ||= {}
  @link_paths[template_name][link_name] = link_path
end


320
321
322
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 320

def add_resolved_link(link_name, link_spec)
  @resolved_links[link_name] = link_spec
end

#bind_instance_networks(ip_provider) ⇒ Object

TODO: Job should not be responsible for reserving IPs. Consider moving this somewhere else? Maybe in the consumer?



284
285
286
287
288
289
290
291
292
293
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 284

def bind_instance_networks(ip_provider)
  needed_instance_plans
    .flat_map(&:network_plans)
    .reject(&:obsolete?)
    .reject(&:existing?)
    .each do |network_plan|
    reservation = network_plan.reservation
    ip_provider.reserve(reservation)
  end
end

#bind_instances(ip_provider) ⇒ Object



278
279
280
281
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 278

def bind_instances(ip_provider)
  instances.each(&:ensure_model_bound)
  bind_instance_networks(ip_provider)
end

#bind_propertiesObject

Extracts only the properties needed by this job. This is decoupled from parsing properties because templates need to be bound to their models before ‘bind_properties’ is being called (as we persist job template property definitions in DB).



248
249
250
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 248

def bind_properties
  @properties = filter_properties(@all_properties)
end

#compilation?Boolean

Returns:

  • (Boolean)


337
338
339
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 337

def compilation?
  false
end

#has_network?(network_name) ⇒ Boolean

Returns:

  • (Boolean)


295
296
297
298
299
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 295

def has_network?(network_name)
  networks.any? do |network|
    network.name == network_name
  end
end

#instance(index) ⇒ Object



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

def instance(index)
  @instances[index]
end

#instance_plans_with_missing_vmsObject



314
315
316
317
318
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 314

def instance_plans_with_missing_vms
  needed_instance_plans.reject do |instance_plan|
    instance_plan.instance.vm_created? || instance_plan.instance.state == 'detached'
  end
end

#is_errand?Boolean

Returns:

  • (Boolean)


305
306
307
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 305

def is_errand?
  @lifecycle == 'errand'
end

#is_service?Boolean

Returns:

  • (Boolean)


301
302
303
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 301

def is_service?
  @lifecycle == 'service'
end


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

def link_path(template_name, link_name)
  @link_paths.fetch(template_name, {})[link_name]
end


324
325
326
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 324

def link_spec
  @resolved_links
end

#needed_instance_plansObject



163
164
165
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 163

def needed_instance_plans
  sorted_instance_plans
end

#obsolete_instance_plansObject



155
156
157
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 155

def obsolete_instance_plans
  @instance_plans.select(&:obsolete?)
end

#package_specHash<String, Hash>

Returns package specs for all packages in the job indexed by package name. To be used by all instances of the job to populate agent state.

Returns:

  • (Hash<String, Hash>)

    All package specs indexed by package name



216
217
218
219
220
221
222
223
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 216

def package_spec
  result = {}
  @packages.each do |name, package|
    result[name] = package.spec
  end

  result.select { |name, _| run_time_dependencies.include? name }
end

#persistent_disk=(disk_size) ⇒ Object

reverse compatibility: translate disk size into a disk pool



310
311
312
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 310

def persistent_disk=(disk_size)
  @persistent_disk_type = DiskType.new(SecureRandom.uuid, disk_size, {})
end

#sorted_instance_plansObject



126
127
128
129
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 126

def sorted_instance_plans
  @sorted_instance_plans ||= InstancePlanSorter.new(@logger)
                             .sort(@instance_plans.reject(&:obsolete?))
end

#specHash

Returns job spec as a Hash. To be used by all instances of the job to populate agent state.

Returns:

  • (Hash)

    Hash representation



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
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 174

def spec
  if @templates.size >= 1
    first_template = @templates[0]
    result = {
      "name" => @name,
      "templates" => [],
      # --- Legacy ---
      "template" => first_template.name,
      "version" => first_template.version,
      "sha1" => first_template.sha1,
      "blobstore_id" => first_template.blobstore_id
    }

    if first_template.logs
      result["logs"] = first_template.logs
    end
    # --- /Legacy ---

    @templates.each do |template|
      template_entry = {
        "name" => template.name,
        "version" => template.version,
        "sha1" => template.sha1,
        "blobstore_id" => template.blobstore_id
      }

      if template.logs
        template_entry["logs"] = template.logs
      end
      result["templates"] << template_entry
    end
    result
  end
end

#state_for_instance(instance_model) ⇒ String?

Returns the state state of job instance by its index

Parameters:

  • index (Integer)

    Instance index

Returns:

  • (String, nil)

    Instance state (nil if not specified)



232
233
234
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 232

def state_for_instance(instance_model)
  @instance_states[instance_model.uuid] || @instance_states[instance_model.index.to_s] || @state
end

#update_specObject



209
210
211
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 209

def update_spec
  update.to_hash
end

#use_compiled_package(compiled_package_model) ⇒ void

This method returns an undefined value.

Registers compiled package with this job.

Parameters:



239
240
241
242
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 239

def use_compiled_package(compiled_package_model)
  compiled_package = CompiledPackage.new(compiled_package_model)
  @packages[compiled_package.name] = compiled_package
end

#validate_package_names_do_not_collide!Object



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/bosh/director/deployment_plan/instance_group.rb', line 252

def validate_package_names_do_not_collide!
  releases_by_package_names = templates
                                .reduce([]) { |memo, t| memo + t.model.package_names.product([t.release]) }
                                .reduce({}) { |memo, package_name_and_release_version|
    package_name = package_name_and_release_version.first
    release_version = package_name_and_release_version.last
    memo[package_name] ||= Set.new
    memo[package_name] << release_version
    memo
  }

  releases_by_package_names.each do |package_name, releases|
    if releases.size > 1
      release1, release2 = releases.to_a[0..1]
      offending_template1 = templates.find { |t| t.release == release1 }
      offending_template2 = templates.find { |t| t.release == release2 }

      raise JobPackageCollision,
        "Package name collision detected in instance group '#{@name}': "\
            "job '#{release1.name}/#{offending_template1.name}' depends on package '#{release1.name}/#{package_name}', "\
            "job '#{release2.name}/#{offending_template2.name}' depends on '#{release2.name}/#{package_name}'. " +
          'BOSH cannot currently collocate two packages with identical names from separate releases.'
    end
  end
end