Class: Bosh::Director::DeploymentPlan::Job
- Includes:
- Common::PropertyHelper, Bosh::Director::DnsHelper, IpUtil, ValidationHelper
- Defined in:
- lib/bosh/director/deployment_plan/job.rb
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)
Constants included from Bosh::Director::DnsHelper
Bosh::Director::DnsHelper::SOA, Bosh::Director::DnsHelper::TTL_4H, Bosh::Director::DnsHelper::TTL_5M
Instance Attribute Summary collapse
-
#canonical_name ⇒ String
Job canonical name (mostly for DNS).
-
#default_network ⇒ DeploymentPlan::Network Job default network
DeploymentPlan::Network Job default network.
-
#deployment ⇒ DeploymentPlan
Current deployment plan.
-
#halt_exception ⇒ Exception
Exception that requires job update process to be interrupted.
-
#instance_states ⇒ Hash<Integer, String>
Individual instance expected states.
-
#name ⇒ String
Job name.
-
#packages ⇒ Hash<String, DeploymentPlan::Package] Packages included into this job
Hash<String, DeploymentPlan::Package] Packages included into this job.
-
#persistent_disk ⇒ Integer
Persistent disk size (no disk if zero).
-
#properties ⇒ Hash
Job properties.
-
#release ⇒ DeploymentPlan::ReleaseVersion
Release this job belongs to.
-
#resource_pool ⇒ DeploymentPlan::ResourcePool
Resource pool this job should be run in.
-
#state ⇒ String
Expected job state.
-
#templates ⇒ Array<DeploymentPlan::Template] Templates included into the job
Array<DeploymentPlan::Template] Templates included into the job.
-
#unneeded_instances ⇒ Array<Models::Instance>
List of excess instance models that are not needed for current deployment.
-
#update ⇒ DeploymentPlan::UpdateConfig
Job update settings.
Class Method Summary collapse
-
.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.
- .is_legacy_spec?(job_spec) ⇒ Boolean
- .parse(deployment, job_spec) ⇒ Bosh::Director::DeploymentPlan::Job
Instance Method Summary collapse
-
#bind_properties ⇒ Object
Extracts only the properties needed by this job.
-
#initialize(deployment, job_spec) ⇒ Job
constructor
A new instance of Job.
-
#instance(index) ⇒ DeploymentPlan::Instance
Returns job instance by index.
-
#instance_state(index) ⇒ String?
Returns the state state of job instance by its index.
-
#instances ⇒ Array<DeploymentPlan::Instance>
Returns all instances of this job.
-
#package_spec ⇒ Hash<String, Hash>
Returns package specs for all packages in the job indexed by package name.
- #parse ⇒ Object
- #parse_disk ⇒ Object
- #parse_instances ⇒ Object
- #parse_name ⇒ Object
- #parse_networks ⇒ Object
- #parse_properties ⇒ Object
- #parse_release ⇒ Object
- #parse_resource_pool ⇒ Object
- #parse_template ⇒ Object
- #parse_update_config ⇒ Object
- #record_update_error(error, options = {}) ⇒ Object
- #should_halt? ⇒ Boolean
-
#spec ⇒ Hash
Returns job spec as a Hash.
-
#use_compiled_package(compiled_package_model) ⇒ void
Registers compiled package with this job.
Methods included from ValidationHelper
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
Methods included from IpUtil
#each_ip, #format_ip, #ip_to_i, #ip_to_netaddr, #process_range
Constructor Details
#initialize(deployment, job_spec) ⇒ Job
Returns a new instance of 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 # All properties available to job @properties = nil # Actual job properties @error_mutex = Mutex.new @packages = {} @halt = false @unneeded_instances = [] end |
Instance Attribute Details
#canonical_name ⇒ String
Returns Job canonical name (mostly for DNS).
23 24 25 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 23 def canonical_name @canonical_name end |
#default_network ⇒ DeploymentPlan::Network Job default network
Returns DeploymentPlan::Network Job default network.
39 40 41 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 39 def default_network @default_network end |
#deployment ⇒ DeploymentPlan
Returns Current deployment plan.
29 30 31 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 29 def deployment @deployment end |
#halt_exception ⇒ Exception
Returns Exception that requires job update process to be interrupted.
66 67 68 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 66 def halt_exception @halt_exception end |
#instance_states ⇒ Hash<Integer, String>
Returns Individual instance expected states.
62 63 64 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 62 def instance_states @instance_states end |
#name ⇒ String
Returns Job name.
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
Returns 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
Returns Persistent disk size (no disk if zero).
26 27 28 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 26 def persistent_disk @persistent_disk end |
#properties ⇒ Hash
Returns Job properties.
45 46 47 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 45 def properties @properties end |
#release ⇒ DeploymentPlan::ReleaseVersion
Returns Release this job belongs to.
32 33 34 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 32 def release @release end |
#resource_pool ⇒ DeploymentPlan::ResourcePool
Returns Resource pool this job should be run in.
36 37 38 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 36 def resource_pool @resource_pool end |
#state ⇒ String
Returns Expected job state.
59 60 61 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 59 def state @state end |
#templates ⇒ Array<DeploymentPlan::Template] Templates included into the job
Returns Array<DeploymentPlan::Template] Templates included into the job.
42 43 44 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 42 def templates @templates end |
#unneeded_instances ⇒ Array<Models::Instance>
Returns List of excess instance models that are not needed for current deployment.
56 57 58 |
# File 'lib/bosh/director/deployment_plan/job.rb', line 56 def unneeded_instances @unneeded_instances end |
#update ⇒ DeploymentPlan::UpdateConfig
Returns Job update settings.
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 |
.parse(deployment, job_spec) ⇒ Bosh::Director::DeploymentPlan::Job
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 |
#instance(index) ⇒ DeploymentPlan::Instance
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 |
#instances ⇒ Array<DeploymentPlan::Instance>
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 |
#parse ⇒ Object
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 # Set the default network to the one and only available network # (if not specified already) 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 # Manifest can contain global and per-job properties section 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, = {}) @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 |
#spec ⇒ Hash
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" => [], # --- 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 |
#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 |