Class: Bosh::Director::DeploymentPlan::Job
Constant Summary
collapse
- 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)
Bosh::Director::DnsHelper::SOA, Bosh::Director::DnsHelper::TTL_4H, Bosh::Director::DnsHelper::TTL_5M
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#invalid_type, #safe_property
#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
Methods included from IpUtil
#each_ip, #format_ip, #ip_to_i, #ip_to_netaddr, #process_range
Constructor Details
#initialize(deployment, job_spec) ⇒ Job
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 79
def initialize(deployment, job_spec)
@deployment = deployment
@job_spec = job_spec
@release = nil
@templates = []
@all_properties = nil
@properties = nil
@error_mutex = Mutex.new
@packages = {}
@halt = false
@unneeded_instances = []
end
|
Instance Attribute Details
#canonical_name ⇒ String
23
24
25
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 23
def canonical_name
@canonical_name
end
|
39
40
41
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 39
def default_network
@default_network
end
|
29
30
31
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 29
def deployment
@deployment
end
|
#halt_exception ⇒ Exception
66
67
68
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 66
def halt_exception
@halt_exception
end
|
#instance_states ⇒ Hash<Integer, String>
62
63
64
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 62
def instance_states
@instance_states
end
|
#name ⇒ String
20
21
22
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 20
def name
@name
end
|
#packages ⇒ Hash<String, DeploymentPlan::Package] Packages included into
this job
49
50
51
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 49
def packages
@packages
end
|
#persistent_disk ⇒ Integer
26
27
28
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 26
def persistent_disk
@persistent_disk
end
|
#properties ⇒ Hash
45
46
47
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 45
def properties
@properties
end
|
32
33
34
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 32
def release
@release
end
|
36
37
38
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 36
def resource_pool
@resource_pool
end
|
#state ⇒ String
59
60
61
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 59
def state
@state
end
|
42
43
44
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 42
def templates
@templates
end
|
56
57
58
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 56
def unneeded_instances
@unneeded_instances
end
|
52
53
54
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 52
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.
117
118
119
120
121
122
123
124
125
126
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 117
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
106
107
108
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 106
def self.is_legacy_spec?(job_spec)
!job_spec.has_key?("templates")
end
|
71
72
73
74
75
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 71
def self.parse(deployment, job_spec)
job = new(deployment, job_spec)
job.parse
job
end
|
Instance Method Details
#bind_properties ⇒ Object
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).
428
429
430
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 428
def bind_properties
@properties = filter_properties(@all_properties)
end
|
Returns job instance by index
185
186
187
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 185
def instance(index)
@instances[index]
end
|
#instance_state(index) ⇒ String?
Returns the state state of job instance by its index
192
193
194
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 192
def instance_state(index)
@instance_states[index] || @state
end
|
Returns all instances of this job
178
179
180
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 178
def instances
@instances
end
|
#package_spec ⇒ Hash<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.
167
168
169
170
171
172
173
174
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 167
def package_spec
result = {}
@packages.each do |name, package|
result[name] = package.spec
end
result.select { |name, _| run_time_dependencies.include? name }
end
|
94
95
96
97
98
99
100
101
102
103
104
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 94
def parse
parse_name
parse_release
parse_template
parse_disk
parse_properties
parse_resource_pool
parse_update_config
parse_instances
parse_networks
end
|
#parse_disk ⇒ Object
262
263
264
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 262
def parse_disk
@persistent_disk = safe_property(@job_spec, "persistent_disk", :class => Integer, :default => 0)
end
|
#parse_instances ⇒ Object
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 304
def parse_instances
@instances = []
@instance_states = {}
@state = safe_property(@job_spec, "state", class: String, optional: true)
job_size = safe_property(@job_spec, "instances", class: Integer)
instance_states = safe_property(@job_spec, "instance_states", class: Hash, default: {})
instance_states.each_pair do |index, state|
begin
index = Integer(index)
rescue ArgumentError
raise JobInvalidInstanceIndex,
"Invalid job index `#{index}', integer expected"
end
unless (0...job_size).include?(index)
raise JobInvalidInstanceIndex,
"`#{@name}/#{index}' is outside of (0..#{job_size-1}) range"
end
unless VALID_JOB_STATES.include?(state)
raise JobInvalidInstanceState,
"Invalid state `#{state}' for `#{@name}/#{index}', valid states are: #{VALID_JOB_STATES.join(", ")}"
end
@instance_states[index] = state
end
if @state && !VALID_JOB_STATES.include?(@state)
raise JobInvalidJobState,
"Invalid state `#{@state}' for `#{@name}', valid states are: #{VALID_JOB_STATES.join(", ")}"
end
job_size.times do |index|
@instances[index] = Instance.new(self, index)
@resource_pool.reserve_capacity(1)
end
end
|
#parse_name ⇒ Object
215
216
217
218
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 215
def parse_name
@name = safe_property(@job_spec, "name", :class => String)
@canonical_name = canonical(@name)
end
|
#parse_networks ⇒ Object
344
345
346
347
348
349
350
351
352
353
354
355
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
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 344
def parse_networks
@default_network = {}
network_specs = safe_property(@job_spec, "networks", :class => Array)
if network_specs.empty?
raise JobMissingNetwork,
"Job `#{@name}' must specify at least one network"
end
network_specs.each do |network_spec|
network_name = safe_property(network_spec, "name", :class => String)
network = @deployment.network(network_name)
if network.nil?
raise JobUnknownNetwork,
"Job `#{@name}' references an unknown network `#{network_name}'"
end
static_ips = nil
if network_spec["static_ips"]
static_ips = []
each_ip(network_spec["static_ips"]) do |ip|
static_ips << ip
end
if static_ips.size != @instances.size
raise JobNetworkInstanceIpMismatch,
"Job `#{@name}' has #{@instances.size} instances but was allocated #{static_ips.size} static IPs"
end
end
default_network = safe_property(network_spec, "default",
:class => Array, :optional => true)
if default_network
default_network.each do |property|
unless Network::VALID_DEFAULTS.include?(property)
raise JobNetworkInvalidDefault,
"Job `#{@name}' specified an invalid default network property `#{property}', " +
"valid properties are: " + Network::VALID_DEFAULTS.join(", ")
end
if @default_network[property]
raise JobNetworkMultipleDefaults,
"Job `#{@name}' specified more than one network to contain default #{property}"
else
@default_network[property] = network_name
end
end
end
@instances.each_with_index do |instance, index|
reservation = NetworkReservation.new
if static_ips
reservation.ip = static_ips[index]
reservation.type = NetworkReservation::STATIC
else
reservation.type = NetworkReservation::DYNAMIC
end
instance.add_network_reservation(network_name, reservation)
end
end
if network_specs.size > 1
missing_default_properties = Network::VALID_DEFAULTS.dup
@default_network.each_key do |key|
missing_default_properties.delete(key)
end
unless missing_default_properties.empty?
raise JobNetworkMissingDefault,
"Job `#{@name}' must specify which network is default for " +
missing_default_properties.sort.join(", ") + ", since it has more than one network configured"
end
else
network = safe_property(network_specs[0], "name", :class => String)
Network::VALID_DEFAULTS.each do |property|
@default_network[property] ||= network
end
end
end
|
#parse_properties ⇒ Object
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 266
def parse_properties
job_properties = safe_property(@job_spec, "properties", :class => Hash, :optional => true)
@all_properties = Bosh::Common::DeepCopy.copy(deployment.properties)
if job_properties
@all_properties.recursive_merge!(job_properties)
end
mappings = safe_property(@job_spec, "property_mappings", :class => Hash, :default => {})
mappings.each_pair do |to, from|
resolved = lookup_property(@all_properties, from)
if resolved.nil?
raise JobInvalidPropertyMapping,
"Cannot satisfy property mapping `#{to}: #{from}', as `#{from}' is not in deployment properties"
end
@all_properties[to] = resolved
end
end
|
#parse_release ⇒ Object
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 220
def parse_release
release_name = safe_property(@job_spec, "release", :class => String,
:optional => true)
if release_name.nil?
if @deployment.releases.size == 1
@release = @deployment.releases.first
else
raise JobMissingRelease,
"Cannot tell what release job `#{@name}' supposed to use, please reference an existing release"
end
else
@release = @deployment.release(release_name)
end
if @release.nil?
raise JobUnknownRelease,
"Job `#{@name}' references an unknown release `#{release_name}'"
end
end
|
#parse_resource_pool ⇒ Object
290
291
292
293
294
295
296
297
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 290
def parse_resource_pool
resource_pool_name = safe_property(@job_spec, "resource_pool", class: String)
@resource_pool = deployment.resource_pool(resource_pool_name)
if @resource_pool.nil?
raise JobUnknownResourcePool,
"Job `#{@name}' references an unknown resource pool `#{resource_pool_name}'"
end
end
|
#parse_template ⇒ Object
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/job.rb', line 241
def parse_template
if @release.nil?
raise DirectorError, "Cannot parse template before parsing release"
end
template_names = safe_property(@job_spec, "template")
if template_names.is_a?(String)
template_names = Array(template_names)
end
unless template_names.is_a?(Array)
invalid_type("template", "String or Array", template_names)
end
template_names.each do |template_name|
@release.use_template_named(template_name)
@templates << @release.template(template_name)
end
end
|
#parse_update_config ⇒ Object
299
300
301
302
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 299
def parse_update_config
update_spec = safe_property(@job_spec, "update", class: Hash, optional: true)
@update = UpdateConfig.new(update_spec, @deployment.update)
end
|
#record_update_error(error, options = {}) ⇒ Object
208
209
210
211
212
213
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 208
def record_update_error(error, options = {})
@error_mutex.synchronize do
@halt = true
@halt_exception = error
end
end
|
#should_halt? ⇒ Boolean
204
205
206
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 204
def should_halt?
@halt
end
|
Returns job spec as a Hash. To be used by all instances of the job to populate agent state.
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
158
159
160
161
162
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 131
def spec
first_template = @templates[0]
result = {
"name" => @name,
"release" => @release.name,
"templates" => [],
"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
@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
|
#use_compiled_package(compiled_package_model) ⇒ void
This method returns an undefined value.
Registers compiled package with this job.
199
200
201
202
|
# File 'lib/bosh/director/deployment_plan/job.rb', line 199
def use_compiled_package(compiled_package_model)
compiled_package = CompiledPackage.new(compiled_package_model)
@packages[compiled_package.name] = compiled_package
end
|