Class: HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef

Inherits:
PlatformHandler show all
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

Methods inherited from PlatformHandler

#<=>, #info, inherited, #name

Methods inherited from Plugin

extend_config_dsl_with, 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

#initialize(platform_type, repository_path, logger: Logger.new(STDOUT), logger_stderr: Logger.new(STDERR), config: Config.new, cmd_runner: CmdRunner.new) ⇒ ServerlessChef

Constructor

Parameters
  • platform_type (Symbol): Platform type

  • repository_path (String): Repository path

  • logger (Logger): Logger to be used [default: Logger.new(STDOUT)]

  • logger_stderr (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]

  • config (Config): Config to be used. [default: Config.new]

  • cmd_runner (CmdRunner): Command executor to be used. [default: CmdRunner.new]



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 59

def initialize(
  platform_type,
  repository_path,
  logger: Logger.new(STDOUT),
  logger_stderr: Logger.new(STDERR),
  config: Config.new,
  cmd_runner: CmdRunner.new
)
  super
  # Mutex for getting the full recipes tree
  @recipes_tree_mutex = Mutex.new
end

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



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
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 224

def actions_to_deploy_on(node, service, use_why_run: true)
  package_dir = "#{@repository_path}/dist/#{@local_env ? 'local' : 'prod'}/#{service}"
  # 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)
  end
  client_options = [
    '--local-mode',
    '--chef-license', 'accept',
    '--json-attributes', "nodes/#{node}.json"
  ]
  client_options << '--why-run' if use_why_run
  if @nodes_handler.get_use_local_chef_of(node)
    # Just run the chef-client directly from the packaged repository
    [{ bash: "cd #{package_dir} && #{@cmd_runner.root? ? '' : 'sudo '}SSL_CERT_DIR=/etc/ssl/certs /opt/chef-workstation/bin/chef-client #{client_options.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.connector(:ssh).ssh_user == 'root' ? '' : "#{@nodes_handler.sudo_on(node)} ")
    [
      {
        # 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 ; else #{sudo}yum groupinstall 'Development Tools' && #{sudo}yum install -y curl ; 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: [
          'set -e',
          "cd ./hpc_deploy/#{package_name}",
          "#{sudo}SSL_CERT_DIR=/etc/ssl/certs /opt/chef/bin/chef-client #{client_options.join(' ')}",
          'cd ..'
        ] + (log_debug? ? [] : ["#{sudo}rm -rf ./hpc_deploy/#{package_name}"])
      }
    ]
  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



495
496
497
498
499
500
501
502
503
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 495

def decode_recipe(recipe_def)
  recipe_def = $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")
  return cookbook_dir, cookbook, recipe
end

#deployable_servicesObject

Get the list of services we can deploy

API
  • This method is mandatory.

Result
  • Array<String>: The corresponding services



127
128
129
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 127

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)?



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
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
423
424
425
426
427
428
429
430
431
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 328

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|
    if impacted_file =~ /^policyfiles\/([^\/]+)\.rb$/
      log_debug "[#{impacted_file}] - Impacted service: #{$1}"
      impacted_services << $1
    elsif impacted_file =~ /^policyfiles\/([^\/]+)\.lock.json$/
      log_debug "[#{impacted_file}] - Impacted service: #{$1}"
      impacted_services << $1
    elsif impacted_file =~ /^nodes\/([^\/]+)\.json/
      log_debug "[#{impacted_file}] - Impacted node: #{$1}"
      impacted_nodes << $1
    else
      cookbook_path = known_cookbook_paths.find { |cookbooks_path| impacted_file =~ /^#{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
        cookbook_name, file_path = impacted_file.match(/^#{cookbook_path}\/(\w+)\/(.+)$/)[1..2]
        cookbook = 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 /recipes\/(.+)\.rb/
          register.call('direct', $1)
        when /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 /(templates|files)\/(.+)/
          # Find recipes using this file name
          included_file = File.basename($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 /resources\/(.+)/
          # Find any recipe using this resource
          included_resource = "#{cookbook}_#{File.basename($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(/#{cookbooks_path}\/(\w+)\/recipes\/(\w+)\.rb/)[1..2]
                register.call("included resource #{included_resource}", recipe_name, cookbook_name: cookbook_name)
              end
            end
          end
        when /libraries\/(.+)/
          # Find any recipe using methods from this library
          lib_methods_regexps = File.read("#{@repository_path}/#{impacted_file}").scan(/(\W|^)def\s+(\w+)(\W|$)/).map { |_grp1, method_name, _grp2| /(\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(/#{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
        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

#known_cookbook_pathsObject

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



438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 438

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.expand_path("#{@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_nodesObject

Get the list of known nodes.

API
  • This method is mandatory.

Result
  • Array<String>: List of node names



96
97
98
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 96

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



107
108
109
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 107

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?



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
191
192
193
194
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 140

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
        Hash[
          (info[:status][:added_files] + info[:status][:changed_files] + info[:status][:untracked_files]).
            sort.
            map { |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) : {}
    unless current_package_info == package_info
      Bundler.with_unbundled_env do
        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}"
      end
      unless @cmd_runner.dry_run
        # 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)
        # Remember the package info
        File.write(package_info_file, package_info.to_json)
      end
    end
  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



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 288

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 = $1
      task_action = $2
      current_task = {
        name: task_name,
        action: task_action,
        status: :identical
      }
      tasks << current_task
    when /^- (.+)$/
      # Diff on the current task
      diff_description = $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]



472
473
474
475
476
477
478
479
480
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 472

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

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?



208
209
210
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 208

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



118
119
120
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 118

def services_for(node)
  [json_for(node)['policy_name']]
end

#setupObject

Setup the platform, install dependencies…

API
  • This method is optional.

API
  • @cmd_runner is accessible.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb', line 75

def setup
  required_version = YAML.load_file("#{@repository_path}/chef_versions.yml")['workstation']
  Bundler.with_unbundled_env do
    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
end