bolt 0.23.0 → 0.24.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 +4 -4
- data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +5 -2
- data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +5 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +5 -8
- data/lib/bolt/applicator.rb +11 -8
- data/lib/bolt/boltdir.rb +13 -5
- data/lib/bolt/catalog.rb +22 -47
- data/lib/bolt/config.rb +1 -26
- data/lib/bolt/executor.rb +1 -1
- data/lib/bolt/outputter.rb +0 -9
- data/lib/bolt/outputter/human.rb +29 -14
- data/lib/bolt/outputter/json.rb +12 -1
- data/lib/bolt/pal.rb +12 -10
- data/lib/bolt/target.rb +0 -6
- data/lib/bolt/task.rb +53 -10
- data/lib/bolt/transport/base.rb +1 -6
- data/lib/bolt/transport/local.rb +11 -13
- data/lib/bolt/transport/local/shell.rb +2 -2
- data/lib/bolt/transport/ssh.rb +16 -11
- data/lib/bolt/transport/winrm.rb +8 -11
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_ext/schemas/task.json +12 -5
- data/libexec/apply_catalog.rb +3 -1
- data/libexec/bolt_catalog +4 -0
- data/vendored/puppet/lib/puppet.rb +2 -1
- data/vendored/puppet/lib/puppet/application/agent.rb +2 -6
- data/vendored/puppet/lib/puppet/application/apply.rb +100 -60
- data/vendored/puppet/lib/puppet/application/cert.rb +26 -291
- data/vendored/puppet/lib/puppet/application/device.rb +0 -5
- data/vendored/puppet/lib/puppet/application/lookup.rb +1 -1
- data/vendored/puppet/lib/puppet/application/ssl.rb +133 -0
- data/vendored/puppet/lib/puppet/application_support.rb +1 -2
- data/vendored/puppet/lib/puppet/configurer.rb +34 -50
- data/vendored/puppet/lib/puppet/configurer/downloader.rb +1 -1
- data/vendored/puppet/lib/puppet/configurer/plugin_handler.rb +1 -1
- data/vendored/puppet/lib/puppet/daemon.rb +1 -1
- data/vendored/puppet/lib/puppet/defaults.rb +40 -117
- data/vendored/puppet/lib/puppet/face/epp.rb +2 -2
- data/vendored/puppet/lib/puppet/face/help.rb +21 -7
- data/vendored/puppet/lib/puppet/face/node/clean.rb +14 -10
- data/vendored/puppet/lib/puppet/feature/base.rb +7 -23
- data/vendored/puppet/lib/puppet/feature/eventlog.rb +1 -1
- data/vendored/puppet/lib/puppet/file_serving/base.rb +2 -2
- data/vendored/puppet/lib/puppet/file_serving/fileset.rb +1 -1
- data/vendored/puppet/lib/puppet/file_serving/metadata.rb +2 -2
- data/vendored/puppet/lib/puppet/functions.rb +133 -0
- data/vendored/puppet/lib/puppet/functions/eyaml_lookup_key.rb +4 -5
- data/vendored/puppet/lib/puppet/functions/filter.rb +7 -6
- data/vendored/puppet/lib/puppet/functions/new.rb +37 -53
- data/vendored/puppet/lib/puppet/functions/warning.rb +1 -1
- data/vendored/puppet/lib/puppet/functions/yaml_data.rb +4 -5
- data/vendored/puppet/lib/puppet/gettext/config.rb +1 -1
- data/vendored/puppet/lib/puppet/graph.rb +0 -2
- data/vendored/puppet/lib/puppet/indirector/catalog/json.rb +14 -3
- data/vendored/puppet/lib/puppet/indirector/catalog/yaml.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/certificate/file.rb +0 -1
- data/vendored/puppet/lib/puppet/indirector/facts/yaml.rb +4 -2
- data/vendored/puppet/lib/puppet/indirector/key/file.rb +1 -6
- data/vendored/puppet/lib/puppet/indirector/node/exec.rb +1 -3
- data/vendored/puppet/lib/puppet/indirector/node/yaml.rb +0 -6
- data/vendored/puppet/lib/puppet/indirector/request.rb +1 -1
- data/vendored/puppet/lib/puppet/indirector/ssl_file.rb +3 -44
- data/vendored/puppet/lib/puppet/indirector/yaml.rb +4 -4
- data/vendored/puppet/lib/puppet/info_service/task_information_service.rb +7 -3
- data/vendored/puppet/lib/puppet/loaders.rb +1 -0
- data/vendored/puppet/lib/puppet/module/task.rb +198 -29
- data/vendored/puppet/lib/puppet/module_tool/applications/unpacker.rb +1 -1
- data/vendored/puppet/lib/puppet/network/format_support.rb +13 -8
- data/vendored/puppet/lib/puppet/network/formats.rb +93 -2
- data/vendored/puppet/lib/puppet/network/http/api/indirected_routes.rb +10 -3
- data/vendored/puppet/lib/puppet/node/facts.rb +11 -1
- data/vendored/puppet/lib/puppet/parser/catalog_compiler.rb +56 -0
- data/vendored/puppet/lib/puppet/parser/compiler.rb +3 -1
- data/vendored/puppet/lib/puppet/parser/functions.rb +3 -1
- data/vendored/puppet/lib/puppet/parser/functions/filter.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/functions/generate.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/functions/sprintf.rb +12 -1
- data/vendored/puppet/lib/puppet/parser/functions/tagged.rb +1 -4
- data/vendored/puppet/lib/puppet/parser/scope.rb +1 -1
- data/vendored/puppet/lib/puppet/parser/script_compiler.rb +7 -2
- data/vendored/puppet/lib/puppet/pops/evaluator/deferred_resolver.rb +5 -3
- data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_converter.rb +23 -4
- data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_support.rb +3 -4
- data/vendored/puppet/lib/puppet/pops/functions/dispatch.rb +4 -0
- data/vendored/puppet/lib/puppet/pops/issues.rb +8 -0
- data/vendored/puppet/lib/puppet/pops/loader/loader.rb +2 -2
- data/vendored/puppet/lib/puppet/pops/loader/loader_paths.rb +3 -1
- data/vendored/puppet/lib/puppet/pops/loader/module_loaders.rb +30 -9
- data/vendored/puppet/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +62 -0
- data/vendored/puppet/lib/puppet/pops/loader/static_loader.rb +0 -1
- data/vendored/puppet/lib/puppet/pops/loader/task_instantiator.rb +13 -70
- data/vendored/puppet/lib/puppet/pops/loaders.rb +19 -29
- data/vendored/puppet/lib/puppet/pops/lookup/hiera_config.rb +1 -1
- data/vendored/puppet/lib/puppet/pops/model/model_label_provider.rb +4 -1
- data/vendored/puppet/lib/puppet/pops/pcore.rb +10 -33
- data/vendored/puppet/lib/puppet/pops/serialization.rb +2 -0
- data/vendored/puppet/lib/puppet/pops/serialization/from_data_converter.rb +2 -1
- data/vendored/puppet/lib/puppet/pops/serialization/to_data_converter.rb +11 -3
- data/vendored/puppet/lib/puppet/pops/serialization/to_stringified_converter.rb +226 -0
- data/vendored/puppet/lib/puppet/pops/types/p_object_type.rb +3 -0
- data/vendored/puppet/lib/puppet/pops/validation/checker4_0.rb +97 -47
- data/vendored/puppet/lib/puppet/pops/validation/validator_factory_4_0.rb +7 -8
- data/vendored/puppet/lib/puppet/property/keyvalue.rb +70 -8
- data/vendored/puppet/lib/puppet/provider/aix_object.rb +483 -0
- data/vendored/puppet/lib/puppet/provider/file/windows.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/group/aix.rb +51 -112
- data/vendored/puppet/lib/puppet/provider/package/gem.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/pip.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/puppet_gem.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/rpm.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/windows/package.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/package/zypper.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/service/systemd.rb +1 -1
- data/vendored/puppet/lib/puppet/provider/service/windows.rb +37 -40
- data/vendored/puppet/lib/puppet/provider/user/aix.rb +142 -254
- data/vendored/puppet/lib/puppet/resource.rb +20 -3
- data/vendored/puppet/lib/puppet/resource/catalog.rb +2 -12
- data/vendored/puppet/lib/puppet/rest/routes.rb +97 -34
- data/vendored/puppet/lib/puppet/settings.rb +1 -1
- data/vendored/puppet/lib/puppet/settings/file_setting.rb +1 -1
- data/vendored/puppet/lib/puppet/ssl/base.rb +1 -9
- data/vendored/puppet/lib/puppet/ssl/certificate_request.rb +1 -13
- data/vendored/puppet/lib/puppet/ssl/certificate_request_attributes.rb +1 -1
- data/vendored/puppet/lib/puppet/ssl/host.rb +114 -232
- data/vendored/puppet/lib/puppet/ssl/key.rb +1 -5
- data/vendored/puppet/lib/puppet/ssl/oids.rb +1 -1
- data/vendored/puppet/lib/puppet/test/test_helper.rb +0 -4
- data/vendored/puppet/lib/puppet/transaction/event.rb +3 -7
- data/vendored/puppet/lib/puppet/transaction/persistence.rb +1 -1
- data/vendored/puppet/lib/puppet/type/exec.rb +18 -16
- data/vendored/puppet/lib/puppet/type/file.rb +3 -3
- data/vendored/puppet/lib/puppet/type/file/source.rb +20 -7
- data/vendored/puppet/lib/puppet/type/group.rb +3 -5
- data/vendored/puppet/lib/puppet/type/notify.rb +1 -1
- data/vendored/puppet/lib/puppet/type/package.rb +2 -5
- data/vendored/puppet/lib/puppet/type/schedule.rb +1 -1
- data/vendored/puppet/lib/puppet/type/service.rb +3 -6
- data/vendored/puppet/lib/puppet/type/tidy.rb +1 -1
- data/vendored/puppet/lib/puppet/type/user.rb +13 -20
- data/vendored/puppet/lib/puppet/util.rb +8 -9
- data/vendored/puppet/lib/puppet/util/execution.rb +3 -3
- data/vendored/puppet/lib/puppet/util/feature.rb +61 -39
- data/vendored/puppet/lib/puppet/util/log/destinations.rb +1 -1
- data/vendored/puppet/lib/puppet/util/rdoc.rb +1 -1
- data/vendored/puppet/lib/puppet/util/run_mode.rb +1 -1
- data/vendored/puppet/lib/puppet/util/storage.rb +1 -1
- data/vendored/puppet/lib/puppet/util/suidmanager.rb +7 -5
- data/vendored/puppet/lib/puppet/util/tag_set.rb +1 -1
- data/vendored/puppet/lib/puppet/util/tagging.rb +1 -1
- data/vendored/puppet/lib/puppet/util/windows.rb +18 -2
- data/vendored/puppet/lib/puppet/util/windows/adsi.rb +154 -205
- data/vendored/puppet/lib/puppet/util/windows/service.rb +770 -0
- data/vendored/puppet/lib/puppet/util/yaml.rb +41 -5
- data/vendored/puppet/lib/puppet/version.rb +1 -1
- data/vendored/puppet/lib/puppet_pal.rb +280 -24
- metadata +8 -38
- data/lib/bolt/catalog/compiler.rb +0 -48
- data/lib/bolt/catalog/loaders.rb +0 -19
- data/vendored/puppet/lib/puppet/application/ca.rb +0 -11
- data/vendored/puppet/lib/puppet/application/certificate.rb +0 -17
- data/vendored/puppet/lib/puppet/application/certificate_request.rb +0 -7
- data/vendored/puppet/lib/puppet/application/certificate_revocation_list.rb +0 -7
- data/vendored/puppet/lib/puppet/face/ca.rb +0 -266
- data/vendored/puppet/lib/puppet/face/certificate.rb +0 -167
- data/vendored/puppet/lib/puppet/face/certificate_request.rb +0 -56
- data/vendored/puppet/lib/puppet/face/certificate_revocation_list.rb +0 -56
- data/vendored/puppet/lib/puppet/graph/random_prioritizer.rb +0 -16
- data/vendored/puppet/lib/puppet/graph/title_hash_prioritizer.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/certificate/ca.rb +0 -9
- data/vendored/puppet/lib/puppet/indirector/certificate/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_request/ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_request/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/ca.rb +0 -8
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/file.rb +0 -8
- data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/rest.rb +0 -11
- data/vendored/puppet/lib/puppet/indirector/certificate_status.rb +0 -4
- data/vendored/puppet/lib/puppet/indirector/certificate_status/file.rb +0 -91
- data/vendored/puppet/lib/puppet/indirector/certificate_status/rest.rb +0 -11
- data/vendored/puppet/lib/puppet/indirector/key/ca.rb +0 -16
- data/vendored/puppet/lib/puppet/indirector/key/disabled_ca.rb +0 -22
- data/vendored/puppet/lib/puppet/indirector/ldap.rb +0 -86
- data/vendored/puppet/lib/puppet/indirector/node/ldap.rb +0 -275
- data/vendored/puppet/lib/puppet/provider/aixobject.rb +0 -392
- data/vendored/puppet/lib/puppet/provider/cron/crontab.rb +0 -297
- data/vendored/puppet/lib/puppet/ssl/certificate_authority.rb +0 -475
- data/vendored/puppet/lib/puppet/ssl/certificate_authority/autosign_command.rb +0 -45
- data/vendored/puppet/lib/puppet/ssl/certificate_authority/interface.rb +0 -324
- data/vendored/puppet/lib/puppet/ssl/certificate_factory.rb +0 -219
- data/vendored/puppet/lib/puppet/ssl/certificate_revocation_list.rb +0 -111
- data/vendored/puppet/lib/puppet/ssl/inventory.rb +0 -55
- data/vendored/puppet/lib/puppet/type/cron.rb +0 -480
@@ -27,16 +27,15 @@ class ValidatorFactory_4_0 < Factory
|
|
27
27
|
# Configure each issue that should **not** be an error
|
28
28
|
#
|
29
29
|
# Validate as per the current runtime configuration
|
30
|
-
p[Issues::RT_NO_STORECONFIGS_EXPORT]
|
31
|
-
p[Issues::RT_NO_STORECONFIGS]
|
30
|
+
p[Issues::RT_NO_STORECONFIGS_EXPORT] = Puppet[:storeconfigs] ? :ignore : :warning
|
31
|
+
p[Issues::RT_NO_STORECONFIGS] = Puppet[:storeconfigs] ? :ignore : :warning
|
32
32
|
|
33
|
-
p[Issues::FUTURE_RESERVED_WORD]
|
33
|
+
p[Issues::FUTURE_RESERVED_WORD] = :deprecation
|
34
34
|
|
35
|
-
p[Issues::DUPLICATE_KEY]
|
36
|
-
p[Issues::NAME_WITH_HYPHEN]
|
37
|
-
p[Issues::EMPTY_RESOURCE_SPECIALIZATION]
|
38
|
-
p[Issues::CLASS_NOT_VIRTUALIZABLE]
|
39
|
-
p[Issues::ILLEGAL_DEFINITION_LOCATION] = Puppet[:strict] == :off ? :ignore : Puppet[:strict]
|
35
|
+
p[Issues::DUPLICATE_KEY] = Puppet[:strict] == :off ? :ignore : Puppet[:strict]
|
36
|
+
p[Issues::NAME_WITH_HYPHEN] = :error
|
37
|
+
p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :ignore
|
38
|
+
p[Issues::CLASS_NOT_VIRTUALIZABLE] = Puppet[:strict] == :off ? :warning : Puppet[:strict]
|
40
39
|
p
|
41
40
|
end
|
42
41
|
end
|
@@ -12,9 +12,20 @@ module Puppet
|
|
12
12
|
# @todo The node with an important message is not very clear.
|
13
13
|
#
|
14
14
|
class KeyValue < Property
|
15
|
+
class << self
|
16
|
+
# This is a class-level variable that child properties can override
|
17
|
+
# if they wish.
|
18
|
+
attr_accessor :log_only_changed_or_new_keys
|
19
|
+
end
|
20
|
+
|
21
|
+
self.log_only_changed_or_new_keys = false
|
15
22
|
|
16
23
|
def hash_to_key_value_s(hash)
|
17
|
-
|
24
|
+
if self.class.log_only_changed_or_new_keys
|
25
|
+
hash = hash.select { |k, _| @changed_or_new_keys.include?(k) }
|
26
|
+
end
|
27
|
+
|
28
|
+
hash.map { |*pair| pair.join(separator) }.join(delimiter)
|
18
29
|
end
|
19
30
|
|
20
31
|
def should_to_s(should_value)
|
@@ -33,11 +44,19 @@ module Puppet
|
|
33
44
|
@resource[membership] == :inclusive
|
34
45
|
end
|
35
46
|
|
36
|
-
def
|
37
|
-
#
|
38
|
-
|
47
|
+
def hashify_should
|
48
|
+
# Puppet casts all should values to arrays. Thus, if the user
|
49
|
+
# passed in a hash for our property's should value, the should_value
|
50
|
+
# parameter will be a single element array so we just extract our value
|
51
|
+
# directly.
|
52
|
+
if ! @should.empty? && @should.first.is_a?(Hash)
|
53
|
+
return @should.first
|
54
|
+
end
|
55
|
+
|
56
|
+
# Here, should is an array of key/value pairs.
|
57
|
+
@should.inject({}) do |hash, key_value|
|
39
58
|
tmp = key_value.split(separator)
|
40
|
-
hash[tmp[0].intern] = tmp[1]
|
59
|
+
hash[tmp[0].strip.intern] = tmp[1]
|
41
60
|
hash
|
42
61
|
end
|
43
62
|
end
|
@@ -53,11 +72,24 @@ module Puppet
|
|
53
72
|
def should
|
54
73
|
return nil unless @should
|
55
74
|
|
56
|
-
members =
|
75
|
+
members = hashify_should
|
57
76
|
current = process_current_hash(retrieve)
|
58
77
|
|
59
78
|
#shared keys will get overwritten by members
|
60
|
-
current.merge(members)
|
79
|
+
should_value = current.merge(members)
|
80
|
+
|
81
|
+
# Figure out the keys that will actually change in our Puppet run.
|
82
|
+
# This lets us reduce the verbosity of Puppet's logging for instances
|
83
|
+
# of this class when we want to.
|
84
|
+
#
|
85
|
+
# NOTE: We use ||= here because we only need to compute the
|
86
|
+
# changed_or_new_keys once (since this property will only be synced once).
|
87
|
+
#
|
88
|
+
@changed_or_new_keys ||= should_value.keys.select do |key|
|
89
|
+
! current.key?(key) || current[key] != should_value[key]
|
90
|
+
end
|
91
|
+
|
92
|
+
should_value
|
61
93
|
end
|
62
94
|
|
63
95
|
# @return [String] Returns a default separator of "="
|
@@ -84,12 +116,42 @@ module Puppet
|
|
84
116
|
|
85
117
|
# Returns true if there is no _is_ value, else returns if _is_ is equal to _should_ using == as comparison.
|
86
118
|
# @return [Boolean] whether the property is in sync or not.
|
87
|
-
#
|
88
119
|
def insync?(is)
|
89
120
|
return true unless is
|
90
121
|
|
91
122
|
(is == self.should)
|
92
123
|
end
|
124
|
+
|
125
|
+
# We only accept an array of key/value pairs (strings), a single
|
126
|
+
# key/value pair (string) or a Hash as valid values for our property.
|
127
|
+
# Note that for an array property value, the 'value' passed into the
|
128
|
+
# block corresponds to the array element.
|
129
|
+
validate do |value|
|
130
|
+
unless value.is_a?(String) || value.is_a?(Hash)
|
131
|
+
raise ArgumentError, _("The %{name} property must be specified as a hash or an array of key/value pairs (strings)!") % { name: name }
|
132
|
+
end
|
133
|
+
|
134
|
+
next if value.is_a?(Hash)
|
135
|
+
|
136
|
+
unless value.include?("#{separator}")
|
137
|
+
raise ArgumentError, _("Key/value pairs must be separated by '%{separator}'") % {separator: separator}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# The validate step ensures that our passed-in value is
|
142
|
+
# either a String or a Hash. If our value's a string,
|
143
|
+
# then nothing else needs to be done. Otherwise, we need
|
144
|
+
# to stringify the hash's keys and values to match our
|
145
|
+
# internal representation of the property's value.
|
146
|
+
munge do |value|
|
147
|
+
next value if value.is_a?(String)
|
148
|
+
|
149
|
+
munged_value = value.to_a.map! do |hash_key, hash_value|
|
150
|
+
[hash_key.to_s.strip.to_sym, hash_value.to_s]
|
151
|
+
end
|
152
|
+
|
153
|
+
Hash[munged_value]
|
154
|
+
end
|
93
155
|
end
|
94
156
|
end
|
95
157
|
end
|
@@ -0,0 +1,483 @@
|
|
1
|
+
# Common code for AIX user/group providers.
|
2
|
+
class Puppet::Provider::AixObject < Puppet::Provider
|
3
|
+
desc "Generic AIX resource provider"
|
4
|
+
|
5
|
+
# Class representing a MappedObject, which can either be an
|
6
|
+
# AIX attribute or a Puppet property. This class lets us
|
7
|
+
# write something like:
|
8
|
+
#
|
9
|
+
# attribute = mappings[:aix_attribute][:uid]
|
10
|
+
# attribute.name
|
11
|
+
# attribute.convert_property_value(uid)
|
12
|
+
#
|
13
|
+
# property = mappings[:puppet_property][:id]
|
14
|
+
# property.name
|
15
|
+
# property.convert_attribute_value(id)
|
16
|
+
#
|
17
|
+
# NOTE: This is an internal class specific to AixObject. It is
|
18
|
+
# not meant to be used anywhere else. That's why we do not have
|
19
|
+
# any validation code in here.
|
20
|
+
#
|
21
|
+
# NOTE: See the comments in the class-level mappings method to
|
22
|
+
# understand what we mean by pure and impure conversion functions.
|
23
|
+
#
|
24
|
+
# NOTE: The 'mapping' code, including this class, could possibly
|
25
|
+
# be moved to a separate module so that it can be re-used in some
|
26
|
+
# of our other providers. See PUP-9082.
|
27
|
+
class MappedObject
|
28
|
+
attr_reader :name
|
29
|
+
|
30
|
+
def initialize(name, conversion_fn, conversion_fn_code)
|
31
|
+
@name = name
|
32
|
+
@conversion_fn = conversion_fn
|
33
|
+
@conversion_fn_code = conversion_fn_code
|
34
|
+
|
35
|
+
return unless pure_conversion_fn?
|
36
|
+
|
37
|
+
# Our conversion function is pure, so we can go ahead
|
38
|
+
# and define it. This way, we can use this MappedObject
|
39
|
+
# at the class-level as well as at the instance-level.
|
40
|
+
define_singleton_method(@conversion_fn) do |value|
|
41
|
+
@conversion_fn_code.call(value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def pure_conversion_fn?
|
46
|
+
@conversion_fn_code.arity == 1
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sets our MappedObject's provider. This only makes sense
|
50
|
+
# if it has an impure conversion function. We will call this
|
51
|
+
# in the instance-level mappings method after the provider
|
52
|
+
# instance has been created to define our conversion function.
|
53
|
+
# Note that a MappedObject with an impure conversion function
|
54
|
+
# cannot be used at the class level.
|
55
|
+
def set_provider(provider)
|
56
|
+
define_singleton_method(@conversion_fn) do |value|
|
57
|
+
@conversion_fn_code.call(provider, value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class << self
|
63
|
+
#-------------
|
64
|
+
# Mappings
|
65
|
+
# ------------
|
66
|
+
|
67
|
+
def mappings
|
68
|
+
return @mappings if @mappings
|
69
|
+
|
70
|
+
@mappings = {}
|
71
|
+
@mappings[:aix_attribute] = {}
|
72
|
+
@mappings[:puppet_property] = {}
|
73
|
+
|
74
|
+
@mappings
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add a mapping from a Puppet property to an AIX attribute. The info must include:
|
78
|
+
#
|
79
|
+
# * :puppet_property -- The puppet property corresponding to this attribute
|
80
|
+
# * :aix_attribute -- The AIX attribute corresponding to this attribute. Defaults
|
81
|
+
# to puppet_property if this is not provided.
|
82
|
+
# * :property_to_attribute -- A lambda that converts a Puppet Property to an AIX attribute
|
83
|
+
# value. Defaults to the identity function if not provided.
|
84
|
+
# * :attribute_to_property -- A lambda that converts an AIX attribute to a Puppet property.
|
85
|
+
# Defaults to the identity function if not provided.
|
86
|
+
#
|
87
|
+
# NOTE: The lambdas for :property_to_attribute or :attribute_to_property can be 'pure'
|
88
|
+
# or 'impure'. A 'pure' lambda is one that needs only the value to do the conversion,
|
89
|
+
# while an 'impure' lambda is one that requires the provider instance along with the
|
90
|
+
# value. 'Pure' lambdas have the interface 'do |value| ...' while 'impure' lambdas have
|
91
|
+
# the interface 'do |provider, value| ...'.
|
92
|
+
#
|
93
|
+
# NOTE: 'Impure' lambdas are useful in case we need to generate more specific error
|
94
|
+
# messages or pass-in instance-specific command-line arguments.
|
95
|
+
def mapping(info = {})
|
96
|
+
identity_fn = lambda { |x| x }
|
97
|
+
info[:aix_attribute] ||= info[:puppet_property]
|
98
|
+
info[:property_to_attribute] ||= identity_fn
|
99
|
+
info[:attribute_to_property] ||= identity_fn
|
100
|
+
|
101
|
+
mappings[:aix_attribute][info[:puppet_property]] = MappedObject.new(
|
102
|
+
info[:aix_attribute],
|
103
|
+
:convert_property_value,
|
104
|
+
info[:property_to_attribute]
|
105
|
+
)
|
106
|
+
mappings[:puppet_property][info[:aix_attribute]] = MappedObject.new(
|
107
|
+
info[:puppet_property],
|
108
|
+
:convert_attribute_value,
|
109
|
+
info[:attribute_to_property]
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Creates a mapping from a purely numeric Puppet property to
|
114
|
+
# an attribute
|
115
|
+
def numeric_mapping(info = {})
|
116
|
+
property = info[:puppet_property]
|
117
|
+
|
118
|
+
# We have this validation here b/c not all numeric properties
|
119
|
+
# handle this at the property level (e.g. like the UID). Given
|
120
|
+
# that, we might as well go ahead and do this validation for all
|
121
|
+
# of our numeric properties. Doesn't hurt.
|
122
|
+
info[:property_to_attribute] = lambda do |value|
|
123
|
+
unless value.is_a?(Integer)
|
124
|
+
raise ArgumentError, _("Invalid value %{value}: %{property} must be an Integer!") % { value: value, property: property }
|
125
|
+
end
|
126
|
+
|
127
|
+
value.to_s
|
128
|
+
end
|
129
|
+
|
130
|
+
# AIX will do the right validation to ensure numeric attributes
|
131
|
+
# can't be set to non-numeric values, so no need for the extra clutter.
|
132
|
+
info[:attribute_to_property] = lambda do |value|
|
133
|
+
value.to_i
|
134
|
+
end
|
135
|
+
|
136
|
+
mapping(info)
|
137
|
+
end
|
138
|
+
|
139
|
+
#-------------
|
140
|
+
# Useful Class Methods
|
141
|
+
# ------------
|
142
|
+
|
143
|
+
# Defines the getter and setter methods for each Puppet property that's mapped
|
144
|
+
# to an AIX attribute. We define only a getter for the :attributes property.
|
145
|
+
#
|
146
|
+
# Provider subclasses should call this method after they've defined all of
|
147
|
+
# their <puppet_property> => <aix_attribute> mappings.
|
148
|
+
def mk_resource_methods
|
149
|
+
# Define the Getter methods for each of our properties + the attributes
|
150
|
+
# property
|
151
|
+
properties = [:attributes]
|
152
|
+
properties += mappings[:aix_attribute].keys
|
153
|
+
properties.each do |property|
|
154
|
+
# Define the getter
|
155
|
+
define_method(property) do
|
156
|
+
get(property)
|
157
|
+
end
|
158
|
+
|
159
|
+
# We have a custom setter for the :attributes property,
|
160
|
+
# so no need to define it.
|
161
|
+
next if property == :attributes
|
162
|
+
|
163
|
+
# Define the setter
|
164
|
+
define_method("#{property}=".to_sym) do |value|
|
165
|
+
set(property, value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# This helper splits a list separated by sep into its corresponding
|
171
|
+
# items. Note that a key precondition here is that none of the items
|
172
|
+
# in the list contain sep.
|
173
|
+
#
|
174
|
+
# Let A be the return value. Then one of our postconditions is:
|
175
|
+
# A.join(sep) == list
|
176
|
+
#
|
177
|
+
# NOTE: This function is only used by the parse_colon_separated_list
|
178
|
+
# function below. It is meant to be an inner lambda. The reason it isn't
|
179
|
+
# here is so we avoid having to create a proc. object for the split_list
|
180
|
+
# lambda each time parse_colon_separated_list is invoked. This will happen
|
181
|
+
# quite often since it is used at the class level and at the instance level.
|
182
|
+
# Since this function is meant to be an inner lambda and thus not exposed
|
183
|
+
# anywhere else, we do not have any unit tests for it. These test cases are
|
184
|
+
# instead covered by the unit tests for parse_colon_separated_list
|
185
|
+
def split_list(list, sep)
|
186
|
+
return [""] if list.empty?
|
187
|
+
|
188
|
+
list.split(sep, -1)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Parses a colon-separated list. Example includes something like:
|
192
|
+
# <item1>:<item2>:<item3>:<item4>
|
193
|
+
#
|
194
|
+
# Returns an array of the parsed items, e.g.
|
195
|
+
# [ <item1>, <item2>, <item3>, <item4> ]
|
196
|
+
#
|
197
|
+
# Note that colons inside items are escaped by #!
|
198
|
+
def parse_colon_separated_list(colon_list)
|
199
|
+
# ALGORITHM:
|
200
|
+
# Treat the colon_list as a list separated by '#!:' We will get
|
201
|
+
# something like:
|
202
|
+
# [ <chunk1>, <chunk2>, ... <chunkn> ]
|
203
|
+
#
|
204
|
+
# Each chunk is now a list separated by ':' and none of the items
|
205
|
+
# in each chunk contains an escaped ':'. Now, split each chunk on
|
206
|
+
# ':' to get:
|
207
|
+
# [ [<piece11>, ..., <piece1n>], [<piece21>, ..., <piece2n], ... ]
|
208
|
+
#
|
209
|
+
# Now note that <item1> = <piece11>, <item2> = <piece12> in our original
|
210
|
+
# list, and that <itemn> = <piece1n>#!:<piece21>. This is the main idea
|
211
|
+
# behind what our inject method is trying to do at the end, except that
|
212
|
+
# we replace '#!:' with ':' since the colons are no longer escaped.
|
213
|
+
chunks = split_list(colon_list, '#!:')
|
214
|
+
chunks.map! { |chunk| split_list(chunk, ':') }
|
215
|
+
|
216
|
+
chunks.inject do |accum, chunk|
|
217
|
+
left = accum.pop
|
218
|
+
right = chunk.shift
|
219
|
+
|
220
|
+
accum.push("#{left}:#{right}")
|
221
|
+
accum += chunk
|
222
|
+
|
223
|
+
accum
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Parses the AIX objects from the command output, returning an array of
|
228
|
+
# hashes with each hash having the following schema:
|
229
|
+
# {
|
230
|
+
# :name => <object_name>
|
231
|
+
# :attributes => <object_attributes>
|
232
|
+
# }
|
233
|
+
#
|
234
|
+
# Output should be of the form
|
235
|
+
# #name:<attr1>:<attr2> ...
|
236
|
+
# <name>:<value1>:<value2> ...
|
237
|
+
# #name:<attr1>:<attr2> ...
|
238
|
+
# <name>:<value1>:<value2> ...
|
239
|
+
#
|
240
|
+
# NOTE: We need to parse the colon-formatted output in case we have
|
241
|
+
# space-separated attributes (e.g. 'gecos'). ":" characters are escaped
|
242
|
+
# with a "#!".
|
243
|
+
def parse_aix_objects(output)
|
244
|
+
# Object names cannot begin with '#', so we are safe to
|
245
|
+
# split individual users this way. We do not have to worry
|
246
|
+
# about an empty list either since there is guaranteed to be
|
247
|
+
# at least one instance of an AIX object (e.g. at least one
|
248
|
+
# user or one group on the system).
|
249
|
+
_, *objects = output.chomp.split(/^#/)
|
250
|
+
|
251
|
+
objects.map! do |object|
|
252
|
+
attributes_line, values_line = object.chomp.split("\n")
|
253
|
+
|
254
|
+
attributes = parse_colon_separated_list(attributes_line.chomp)
|
255
|
+
attributes.map!(&:to_sym)
|
256
|
+
|
257
|
+
values = parse_colon_separated_list(values_line.chomp)
|
258
|
+
|
259
|
+
attributes_hash = Hash[attributes.zip(values)]
|
260
|
+
|
261
|
+
object_name = attributes_hash.delete(:name)
|
262
|
+
|
263
|
+
Hash[[[:name, object_name.to_s], [:attributes, attributes_hash]]]
|
264
|
+
end
|
265
|
+
|
266
|
+
objects
|
267
|
+
end
|
268
|
+
|
269
|
+
# Lists all instances of the given object, taking in an optional set
|
270
|
+
# of ia_module arguments. Returns an array of hashes, each hash
|
271
|
+
# having the schema
|
272
|
+
# {
|
273
|
+
# :name => <object_name>
|
274
|
+
# :id => <object_id>
|
275
|
+
# }
|
276
|
+
def list_all(ia_module_args = [])
|
277
|
+
cmd = [command(:list), '-c', *ia_module_args, '-a', 'id', 'ALL']
|
278
|
+
parse_aix_objects(execute(cmd)).to_a.map do |object|
|
279
|
+
name = object[:name]
|
280
|
+
id = object[:attributes].delete(:id)
|
281
|
+
|
282
|
+
Hash[[[:name, name,],[:id, id]]]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
#-------------
|
287
|
+
# Provider API
|
288
|
+
# ------------
|
289
|
+
|
290
|
+
def instances
|
291
|
+
list_all.to_a.map! do |object|
|
292
|
+
new({ :name => object[:name] })
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Instantiate our mappings. These need to be at the instance-level
|
298
|
+
# since some of our mapped objects may have impure conversion functions
|
299
|
+
# that need our provider instance.
|
300
|
+
def mappings
|
301
|
+
return @mappings if @mappings
|
302
|
+
|
303
|
+
@mappings = {}
|
304
|
+
self.class.mappings.each do |type, mapped_objects|
|
305
|
+
@mappings[type] = {}
|
306
|
+
mapped_objects.each do |input, mapped_object|
|
307
|
+
if mapped_object.pure_conversion_fn?
|
308
|
+
# Our mapped_object has a pure conversion function so we
|
309
|
+
# can go ahead and use it as-is.
|
310
|
+
@mappings[type][input] = mapped_object
|
311
|
+
next
|
312
|
+
end
|
313
|
+
|
314
|
+
# Otherwise, we need to dup it and set its provider to our
|
315
|
+
# provider instance. The dup is necessary so that we do not
|
316
|
+
# touch the class-level mapped object.
|
317
|
+
@mappings[type][input] = mapped_object.dup
|
318
|
+
@mappings[type][input].set_provider(self)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
@mappings
|
323
|
+
end
|
324
|
+
|
325
|
+
# Converts the given attributes hash to CLI args.
|
326
|
+
def attributes_to_args(attributes)
|
327
|
+
attributes.map do |attribute, value|
|
328
|
+
"#{attribute}=#{value}"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def ia_module_args
|
333
|
+
return [] unless @resource[:ia_load_module]
|
334
|
+
["-R", @resource[:ia_load_module].to_s]
|
335
|
+
end
|
336
|
+
|
337
|
+
def lscmd
|
338
|
+
[self.class.command(:list), '-c'] + ia_module_args + [@resource[:name]]
|
339
|
+
end
|
340
|
+
|
341
|
+
def addcmd(attributes)
|
342
|
+
attribute_args = attributes_to_args(attributes)
|
343
|
+
[self.class.command(:add)] + ia_module_args + attribute_args + [@resource[:name]]
|
344
|
+
end
|
345
|
+
|
346
|
+
def deletecmd
|
347
|
+
[self.class.command(:delete)] + ia_module_args + [@resource[:name]]
|
348
|
+
end
|
349
|
+
|
350
|
+
def modifycmd(new_attributes)
|
351
|
+
attribute_args = attributes_to_args(new_attributes)
|
352
|
+
[self.class.command(:modify)] + ia_module_args + attribute_args + [@resource[:name]]
|
353
|
+
end
|
354
|
+
|
355
|
+
# Modifies the AIX object by setting its new attributes.
|
356
|
+
def modify_object(new_attributes)
|
357
|
+
execute(modifycmd(new_attributes))
|
358
|
+
object_info(true)
|
359
|
+
end
|
360
|
+
|
361
|
+
# Gets a Puppet property's value from object_info
|
362
|
+
def get(property)
|
363
|
+
return :absent unless exists?
|
364
|
+
object_info[property] || :absent
|
365
|
+
end
|
366
|
+
|
367
|
+
# Sets a mapped Puppet property's value.
|
368
|
+
def set(property, value)
|
369
|
+
aix_attribute = mappings[:aix_attribute][property]
|
370
|
+
modify_object(
|
371
|
+
{ aix_attribute.name => aix_attribute.convert_property_value(value) }
|
372
|
+
)
|
373
|
+
rescue Puppet::ExecutionFailure => detail
|
374
|
+
raise Puppet::Error, _("Could not set %{property} on %{resource}[%{name}]: %{detail}") % { property: property, resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
|
375
|
+
end
|
376
|
+
|
377
|
+
# This routine validates our new attributes property value to ensure
|
378
|
+
# that it does not contain any Puppet properties.
|
379
|
+
def validate_new_attributes(new_attributes)
|
380
|
+
# Gather all of the <puppet property>, <aix attribute> conflicts to print
|
381
|
+
# them all out when we create our error message. This makes it easy for the
|
382
|
+
# user to update their manifest based on our error message.
|
383
|
+
conflicts = {}
|
384
|
+
mappings[:aix_attribute].each do |property, aix_attribute|
|
385
|
+
next unless new_attributes.key?(aix_attribute.name)
|
386
|
+
|
387
|
+
conflicts[:properties] ||= []
|
388
|
+
conflicts[:properties].push(property)
|
389
|
+
|
390
|
+
conflicts[:attributes] ||= []
|
391
|
+
conflicts[:attributes].push(aix_attribute.name)
|
392
|
+
end
|
393
|
+
|
394
|
+
return if conflicts.empty?
|
395
|
+
|
396
|
+
properties, attributes = conflicts.keys.map do |key|
|
397
|
+
conflicts[key].map! { |name| "'#{name}'" }.join(', ')
|
398
|
+
end
|
399
|
+
|
400
|
+
detail = _("attributes is setting the %{properties} properties via. the %{attributes} attributes, respectively! Please specify these property values in the resource declaration instead.") % { properties: properties, attributes: attributes }
|
401
|
+
|
402
|
+
raise Puppet::Error, _("Could not set attributes on %{resource}[%{name}]: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }
|
403
|
+
end
|
404
|
+
|
405
|
+
# Modifies the attribute property. Note we raise an error if the user specified
|
406
|
+
# an AIX attribute corresponding to a Puppet property.
|
407
|
+
def attributes=(new_attributes)
|
408
|
+
validate_new_attributes(new_attributes)
|
409
|
+
modify_object(new_attributes)
|
410
|
+
rescue Puppet::ExecutionFailure => detail
|
411
|
+
raise Puppet::Error, _("Could not set attributes on %{resource}[%{name}]: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
|
412
|
+
end
|
413
|
+
|
414
|
+
# Collects the current property values of all mapped properties +
|
415
|
+
# the attributes property.
|
416
|
+
def object_info(refresh = false)
|
417
|
+
return @object_info if @object_info && ! refresh
|
418
|
+
@object_info = nil
|
419
|
+
|
420
|
+
begin
|
421
|
+
output = execute(lscmd)
|
422
|
+
rescue Puppet::ExecutionFailure
|
423
|
+
Puppet.debug(_("aix.object_info(): Could not find %{resource}[%{name}]") % { resource: @resource.class.name, name: @resource.name })
|
424
|
+
|
425
|
+
return @object_info
|
426
|
+
end
|
427
|
+
|
428
|
+
# If lscmd succeeds, then output will contain our object's information.
|
429
|
+
# Thus, .parse_aix_objects will always return a single element array.
|
430
|
+
aix_attributes = self.class.parse_aix_objects(output).first[:attributes]
|
431
|
+
aix_attributes.each do |attribute, value|
|
432
|
+
@object_info ||= {}
|
433
|
+
|
434
|
+
# If our attribute has a Puppet property, then we store that. Else, we store it as part
|
435
|
+
# of our :attributes property hash
|
436
|
+
if (property = mappings[:puppet_property][attribute])
|
437
|
+
@object_info[property.name] = property.convert_attribute_value(value)
|
438
|
+
else
|
439
|
+
@object_info[:attributes] ||= {}
|
440
|
+
@object_info[:attributes][attribute] = value
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
@object_info
|
445
|
+
end
|
446
|
+
|
447
|
+
#-------------
|
448
|
+
# Methods that manage the ensure property
|
449
|
+
# ------------
|
450
|
+
|
451
|
+
# Check that the AIX object exists
|
452
|
+
def exists?
|
453
|
+
! object_info.nil?
|
454
|
+
end
|
455
|
+
|
456
|
+
# Creates a new instance of the resource
|
457
|
+
def create
|
458
|
+
attributes = @resource.should(:attributes) || {}
|
459
|
+
validate_new_attributes(attributes)
|
460
|
+
|
461
|
+
mappings[:aix_attribute].each do |property, aix_attribute|
|
462
|
+
property_should = @resource.should(property)
|
463
|
+
next if property_should.nil?
|
464
|
+
attributes[aix_attribute.name] = aix_attribute.convert_property_value(property_should)
|
465
|
+
end
|
466
|
+
|
467
|
+
execute(addcmd(attributes))
|
468
|
+
rescue Puppet::ExecutionFailure => detail
|
469
|
+
raise Puppet::Error, _("Could not create %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
|
470
|
+
end
|
471
|
+
|
472
|
+
# Deletes this instance resource
|
473
|
+
def delete
|
474
|
+
execute(deletecmd)
|
475
|
+
|
476
|
+
# Recollect the object info so that our current properties reflect
|
477
|
+
# the actual state of the system. Otherwise, puppet resource reports
|
478
|
+
# the wrong info. at the end. Note that this should return nil.
|
479
|
+
object_info(true)
|
480
|
+
rescue Puppet::ExecutionFailure => detail
|
481
|
+
raise Puppet::Error, _("Could not delete %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
|
482
|
+
end
|
483
|
+
end
|