puppet 5.5.6-x86-mingw32 → 5.5.7-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/Gemfile.lock +12 -12
- data/Rakefile +9 -0
- data/lib/puppet/application.rb +5 -0
- data/lib/puppet/application/apply.rb +1 -0
- data/lib/puppet/application/master.rb +9 -7
- data/lib/puppet/application/script.rb +1 -1
- data/lib/puppet/defaults.rb +51 -31
- data/lib/puppet/etc.rb +20 -0
- data/lib/puppet/file_serving/fileset.rb +1 -1
- data/lib/puppet/functions.rb +123 -0
- data/lib/puppet/functions/new.rb +37 -53
- data/lib/puppet/functions/warning.rb +1 -1
- data/lib/puppet/loaders.rb +1 -0
- data/lib/puppet/parser/functions.rb +3 -1
- data/lib/puppet/parser/functions/sprintf.rb +12 -1
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +16 -0
- data/lib/puppet/pops/evaluator/runtime3_support.rb +3 -4
- data/lib/puppet/pops/issues.rb +8 -0
- data/lib/puppet/pops/loader/loader.rb +2 -2
- data/lib/puppet/pops/loader/loader_paths.rb +3 -1
- data/lib/puppet/pops/loader/module_loaders.rb +1 -1
- data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +62 -0
- data/lib/puppet/pops/loaders.rb +5 -21
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
- data/lib/puppet/pops/parser/lexer2.rb +1 -1
- data/lib/puppet/pops/validation/checker4_0.rb +31 -6
- data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
- data/lib/puppet/property/keyvalue.rb +70 -8
- data/lib/puppet/provider/aix_object.rb +483 -0
- data/lib/puppet/provider/exec.rb +54 -57
- data/lib/puppet/provider/group/aix.rb +40 -115
- data/lib/puppet/provider/group/pw.rb +4 -8
- data/lib/puppet/provider/group/windows_adsi.rb +7 -4
- data/lib/puppet/provider/nameservice.rb +1 -25
- data/lib/puppet/provider/nameservice/directoryservice.rb +5 -3
- data/lib/puppet/provider/package/portage.rb +2 -2
- data/lib/puppet/provider/package/windows.rb +2 -2
- data/lib/puppet/provider/package/windows/exe_package.rb +3 -10
- data/lib/puppet/provider/package/zypper.rb +1 -1
- data/lib/puppet/provider/service/launchd.rb +19 -3
- data/lib/puppet/provider/service/windows.rb +49 -40
- data/lib/puppet/provider/user/aix.rb +180 -246
- data/lib/puppet/provider/user/windows_adsi.rb +9 -1
- data/lib/puppet/resource/catalog.rb +1 -5
- data/lib/puppet/type/augeas.rb +1 -1
- data/lib/puppet/type/exec.rb +16 -14
- data/lib/puppet/type/file.rb +2 -2
- data/lib/puppet/type/file/source.rb +9 -5
- data/lib/puppet/type/group.rb +65 -23
- data/lib/puppet/type/k5login.rb +2 -2
- data/lib/puppet/type/notify.rb +1 -1
- data/lib/puppet/type/package.rb +3 -6
- data/lib/puppet/type/resources.rb +12 -2
- data/lib/puppet/type/schedule.rb +8 -1
- data/lib/puppet/type/selboolean.rb +2 -2
- data/lib/puppet/type/selmodule.rb +3 -4
- data/lib/puppet/type/service.rb +2 -5
- data/lib/puppet/type/tidy.rb +1 -1
- data/lib/puppet/type/user.rb +15 -20
- data/lib/puppet/type/yumrepo.rb +2 -2
- data/lib/puppet/type/zone.rb +2 -2
- data/lib/puppet/util.rb +7 -3
- data/lib/puppet/util/execution.rb +15 -1
- data/lib/puppet/util/posix.rb +15 -0
- data/lib/puppet/util/storage.rb +12 -0
- data/lib/puppet/util/windows.rb +4 -2
- data/lib/puppet/util/windows/adsi.rb +235 -205
- data/lib/puppet/util/windows/process.rb +23 -3
- data/lib/puppet/util/windows/security.rb +14 -0
- data/lib/puppet/util/windows/service.rb +977 -0
- data/lib/puppet/util/windows/user.rb +3 -5
- data/lib/puppet/version.rb +1 -1
- data/locales/ja/puppet.po +705 -374
- data/locales/puppet.pot +485 -261
- data/man/man5/puppet.conf.5 +36 -15
- data/man/man8/puppet-agent.8 +1 -1
- data/man/man8/puppet-apply.8 +1 -1
- data/man/man8/puppet-ca.8 +1 -1
- data/man/man8/puppet-catalog.8 +1 -1
- data/man/man8/puppet-cert.8 +1 -1
- data/man/man8/puppet-certificate.8 +1 -1
- data/man/man8/puppet-certificate_request.8 +1 -1
- data/man/man8/puppet-certificate_revocation_list.8 +1 -1
- data/man/man8/puppet-config.8 +1 -1
- data/man/man8/puppet-describe.8 +1 -1
- data/man/man8/puppet-device.8 +1 -1
- data/man/man8/puppet-doc.8 +1 -1
- data/man/man8/puppet-epp.8 +1 -1
- data/man/man8/puppet-facts.8 +1 -1
- data/man/man8/puppet-filebucket.8 +1 -1
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +1 -1
- data/man/man8/puppet-key.8 +1 -1
- data/man/man8/puppet-lookup.8 +1 -1
- data/man/man8/puppet-man.8 +1 -1
- data/man/man8/puppet-master.8 +1 -1
- data/man/man8/puppet-module.8 +1 -1
- data/man/man8/puppet-node.8 +1 -1
- data/man/man8/puppet-parser.8 +1 -1
- data/man/man8/puppet-plugin.8 +1 -1
- data/man/man8/puppet-report.8 +1 -1
- data/man/man8/puppet-resource.8 +1 -1
- data/man/man8/puppet-script.8 +1 -1
- data/man/man8/puppet-status.8 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/fixtures/unit/provider/aix_object/aix_colon_list_real_world_input.out +1 -0
- data/spec/fixtures/unit/provider/aix_object/aix_colon_list_real_world_output.out +1 -0
- data/spec/fixtures/unit/provider/user/aix/aix_passwd_file.out +32 -0
- data/spec/integration/parser/collection_spec.rb +4 -8
- data/spec/integration/provider/service/windows_spec.rb +5 -5
- data/spec/integration/type/file_spec.rb +6 -6
- data/spec/integration/util/windows/adsi_spec.rb +6 -5
- data/spec/integration/util/windows/security_spec.rb +10 -7
- data/spec/integration/util/windows/user_spec.rb +37 -17
- data/spec/spec_helper.rb +0 -1
- data/spec/unit/application/apply_spec.rb +41 -2
- data/spec/unit/application/master_spec.rb +7 -0
- data/spec/unit/application_spec.rb +21 -3
- data/spec/unit/defaults_spec.rb +20 -0
- data/spec/unit/etc_spec.rb +25 -0
- data/spec/unit/file_serving/fileset_spec.rb +11 -11
- data/spec/unit/gettext/config_spec.rb +1 -1
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +6 -6
- data/spec/unit/pops/loaders/loaders_spec.rb +40 -7
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
- data/spec/unit/pops/validator/validator_spec.rb +129 -10
- data/spec/unit/property/keyvalue_spec.rb +97 -6
- data/spec/unit/provider/aix_object_spec.rb +805 -0
- data/spec/unit/provider/group/aix_spec.rb +57 -0
- data/spec/unit/provider/group/pw_spec.rb +0 -6
- data/spec/unit/provider/group/windows_adsi_spec.rb +34 -35
- data/spec/unit/provider/nameservice/directoryservice_spec.rb +2 -2
- data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
- data/spec/unit/provider/package/windows_spec.rb +4 -4
- data/spec/unit/provider/service/launchd_spec.rb +19 -0
- data/spec/unit/provider/service/windows_spec.rb +71 -78
- data/spec/unit/provider/user/aix_spec.rb +162 -116
- data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
- data/spec/unit/resource/catalog_spec.rb +2 -2
- data/spec/unit/ssl/certificate_authority_spec.rb +0 -1
- data/spec/unit/type/group_spec.rb +111 -13
- data/spec/unit/type/resources_spec.rb +18 -0
- data/spec/unit/util/execution_spec.rb +77 -0
- data/spec/unit/util/posix_spec.rb +28 -0
- data/spec/unit/util/storage_spec.rb +107 -0
- data/spec/unit/util/windows/adsi_spec.rb +108 -13
- data/spec/unit/util/windows/service_spec.rb +669 -0
- metadata +17 -5
- data/lib/puppet/provider/aixobject.rb +0 -392
- data/spec/unit/provider/aixobject_spec.rb +0 -101
@@ -31,7 +31,7 @@ module ModuleLoaders
|
|
31
31
|
nil,
|
32
32
|
puppet_lib, # may or may not have a 'lib' above 'puppet'
|
33
33
|
'puppet_system',
|
34
|
-
[:func_4x, :datatype] # only load ruby functions and types from "puppet"
|
34
|
+
[:func_4x, :func_3x, :datatype] # only load ruby functions and types from "puppet"
|
35
35
|
)
|
36
36
|
end
|
37
37
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# The RubyLegacyFunctionInstantiator instantiates a Puppet::Functions::Function given the ruby source
|
2
|
+
# that calls Puppet::Functions.create_function.
|
3
|
+
#
|
4
|
+
class Puppet::Pops::Loader::RubyLegacyFunctionInstantiator
|
5
|
+
# Produces an instance of the Function class with the given typed_name, or fails with an error if the
|
6
|
+
# given ruby source does not produce this instance when evaluated.
|
7
|
+
#
|
8
|
+
# @param loader [Puppet::Pops::Loader::Loader] The loader the function is associated with
|
9
|
+
# @param typed_name [Puppet::Pops::Loader::TypedName] the type / name of the function to load
|
10
|
+
# @param source_ref [URI, String] a reference to the source / origin of the ruby code to evaluate
|
11
|
+
# @param ruby_code_string [String] ruby code in a string
|
12
|
+
#
|
13
|
+
# @return [Puppet::Pops::Functions.Function] - an instantiated function with global scope closure associated with the given loader
|
14
|
+
#
|
15
|
+
def self.create(loader, typed_name, source_ref, ruby_code_string)
|
16
|
+
unless ruby_code_string.is_a?(String) && ruby_code_string =~ /Puppet\:\:Parser\:\:Functions.*newfunction/m
|
17
|
+
raise ArgumentError, _("The code loaded from %{source_ref} does not seem to be a Puppet 3x API function - no 'newfunction' call.") % { source_ref: source_ref }
|
18
|
+
end
|
19
|
+
# make the private loader available in a binding to allow it to be passed on
|
20
|
+
loader_for_function = loader.private_loader
|
21
|
+
here = get_binding(loader_for_function)
|
22
|
+
|
23
|
+
# Avoid reloading the function if already loaded via one of the APIs that trigger 3x function loading
|
24
|
+
# Check if function is already loaded the 3x way (and obviously not the 4x way since we would not be here in the
|
25
|
+
# first place.
|
26
|
+
environment = Puppet.lookup(:current_environment)
|
27
|
+
func_info = Puppet::Parser::Functions.environment_module(environment).get_function_info(typed_name.name.to_sym)
|
28
|
+
if func_info.nil?
|
29
|
+
# This will to do the 3x loading and define the "function_<name>" and "real_function_<name>" methods
|
30
|
+
# in the anonymous module used to hold function definitions.
|
31
|
+
#
|
32
|
+
func_info = eval(ruby_code_string, here, source_ref, 1)
|
33
|
+
|
34
|
+
# Validate what was loaded
|
35
|
+
unless func_info.is_a?(Hash)
|
36
|
+
raise ArgumentError, _("The code loaded from %{source_ref} did not produce the expected 3x function info Hash when evaluated. Got '%{klass}'") % { source_ref: source_ref, klass: created.class }
|
37
|
+
end
|
38
|
+
unless func_info[:name] == "function_#{typed_name.name()}"
|
39
|
+
raise ArgumentError, _("The code loaded from %{source_ref} produced mis-matched name, expected 'function_%{type_name}', got %{created_name}") % {
|
40
|
+
source_ref: source_ref, type_name: typed_name.name, created_name: func_info[:name] }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
created = Puppet::Functions::Function3x.create_function(typed_name.name(), func_info, loader_for_function)
|
45
|
+
|
46
|
+
# create the function instance - it needs closure (scope), and loader (i.e. where it should start searching for things
|
47
|
+
# when calling functions etc.
|
48
|
+
# It should be bound to global scope
|
49
|
+
|
50
|
+
# Sets closure scope to nil, to let it be picked up at runtime from Puppet.lookup(:global_scope)
|
51
|
+
# If function definition used the loader from the binding to create a new loader, that loader wins
|
52
|
+
created.new(nil, loader_for_function)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Produces a binding where the given loader is bound as a local variable (loader_injected_arg). This variable can be used in loaded
|
56
|
+
# ruby code - e.g. to call Puppet::Function.create_loaded_function(:name, loader,...)
|
57
|
+
#
|
58
|
+
def self.get_binding(loader_injected_arg)
|
59
|
+
binding
|
60
|
+
end
|
61
|
+
private_class_method :get_binding
|
62
|
+
end
|
data/lib/puppet/pops/loaders.rb
CHANGED
@@ -505,8 +505,8 @@ class Loaders
|
|
505
505
|
nil
|
506
506
|
else
|
507
507
|
module_data.private_loader =
|
508
|
-
if module_data.restrict_to_dependencies?
|
509
|
-
|
508
|
+
if module_data.restrict_to_dependencies?
|
509
|
+
create_loader_with_dependencies_first(module_data)
|
510
510
|
else
|
511
511
|
create_loader_with_all_modules_visible(module_data)
|
512
512
|
end
|
@@ -516,29 +516,13 @@ class Loaders
|
|
516
516
|
private
|
517
517
|
|
518
518
|
def create_loader_with_all_modules_visible(from_module_data)
|
519
|
-
Puppet.debug{"ModuleLoader: module '#{from_module_data.name}' has unknown dependencies - it will have all other modules visible"}
|
520
|
-
|
521
519
|
@loaders.add_loader_by_name(Loader::DependencyLoader.new(from_module_data.public_loader, "#{from_module_data.name} private", all_module_loaders()))
|
522
520
|
end
|
523
521
|
|
524
|
-
def
|
525
|
-
if from_module_data.unmet_dependencies?
|
526
|
-
if Puppet[:strict] != :off
|
527
|
-
msg = "ModuleLoader: module '#{from_module_data.name}' has unresolved dependencies" \
|
528
|
-
" - it will only see those that are resolved." \
|
529
|
-
" Use 'puppet module list --tree' to see information about modules"
|
530
|
-
case Puppet[:strict]
|
531
|
-
when :error
|
532
|
-
raise LoaderError.new(msg)
|
533
|
-
when :warning
|
534
|
-
Puppet.warn_once(:unresolved_module_dependencies,
|
535
|
-
"unresolved_dependencies_for_module_#{from_module_data.name}",
|
536
|
-
msg)
|
537
|
-
end
|
538
|
-
end
|
539
|
-
end
|
522
|
+
def create_loader_with_dependencies_first(from_module_data)
|
540
523
|
dependency_loaders = from_module_data.dependency_names.collect { |name| @index[name].public_loader }
|
541
|
-
|
524
|
+
visible_loaders = dependency_loaders + (all_module_loaders() - dependency_loaders)
|
525
|
+
@loaders.add_loader_by_name(Loader::DependencyLoader.new(from_module_data.public_loader, "#{from_module_data.name} private", visible_loaders))
|
542
526
|
end
|
543
527
|
end
|
544
528
|
end
|
@@ -98,8 +98,7 @@ module HeredocSupport
|
|
98
98
|
|
99
99
|
# Use a new lexer instance configured with a sub-locator to enable correct positioning
|
100
100
|
sublexer = self.class.new()
|
101
|
-
locator = Locator::SubLocator.
|
102
|
-
locator.file, heredoc_line, heredoc_offset, leading.length())
|
101
|
+
locator = Locator::SubLocator.new(locator, heredoc_line, heredoc_offset, leading.length())
|
103
102
|
|
104
103
|
# Emit a token that provides the grammar with location information about the lines on which the heredoc
|
105
104
|
# content is based.
|
@@ -189,7 +189,7 @@ class Lexer2
|
|
189
189
|
',' => lambda { emit(TOKEN_COMMA, @scanner.pos) },
|
190
190
|
'[' => lambda do
|
191
191
|
before = @scanner.pos
|
192
|
-
if (before == 0 ||
|
192
|
+
if (before == 0 || locator.string[locator.char_offset(before)-1,1] =~ /[[:blank:]\r\n]+/)
|
193
193
|
emit(TOKEN_LISTSTART, before)
|
194
194
|
else
|
195
195
|
emit(TOKEN_LBRACK, before)
|
@@ -48,6 +48,7 @@ class Checker4_0 < Evaluator::LiteralEvaluator
|
|
48
48
|
# tree iterate the model, and call check for each element
|
49
49
|
@path = []
|
50
50
|
check(model)
|
51
|
+
internal_check_top_construct_in_module(model)
|
51
52
|
model._pcore_all_contents(@path) { |element| check(element) }
|
52
53
|
end
|
53
54
|
|
@@ -396,7 +397,7 @@ class Checker4_0 < Evaluator::LiteralEvaluator
|
|
396
397
|
acceptor.accept(Issues::ILLEGAL_DEFINITION_NAME, o, {:name=>o.name})
|
397
398
|
end
|
398
399
|
|
399
|
-
internal_check_file_namespace(o
|
400
|
+
internal_check_file_namespace(o)
|
400
401
|
internal_check_reserved_type_name(o, o.name)
|
401
402
|
internal_check_future_reserved_word(o, o.name)
|
402
403
|
end
|
@@ -535,18 +536,42 @@ class Checker4_0 < Evaluator::LiteralEvaluator
|
|
535
536
|
NO_NAMESPACE = :no_namespace
|
536
537
|
NO_PATH = :no_path
|
537
538
|
BAD_MODULE_FILE = :bad_module_file
|
538
|
-
|
539
|
+
|
540
|
+
def internal_check_file_namespace(o)
|
541
|
+
file = o.locator.file
|
539
542
|
return if file.nil? || file == '' #e.g. puppet apply -e '...'
|
540
543
|
|
541
544
|
file_namespace = namespace_for_file(file)
|
542
545
|
return if file_namespace == NO_NAMESPACE
|
543
546
|
|
544
547
|
# Downcasing here because check is case-insensitive
|
545
|
-
if file_namespace == BAD_MODULE_FILE || !name.downcase.start_with?(file_namespace)
|
546
|
-
acceptor.accept(Issues::ILLEGAL_DEFINITION_LOCATION, o, {:name => name, :file => file})
|
548
|
+
if file_namespace == BAD_MODULE_FILE || !o.name.downcase.start_with?(file_namespace)
|
549
|
+
acceptor.accept(Issues::ILLEGAL_DEFINITION_LOCATION, o, {:name => o.name, :file => file})
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
def internal_check_top_construct_in_module(prog)
|
554
|
+
return unless prog.is_a?(Model::Program) && !prog.body.nil?
|
555
|
+
|
556
|
+
#Check that this is a module autoloaded file
|
557
|
+
file = prog.locator.file
|
558
|
+
return if file.nil?
|
559
|
+
return if namespace_for_file(file) == NO_NAMESPACE
|
560
|
+
|
561
|
+
body = prog.body
|
562
|
+
return if prog.body.is_a?(Model::Nop) #Ignore empty or comment-only files
|
563
|
+
|
564
|
+
if(body.is_a?(Model::BlockExpression))
|
565
|
+
body.statements.each { |s| acceptor.accept(Issues::ILLEGAL_TOP_CONSTRUCT_LOCATION, s) unless valid_top_construct?(s) }
|
566
|
+
else
|
567
|
+
acceptor.accept(Issues::ILLEGAL_TOP_CONSTRUCT_LOCATION, body) unless valid_top_construct?(body)
|
547
568
|
end
|
548
569
|
end
|
549
570
|
|
571
|
+
def valid_top_construct?(o)
|
572
|
+
o.is_a?(Model::Definition) && !o.is_a?(Model::NodeDefinition)
|
573
|
+
end
|
574
|
+
|
550
575
|
# @api private
|
551
576
|
class Puppet::Util::FileNamespaceAdapter < Puppet::Pops::Adaptable::Adapter
|
552
577
|
attr_accessor :file_to_namespace
|
@@ -600,9 +625,9 @@ class Checker4_0 < Evaluator::LiteralEvaluator
|
|
600
625
|
|
601
626
|
def is_parent_dir_of(parent_dir, child_dir)
|
602
627
|
parent_dir_path = Pathname.new(parent_dir)
|
603
|
-
clean_parent = parent_dir_path.cleanpath
|
628
|
+
clean_parent = parent_dir_path.cleanpath.to_s + File::SEPARATOR
|
604
629
|
|
605
|
-
return child_dir.to_s.start_with?(clean_parent
|
630
|
+
return child_dir.to_s.start_with?(clean_parent)
|
606
631
|
end
|
607
632
|
|
608
633
|
def dir_to_names(relative_path)
|
@@ -37,6 +37,7 @@ class ValidatorFactory_4_0 < Factory
|
|
37
37
|
p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :ignore
|
38
38
|
p[Issues::CLASS_NOT_VIRTUALIZABLE] = Puppet[:strict] == :off ? :warning : Puppet[:strict]
|
39
39
|
p[Issues::ILLEGAL_DEFINITION_LOCATION] = :deprecation
|
40
|
+
p[Issues::ILLEGAL_TOP_CONSTRUCT_LOCATION] = :deprecation
|
40
41
|
p
|
41
42
|
end
|
42
43
|
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
|