bolt 2.30.0 → 2.31.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bolt might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8ca2906e21e39d1da306c9a02ddb970f64955133fcab01574e4138c1e6e154e
4
- data.tar.gz: 4c875d82bf7ff9d4117440eca9e1276c1b9c2fa842fda4669227ebb0ec56f170
3
+ metadata.gz: 4b9f29b79c8544029c9a69f6dc76b083857a87e178c9aae0359e49c59ce3cfdb
4
+ data.tar.gz: 02166a6dda2dc381365b7556f506a419e2717267e88f6015af430f7f725d75d0
5
5
  SHA512:
6
- metadata.gz: bd8e4327ddfeb4d88fdd1f94ab4233bcf1f0d8ce1390769587197dec11bfa024a16889c5693ec4a4333565cd7553a8c13487b6674ba5427a63f9408961e6a3a7
7
- data.tar.gz: f2bcbe28ba4c26bc36d3c52ab89a8bafa6a132c930c310a92e48b841d0274389022f2480d3ed397bcc4bcf1f77fb272da82697362d33feccfe05ab0ca203cf6c
6
+ metadata.gz: 3a282194ca9ccf988e7282afc3a3a0b57b4edc16bb5bf61790fb0eb0ef234e0c7a76c0ea6cd44915047a99e6d423311be1307f435d8000c568d0552268f6afa6
7
+ data.tar.gz: 957e6be1a72af03bd448fe070e6f9bb0b78aa1bb65e90a8bda251ef0f6c56e5ffaa8ff64aa0c5852963d9fecb87144b61ffd24494fe0aabcbdff43ecde9947a3
data/Puppetfile CHANGED
@@ -7,28 +7,28 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
7
7
  # Core modules used by 'apply'
8
8
  mod 'puppetlabs-service', '1.3.0'
9
9
  mod 'puppetlabs-puppet_agent', '4.1.1'
10
- mod 'puppetlabs-facts', '1.0.0'
10
+ mod 'puppetlabs-facts', '1.1.0'
11
11
 
12
12
  # Core types and providers for Puppet 6
13
- mod 'puppetlabs-augeas_core', '1.0.5'
13
+ mod 'puppetlabs-augeas_core', '1.1.1'
14
14
  mod 'puppetlabs-host_core', '1.0.3'
15
- mod 'puppetlabs-scheduled_task', '2.0.1'
16
- mod 'puppetlabs-sshkeys_core', '1.0.3'
17
- mod 'puppetlabs-zfs_core', '1.0.4'
18
- mod 'puppetlabs-cron_core', '1.0.3'
15
+ mod 'puppetlabs-scheduled_task', '2.2.1'
16
+ mod 'puppetlabs-sshkeys_core', '2.1.0'
17
+ mod 'puppetlabs-zfs_core', '1.1.0'
18
+ mod 'puppetlabs-cron_core', '1.0.4'
19
19
  mod 'puppetlabs-mount_core', '1.0.4'
20
20
  mod 'puppetlabs-selinux_core', '1.0.4'
21
- mod 'puppetlabs-yumrepo_core', '1.0.6'
21
+ mod 'puppetlabs-yumrepo_core', '1.0.7'
22
22
  mod 'puppetlabs-zone_core', '1.0.3'
23
23
 
24
24
  # Useful additional modules
25
- mod 'puppetlabs-package', '1.1.0'
25
+ mod 'puppetlabs-package', '1.3.0'
26
26
  mod 'puppetlabs-puppet_conf', '0.6.0'
27
27
  mod 'puppetlabs-python_task_helper', '0.4.3'
28
28
  mod 'puppetlabs-reboot', '3.0.0'
29
29
  mod 'puppetlabs-ruby_task_helper', '0.5.1'
30
30
  mod 'puppetlabs-ruby_plugin_helper', '0.1.0'
31
- mod 'puppetlabs-stdlib', '6.3.0'
31
+ mod 'puppetlabs-stdlib', '6.5.0'
32
32
 
33
33
  # Plugin modules
34
34
  mod 'puppetlabs-aws_inventory', '0.5.2'
@@ -6,15 +6,15 @@ require 'tempfile'
6
6
  #
7
7
  # > **Note:** Not available in apply block
8
8
  Puppet::Functions.create_function(:write_file) do
9
- # @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
10
9
  # @param content File content to write.
11
10
  # @param destination An absolute path on the target(s).
11
+ # @param targets A pattern identifying zero or more targets. See {get_targets} for accepted patterns.
12
12
  # @option options [Boolean] _catch_errors Whether to catch raised errors.
13
13
  # @option options [String] _run_as User to run as using privilege escalation.
14
14
  # @return A list of results, one entry per target.
15
15
  # @example Write a file to a target
16
16
  # $content = 'Hello, world!'
17
- # write_file($targets, $content, '/Users/me/hello.txt')
17
+ # write_file($content, '/Users/me/hello.txt', $targets)
18
18
  dispatch :write_file do
19
19
  required_param 'String', :content
20
20
  required_param 'String[1]', :destination
@@ -587,8 +587,24 @@ module Bolt
587
587
  end
588
588
 
589
589
  def list_targets
590
+ inventoryfile = config.inventoryfile || config.default_inventoryfile
591
+
592
+ # Retrieve the known group and target names. This needs to be done before
593
+ # updating targets, as that will add adhoc targets to the inventory.
594
+ known_names = inventory.target_names
595
+
590
596
  update_targets(options)
591
- outputter.print_targets(options[:targets])
597
+
598
+ inventory_targets, adhoc_targets = options[:targets].partition do |target|
599
+ known_names.include?(target.name)
600
+ end
601
+
602
+ target_list = {
603
+ inventory: inventory_targets,
604
+ adhoc: adhoc_targets
605
+ }
606
+
607
+ outputter.print_targets(target_list, inventoryfile)
592
608
  end
593
609
 
594
610
  def show_targets
@@ -617,10 +633,10 @@ module Bolt
617
633
  message = <<~MESSAGE.chomp
618
634
  Invalid plan name '#{plan_name}'. Plan names are composed of one or more name segments
619
635
  separated by double colons '::'.
620
-
636
+
621
637
  Each name segment must begin with a lowercase letter, and may only include lowercase
622
638
  letters, digits, and underscores.
623
-
639
+
624
640
  Examples of valid plan names:
625
641
  - #{config.project.name}
626
642
  - #{config.project.name}::my_plan
@@ -938,6 +954,7 @@ module Bolt
938
954
  # Loads a Puppetfile and installs its modules.
939
955
  #
940
956
  def install_puppetfile(config, puppetfile, moduledir)
957
+ outputter.print_message("Installing modules from Puppetfile")
941
958
  installer = Bolt::ModuleInstaller.new(outputter, pal)
942
959
  ok = installer.install_puppetfile(puppetfile, moduledir, config)
943
960
  ok ? 0 : 1
@@ -962,7 +979,7 @@ module Bolt
962
979
  end
963
980
 
964
981
  def pal
965
- @pal ||= Bolt::PAL.new(config.modulepath,
982
+ @pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
966
983
  config.hiera_config,
967
984
  config.project.resource_types,
968
985
  config.compile_concurrency,
@@ -1061,7 +1078,7 @@ module Bolt
1061
1078
  'Task' => [],
1062
1079
  'Plugin' => Bolt::Plugin::BUILTIN_PLUGINS }
1063
1080
  if %w[plan task].include?(options[:subcommand]) && options[:action] == 'run'
1064
- default_content = Bolt::PAL.new([], nil, nil)
1081
+ default_content = Bolt::PAL.new(Bolt::Config::Modulepath.new([]), nil, nil)
1065
1082
  content['Plan'] = default_content.list_plans.each_with_object([]) do |iter, col|
1066
1083
  col << iter&.first
1067
1084
  end
@@ -1076,7 +1093,7 @@ module Bolt
1076
1093
  # Gem installs include the aggregate, canary, and puppetdb_fact modules, while
1077
1094
  # package installs include modules listed in the Bolt repo Puppetfile
1078
1095
  def incomplete_install?
1079
- (Dir.children(Bolt::PAL::MODULES_PATH) - %w[aggregate canary puppetdb_fact secure_env_vars]).empty?
1096
+ (Dir.children(Bolt::Config::Modulepath::MODULES_PATH) - %w[aggregate canary puppetdb_fact secure_env_vars]).empty?
1080
1097
  end
1081
1098
 
1082
1099
  # Mimicks the output from Outputter::Human#fatal_error. This should be used to print
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bolt/config'
4
+
5
+ module Bolt
6
+ class Config
7
+ class Modulepath
8
+ BOLTLIB_PATH = File.expand_path('../../../bolt-modules', __dir__)
9
+ MODULES_PATH = File.expand_path('../../../modules', __dir__)
10
+
11
+ # The user_modulepath only includes the original modulepath and is used during pluginsync.
12
+ # We don't want to pluginsync any of the content from BOLT_MODULES since that content
13
+ # includes core modules that can conflict with modules installed with an agent.
14
+ attr_reader :user_modulepath
15
+
16
+ def initialize(user_modulepath, boltlib_path: BOLTLIB_PATH, builtin_content_path: MODULES_PATH)
17
+ @user_modulepath = Array(user_modulepath).flatten
18
+ @boltlib_path = Array(boltlib_path).flatten
19
+ @builtin_content_path = Array(builtin_content_path).flatten
20
+ end
21
+
22
+ # The full_modulepath includes both the BOLTLIB
23
+ # path and the MODULES_PATH to ensure bolt functions and
24
+ # built-in content are available in the compliler
25
+ def full_modulepath
26
+ @boltlib_path + @user_modulepath + @builtin_content_path
27
+ end
28
+ end
29
+ end
30
+ end
@@ -374,7 +374,7 @@ module Bolt
374
374
  },
375
375
  "ssh-command" => {
376
376
  type: [Array, String],
377
- description: "The command and flags to use when SSHing. This option is used when you need support for "\
377
+ description: "The command and options to use when SSHing. This option is used when you need support for "\
378
378
  "features or algorithms that are not supported by the net-ssh Ruby library. **This option "\
379
379
  "is experimental.** You can read more about this option in [Native SSH "\
380
380
  "transport](experimental_features.md#native-ssh-transport).",
@@ -56,16 +56,17 @@ module Bolt
56
56
  rescue Psych::Exception
57
57
  raise Bolt::ParseError, "Could not parse inventory from $#{ENVIRONMENT_VAR}"
58
58
  end
59
+ elsif config.inventoryfile
60
+ data = Bolt::Util.read_yaml_hash(config.inventoryfile, 'inventory')
61
+ logger.debug("Loaded inventory from #{config.inventoryfile}")
59
62
  else
60
- data = if config.inventoryfile
61
- Bolt::Util.read_yaml_hash(config.inventoryfile, 'inventory')
62
- else
63
- i = Bolt::Util.read_optional_yaml_hash(config.default_inventoryfile, 'inventory')
64
- logger.debug("Loaded inventory from #{config.default_inventoryfile}") if i
65
- i
66
- end
67
- # This avoids rubocop complaining about identical conditionals
68
- logger.debug("Loaded inventory from #{config.inventoryfile}") if config.inventoryfile
63
+ data = Bolt::Util.read_optional_yaml_hash(config.default_inventoryfile, 'inventory')
64
+
65
+ if config.default_inventoryfile.exist?
66
+ logger.debug("Loaded inventory from #{config.default_inventoryfile}")
67
+ else
68
+ logger.debug("Tried to load inventory from #{config.default_inventoryfile}, but the file does not exist")
69
+ end
69
70
  end
70
71
 
71
72
  # Resolve plugin references from transport config
@@ -16,20 +16,26 @@ module Bolt
16
16
  def add(name, modules, puppetfile_path, moduledir, config_path)
17
17
  require 'bolt/puppetfile'
18
18
 
19
+ @outputter.print_message("Adding module #{name} to project\n\n")
20
+
19
21
  # If the project configuration file already includes this module,
20
22
  # exit early.
21
23
  puppetfile = Bolt::Puppetfile.new(modules)
22
24
  new_module = Bolt::Puppetfile::Module.from_hash('name' => name)
23
25
 
24
26
  if puppetfile.modules.include?(new_module)
25
- @outputter.print_message "Project configuration file #{config_path} already "\
26
- "includes module #{new_module}. Nothing to do."
27
+ @outputter.print_action_step(
28
+ "Project configuration file #{config_path} already includes module #{new_module}. Nothing to do."
29
+ )
27
30
  return true
28
31
  end
29
32
 
30
33
  # If the Puppetfile exists, make sure it's managed by Bolt.
31
34
  if puppetfile_path.exist?
32
35
  assert_managed_puppetfile(puppetfile, puppetfile_path)
36
+ existing = Bolt::Puppetfile.parse(puppetfile_path)
37
+ else
38
+ existing = Bolt::Puppetfile.new
33
39
  end
34
40
 
35
41
  # Create a Puppetfile object that includes the new module and its
@@ -37,8 +43,11 @@ module Bolt
37
43
  # project config or modify the Puppetfile.
38
44
  puppetfile = add_new_module_to_puppetfile(new_module, modules, puppetfile_path)
39
45
 
46
+ # Display the diff between the existing Puppetfile and the new Puppetfile.
47
+ print_puppetfile_diff(existing, puppetfile)
48
+
40
49
  # Add the module to the project configuration.
41
- @outputter.print_message "Updating project configuration file at #{config_path}"
50
+ @outputter.print_action_step("Updating project configuration file at #{config_path}")
42
51
 
43
52
  data = Bolt::Util.read_yaml_hash(config_path, 'project')
44
53
  data['modules'] ||= []
@@ -54,7 +63,7 @@ module Bolt
54
63
  end
55
64
 
56
65
  # Write the Puppetfile.
57
- @outputter.print_message "Writing Puppetfile at #{puppetfile_path}"
66
+ @outputter.print_action_step("Writing Puppetfile at #{puppetfile_path}")
58
67
  puppetfile.write(puppetfile_path, moduledir)
59
68
 
60
69
  # Install the modules.
@@ -64,7 +73,7 @@ module Bolt
64
73
  # Creates a new Puppetfile that includes the new module and its dependencies.
65
74
  #
66
75
  private def add_new_module_to_puppetfile(new_module, modules, path)
67
- @outputter.print_message "Resolving module dependencies, this may take a moment"
76
+ @outputter.print_action_step("Resolving module dependencies, this may take a moment")
68
77
 
69
78
  # If there is an existing Puppetfile, add the new module and attempt
70
79
  # to resolve. This will not update the versions of any installed modules.
@@ -92,11 +101,72 @@ module Bolt
92
101
  puppetfile
93
102
  end
94
103
 
104
+ # Outputs a diff of an old Puppetfile and a new Puppetfile.
105
+ #
106
+ def print_puppetfile_diff(old, new)
107
+ # Build hashes mapping the module title to the module object. This makes it
108
+ # a little easier to determine which modules have been added, removed, or
109
+ # modified.
110
+ old = old.modules.each_with_object({}) do |mod, acc|
111
+ acc[mod.title] = mod
112
+ end
113
+
114
+ new = new.modules.each_with_object({}) do |mod, acc|
115
+ acc[mod.title] = mod
116
+ end
117
+
118
+ # New modules are those present in new but not in old.
119
+ added = new.reject { |title, _mod| old.include?(title) }.values
120
+
121
+ if added.any?
122
+ diff = "Adding the following modules:\n"
123
+ added.each { |mod| diff += "#{mod.title} #{mod.version}\n" }
124
+ @outputter.print_action_step(diff)
125
+ end
126
+
127
+ # Upgraded modules are those that have a newer version in new than old.
128
+ upgraded = new.select do |title, mod|
129
+ if old.include?(title)
130
+ SemanticPuppet::Version.parse(mod.version) > SemanticPuppet::Version.parse(old[title].version)
131
+ end
132
+ end.keys
133
+
134
+ if upgraded.any?
135
+ diff = "Upgrading the following modules:\n"
136
+ upgraded.each { |title| diff += "#{title} #{old[title].version} to #{new[title].version}\n" }
137
+ @outputter.print_action_step(diff)
138
+ end
139
+
140
+ # Downgraded modules are those that have an older version in new than old.
141
+ downgraded = new.select do |title, mod|
142
+ if old.include?(title)
143
+ SemanticPuppet::Version.parse(mod.version) < SemanticPuppet::Version.parse(old[title].version)
144
+ end
145
+ end.keys
146
+
147
+ if downgraded.any?
148
+ diff = "Downgrading the following modules: \n"
149
+ downgraded.each { |title| diff += "#{title} #{old[title].version} to #{new[title].version}\n" }
150
+ @outputter.print_action_step(diff)
151
+ end
152
+
153
+ # Removed modules are those present in old but not in new.
154
+ removed = old.reject { |title, _mod| new.include?(title) }.values
155
+
156
+ if removed.any?
157
+ diff = "Removing the following modules:\n"
158
+ removed.each { |mod| diff += "#{mod.title} #{mod.version}\n" }
159
+ @outputter.print_action_step(diff)
160
+ end
161
+ end
162
+
95
163
  # Installs a project's module dependencies.
96
164
  #
97
165
  def install(modules, path, moduledir, force: false, resolve: true)
98
166
  require 'bolt/puppetfile'
99
167
 
168
+ @outputter.print_message("Installing project modules\n\n")
169
+
100
170
  puppetfile = Bolt::Puppetfile.new(modules)
101
171
 
102
172
  # If the Puppetfile exists, check if it includes specs for each declared
@@ -110,16 +180,16 @@ module Bolt
110
180
  if path.exist? && !force
111
181
  assert_managed_puppetfile(puppetfile, path)
112
182
  else
113
- @outputter.print_message "Resolving module dependencies, this may take a moment"
183
+ @outputter.print_action_step("Resolving module dependencies, this may take a moment")
114
184
  puppetfile.resolve
115
185
 
116
- @outputter.print_message "Writing Puppetfile at #{path}"
186
+ @outputter.print_action_step("Writing Puppetfile at #{path}")
117
187
  # We get here either through 'bolt module install' which uses the
118
188
  # managed modulepath (which isn't configurable) or through bolt
119
189
  # project init --modules, which uses the default modulepath. This
120
190
  # should be safe to assume that if `.modules/` is the moduledir the
121
191
  # user is using the new workflow
122
- if moduledir.basename == '.modules'
192
+ if moduledir.basename.to_s == '.modules'
123
193
  puppetfile.write(path, moduledir)
124
194
  else
125
195
  puppetfile.write(path)
@@ -136,7 +206,7 @@ module Bolt
136
206
  def install_puppetfile(path, moduledir, config = {})
137
207
  require 'bolt/puppetfile/installer'
138
208
 
139
- @outputter.print_message "Syncing modules from #{path} to #{moduledir}"
209
+ @outputter.print_action_step("Syncing modules from #{path} to #{moduledir}")
140
210
  ok = Bolt::Puppetfile::Installer.new(config).install(path, moduledir)
141
211
 
142
212
  # Automatically generate types after installing modules
@@ -248,7 +248,7 @@ module Bolt
248
248
  task_info << "MODULE:\n"
249
249
 
250
250
  path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
251
- task_info << if path.start_with?(Bolt::PAL::MODULES_PATH)
251
+ task_info << if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
252
252
  "built-in module"
253
253
  else
254
254
  path
@@ -278,7 +278,7 @@ module Bolt
278
278
  plan_info << "MODULE:\n"
279
279
 
280
280
  path = plan['module']
281
- plan_info << if path.start_with?(Bolt::PAL::MODULES_PATH)
281
+ plan_info << if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
282
282
  "built-in module"
283
283
  else
284
284
  path
@@ -331,10 +331,28 @@ module Bolt
331
331
  end
332
332
  end
333
333
 
334
- def print_targets(targets)
335
- count = "#{targets.count} target#{'s' unless targets.count == 1}"
336
- @stream.puts targets.map(&:name).join("\n")
337
- @stream.puts colorize(:green, count)
334
+ def print_targets(target_list, inventoryfile)
335
+ adhoc = colorize(:yellow, "(Not found in inventory file)")
336
+
337
+ targets = []
338
+ targets += target_list[:inventory].map { |target| [target.name, nil] }
339
+ targets += target_list[:adhoc].map { |target| [target.name, adhoc] }
340
+
341
+ if targets.any?
342
+ print_table(targets, 0, 2)
343
+ @stream.puts
344
+ end
345
+
346
+ @stream.puts "INVENTORY FILE:"
347
+ if inventoryfile.exist?
348
+ @stream.puts inventoryfile
349
+ else
350
+ @stream.puts wrap("Tried to load inventory from #{inventoryfile}, but the file does not exist")
351
+ end
352
+
353
+ @stream.puts "\nTARGET COUNT:"
354
+ @stream.puts "#{targets.count} total, #{target_list[:inventory].count} from inventory, "\
355
+ "#{target_list[:adhoc].count} adhoc"
338
356
  end
339
357
 
340
358
  def print_target_info(targets)
@@ -413,7 +431,7 @@ module Bolt
413
431
  @stream.puts(colorize(:red, indent(4, message)))
414
432
  end
415
433
 
416
- def print_migrate_step(step)
434
+ def print_action_step(step)
417
435
  first, *remaining = wrap(step, 76).lines
418
436
 
419
437
  first = indent(2, "→ #{first}")
@@ -423,7 +441,7 @@ module Bolt
423
441
  @stream.puts(step)
424
442
  end
425
443
 
426
- def print_migrate_error(error)
444
+ def print_action_error(error)
427
445
  # Running everything through 'wrap' messes with newlines. Separating
428
446
  # into lines and wrapping each individually ensures separate errors are
429
447
  # distinguishable.
@@ -48,7 +48,7 @@ module Bolt
48
48
 
49
49
  def print_task_info(task)
50
50
  path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
51
- module_dir = if path.start_with?(Bolt::PAL::MODULES_PATH)
51
+ module_dir = if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
52
52
  "built-in module"
53
53
  else
54
54
  path
@@ -62,7 +62,7 @@ module Bolt
62
62
 
63
63
  def print_plan_info(plan)
64
64
  path = plan.delete('module')
65
- plan['module_dir'] = if path.start_with?(Bolt::PAL::MODULES_PATH)
65
+ plan['module_dir'] = if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH)
66
66
  "built-in module"
67
67
  else
68
68
  path
@@ -100,10 +100,19 @@ module Bolt
100
100
  "moduledir": moduledir.to_s }.to_json)
101
101
  end
102
102
 
103
- def print_targets(targets)
103
+ def print_targets(target_list, inventoryfile)
104
104
  @stream.puts ::JSON.pretty_generate(
105
- "targets": targets.map(&:name),
106
- "count": targets.count
105
+ "inventory": {
106
+ "targets": target_list[:inventory].map(&:name),
107
+ "count": target_list[:inventory].count,
108
+ "file": inventoryfile.to_s
109
+ },
110
+ "adhoc": {
111
+ "targets": target_list[:adhoc].map(&:name),
112
+ "count": target_list[:adhoc].count
113
+ },
114
+ "targets": target_list.values.flatten.map(&:name),
115
+ "count": target_list.values.flatten.count
107
116
  )
108
117
  end
109
118
 
@@ -137,10 +146,10 @@ module Bolt
137
146
  end
138
147
  alias print_error print_message
139
148
 
140
- def print_migrate_step(step)
149
+ def print_action_step(step)
141
150
  $stderr.puts(step)
142
151
  end
143
- alias print_migrate_error print_migrate_step
152
+ alias print_action_error print_action_step
144
153
  end
145
154
  end
146
155
  end
@@ -5,18 +5,16 @@ require 'bolt/executor'
5
5
  require 'bolt/error'
6
6
  require 'bolt/plan_result'
7
7
  require 'bolt/util'
8
+ require 'bolt/config/modulepath'
8
9
  require 'etc'
9
10
 
10
11
  module Bolt
11
12
  class PAL
12
- BOLTLIB_PATH = File.expand_path('../../bolt-modules', __dir__)
13
- MODULES_PATH = File.expand_path('../../modules', __dir__)
14
-
15
13
  # PALError is used to convert errors from executing puppet code into
16
14
  # Bolt::Errors
17
15
  class PALError < Bolt::Error
18
16
  def self.from_preformatted_error(err)
19
- if err.cause&.is_a? Bolt::Error
17
+ if err.cause.is_a? Bolt::Error
20
18
  err.cause
21
19
  else
22
20
  from_error(err)
@@ -45,16 +43,16 @@ module Bolt
45
43
  end
46
44
  end
47
45
 
48
- attr_reader :modulepath, :user_modulepath
49
-
50
46
  def initialize(modulepath, hiera_config, resource_types, max_compiles = Etc.nprocessors,
51
47
  trusted_external = nil, apply_settings = {}, project = nil)
48
+ unless modulepath.is_a?(Bolt::Config::Modulepath)
49
+ msg = "Type error in PAL: modulepath must be a Bolt::Config::Modulepath"
50
+ raise Bolt::Error.new(msg, "bolt/execution-error")
51
+ end
52
52
  # Nothing works without initialized this global state. Reinitializing
53
53
  # is safe and in practice only happens in tests
54
54
  self.class.load_puppet
55
-
56
- @user_modulepath = modulepath
57
- @modulepath = [BOLTLIB_PATH, *modulepath, MODULES_PATH]
55
+ @modulepath = modulepath
58
56
  @hiera_config = hiera_config
59
57
  @trusted_external = trusted_external
60
58
  @apply_settings = apply_settings
@@ -63,13 +61,21 @@ module Bolt
63
61
  @project = project
64
62
 
65
63
  @logger = Bolt::Logger.logger(self)
66
- if modulepath && !modulepath.empty?
67
- @logger.debug("Loading modules from #{@modulepath.join(File::PATH_SEPARATOR)}")
64
+ unless user_modulepath.empty?
65
+ @logger.debug("Loading modules from #{full_modulepath.join(File::PATH_SEPARATOR)}")
68
66
  end
69
67
 
70
68
  @loaded = false
71
69
  end
72
70
 
71
+ def full_modulepath
72
+ @modulepath.full_modulepath
73
+ end
74
+
75
+ def user_modulepath
76
+ @modulepath.user_modulepath
77
+ end
78
+
73
79
  # Puppet logging is global so this is class method to avoid confusion
74
80
  def self.configure_logging
75
81
  Puppet::Util::Log.destinations.clear
@@ -157,7 +163,7 @@ module Bolt
157
163
  def in_bolt_compiler
158
164
  # TODO: If we always call this inside a bolt_executor we can remove this here
159
165
  setup
160
- r = Puppet::Pal.in_tmp_environment('bolt', modulepath: @modulepath, facts: {}) do |pal|
166
+ r = Puppet::Pal.in_tmp_environment('bolt', modulepath: full_modulepath, facts: {}) do |pal|
161
167
  # Only load the project if it a) exists, b) has a name it can be loaded with
162
168
  Puppet.override(bolt_project: @project,
163
169
  yaml_plan_instantiator: Bolt::PAL::YamlPlan::Loader) do
@@ -212,11 +218,11 @@ module Bolt
212
218
  apply_executor: applicator || Applicator.new(
213
219
  inventory,
214
220
  executor,
215
- @modulepath,
221
+ full_modulepath,
216
222
  # Skip syncing built-in plugins, since we vendor some Puppet 6
217
223
  # versions of "core" types, which are already present on the agent,
218
224
  # but may cause issues on Puppet 5 agents.
219
- @user_modulepath,
225
+ user_modulepath,
220
226
  @project,
221
227
  pdb_client,
222
228
  @hiera_config,
@@ -443,8 +449,8 @@ module Bolt
443
449
  # The information hash provides the name, version, and a string
444
450
  # indicating whether the module belongs to an internal module group.
445
451
  def list_modules
446
- internal_module_groups = { BOLTLIB_PATH => 'Plan Language Modules',
447
- MODULES_PATH => 'Packaged Modules',
452
+ internal_module_groups = { Bolt::Config::Modulepath::BOLTLIB_PATH => 'Plan Language Modules',
453
+ Bolt::Config::Modulepath::MODULES_PATH => 'Packaged Modules',
448
454
  @project.managed_moduledir.to_s => 'Project Dependencies' }
449
455
 
450
456
  in_bolt_compiler do
@@ -168,7 +168,7 @@ module Bolt
168
168
  end
169
169
 
170
170
  def modules
171
- @modules ||= Bolt::Module.discover(@pal.modulepath)
171
+ @modules ||= Bolt::Module.discover(@pal.full_modulepath)
172
172
  end
173
173
 
174
174
  def add_plugin(plugin)
@@ -190,7 +190,7 @@ module Bolt
190
190
  Invalid project name '#{name}' in bolt-project.yaml; project name must begin with a lowercase letter
191
191
  and can include lowercase letters, numbers, and underscores.
192
192
  ERROR_STRING
193
- elsif Dir.children(Bolt::PAL::BOLTLIB_PATH).include?(name)
193
+ elsif Dir.children(Bolt::Config::Modulepath::BOLTLIB_PATH).include?(name)
194
194
  raise Bolt::ValidationError, "The project '#{name}' will not be loaded. The project name conflicts "\
195
195
  "with a built-in Bolt module of the same name."
196
196
  end
@@ -21,7 +21,7 @@ module Bolt
21
21
 
22
22
  @outputter.print_message("Migrating project #{@config.project.path}\n\n")
23
23
 
24
- @outputter.print_migrate_step(
24
+ @outputter.print_action_step(
25
25
  "Migrating a Bolt project may make irreversible changes to the project's "\
26
26
  "configuration and inventory files. Before continuing, make sure the "\
27
27
  "project has a backup or uses a version control system."
@@ -12,7 +12,7 @@ module Bolt
12
12
 
13
13
  protected def backup_file(origin_path, backup_dir)
14
14
  unless File.exist?(origin_path)
15
- @outputter.print_migrate_step(
15
+ @outputter.print_action_step(
16
16
  "Could not find file #{origin_path}, skipping backup."
17
17
  )
18
18
  return
@@ -24,7 +24,7 @@ module Bolt
24
24
  filename = File.basename(origin_path)
25
25
  backup_path = File.join(backup_dir, "#{filename}.#{date}.bak")
26
26
 
27
- @outputter.print_migrate_step(
27
+ @outputter.print_action_step(
28
28
  "Backing up #{filename} from #{origin_path} to #{backup_path}"
29
29
  )
30
30
 
@@ -39,7 +39,7 @@ module Bolt
39
39
  backup_file(config_file, backup_dir)
40
40
 
41
41
  begin
42
- @outputter.print_migrate_step(
42
+ @outputter.print_action_step(
43
43
  "Moving transportation configuration options '#{transport_data.keys.join(', ')}' "\
44
44
  "from bolt.yaml to inventory.yaml"
45
45
  )
@@ -51,10 +51,10 @@ module Bolt
51
51
  end
52
52
  end
53
53
 
54
- @outputter.print_migrate_step("Renaming bolt.yaml to bolt-project.yaml")
54
+ @outputter.print_action_step("Renaming bolt.yaml to bolt-project.yaml")
55
55
  FileUtils.mv(config_file, project_file)
56
56
 
57
- @outputter.print_migrate_step(
57
+ @outputter.print_action_step(
58
58
  "Successfully migrated config. Please add a 'name' key to bolt-project.yaml "\
59
59
  "to use project-level tasks and plans. Learn more about projects by running "\
60
60
  "'bolt guide project'."
@@ -28,7 +28,7 @@ module Bolt
28
28
 
29
29
  begin
30
30
  File.write(inventory_file, data.to_yaml)
31
- @outputter.print_migrate_step(
31
+ @outputter.print_action_step(
32
32
  "Successfully migrated Bolt inventory to the latest version."
33
33
  )
34
34
  true
@@ -19,7 +19,7 @@ module Bolt
19
19
 
20
20
  # Notify user to manually migrate modules if using non-default modulepath
21
21
  if configured_modulepath != modulepath
22
- @outputter.print_migrate_step(
22
+ @outputter.print_action_step(
23
23
  "Project has a non-default configured modulepath, unable to automatically "\
24
24
  "migrate project modules. To migrate project modules manually, see "\
25
25
  "http://pup.pt/bolt-modules"
@@ -46,10 +46,10 @@ module Bolt
46
46
  require 'bolt/puppetfile/installer'
47
47
 
48
48
  begin
49
- @outputter.print_migrate_step("Parsing Puppetfile at #{puppetfile_path}")
49
+ @outputter.print_action_step("Parsing Puppetfile at #{puppetfile_path}")
50
50
  puppetfile = Bolt::Puppetfile.parse(puppetfile_path, skip_unsupported_modules: true)
51
51
  rescue Bolt::Error => e
52
- @outputter.print_migrate_error("#{e.message}\nSkipping module migration.")
52
+ @outputter.print_action_error("#{e.message}\nSkipping module migration.")
53
53
  return false
54
54
  end
55
55
 
@@ -62,10 +62,10 @@ module Bolt
62
62
  # Attempt to resolve dependencies
63
63
  begin
64
64
  @outputter.print_message('')
65
- @outputter.print_migrate_step("Resolving module dependencies, this may take a moment")
65
+ @outputter.print_action_step("Resolving module dependencies, this may take a moment")
66
66
  puppetfile.resolve
67
67
  rescue Bolt::Error => e
68
- @outputter.print_migrate_error("#{e.message}\nSkipping module migration.")
68
+ @outputter.print_action_error("#{e.message}\nSkipping module migration.")
69
69
  return false
70
70
  end
71
71
 
@@ -90,17 +90,17 @@ module Bolt
90
90
  # Show the new Puppetfile content
91
91
  message = "Generated new Puppetfile content:\n\n"
92
92
  message += puppetfile.modules.map(&:to_spec).join("\n").to_s
93
- @outputter.print_migrate_step(message)
93
+ @outputter.print_action_step(message)
94
94
 
95
95
  # Write Puppetfile
96
- @outputter.print_migrate_step("Updating Puppetfile at #{puppetfile_path}")
96
+ @outputter.print_action_step("Updating Puppetfile at #{puppetfile_path}")
97
97
  puppetfile.write(puppetfile_path, managed_moduledir)
98
98
 
99
99
  # Install Puppetfile
100
- @outputter.print_migrate_step("Syncing modules from #{puppetfile_path} to #{managed_moduledir}")
100
+ @outputter.print_action_step("Syncing modules from #{puppetfile_path} to #{managed_moduledir}")
101
101
  Bolt::Puppetfile::Installer.new({}).install(puppetfile_path, managed_moduledir)
102
102
  else
103
- @outputter.print_migrate_step(
103
+ @outputter.print_action_step(
104
104
  "Project does not include any managed modules, deleting Puppetfile "\
105
105
  "at #{puppetfile_path}"
106
106
  )
@@ -112,7 +112,7 @@ module Bolt
112
112
  # the selected modules.
113
113
  #
114
114
  private def select_modules(modules)
115
- @outputter.print_migrate_step(
115
+ @outputter.print_action_step(
116
116
  "Select modules that are direct dependencies of your project. Bolt will "\
117
117
  "automatically manage dependencies for each module selected, so do not "\
118
118
  "select a module's dependencies unless you use content from it directly "\
@@ -135,7 +135,7 @@ module Bolt
135
135
  sources.select! { |source| Dir.exist?(source) }
136
136
 
137
137
  if sources.any?
138
- @outputter.print_migrate_step(
138
+ @outputter.print_action_step(
139
139
  "Moving modules from #{sources.join(', ')} to #{moduledir}"
140
140
  )
141
141
 
@@ -166,7 +166,7 @@ module Bolt
166
166
  # Deletes modules from a specified directory.
167
167
  #
168
168
  private def delete_modules(moduledir, modules)
169
- @outputter.print_migrate_step("Cleaning up #{moduledir}")
169
+ @outputter.print_action_step("Cleaning up #{moduledir}")
170
170
  moduledir = Pathname.new(moduledir)
171
171
 
172
172
  modules.each do |mod|
@@ -178,7 +178,7 @@ module Bolt
178
178
  # Adds a list of modules to the project configuration file.
179
179
  #
180
180
  private def update_project_config(modules, config_file)
181
- @outputter.print_migrate_step("Updating project configuration at #{config_file}")
181
+ @outputter.print_action_step("Updating project configuration at #{config_file}")
182
182
  data = Bolt::Util.read_optional_yaml_hash(config_file, 'project')
183
183
  data.merge!('modules' => modules)
184
184
  data.delete('modulepath')
@@ -61,8 +61,15 @@ module Bolt
61
61
  #
62
62
  def write(path, moduledir = nil)
63
63
  File.open(path, 'w') do |file|
64
- file.puts '# This Puppetfile is managed by Bolt. Do not edit.'
65
- file.puts "moduledir '#{moduledir.basename}'" if moduledir
64
+ if moduledir
65
+ file.puts "# This Puppetfile is managed by Bolt. Do not edit."
66
+ file.puts "# For more information, see https://pup.pt/bolt-modules"
67
+ file.puts
68
+ file.puts "# The following directive installs modules to the managed moduledir."
69
+ file.puts "moduledir '#{moduledir.basename}'"
70
+ file.puts
71
+ end
72
+
66
73
  modules.each { |mod| file.puts mod.to_spec }
67
74
  end
68
75
  rescue SystemCallError => e
@@ -13,7 +13,10 @@ module Bolt
13
13
  def initialize(owner, name, version = nil)
14
14
  @owner = owner
15
15
  @name = name
16
- @version = version unless version == :latest
16
+
17
+ if version.is_a?(String)
18
+ @version = version[0] == '=' ? version[1..-1] : version
19
+ end
17
20
  end
18
21
 
19
22
  # Creates a new module from a hash.
@@ -202,13 +202,14 @@ module Bolt
202
202
  end
203
203
 
204
204
  def handle_sudo_errors(err)
205
- if err =~ /^#{conn.user} is not in the sudoers file\./
205
+ case err
206
+ when /^#{conn.user} is not in the sudoers file\./
206
207
  @logger.trace { err }
207
208
  raise Bolt::Node::EscalateError.new(
208
209
  "User #{conn.user} does not have sudo permission on #{target}",
209
210
  'SUDO_DENIED'
210
211
  )
211
- elsif err =~ /^Sorry, try again\./
212
+ when /^Sorry, try again\./
212
213
  @logger.trace { err }
213
214
  raise Bolt::Node::EscalateError.new(
214
215
  "Sudo password for user #{conn.user} not recognized on #{target}",
@@ -30,7 +30,7 @@ module Bolt
30
30
  @transport_logger = transport_logger
31
31
  @logger.trace("Initializing ssh connection to #{@target.safe_name}")
32
32
 
33
- if target.options['private-key']&.instance_of?(String)
33
+ if target.options['private-key'].instance_of?(String)
34
34
  begin
35
35
  Bolt::Util.validate_file('ssh key', target.options['private-key'])
36
36
  rescue Bolt::FileError => e
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '2.30.0'
4
+ VERSION = '2.31.0'
5
5
  end
@@ -14,7 +14,9 @@ require 'json-schema'
14
14
 
15
15
  # These are only needed for the `/plans` endpoint.
16
16
  require 'puppet'
17
- require 'bolt_server/pe/pal'
17
+
18
+ # Needed by the `/project_file_metadatas` endpoint
19
+ require 'puppet/file_serving/fileset'
18
20
 
19
21
  module BoltServer
20
22
  class TransportApp < Sinatra::Base
@@ -35,6 +37,17 @@ module BoltServer
35
37
  transport-winrm
36
38
  ].freeze
37
39
 
40
+ # PE_BOLTLIB_PATH is intended to function exactly like the BOLTLIB_PATH used
41
+ # in Bolt::PAL. Paths and variable names are similar to what exists in
42
+ # Bolt::PAL, but with a 'PE' prefix.
43
+ PE_BOLTLIB_PATH = '/opt/puppetlabs/server/apps/bolt-server/pe-bolt-modules'
44
+
45
+ # For now at least, we maintain an entirely separate codedir from
46
+ # puppetserver by default, so that filesync can work properly. If filesync
47
+ # is not used, this can instead match the usual puppetserver codedir.
48
+ # See the `orchestrator.bolt.codedir` tk config setting.
49
+ DEFAULT_BOLT_CODEDIR = '/opt/puppetlabs/server/data/orchestration-services/code'
50
+
38
51
  def initialize(config)
39
52
  @config = config
40
53
  @schemas = Hash[REQUEST_SCHEMAS.map do |basename|
@@ -191,10 +204,52 @@ module BoltServer
191
204
  [@executor.run_script(target, file_location, body['arguments'])]
192
205
  end
193
206
 
207
+ # This function is nearly identical to Bolt::Pal's `with_puppet_settings` with the
208
+ # one difference that we set the codedir to point to actual code, rather than the
209
+ # tmpdir. We only use this funtion inside the Modulepath initializer so that Puppet
210
+ # is correctly configured to pull environment configuration correctly. If we don't
211
+ # set codedir in this way: when we try to load and interpolate the modulepath it
212
+ # won't correctly load.
213
+ #
214
+ # WARNING: THIS FUNCTION SHOULD ONLY BE CALLED INSIDE A SYNCHRONIZED PAL MUTEX
215
+ def with_pe_pal_init_settings(codedir, environmentpath, basemodulepath)
216
+ Dir.mktmpdir('pe-bolt') do |dir|
217
+ cli = []
218
+ Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
219
+ dir = setting == :codedir ? codedir : dir
220
+ cli << "--#{setting}" << dir
221
+ end
222
+ cli << "--environmentpath" << environmentpath
223
+ cli << "--basemodulepath" << basemodulepath
224
+ Puppet.settings.send(:clear_everything_for_tests)
225
+ Puppet.initialize_settings(cli)
226
+ yield
227
+ end
228
+ end
229
+
230
+ # Use puppet to identify the modulepath from an environment.
231
+ #
232
+ # WARNING: THIS FUNCTION SHOULD ONLY BE CALLED INSIDE A SYNCHRONIZED PAL MUTEX
233
+ def modulepath_from_environment(environment_name)
234
+ codedir = DEFAULT_BOLT_CODEDIR
235
+ environmentpath = "#{codedir}/environments"
236
+ basemodulepath = "#{codedir}/modules:/opt/puppetlabs/puppet/modules"
237
+ modulepath_dirs = nil
238
+ with_pe_pal_init_settings(codedir, environmentpath, basemodulepath) do
239
+ environment = Puppet.lookup(:environments).get!(environment_name)
240
+ modulepath_dirs = environment.modulepath
241
+ end
242
+ modulepath_dirs
243
+ end
244
+
194
245
  def in_pe_pal_env(environment)
195
246
  return [400, '`environment` is a required argument'] if environment.nil?
196
247
  @pal_mutex.synchronize do
197
- pal = BoltServer::PE::PAL.new({}, environment)
248
+ modulepath_obj = Bolt::Config::Modulepath.new(
249
+ modulepath_from_environment(environment),
250
+ boltlib_path: [PE_BOLTLIB_PATH, Bolt::Config::Modulepath::BOLTLIB_PATH]
251
+ )
252
+ pal = Bolt::PAL.new(modulepath_obj, nil, nil)
198
253
  yield pal
199
254
  rescue Puppet::Environments::EnvironmentNotFound
200
255
  [400, {
@@ -213,16 +268,11 @@ module BoltServer
213
268
  @pal_mutex.synchronize do
214
269
  project = Bolt::Project.create_project(project_dir)
215
270
  bolt_config = Bolt::Config.from_project(project, { log: { 'bolt-debug.log' => 'disable' } })
216
- pal = Bolt::PAL.new(bolt_config.modulepath, nil, nil, nil, nil, nil, bolt_config.project)
217
- module_path = [
218
- BoltServer::PE::PAL::PE_BOLTLIB_PATH,
219
- Bolt::PAL::BOLTLIB_PATH,
220
- *bolt_config.modulepath,
221
- Bolt::PAL::MODULES_PATH
222
- ]
223
- # CODEREVIEW: I *think* this is the only thing we need to make different between bolt's PAL. Is it acceptable
224
- # to hack this? Modulepath is currently a readable attribute, could we make it writeable?
225
- pal.instance_variable_set(:@modulepath, module_path)
271
+ modulepath_object = Bolt::Config::Modulepath.new(
272
+ bolt_config.modulepath,
273
+ boltlib_path: [PE_BOLTLIB_PATH, Bolt::Config::Modulepath::BOLTLIB_PATH]
274
+ )
275
+ pal = Bolt::PAL.new(modulepath_object, nil, nil, nil, nil, nil, bolt_config.project)
226
276
  context = {
227
277
  pal: pal,
228
278
  config: bolt_config
@@ -307,6 +357,23 @@ module BoltServer
307
357
  plans.map { |plan_name| { 'name' => plan_name } }
308
358
  end
309
359
 
360
+ def file_metadatas(pal, module_name, file)
361
+ pal.in_bolt_compiler do
362
+ mod = Puppet.lookup(:current_environment).module(module_name)
363
+ raise ArgumentError, "`module_name`: #{module_name} does not exist" unless mod
364
+ abs_file_path = mod.file(file)
365
+ raise ArgumentError, "`file`: #{file} does not exist inside the module's 'files' directory" unless abs_file_path
366
+ fileset = Puppet::FileServing::Fileset.new(abs_file_path, 'recurse' => 'yes')
367
+ Puppet::FileServing::Fileset.merge(fileset).collect do |relative_file_path, base_path|
368
+ metadata = Puppet::FileServing::Metadata.new(base_path, relative_path: relative_file_path)
369
+ metadata.checksum_type = 'sha256'
370
+ metadata.links = 'follow'
371
+ metadata.collect
372
+ metadata.to_data_hash
373
+ end
374
+ end
375
+ end
376
+
310
377
  get '/' do
311
378
  200
312
379
  end
@@ -550,6 +617,19 @@ module BoltServer
550
617
  end
551
618
  end
552
619
 
620
+ # Implements puppetserver's file_metadatas endpoint for projects.
621
+ #
622
+ # @param project_ref [String] the project_ref to fetch the file metadatas from
623
+ get '/project_file_metadatas/:module_name/*' do
624
+ in_bolt_project(params['project_ref']) do |context|
625
+ file = params[:splat].first
626
+ metadatas = file_metadatas(context[:pal], params[:module_name], file)
627
+ [200, metadatas.to_json]
628
+ end
629
+ rescue ArgumentError => e
630
+ [400, e.message]
631
+ end
632
+
553
633
  error 404 do
554
634
  err = Bolt::Error.new("Could not find route #{request.path}",
555
635
  'boltserver/not-found')
@@ -105,7 +105,7 @@ module BoltSpec
105
105
 
106
106
  # Set the things
107
107
  Puppet[:tasks] = true
108
- RSpec.configuration.module_path = [modulepath, Bolt::PAL::BOLTLIB_PATH].join(File::PATH_SEPARATOR)
108
+ RSpec.configuration.module_path = [modulepath, Bolt::Config::Modulepath::BOLTLIB_PATH].join(File::PATH_SEPARATOR)
109
109
  opts = {
110
110
  bolt_executor: executor,
111
111
  bolt_inventory: inventory,
@@ -153,7 +153,9 @@ module BoltSpec
153
153
  end
154
154
 
155
155
  def pal
156
- @pal ||= Bolt::PAL.new(config.modulepath, config.hiera_config, config.project.resource_types)
156
+ @pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
157
+ config.hiera_config,
158
+ config.project.resource_types)
157
159
  end
158
160
 
159
161
  BoltSpec::Plans::MOCKED_ACTIONS.each do |action|
@@ -224,7 +224,7 @@ module BoltSpec
224
224
 
225
225
  def run_plan(name, params)
226
226
  pal = Bolt::PAL.new(
227
- config.modulepath,
227
+ Bolt::Config::Modulepath.new(config.modulepath),
228
228
  config.hiera_config,
229
229
  config.project.resource_types,
230
230
  config.compile_concurrency,
@@ -179,7 +179,7 @@ module BoltSpec
179
179
  end
180
180
 
181
181
  def pal
182
- @pal ||= Bolt::PAL.new(config.modulepath,
182
+ @pal ||= Bolt::PAL.new(Bolt::Config::Modulepath.new(config.modulepath),
183
183
  config.hiera_config,
184
184
  config.project.resource_types,
185
185
  config.compile_concurrency)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bolt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.30.0
4
+ version: 2.31.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-30 00:00:00.000000000 Z
11
+ date: 2020-10-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -444,6 +444,7 @@ files:
444
444
  - lib/bolt/catalog/logging.rb
445
445
  - lib/bolt/cli.rb
446
446
  - lib/bolt/config.rb
447
+ - lib/bolt/config/modulepath.rb
447
448
  - lib/bolt/config/options.rb
448
449
  - lib/bolt/config/transport/base.rb
449
450
  - lib/bolt/config/transport/docker.rb
@@ -542,7 +543,6 @@ files:
542
543
  - lib/bolt_server/base_config.rb
543
544
  - lib/bolt_server/config.rb
544
545
  - lib/bolt_server/file_cache.rb
545
- - lib/bolt_server/pe/pal.rb
546
546
  - lib/bolt_server/schemas/action-check_node_connections.json
547
547
  - lib/bolt_server/schemas/action-run_command.json
548
548
  - lib/bolt_server/schemas/action-run_script.json
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bolt/pal'
4
- require 'bolt/util'
5
-
6
- module BoltServer
7
- module PE
8
- class PAL < Bolt::PAL
9
- # PE_BOLTLIB_PATH is intended to function exactly like the BOLTLIB_PATH used
10
- # in Bolt::PAL. Paths and variable names are similar to what exists in
11
- # Bolt::PAL, but with a 'PE' prefix.
12
- PE_BOLTLIB_PATH = '/opt/puppetlabs/server/apps/bolt-server/pe-bolt-modules'
13
-
14
- # For now at least, we maintain an entirely separate codedir from
15
- # puppetserver by default, so that filesync can work properly. If filesync
16
- # is not used, this can instead match the usual puppetserver codedir.
17
- # See the `orchestrator.bolt.codedir` tk config setting.
18
- DEFAULT_BOLT_CODEDIR = '/opt/puppetlabs/server/data/orchestration-services/code'
19
-
20
- # This function is nearly identical to Bolt::Pal's `with_puppet_settings` with the
21
- # one difference that we set the codedir to point to actual code, rather than the
22
- # tmpdir. We only use this funtion inside the PEBolt::PAL initializer so that Puppet
23
- # is correctly configured to pull environment configuration correctly. If we don't
24
- # set codedir in this way: when we try to load and interpolate the modulepath it
25
- # won't correctly load.
26
- def with_pe_pal_init_settings(codedir, environmentpath, basemodulepath)
27
- Dir.mktmpdir('pe-bolt') do |dir|
28
- cli = []
29
- Puppet::Settings::REQUIRED_APP_SETTINGS.each do |setting|
30
- dir = setting == :codedir ? codedir : dir
31
- cli << "--#{setting}" << dir
32
- end
33
- cli << "--environmentpath" << environmentpath
34
- cli << "--basemodulepath" << basemodulepath
35
- Puppet.settings.send(:clear_everything_for_tests)
36
- Puppet.initialize_settings(cli)
37
- yield
38
- # Ensure the puppet settings go back to what bolt expects after
39
- # we finish with the settings we need for PEBolt::PAL init.
40
- with_puppet_settings { |_| nil }
41
- end
42
- end
43
-
44
- def initialize(plan_executor_config, environment_name, hiera_config = nil, max_compiles = nil)
45
- # Bolt::PAL#initialize takes the modulepath as its first argument, but we
46
- # want to customize it later, so we pass an empty value:
47
- super([], hiera_config, max_compiles)
48
-
49
- codedir = plan_executor_config['codedir'] || DEFAULT_BOLT_CODEDIR
50
- environmentpath = plan_executor_config['environmentpath'] || "#{codedir}/environments"
51
- basemodulepath = plan_executor_config['basemodulepath'] || "#{codedir}/modules:/opt/puppetlabs/puppet/modules"
52
-
53
- with_pe_pal_init_settings(codedir, environmentpath, basemodulepath) do
54
- environment = Puppet.lookup(:environments).get!(environment_name)
55
- # A new modulepath is created from scratch (rather than using super's @modulepath)
56
- # so that we can have full control over all the entries in modulepath. In the future
57
- # it's likely we will need to preceed _both_ Bolt::PAL::BOLTLIB_PATH _and_
58
- # Bolt::PAL::MODULES_PATH which would be more complex if we tried to use @modulepath since
59
- # we need to append our modulepaths and exclude modules shiped in bolt gem code
60
- modulepath_dirs = environment.modulepath
61
- @user_modulepath = modulepath_dirs
62
- @modulepath = [PE_BOLTLIB_PATH, Bolt::PAL::BOLTLIB_PATH, *modulepath_dirs]
63
- end
64
- end
65
- end
66
- end
67
- end