Class: HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef
- Inherits:
-
PlatformHandler
- Object
- Plugin
- PlatformHandler
- HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef
- Defined in:
- lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb,
lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef/dsl_parser.rb,
lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef/recipes_tree_builder.rb
Overview
Handle a Chef repository without using a Chef Infra Server. Inventory is read from nodes/*.json. Services are defined from policy files in policyfiles/*.rb. Roles are not supported as they are considered made obsolete with the usage of policies by the Chef community. Required Chef versions are taken from a chef_versions.yml file containing the following keys:
-
workstation (String): The Chef Workstation version to be installed during setup (can be specified as major.minor only)
-
client (String): The Chef Infra Client version to be installed during nodes deployment (can be specified as major.minor only)
Defined Under Namespace
Modules: MyDSLExtension Classes: DslParser, RecipesTreeBuilder
Constant Summary
Constants included from LoggerHelpers
LoggerHelpers::LEVELS_MODIFIERS, LoggerHelpers::LEVELS_TO_STDERR
Instance Attribute Summary
Attributes inherited from PlatformHandler
#actions_executor, #nodes_handler, #platform_type, #repository_path
Instance Method Summary collapse
-
#actions_to_deploy_on(node, service, use_why_run: true) ⇒ Object
Get the list of actions to perform to deploy on a given node.
-
#decode_recipe(recipe_def) ⇒ Object
Return the cookbook directory, cookbook name and recipe name from which a recipe definition is found.
-
#deployable_services ⇒ Object
Get the list of services we can deploy [API] - This method is mandatory.
-
#impacts_from(files_diffs) ⇒ Object
Get the list of impacted nodes and services from a files diff.
-
#init ⇒ Object
Initialize a new instance of this platform handler.
-
#known_cookbook_paths ⇒ Object
Return the list of possible cookbook paths from this repository only.
-
#known_nodes ⇒ Object
Get the list of known nodes.
-
#metadata_for(node) ⇒ Object
Get the metadata of a given node.
-
#package(services:, secrets:, local_environment:) ⇒ Object
Package the repository, ready to be deployed on artefacts or directly to a node.
-
#parse_deploy_output(stdout, _stderr) ⇒ Object
Parse stdout and stderr of a given deploy run and get the list of tasks with their status [API] - This method is mandatory.
-
#policy_run_list(policy) ⇒ Object
Get the run list of a given policy.
-
#prepare_for_deploy(services:, secrets:, local_environment:, why_run:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument Prepare deployments.
-
#services_for(node) ⇒ Object
Return the services for a given node [API] - This method is mandatory.
-
#setup ⇒ Object
Setup the platform, install dependencies…
Methods inherited from PlatformHandler
#<=>, #info, inherited, #initialize, #name
Methods inherited from Plugin
extend_config_dsl_with, #initialize, valid?
Methods included from LoggerHelpers
#err, #init_loggers, #log_component=, #log_debug?, #log_level=, #out, #section, #set_loggers_format, #stderr_device, #stderr_device=, #stderr_displayed?, #stdout_device, #stdout_device=, #stdout_displayed?, #stdouts_to_s, #with_progress_bar
Constructor Details
This class inherits a constructor from HybridPlatformsConductor::PlatformHandler
Instance Method Details
#actions_to_deploy_on(node, service, use_why_run: true) ⇒ Object
Get the list of actions to perform to deploy on a given node. Those actions can be executed in parallel with other deployments on other nodes. They must be thread safe.
- API
-
This method is mandatory.
-
- API
-
@cmd_runner is accessible.
-
- API
-
@actions_executor is accessible.
-
- Parameters
-
node (String): Node to deploy on
-
service (String): Service to be deployed
-
use_why_run (Boolean): Do we use a why-run mode? [default = true]
- Result
-
Array< Hash<Symbol,Object> >: List of actions to be done
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 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 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 222 def actions_to_deploy_on(node, service, use_why_run: true) package_dir = "#{@repository_path}/dist/#{@local_env ? 'local' : 'prod'}/#{service}" gems_to_install = [] # Generate the nodes attributes file unless @cmd_runner.dry_run FileUtils.mkdir_p "#{package_dir}/nodes" File.write("#{package_dir}/nodes/#{node}.json", (known_nodes.include?(node) ? (node) : {}).merge(@nodes_handler.(node)).to_json) # Get the gems to be installed gems_to_install = JSON.parse(File.read("#{package_dir}/gems.json")) end = [ '--local-mode', '--chef-license', 'accept', '--json-attributes', "nodes/#{node}.json" ] << '--why-run' if use_why_run # client_options.concat ['--log_level', 'debug'] if log_debug? # Force setting of TERM variable and usage of unbuffer to get colored output from chef-client even if executed through a non-interactive SSH session. client_env = { 'SSL_CERT_DIR' => '/etc/ssl/certs', 'TERM' => 'xterm-256color' } if @nodes_handler.get_use_local_chef_of(node) # Just run the chef-client directly from the packaged repository sudo_prefix = @cmd_runner.root? ? '' : 'sudo -E ' [ { bash: [ 'set -e', "cd #{package_dir}" ] + client_env.map { |var_name, value| "export #{var_name}=#{value}" } + gems_to_install.map { |(gem_name, gem_version)| "#{sudo_prefix}/opt/chef-workstation/bin/chef gem install #{gem_name} --version \"#{gem_version}\"" } + [ "#{sudo_prefix}/opt/chef-workstation/bin/chef-client #{.join(' ')}" ] } ] else # Upload the package and run it from the node package_name = File.basename(package_dir) chef_versions_file = "#{@repository_path}/chef_versions.yml" raise "Missing file #{chef_versions_file} specifying the Chef Infra Client version to be deployed" unless File.exist?(chef_versions_file) required_chef_client_version = YAML.load_file(chef_versions_file)['client'] sudo = @actions_executor.sudo_prefix(node, forward_env: true) [ { # Install dependencies remote_bash: [ 'set -e', 'set -o pipefail', "if [ -n \"$(command -v apt)\" ]; then #{sudo}apt update && #{sudo}apt install -y curl build-essential expect ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl expect ; fi", 'mkdir -p ./hpc_deploy', 'rm -rf ./hpc_deploy/tmp', 'mkdir -p ./hpc_deploy/tmp', 'curl --location https://omnitruck.chef.io/install.sh --output ./hpc_deploy/install.sh', 'chmod a+x ./hpc_deploy/install.sh', "#{sudo}TMPDIR=./hpc_deploy/tmp ./hpc_deploy/install.sh -d /opt/artefacts -v #{required_chef_client_version} -s once" ] }, { scp: { package_dir => './hpc_deploy' }, remote_bash: { commands: [ 'set -e', "cd ./hpc_deploy/#{package_name}" ] + gems_to_install.map { |(gem_name, gem_version)| "#{sudo}/opt/chef/embedded/bin/gem install #{gem_name} --version \"#{gem_version}\"" } + [ "#{sudo}unbuffer /opt/chef/bin/chef-client #{.join(' ')}", 'cd -' ] + (log_debug? ? [] : ["#{sudo}rm -rf ./hpc_deploy/#{package_name}"]), env: client_env } } ] end end |
#decode_recipe(recipe_def) ⇒ Object
Return the cookbook directory, cookbook name and recipe name from which a recipe definition is found. The following forms are handled:
- Parameters
-
recipe_def (String): Recipe definition (cookbook or cookbook::recipe).
- Result
-
String: The cookbook directory, or nil if unknown
-
Symbol: The cookbook name
-
Symbol: The recipe name
524 525 526 527 528 529 530 531 532 533 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 524 def decode_recipe(recipe_def) recipe_def = Regexp.last_match(1) if recipe_def =~ /^recipe\[(.+)\]$/ cookbook, recipe = recipe_def.split('::').map(&:to_sym) recipe = :default if recipe.nil? # Find the cookbook it belongs to cookbook_dir = known_cookbook_paths.find { |cookbook_path| File.exist?("#{@repository_path}/#{cookbook_path}/#{cookbook}") } raise "Unknown recipe #{cookbook}::#{recipe} from cookbook #{@repository_path}/#{cookbook_dir}/#{cookbook}." if !cookbook_dir.nil? && !File.exist?("#{@repository_path}/#{cookbook_dir}/#{cookbook}/recipes/#{recipe}.rb") [cookbook_dir, cookbook, recipe] end |
#deployable_services ⇒ Object
Get the list of services we can deploy
- API
-
This method is mandatory.
-
- Result
-
Array<String>: The corresponding services
111 112 113 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 111 def deployable_services Dir.glob("#{@repository_path}/policyfiles/*.rb").map { |file| File.basename(file, '.rb') } end |
#impacts_from(files_diffs) ⇒ Object
Get the list of impacted nodes and services from a files diff.
- API
-
This method is optional
-
- Parameters
-
files_diffs (Hash< String, Hash< Symbol, Object > >): List of diffs info, per file name having a diff. Diffs info have the following properties:
-
moved_to (String): The new file path, in case it has been moved [optional]
-
diff (String): The diff content
-
- Result
-
Array<String>: The list of nodes impacted by this diff
-
Array<String>: The list of services impacted by this diff
-
Boolean: Are there some files that have a global impact (meaning all nodes are potentially impacted by this diff)?
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 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 356 def impacts_from(files_diffs) impacted_nodes = [] impacted_services = [] # List of impacted [cookbook, recipe] # Array< [Symbol, Symbol] > impacted_recipes = [] impacted_global = false files_diffs.keys.sort.each do |impacted_file| case impacted_file when %r{^policyfiles/([^/]+)\.rb$}, %r{^policyfiles/([^/]+)\.lock.json$} log_debug "[#{impacted_file}] - Impacted service: #{Regexp.last_match(1)}" impacted_services << Regexp.last_match(1) when %r{^nodes/([^/]+)\.json} log_debug "[#{impacted_file}] - Impacted node: #{Regexp.last_match(1)}" impacted_nodes << Regexp.last_match(1) else cookbook_path = known_cookbook_paths.find { |cookbooks_path| impacted_file =~ %r{^#{Regexp.escape(cookbooks_path)}/.+$} } if cookbook_path.nil? # Global file log_debug "[#{impacted_file}] - Global file impacted" impacted_global = true else # File belonging to a cookbook file_cookbook_name, file_path = impacted_file.match(%r{^#{cookbook_path}/(\w+)/(.+)$})[1..2] cookbook = file_cookbook_name.to_sym # Small helper to register a recipe register = proc do |source, recipe_name, cookbook_name: cookbook| cookbook_name = cookbook_name.to_sym if cookbook_name.is_a?(String) log_debug "[#{impacted_file}] - Impacted recipe from #{source}: #{cookbook_name}::#{recipe_name}" impacted_recipes << [cookbook_name, recipe_name.to_sym] end case file_path when %r{recipes/(.+)\.rb} register.call('direct', Regexp.last_match(1)) when %r{attributes/.+\.rb}, 'metadata.rb' # Consider all recipes are impacted Dir.glob("#{@repository_path}/#{cookbook_path}/#{cookbook}/recipes/*.rb") do |recipe_path| register.call('attributes', File.basename(recipe_path, '.rb')) end when %r{(templates|files)/(.+)} # Find recipes using this file name included_file = File.basename(Regexp.last_match(2)) template_regexp = /["']#{Regexp.escape(included_file)}["']/ Dir.glob("#{@repository_path}/#{cookbook_path}/#{cookbook}/recipes/*.rb") do |recipe_path| register.call("included file #{included_file}", File.basename(recipe_path, '.rb')) if File.read(recipe_path) =~ template_regexp end when %r{resources/(.+)} # Find any recipe using this resource included_resource = "#{cookbook}_#{File.basename(Regexp.last_match(1), '.rb')}" resource_regexp = /(\W|^)#{Regexp.escape(included_resource)}(\W|$)/ known_cookbook_paths.each do |cookbooks_path| Dir.glob("#{@repository_path}/#{cookbooks_path}/**/recipes/*.rb") do |recipe_path| if File.read(recipe_path) =~ resource_regexp cookbook_name, recipe_name = recipe_path.match(%r{#{cookbooks_path}/(\w+)/recipes/(\w+)\.rb})[1..2] register.call("included resource #{included_resource}", recipe_name, cookbook_name: cookbook_name) end end end when %r{libraries/(.+)} # Find any recipe using methods from this library if File.exist?("#{@repository_path}/#{impacted_file}") lib_methods_regexps = File.read("#{@repository_path}/#{impacted_file}").scan(/(\W|^)def\s+(\w+)(\W|$)/).map { |_grp_1, method_name, _grp_2| /(\W|^)#{Regexp.escape(method_name)}(\W|$)/ } known_cookbook_paths.each do |cookbooks_path| Dir.glob("#{@repository_path}/#{cookbooks_path}/**/recipes/*.rb") do |recipe_path| file_content = File.read(recipe_path) found_lib_regexp = lib_methods_regexps.find { |regexp| file_content =~ regexp } unless found_lib_regexp.nil? cookbook_name, recipe_name = recipe_path.match(%r{#{cookbooks_path}/(\w+)/recipes/(\w+)\.rb})[1..2] register.call("included library helper #{found_lib_regexp.source[6..-7]}", recipe_name, cookbook_name: cookbook_name) end end end end when 'README.md', 'README.rdoc', 'CHANGELOG.md', '.rubocop.yml' # Ignore them else log_warn "[#{impacted_file}] - Unknown impact for cookbook file belonging to #{cookbook}" # Consider all recipes are impacted by default Dir.glob("#{@repository_path}/#{cookbook_path}/#{cookbook}/recipes/*.rb") do |recipe_path| register.call('attributes', File.basename(recipe_path, '.rb')) end end end end end # Devise the impacted services from the impacted recipes we just found. impacted_recipes.uniq! log_debug "* #{impacted_recipes.size} impacted recipes:\n#{impacted_recipes.map { |(cookbook, recipe)| "#{cookbook}::#{recipe}" }.sort.join("\n")}" recipes_tree = full_recipes_tree [ impacted_nodes, ( impacted_services + # Gather the list of services using the impacted recipes impacted_recipes.map do |(cookbook, recipe)| recipe_info = recipes_tree.dig cookbook, recipe recipe_info.nil? ? [] : recipe_info[:used_by_policies] end.flatten ).sort.uniq, impacted_global ] end |
#init ⇒ Object
Initialize a new instance of this platform handler.
- API
-
This method is optional.
-
- API
-
@cmd_runner is accessible.
-
53 54 55 56 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 53 def init # Mutex for getting the full recipes tree @recipes_tree_mutex = Mutex.new end |
#known_cookbook_paths ⇒ Object
Return the list of possible cookbook paths from this repository only. Returned paths are relative to the repository path.
- Result
-
Array<String>: Known cookbook paths
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 466 def known_cookbook_paths # Keep a cache of it for performance. unless defined?(@cookbook_paths) config_file = "#{@repository_path}/config.rb" @cookbook_paths = ( ['cookbooks'] + if File.exist?(config_file) # Read the knife configuration to get cookbook paths dsl_parser = DslParser.new dsl_parser.parse(config_file) cookbook_path_call = dsl_parser.calls.find { |call_info| call_info[:method] == :cookbook_path } cookbook_path_call.nil? ? [] : cookbook_path_call[:args].first else [] end ). map do |dir| # Only keep dirs that actually exist and are part of our repository full_path = dir.start_with?('/') ? dir : File.("#{@repository_path}/#{dir}") full_path.start_with?(@repository_path) && File.exist?(full_path) ? full_path.gsub("#{@repository_path}/", '') : nil end. compact. sort. uniq end @cookbook_paths end |
#known_nodes ⇒ Object
Get the list of known nodes.
- API
-
This method is mandatory.
-
- Result
-
Array<String>: List of node names
80 81 82 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 80 def known_nodes Dir.glob("#{@repository_path}/nodes/*.json").map { |file| File.basename(file, '.json') } end |
#metadata_for(node) ⇒ Object
Get the metadata of a given node.
- API
-
This method is mandatory.
-
- Parameters
-
node (String): Node to read metadata from
- Result
-
Hash<Symbol,Object>: The corresponding metadata
91 92 93 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 91 def (node) (json_for(node)['normal'] || {}).transform_keys(&:to_sym) end |
#package(services:, secrets:, local_environment:) ⇒ Object
Package the repository, ready to be deployed on artefacts or directly to a node.
- API
-
This method is optional.
-
- API
-
@cmd_runner is accessible.
-
- API
-
@actions_executor is accessible.
-
- Parameters
-
services (Hash< String, Array<String> >): Services to be deployed, per node
-
secrets (Hash): Secrets to be used for deployment
-
local_environment (Boolean): Are we deploying to a local environment?
124 125 126 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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 124 def package(services:, secrets:, local_environment:) # Make a stamp of the info that has been packaged, so that we don't package it again if useless package_info = { secrets: secrets, commit: info[:commit].nil? ? Time.now.utc.strftime('%F %T') : info[:commit][:id], other_files: if info[:status].nil? {} else (info[:status][:added_files] + info[:status][:changed_files] + info[:status][:untracked_files]). sort. to_h { |f| [f, File.mtime("#{@repository_path}/#{f}").strftime('%F %T')] } end, deleted_files: info[:status].nil? ? [] : info[:status][:deleted_files].sort } # Each service is packaged individually. services.values.flatten.sort.uniq.each do |service| package_dir = "dist/#{local_environment ? 'local' : 'prod'}/#{service}" package_info_file = "#{@repository_path}/#{package_dir}/hpc_package.info" current_package_info = File.exist?(package_info_file) ? JSON.parse(File.read(package_info_file)).transform_keys(&:to_sym) : {} next if current_package_info == package_info policy_file = "policyfiles/#{service}.rb" if local_environment local_policy_file = "policyfiles/#{service}.local.rb" # In local mode, we always regenerate the lock file as we may modify the run list run_list = known_cookbook_paths.any? { |cookbook_path| File.exist?("#{@repository_path}/#{cookbook_path}/hpc_test/recipes/before_run.rb") } ? ['hpc_test::before_run'] : [] dsl_parser = DslParser.new dsl_parser.parse("#{@repository_path}/#{policy_file}") run_list.concat dsl_parser.calls.find { |call_info| call_info[:method] == :run_list }[:args].flatten run_list << 'hpc_test::after_run' if known_cookbook_paths.any? { |cookbook_path| File.exist?("#{@repository_path}/#{cookbook_path}/hpc_test/recipes/after_run.rb") } File.write("#{@repository_path}/#{local_policy_file}", File.read("#{@repository_path}/#{policy_file}") + "\nrun_list #{run_list.map { |recipe| "'#{recipe}'" }.join(', ')}\n") policy_file = local_policy_file end lock_file = "#{File.dirname(policy_file)}/#{File.basename(policy_file, '.rb')}.lock.json" # If the policy lock file does not exist, generate it @cmd_runner.run_cmd "cd #{@repository_path} && /opt/chef-workstation/bin/chef install #{policy_file} --chef-license accept" unless File.exist?("#{@repository_path}/#{lock_file}") extra_cp_data_bags = File.exist?("#{@repository_path}/data_bags") ? " && cp -ar data_bags/ #{package_dir}/" : '' @cmd_runner.run_cmd "cd #{@repository_path} && \ #{@cmd_runner.root? ? '' : 'sudo '}rm -rf #{package_dir} && \ /opt/chef-workstation/bin/chef export #{policy_file} #{package_dir} --chef-license accept#{extra_cp_data_bags}" next if @cmd_runner.dry_run # Write the list of gems to be installed for this package File.write( "#{@repository_path}/#{package_dir}/gems.json", Dir.glob("#{@repository_path}/#{package_dir}/cookbook_artifacts/*/metadata.json").map do || JSON.parse(File.read())['gems'] end.flatten(1).to_json ) # Create secrets file secrets_file = "#{@repository_path}/#{package_dir}/data_bags/hpc_secrets/hpc_secrets.json" FileUtils.mkdir_p(File.dirname(secrets_file)) File.write(secrets_file, secrets.merge(id: 'hpc_secrets').to_json) # Make the testadmin public key available for deployment for hpc_test cookbook testadmin_pub_key = "#{@config.hybrid_platforms_dir}/testadmin.key.pub" if local_environment && File.exist?(testadmin_pub_key) Dir.glob("#{@repository_path}/#{package_dir}/cookbook_artifacts/hpc_test-*") do |hpc_test_cookbook_path| hpc_test_files_dir = "#{hpc_test_cookbook_path}/files/default" FileUtils.mkdir_p hpc_test_files_dir FileUtils.cp(testadmin_pub_key, "#{hpc_test_files_dir}/testadmin.key.pub") end end # Remember the package info File.write(package_info_file, package_info.to_json) end end |
#parse_deploy_output(stdout, _stderr) ⇒ Object
Parse stdout and stderr of a given deploy run and get the list of tasks with their status
- API
-
This method is mandatory.
-
- Parameters
-
stdout (String): stdout to be parsed
-
stderr (String): stderr to be parsed
- Result
-
Array< Hash<Symbol,Object> >: List of task properties. The following properties should be returned, among free ones:
-
name (String): Task name
-
status (Symbol): Task status. Should be one of:
-
:changed: The task has been changed
-
:identical: The task has not been changed
-
-
diffs (String): Differences, if any
-
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 343 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 316 def parse_deploy_output(stdout, _stderr) tasks = [] current_task = nil stdout.split("\n").each do |line| # Remove control chars and spaces around case line.gsub(/\e\[[^\x40-\x7E]*[\x40-\x7E]/, '').strip when /^\* (\w+\[[^\]]+\]) action (.+)$/ # New task task_name = Regexp.last_match(1) task_action = Regexp.last_match(2) current_task = { name: task_name, action: task_action, status: :identical } tasks << current_task when /^- (.+)$/ # Diff on the current task diff_description = Regexp.last_match(1) unless current_task.nil? current_task[:diffs] = '' unless current_task.key?(:diffs) current_task[:diffs] << "#{diff_description}\n" current_task[:status] = :changed end end end tasks end |
#policy_run_list(policy) ⇒ Object
Get the run list of a given policy
- Parameters
-
policy (String): Policy to get the run list from
- Result
-
Array<[String or nil, Symbol, Symbol]>: Run list of the given policy, as [cookbook_dir, cookbook, recipe]
500 501 502 503 504 505 506 507 508 509 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 500 def policy_run_list(policy) # Read the policy file dsl_parser = DslParser.new policy_file = "#{@repository_path}/policyfiles/#{policy}.rb" dsl_parser.parse(policy_file) run_list_call = dsl_parser.calls.find { |call_info| call_info[:method] == :run_list } raise "Policy #{policy} has no run list defined in #{policy_file}" if run_list_call.nil? run_list_call[:args].map { |recipe_def| decode_recipe(recipe_def) } end |
#prepare_for_deploy(services:, secrets:, local_environment:, why_run:) ⇒ Object
rubocop:disable Lint/UnusedMethodArgument Prepare deployments. This method is called just before getting and executing the actions to be deployed. It is called once per platform.
- API
-
This method is optional.
-
- API
-
@cmd_runner is accessible.
-
- API
-
@actions_executor is accessible.
-
- Parameters
-
services (Hash< String, Array<String> >): Services to be deployed, per node
-
secrets (Hash): Secrets to be used for deployment
-
local_environment (Boolean): Are we deploying to a local environment?
-
why_run (Boolean): Are we deploying in why-run mode?
205 206 207 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 205 def prepare_for_deploy(services:, secrets:, local_environment:, why_run:) @local_env = local_environment end |
#services_for(node) ⇒ Object
Return the services for a given node
- API
-
This method is mandatory.
-
- Parameters
-
node (String): node to read configuration from
- Result
-
Array<String>: The corresponding services
102 103 104 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 102 def services_for(node) [json_for(node)['policy_name']] end |
#setup ⇒ Object
Setup the platform, install dependencies…
- API
-
This method is optional.
-
- API
-
@cmd_runner is accessible.
-
61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 61 def setup required_version = YAML.load_file("#{@repository_path}/chef_versions.yml")['workstation'] exit_status, stdout, _stderr = @cmd_runner.run_cmd '/opt/chef-workstation/bin/chef --version', expected_code: [0, :command_error] existing_version = if exit_status == :command_error 'not installed' else expected_match = stdout.match(/^Chef Workstation version: (.+)\.\d+$/) expected_match.nil? ? 'unreadable' : expected_match[1] end log_debug "Current Chef version: #{existing_version}. Required version: #{required_version}" @cmd_runner.run_cmd "curl -L https://omnitruck.chef.io/install.sh | #{@cmd_runner.root? ? '' : 'sudo '}bash -s -- -P chef-workstation -v #{required_version}" unless existing_version == required_version end |