bolt 2.7.0 → 2.11.1
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 +4 -4
- data/Puppetfile +4 -3
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resourceinstance.rb +27 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/result.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/resultset.rb +2 -0
- data/bolt-modules/boltlib/lib/puppet/datatypes/target.rb +4 -3
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +192 -0
- data/bolt-modules/boltlib/lib/puppet/functions/set_resources.rb +122 -0
- data/bolt-modules/boltlib/types/planresult.pp +12 -1
- data/bolt-modules/file/lib/puppet/functions/file/exists.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/join.rb +1 -1
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +2 -1
- data/bolt-modules/file/lib/puppet/functions/file/readable.rb +3 -1
- data/bolt-modules/file/lib/puppet/functions/file/write.rb +3 -1
- data/lib/bolt/applicator.rb +3 -2
- data/lib/bolt/apply_inventory.rb +1 -1
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/apply_target.rb +11 -2
- data/lib/bolt/bolt_option_parser.rb +22 -6
- data/lib/bolt/cli.rb +52 -22
- data/lib/bolt/config.rb +57 -27
- data/lib/bolt/config/transport/base.rb +3 -3
- data/lib/bolt/config/transport/docker.rb +2 -0
- data/lib/bolt/config/transport/local.rb +2 -0
- data/lib/bolt/config/transport/orch.rb +4 -2
- data/lib/bolt/config/transport/remote.rb +2 -0
- data/lib/bolt/config/transport/ssh.rb +51 -2
- data/lib/bolt/config/transport/winrm.rb +3 -1
- data/lib/bolt/executor.rb +16 -0
- data/lib/bolt/inventory.rb +2 -1
- data/lib/bolt/inventory/group.rb +1 -0
- data/lib/bolt/inventory/inventory.rb +5 -0
- data/lib/bolt/inventory/target.rb +17 -1
- data/lib/bolt/node/output.rb +1 -1
- data/lib/bolt/outputter/human.rb +5 -4
- data/lib/bolt/outputter/json.rb +1 -1
- data/lib/bolt/pal.rb +32 -14
- data/lib/bolt/pal/yaml_plan.rb +1 -0
- data/lib/bolt/plugin.rb +14 -8
- data/lib/bolt/plugin/module.rb +40 -7
- data/lib/bolt/plugin/puppetdb.rb +5 -2
- data/lib/bolt/project.rb +135 -0
- data/lib/bolt/puppetdb/config.rb +16 -28
- data/lib/bolt/rerun.rb +1 -1
- data/lib/bolt/resource_instance.rb +126 -0
- data/lib/bolt/result.rb +46 -23
- data/lib/bolt/result_set.rb +2 -5
- data/lib/bolt/secret.rb +20 -4
- data/lib/bolt/shell/bash.rb +12 -5
- data/lib/bolt/shell/powershell.rb +12 -4
- data/lib/bolt/target.rb +16 -1
- data/lib/bolt/transport/base.rb +24 -8
- data/lib/bolt/transport/orch.rb +4 -0
- data/lib/bolt/transport/ssh.rb +6 -2
- data/lib/bolt/transport/ssh/connection.rb +4 -0
- data/lib/bolt/transport/ssh/exec_connection.rb +110 -0
- data/lib/bolt/transport/winrm/connection.rb +6 -2
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/pe/pal.rb +1 -38
- data/lib/bolt_server/transport_app.rb +7 -7
- data/lib/bolt_spec/bolt_context.rb +3 -6
- data/lib/bolt_spec/plans.rb +1 -1
- data/lib/bolt_spec/plans/mock_executor.rb +1 -0
- data/lib/bolt_spec/run.rb +10 -13
- metadata +10 -7
- data/lib/bolt/boltdir.rb +0 -54
- data/lib/bolt/plugin/pkcs7.rb +0 -104
- data/lib/bolt/secret/base.rb +0 -41
data/lib/bolt/pal/yaml_plan.rb
CHANGED
data/lib/bolt/plugin.rb
CHANGED
@@ -115,17 +115,13 @@ module Bolt
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def boltdir
|
118
|
-
@config.
|
118
|
+
@config.project.path
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
def self.setup(config, pal,
|
122
|
+
def self.setup(config, pal, analytics = Bolt::Analytics::NoopClient.new)
|
123
123
|
plugins = new(config, pal, analytics)
|
124
124
|
|
125
|
-
# PDB is special because it needs the PDB client. Since it has no config,
|
126
|
-
# we can just add it first.
|
127
|
-
plugins.add_plugin(Bolt::Plugin::Puppetdb.new(pdb_client))
|
128
|
-
|
129
125
|
# Initialize any plugins referenced in plugin config. This will also indirectly
|
130
126
|
# initialize any plugins they depend on.
|
131
127
|
if plugins.reference?(config.plugins)
|
@@ -142,7 +138,7 @@ module Bolt
|
|
142
138
|
plugins
|
143
139
|
end
|
144
140
|
|
145
|
-
RUBY_PLUGINS = %w[task
|
141
|
+
RUBY_PLUGINS = %w[task prompt env_var puppetdb].freeze
|
146
142
|
BUILTIN_PLUGINS = %w[task terraform pkcs7 prompt vault aws_inventory puppetdb azure_inventory
|
147
143
|
yaml env_var gcloud_inventory].freeze
|
148
144
|
DEFAULT_PLUGIN_HOOKS = { 'puppet_library' => { 'plugin' => 'puppet_agent', 'stop_service' => true } }.freeze
|
@@ -161,6 +157,13 @@ module Bolt
|
|
161
157
|
@unknown = Set.new
|
162
158
|
@resolution_stack = []
|
163
159
|
@unresolved_plugin_configs = config.plugins.dup
|
160
|
+
# The puppetdb plugin config comes from the puppetdb section, not from
|
161
|
+
# the plugins section
|
162
|
+
if @unresolved_plugin_configs.key?('puppetdb')
|
163
|
+
msg = "Configuration for the PuppetDB plugin must be in the 'puppetdb' config section, not 'plugins'"
|
164
|
+
raise Bolt::Error.new(msg, 'bolt/plugin-error')
|
165
|
+
end
|
166
|
+
@unresolved_plugin_configs['puppetdb'] = config.puppetdb if config.puppetdb
|
164
167
|
@plugin_hooks = DEFAULT_PLUGIN_HOOKS.dup
|
165
168
|
end
|
166
169
|
|
@@ -168,7 +171,6 @@ module Bolt
|
|
168
171
|
@modules ||= Bolt::Module.discover(@pal.modulepath)
|
169
172
|
end
|
170
173
|
|
171
|
-
# Generally this is private. Puppetdb is special though
|
172
174
|
def add_plugin(plugin)
|
173
175
|
@plugins[plugin.name] = plugin
|
174
176
|
end
|
@@ -235,6 +237,10 @@ module Bolt
|
|
235
237
|
end
|
236
238
|
end
|
237
239
|
|
240
|
+
def puppetdb_client
|
241
|
+
by_name('puppetdb').puppetdb_client
|
242
|
+
end
|
243
|
+
|
238
244
|
# Evaluate all _plugin references in a data structure. Leaves are
|
239
245
|
# evaluated and then their parents are evaluated with references replaced
|
240
246
|
# by their values. If the result of a reference contains more references,
|
data/lib/bolt/plugin/module.rb
CHANGED
@@ -30,6 +30,10 @@ module Bolt
|
|
30
30
|
@module = mod
|
31
31
|
@config = config
|
32
32
|
@context = context
|
33
|
+
|
34
|
+
if @module.name == 'pkcs7'
|
35
|
+
@config = handle_deprecated_pkcs7_keys(@config)
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
# This method interacts with the module on disk so it's separate from initialize
|
@@ -155,7 +159,21 @@ module Bolt
|
|
155
159
|
# handled previously. That may not always be the case so filter them
|
156
160
|
# out now.
|
157
161
|
meta, params = opts.partition { |key, _val| key.start_with?('_') }.map(&:to_h)
|
158
|
-
|
162
|
+
|
163
|
+
if task.module_name == 'pkcs7'
|
164
|
+
params = handle_deprecated_pkcs7_keys(params)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Reject parameters from config that are not accepted by the task and
|
168
|
+
# merge in parameter defaults
|
169
|
+
params = if task.parameters
|
170
|
+
task.parameter_defaults
|
171
|
+
.merge(config.slice(*task.parameters.keys))
|
172
|
+
.merge(params)
|
173
|
+
else
|
174
|
+
config.merge(params)
|
175
|
+
end
|
176
|
+
|
159
177
|
validate_params(task, params)
|
160
178
|
|
161
179
|
meta['_boltdir'] = @context.boltdir.to_s
|
@@ -163,6 +181,23 @@ module Bolt
|
|
163
181
|
[params, meta]
|
164
182
|
end
|
165
183
|
|
184
|
+
# Raises a deprecation warning if the pkcs7 plugin is using deprecated keys and
|
185
|
+
# modifies the keys so they are the correct format
|
186
|
+
def handle_deprecated_pkcs7_keys(params)
|
187
|
+
if (params.key?('private-key') || params.key?('public-key')) && !@deprecation_warning_issued
|
188
|
+
@deprecation_warning_issued = true
|
189
|
+
|
190
|
+
message = "pkcs7 keys 'private-key' and 'public-key' have been deprecated and will be "\
|
191
|
+
"removed in a future version of Bolt; use 'private_key' and 'public_key' instead."
|
192
|
+
Logging.logger[self].warn(message)
|
193
|
+
end
|
194
|
+
|
195
|
+
params['private_key'] = params.delete('private-key') if params.key?('private-key')
|
196
|
+
params['public_key'] = params.delete('public-key') if params.key?('public-key')
|
197
|
+
|
198
|
+
params
|
199
|
+
end
|
200
|
+
|
166
201
|
def extract_task_parameter_schema
|
167
202
|
# Get the intersection of expected types (using Set)
|
168
203
|
type_set = @hook_map.each_with_object({}) do |(_hook, task), acc|
|
@@ -220,13 +255,11 @@ module Bolt
|
|
220
255
|
end
|
221
256
|
|
222
257
|
def validate_resolve_reference(opts)
|
223
|
-
|
224
|
-
|
225
|
-
params = merged.reject { |k, _v| k.start_with?('_') }
|
258
|
+
task = @hook_map[:resolve_reference]['task']
|
259
|
+
params, _metaparams = process_params(task, opts)
|
226
260
|
|
227
|
-
|
228
|
-
|
229
|
-
validate_params(sig, params)
|
261
|
+
if task
|
262
|
+
validate_params(task, params)
|
230
263
|
end
|
231
264
|
|
232
265
|
if @hook_map.include?(:validate_resolve_reference)
|
data/lib/bolt/plugin/puppetdb.rb
CHANGED
@@ -14,8 +14,11 @@ module Bolt
|
|
14
14
|
TEMPLATE_OPTS = %w[alias config facts features name uri vars].freeze
|
15
15
|
PLUGIN_OPTS = %w[_plugin query target_mapping].freeze
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
attr_reader :puppetdb_client
|
18
|
+
|
19
|
+
def initialize(config:, context:)
|
20
|
+
pdb_config = Bolt::PuppetDB::Config.load_config(config, context.boltdir)
|
21
|
+
@puppetdb_client = Bolt::PuppetDB::Client.new(pdb_config)
|
19
22
|
@logger = Logging.logger[self]
|
20
23
|
end
|
21
24
|
|
data/lib/bolt/project.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'bolt/pal'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
class Project
|
8
|
+
BOLTDIR_NAME = 'Boltdir'
|
9
|
+
PROJECT_SETTINGS = {
|
10
|
+
"name" => "The name of the project",
|
11
|
+
"plans" => "An array of plan names to whitelist. Whitelisted plans are included in `bolt plan show` output",
|
12
|
+
"tasks" => "An array of task names to whitelist. Whitelisted plans are included in `bolt task show` output"
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader :path, :config_file, :inventory_file, :modulepath, :hiera_config,
|
16
|
+
:puppetfile, :rerunfile, :type, :resource_types
|
17
|
+
|
18
|
+
def self.default_project
|
19
|
+
Project.new(File.join('~', '.puppetlabs', 'bolt'), 'user')
|
20
|
+
end
|
21
|
+
|
22
|
+
# Search recursively up the directory hierarchy for the Project. Look for a
|
23
|
+
# directory called Boltdir or a file called bolt.yaml (for a control repo
|
24
|
+
# type Project). Otherwise, repeat the check on each directory up the
|
25
|
+
# hierarchy, falling back to the default if we reach the root.
|
26
|
+
def self.find_boltdir(dir)
|
27
|
+
dir = Pathname.new(dir)
|
28
|
+
if (dir + BOLTDIR_NAME).directory?
|
29
|
+
new(dir + BOLTDIR_NAME, 'embedded')
|
30
|
+
elsif (dir + 'bolt.yaml').file? || (dir + 'bolt-project.yaml').file?
|
31
|
+
new(dir, 'local')
|
32
|
+
elsif dir.root?
|
33
|
+
default_project
|
34
|
+
else
|
35
|
+
find_boltdir(dir.parent)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(path, type = 'option')
|
40
|
+
@path = Pathname.new(path).expand_path
|
41
|
+
@config_file = @path + 'bolt.yaml'
|
42
|
+
@inventory_file = @path + 'inventory.yaml'
|
43
|
+
@modulepath = [(@path + 'modules').to_s, (@path + 'site-modules').to_s, (@path + 'site').to_s]
|
44
|
+
@hiera_config = @path + 'hiera.yaml'
|
45
|
+
@puppetfile = @path + 'Puppetfile'
|
46
|
+
@rerunfile = @path + '.rerun.json'
|
47
|
+
@resource_types = @path + '.resource_types'
|
48
|
+
@type = type
|
49
|
+
|
50
|
+
@project_file = @path + 'bolt-project.yaml'
|
51
|
+
@data = Bolt::Util.read_optional_yaml_hash(File.expand_path(@project_file), 'project') || {}
|
52
|
+
validate if load_as_module?
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
@path.to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
# This API is used to prepend the project as a module to Puppet's internal
|
60
|
+
# module_references list. CHANGE AT YOUR OWN RISK
|
61
|
+
def to_h
|
62
|
+
{ path: @path, name: name }
|
63
|
+
end
|
64
|
+
|
65
|
+
def eql?(other)
|
66
|
+
path == other.path
|
67
|
+
end
|
68
|
+
alias == eql?
|
69
|
+
|
70
|
+
def load_as_module?
|
71
|
+
@project_file.file?
|
72
|
+
end
|
73
|
+
|
74
|
+
def name
|
75
|
+
# If the project is in mymod/Boltdir/bolt-project.yaml, use mymod as the project name
|
76
|
+
dirname = @path.basename.to_s == 'Boltdir' ? @path.parent.basename.to_s : @path.basename.to_s
|
77
|
+
pname = @data['name'] || dirname
|
78
|
+
pname.include?('-') ? pname.split('-', 2)[1] : pname
|
79
|
+
end
|
80
|
+
|
81
|
+
def tasks
|
82
|
+
@data['tasks']
|
83
|
+
end
|
84
|
+
|
85
|
+
def plans
|
86
|
+
@data['plans']
|
87
|
+
end
|
88
|
+
|
89
|
+
def project_directory_name?(name)
|
90
|
+
# it must match an installed project name according to forge validator
|
91
|
+
name =~ /^[a-z][a-z0-9_]*$/
|
92
|
+
end
|
93
|
+
|
94
|
+
def project_namespaced_name?(name)
|
95
|
+
# it must match the full project name according to forge validator
|
96
|
+
name =~ /^[a-zA-Z0-9]+[-][a-z][a-z0-9_]*$/
|
97
|
+
end
|
98
|
+
|
99
|
+
def validate
|
100
|
+
n = @data['name']
|
101
|
+
if n && !project_directory_name?(n) && !project_namespaced_name?(n)
|
102
|
+
raise Bolt::ValidationError, <<~ERROR_STRING
|
103
|
+
Invalid project name '#{n}' in bolt-project.yaml; project names must match either:
|
104
|
+
An installed project name (ex. projectname) matching the expression /^[a-z][a-z0-9_]*$/ -or-
|
105
|
+
A namespaced project name (ex. author-projectname) matching the expression /^[a-zA-Z0-9]+[-][a-z][a-z0-9_]*$/
|
106
|
+
ERROR_STRING
|
107
|
+
elsif !project_directory_name?(name) && !project_namespaced_name?(name)
|
108
|
+
raise Bolt::ValidationError, <<~ERROR_STRING
|
109
|
+
Invalid project name '#{name}'; project names must match either:
|
110
|
+
A project name (ex. projectname) matching the expression /^[a-z][a-z0-9_]*$/ -or-
|
111
|
+
A namespaced project name (ex. author-projectname) matching the expression /^[a-zA-Z0-9]+[-][a-z][a-z0-9_]*$/
|
112
|
+
|
113
|
+
Configure project name in <project_dir>/bolt-project.yaml
|
114
|
+
ERROR_STRING
|
115
|
+
# If the project name is the same as one of the built-in modules raise a warning
|
116
|
+
elsif Dir.children(Bolt::PAL::BOLTLIB_PATH).include?(name)
|
117
|
+
raise Bolt::ValidationError, "The project '#{name}' will not be loaded. The project name conflicts "\
|
118
|
+
"with a built-in Bolt module of the same name."
|
119
|
+
end
|
120
|
+
|
121
|
+
%w[tasks plans].each do |conf|
|
122
|
+
unless @data.fetch(conf, []).is_a?(Array)
|
123
|
+
raise Bolt::ValidationError, "'#{conf}' in bolt-project.yaml must be an array"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def check_deprecated_file
|
129
|
+
if (@path + 'project.yaml').file?
|
130
|
+
logger = Logging.logger[self]
|
131
|
+
logger.warn "Project configuration file 'project.yaml' is deprecated; use 'bolt-project.yaml' instead."
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/bolt/puppetdb/config.rb
CHANGED
@@ -22,37 +22,29 @@ module Bolt
|
|
22
22
|
File.expand_path(File.join(Dir::COMMON_APPDATA, 'PuppetLabs/client-tools/puppetdb.conf'))
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.load_config(
|
25
|
+
def self.load_config(options, project_path = nil)
|
26
26
|
config = {}
|
27
27
|
global_path = Bolt::Util.windows? ? default_windows_config : DEFAULT_CONFIG[:global]
|
28
|
-
if filename
|
29
|
-
if File.exist?(filename)
|
30
|
-
config = JSON.parse(File.read(filename))
|
31
|
-
else
|
32
|
-
raise Bolt::PuppetDBError, "config file #{filename} does not exist"
|
33
|
-
end
|
34
|
-
else
|
35
|
-
if File.exist?(DEFAULT_CONFIG[:user])
|
36
|
-
filepath = DEFAULT_CONFIG[:user]
|
37
|
-
elsif File.exist?(global_path)
|
38
|
-
filepath = global_path
|
39
|
-
end
|
40
28
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
29
|
+
if File.exist?(DEFAULT_CONFIG[:user])
|
30
|
+
filepath = DEFAULT_CONFIG[:user]
|
31
|
+
elsif File.exist?(global_path)
|
32
|
+
filepath = global_path
|
33
|
+
end
|
34
|
+
|
35
|
+
begin
|
36
|
+
config = JSON.parse(File.read(filepath)) if filepath
|
37
|
+
rescue StandardError => e
|
38
|
+
Logging.logger[self].error("Could not load puppetdb.conf from #{filepath}: #{e.message}")
|
46
39
|
end
|
47
40
|
|
48
41
|
config = config.fetch('puppetdb', {})
|
49
|
-
new(config.merge(options),
|
42
|
+
new(config.merge(options), project_path)
|
50
43
|
end
|
51
44
|
|
52
|
-
def initialize(settings,
|
45
|
+
def initialize(settings, project_path = nil)
|
53
46
|
@settings = settings
|
54
|
-
|
55
|
-
expand_paths
|
47
|
+
expand_paths(project_path)
|
56
48
|
end
|
57
49
|
|
58
50
|
def token
|
@@ -68,14 +60,10 @@ module Bolt
|
|
68
60
|
@token = @token.strip if @token
|
69
61
|
end
|
70
62
|
|
71
|
-
def expand_paths
|
63
|
+
def expand_paths(project_path)
|
72
64
|
%w[cacert cert key token].each do |file|
|
73
65
|
next unless @settings[file]
|
74
|
-
@settings[file] =
|
75
|
-
File.expand_path(@settings[file], @boltdir_path)
|
76
|
-
else
|
77
|
-
File.expand_path(@settings[file])
|
78
|
-
end
|
66
|
+
@settings[file] = File.expand_path(@settings[file], project_path)
|
79
67
|
end
|
80
68
|
end
|
81
69
|
|
data/lib/bolt/rerun.rb
CHANGED
@@ -45,7 +45,7 @@ module Bolt
|
|
45
45
|
end
|
46
46
|
|
47
47
|
if result_set.is_a?(Bolt::ResultSet)
|
48
|
-
data = result_set.map { |res| res.
|
48
|
+
data = result_set.map { |res| { target: res.target.name, status: res.status } }
|
49
49
|
FileUtils.mkdir_p(File.dirname(@path))
|
50
50
|
File.write(@path, data.to_json)
|
51
51
|
elsif File.exist?(@path)
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Bolt
|
6
|
+
class ResourceInstance
|
7
|
+
attr_reader :target, :type, :title, :state, :desired_state
|
8
|
+
attr_accessor :events
|
9
|
+
|
10
|
+
# Needed by Puppet to recognize Bolt::ResourceInstance as a Puppet object when deserializing
|
11
|
+
def self._pcore_type
|
12
|
+
ResourceInstance
|
13
|
+
end
|
14
|
+
|
15
|
+
# Needed by Puppet to serialize with _pcore_init_hash instead of the object's attributes
|
16
|
+
def self._pcore_init_from_hash(_init_hash)
|
17
|
+
raise "ResourceInstance shouldn't be instantiated from a pcore_init class method. "\
|
18
|
+
"How did this get called?"
|
19
|
+
end
|
20
|
+
|
21
|
+
def _pcore_init_from_hash(init_hash)
|
22
|
+
initialize(init_hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Parameters will already be validated when calling ResourceInstance.new or
|
26
|
+
# set_resources() from a plan. We don't perform any validation in the class
|
27
|
+
# itself since Puppet will pass an empty hash to the initializer as part of
|
28
|
+
# the deserialization process before passing the _pcore_init_hash.
|
29
|
+
def initialize(resource_hash)
|
30
|
+
@target = resource_hash['target']
|
31
|
+
@type = resource_hash['type'].to_s.capitalize
|
32
|
+
@title = resource_hash['title']
|
33
|
+
# get_resources() returns observed state under the 'parameters' key
|
34
|
+
@state = resource_hash['state'] || resource_hash['parameters'] || {}
|
35
|
+
@desired_state = resource_hash['desired_state'] || {}
|
36
|
+
@events = resource_hash['events'] || []
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates a ResourceInstance from a data hash in a plan when calling
|
40
|
+
# ResourceInstance.new($resource_hash) or $target.set_resources($resource_hash)
|
41
|
+
def self.from_asserted_hash(resource_hash)
|
42
|
+
new(resource_hash)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Creates a ResourceInstance from positional arguments in a plan when
|
46
|
+
# calling ResourceInstance.new(target, type, title, ...)
|
47
|
+
def self.from_asserted_args(target,
|
48
|
+
type,
|
49
|
+
title,
|
50
|
+
state = nil,
|
51
|
+
desired_state = nil,
|
52
|
+
events = nil)
|
53
|
+
new(
|
54
|
+
'target' => target,
|
55
|
+
'type' => type,
|
56
|
+
'title' => title,
|
57
|
+
'state' => state,
|
58
|
+
'desired_state' => desired_state,
|
59
|
+
'events' => events
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def eql?(other)
|
64
|
+
self.class.equal?(other.class) &&
|
65
|
+
target == other.target &&
|
66
|
+
type == other.type &&
|
67
|
+
title == other.title
|
68
|
+
end
|
69
|
+
alias == eql?
|
70
|
+
|
71
|
+
def to_hash
|
72
|
+
{
|
73
|
+
'target' => target,
|
74
|
+
'type' => type,
|
75
|
+
'title' => title,
|
76
|
+
'state' => state,
|
77
|
+
'desired_state' => desired_state,
|
78
|
+
'events' => events
|
79
|
+
}
|
80
|
+
end
|
81
|
+
alias _pcore_init_hash to_hash
|
82
|
+
|
83
|
+
def to_json(opts = nil)
|
84
|
+
to_hash.to_json(opts)
|
85
|
+
end
|
86
|
+
|
87
|
+
def reference
|
88
|
+
"#{type}[#{title}]"
|
89
|
+
end
|
90
|
+
alias to_s reference
|
91
|
+
|
92
|
+
def add_event(event)
|
93
|
+
@events << event
|
94
|
+
end
|
95
|
+
|
96
|
+
# rubocop:disable Naming/AccessorMethodName
|
97
|
+
def set_state(state)
|
98
|
+
assert_hash('state', state)
|
99
|
+
@state.merge!(state)
|
100
|
+
end
|
101
|
+
# rubocop:enable Naming/AccessorMethodName
|
102
|
+
|
103
|
+
def overwrite_state(state)
|
104
|
+
assert_hash('state', state)
|
105
|
+
@state = state
|
106
|
+
end
|
107
|
+
|
108
|
+
# rubocop:disable Naming/AccessorMethodName
|
109
|
+
def set_desired_state(desired_state)
|
110
|
+
assert_hash('desired_state', desired_state)
|
111
|
+
@desired_state.merge!(desired_state)
|
112
|
+
end
|
113
|
+
# rubocop:enable Naming/AccessorMethodName
|
114
|
+
|
115
|
+
def overwrite_desired_state(desired_state)
|
116
|
+
assert_hash('desired_state', desired_state)
|
117
|
+
@desired_state = desired_state
|
118
|
+
end
|
119
|
+
|
120
|
+
def assert_hash(loc, value)
|
121
|
+
unless value.is_a?(Hash)
|
122
|
+
raise Bolt::ValidationError, "#{loc} must be of type Hash; got #{value.class}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|