class Bosh::Director::DeploymentPlan::InstanceGroup
Constants
- DEFAULT_LIFECYCLE_PROFILE
- 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)
- VALID_LIFECYCLE_PROFILES
Attributes
@return [String] Job canonical name (mostly for DNS)
@return [DeploymentPlan::Env]
@return [Hash<Integer, String>] Individual instance expected states
@return [Array<DeploymentPlan::Instance>] All job instances
@return [String] Lifecycle profile
@return [String] Job name
@return [Hash<String, DeploymentPlan::Package] Packages included into
this job
@return [DiskType] Persistent disk type (or nil)
@return [Hash] Job properties
@return [DeploymentPlan::ReleaseVersion] Release this job belongs to
@return [String] Expected job state
@return [DeploymentPlan::Stemcell]
@return [Array<DeploymentPlan::Template] Templates included into the job
@return [Array<Models::Instance>] List of excess instance models that
are not needed for current deployment
@return [DeploymentPlan::UpdateConfig] Job update settings
@return [DeploymentPlan::VmExtension]
@return [DeploymentPlan::VmType]
Public Class Methods
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.
# 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
# File lib/bosh/director/deployment_plan/instance_group.rb, line 118 def self.is_legacy_spec?(job_spec) !job_spec.has_key?("templates") end
# 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
# 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
Public Instance Methods
# File lib/bosh/director/deployment_plan/instance_group.rb, line 122 def add_instance_plans(instance_plans) @instance_plans = instance_plans end
# 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
# 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
TODO: Job should not be responsible for reserving IPs. Consider moving this somewhere else? Maybe in the consumer?
# 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
# 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
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).
# File lib/bosh/director/deployment_plan/instance_group.rb, line 248 def bind_properties @properties = filter_properties(@all_properties) end
# File lib/bosh/director/deployment_plan/instance_group.rb, line 337 def compilation? false end
# 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
# File lib/bosh/director/deployment_plan/instance_group.rb, line 225 def instance(index) @instances[index] end
# 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
# File lib/bosh/director/deployment_plan/instance_group.rb, line 305 def is_errand? @lifecycle == 'errand' end
# File lib/bosh/director/deployment_plan/instance_group.rb, line 301 def is_service? @lifecycle == 'service' end
# 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
# File lib/bosh/director/deployment_plan/instance_group.rb, line 324 def link_spec @resolved_links end
# File lib/bosh/director/deployment_plan/instance_group.rb, line 163 def needed_instance_plans sorted_instance_plans end
# File lib/bosh/director/deployment_plan/instance_group.rb, line 155 def obsolete_instance_plans @instance_plans.select(&:obsolete?) end
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. @return [Hash<String, Hash>] All package specs indexed by package name
# 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
reverse compatibility: translate disk size into a disk pool
# 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
# 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
Returns job spec as a Hash
. To be used by all instances of the job to populate agent state. @return [Hash] Hash
representation
# 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
Returns the state state of job instance by its index @param [Integer] index Instance
index @return [String, nil] Instance
state (nil if not specified)
# 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
# File lib/bosh/director/deployment_plan/instance_group.rb, line 209 def update_spec update.to_hash end
Registers compiled package with this job. @param [Models::CompiledPackage] compiled_package_model Compiled package @return [void]
# 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
# 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
Private Instance Methods
# File lib/bosh/director/deployment_plan/instance_group.rb, line 364 def extract_template_properties(collection) result = {} @templates.each do |template| # If a template has properties that were defined in the deployment manifest # for that template only, then we need to bind only these properties, and not # make them available to other templates in the same deployment job. That can # be done by checking @template_scoped_properties variable of each # template result[template.name] ||= {} if template.has_template_scoped_properties(@name) template.bind_template_scoped_properties(@name) result[template.name] = template.template_scoped_properties[@name] else template.properties.each_pair do |name, definition| copy_property(result[template.name], collection, name, definition["default"]) end end end result end
@param [Hash] collection All properties collection @return [Hash] Properties required by templates included in this job
# File lib/bosh/director/deployment_plan/instance_group.rb, line 345 def filter_properties(collection) if @templates.none? { |template| template.properties} result = {} @templates.each do |template| result[template.name] = collection end return result end if @templates.all? { |template| template.properties } return extract_template_properties(collection) end raise JobIncompatibleSpecs, "Instance group '#{name}' has specs with conflicting property definition styles between" + " its job spec templates. This may occur if colocating jobs, one of which has a spec file including" + " 'properties' and one which doesn't." end
# File lib/bosh/director/deployment_plan/instance_group.rb, line 387 def run_time_dependencies templates.flat_map { |template| template.package_models }.uniq.map(&:name) end