Class: Bosh::Director::DeploymentPlan::Job

Inherits:
Object
  • Object
show all
Includes:
Common::PropertyHelper
Defined in:
lib/bosh/director/deployment_plan/job.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(deployment) ⇒ Job

Returns a new instance of Job.

Parameters:



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/bosh/director/deployment_plan/job.rb', line 85

def initialize(deployment)
  @deployment = deployment

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

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

  @error_mutex = Mutex.new
  @packages = {}
  @halt = false
end

Instance Attribute Details

#all_propertiesObject

Returns the value of attribute all_properties.



73
74
75
# File 'lib/bosh/director/deployment_plan/job.rb', line 73

def all_properties
  @all_properties
end

#canonical_nameString

Returns Job canonical name (mostly for DNS).

Returns:

  • (String)

    Job canonical name (mostly for DNS)



25
26
27
# File 'lib/bosh/director/deployment_plan/job.rb', line 25

def canonical_name
  @canonical_name
end

#default_networkDeploymentPlan::Network

Returns Job default network.

Returns:



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

def default_network
  @default_network
end

#deploymentDeploymentPlan

Returns Current deployment plan.

Returns:



31
32
33
# File 'lib/bosh/director/deployment_plan/job.rb', line 31

def deployment
  @deployment
end

#halt_exceptionException

Returns Exception that requires job update process to be interrupted.

Returns:

  • (Exception)

    Exception that requires job update process to be interrupted



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

def halt_exception
  @halt_exception
end

#instance_statesHash<Integer, String>

Returns Individual instance expected states.

Returns:

  • (Hash<Integer, String>)

    Individual instance expected states



67
68
69
# File 'lib/bosh/director/deployment_plan/job.rb', line 67

def instance_states
  @instance_states
end

#instancesArray<DeploymentPlan::Instance>

Returns All job instances.

Returns:



57
58
59
# File 'lib/bosh/director/deployment_plan/job.rb', line 57

def instances
  @instances
end

#lifecycleString

Returns Lifecycle profile.

Returns:

  • (String)

    Lifecycle profile



22
23
24
# File 'lib/bosh/director/deployment_plan/job.rb', line 22

def lifecycle
  @lifecycle
end

#nameString

Returns Job name.

Returns:

  • (String)

    Job name



19
20
21
# File 'lib/bosh/director/deployment_plan/job.rb', line 19

def name
  @name
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



51
52
53
# File 'lib/bosh/director/deployment_plan/job.rb', line 51

def packages
  @packages
end

#persistent_diskInteger

Returns Persistent disk size (no disk if zero).

Returns:

  • (Integer)

    Persistent disk size (no disk if zero)



28
29
30
# File 'lib/bosh/director/deployment_plan/job.rb', line 28

def persistent_disk
  @persistent_disk
end

#propertiesHash

Returns Job properties.

Returns:

  • (Hash)

    Job properties



47
48
49
# File 'lib/bosh/director/deployment_plan/job.rb', line 47

def properties
  @properties
end

#releaseDeploymentPlan::ReleaseVersion

Returns Release this job belongs to.

Returns:



34
35
36
# File 'lib/bosh/director/deployment_plan/job.rb', line 34

def release
  @release
end

#resource_poolDeploymentPlan::ResourcePool

Returns Resource pool this job should be run in.

Returns:



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

def resource_pool
  @resource_pool
end

#stateString

Returns Expected job state.

Returns:

  • (String)

    Expected job state



64
65
66
# File 'lib/bosh/director/deployment_plan/job.rb', line 64

def state
  @state
end

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

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

Returns:



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

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



61
62
63
# File 'lib/bosh/director/deployment_plan/job.rb', line 61

def unneeded_instances
  @unneeded_instances
end

#updateDeploymentPlan::UpdateConfig

Returns Job update settings.

Returns:



54
55
56
# File 'lib/bosh/director/deployment_plan/job.rb', line 54

def update
  @update
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.



113
114
115
116
117
118
119
120
121
122
# File 'lib/bosh/director/deployment_plan/job.rb', line 113

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"]
  }
  job_spec["templates"] = [template]
end

.is_legacy_spec?(job_spec) ⇒ Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/bosh/director/deployment_plan/job.rb', line 102

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

.parse(deployment, job_spec, event_log) ⇒ Bosh::Director::DeploymentPlan::Job

Parameters:

Returns:



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

def self.parse(deployment, job_spec, event_log)
  parser = JobSpecParser.new(deployment, event_log)
  parser.parse(job_spec)
end

Instance Method Details

#bind_instance_networksObject



248
249
250
251
252
253
254
255
256
257
# File 'lib/bosh/director/deployment_plan/job.rb', line 248

def bind_instance_networks
  instances.each do |instance|
    instance.network_reservations.each do |net_name, reservation|
      unless reservation.reserved?
        network = @deployment.network(net_name)
        network.reserve!(reservation, "`#{name}/#{instance.index}'")
      end
    end
  end
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).



208
209
210
# File 'lib/bosh/director/deployment_plan/job.rb', line 208

def bind_properties
  @properties = filter_properties(@all_properties)
end

#bind_unallocated_vmsObject



238
239
240
241
242
243
244
245
246
# File 'lib/bosh/director/deployment_plan/job.rb', line 238

def bind_unallocated_vms
  instances.each do |instance|
    instance.bind_unallocated_vm

    # Now that we know every VM has been allocated and
    # instance models are bound, we can sync the state.
    instance.sync_state_with_db
  end
end

#can_run_as_errand?Boolean

Returns:

  • (Boolean)


263
264
265
# File 'lib/bosh/director/deployment_plan/job.rb', line 263

def can_run_as_errand?
  @lifecycle == 'errand'
end

#instance(index) ⇒ DeploymentPlan::Instance

Returns job instance by index

Parameters:

  • index (Integer)

Returns:



174
175
176
# File 'lib/bosh/director/deployment_plan/job.rb', line 174

def instance(index)
  @instances[index]
end

#instance_state(index) ⇒ 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)



181
182
183
# File 'lib/bosh/director/deployment_plan/job.rb', line 181

def instance_state(index)
  @instance_states[index] || @state
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



162
163
164
165
166
167
168
169
# File 'lib/bosh/director/deployment_plan/job.rb', line 162

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

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

#record_update_error(error, options = {}) ⇒ Object



197
198
199
200
201
202
# File 'lib/bosh/director/deployment_plan/job.rb', line 197

def record_update_error(error, options = {})
  @error_mutex.synchronize do
    @halt = true
    @halt_exception = error
  end
end

#should_halt?Boolean

Returns:

  • (Boolean)


193
194
195
# File 'lib/bosh/director/deployment_plan/job.rb', line 193

def should_halt?
  @halt
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



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/bosh/director/deployment_plan/job.rb', line 127

def spec
  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

#starts_on_deploy?Boolean

Returns:

  • (Boolean)


259
260
261
# File 'lib/bosh/director/deployment_plan/job.rb', line 259

def starts_on_deploy?
  @lifecycle == 'service'
end

#use_compiled_package(compiled_package_model) ⇒ void

This method returns an undefined value.

Registers compiled package with this job.

Parameters:



188
189
190
191
# File 'lib/bosh/director/deployment_plan/job.rb', line 188

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



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/bosh/director/deployment_plan/job.rb', line 212

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 job `#{@name}': "\
            "template `#{release1.name}/#{offending_template1.name}' depends on package `#{release1.name}/#{package_name}', "\
            "template `#{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