puppet 6.0.0 → 6.0.1
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.lock +4 -4
- data/lib/puppet/application/apply.rb +99 -59
- data/lib/puppet/application/cert.rb +2 -112
- data/lib/puppet/configurer.rb +2 -3
- data/lib/puppet/defaults.rb +14 -1
- data/lib/puppet/etc.rb +20 -0
- data/lib/puppet/module/task.rb +29 -38
- data/lib/puppet/parser/catalog_compiler.rb +24 -0
- data/lib/puppet/parser/compiler.rb +3 -1
- data/lib/puppet/pops/evaluator/deferred_resolver.rb +3 -0
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +2 -2
- data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +18 -10
- data/lib/puppet/pops/loader/task_instantiator.rb +13 -70
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
- data/lib/puppet/pops/parser/lexer2.rb +1 -1
- data/lib/puppet/pops/pcore.rb +10 -33
- data/lib/puppet/pops/serialization.rb +1 -0
- data/lib/puppet/pops/serialization/to_data_converter.rb +9 -1
- data/lib/puppet/provider/exec.rb +57 -57
- data/lib/puppet/provider/group/aix.rb +1 -15
- 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/service/launchd.rb +19 -3
- data/lib/puppet/provider/user/aix.rb +48 -2
- data/lib/puppet/type/group.rb +62 -18
- data/lib/puppet/type/schedule.rb +7 -0
- data/lib/puppet/util/execution.rb +14 -1
- data/lib/puppet/util/posix.rb +15 -0
- data/lib/puppet/util/storage.rb +12 -0
- data/lib/puppet/util/windows/adsi.rb +60 -1
- data/lib/puppet/util/windows/process.rb +16 -1
- data/lib/puppet/util/windows/service.rb +68 -26
- data/lib/puppet/version.rb +1 -1
- data/lib/puppet_pal.rb +36 -3
- data/locales/ja/puppet.po +598 -861
- data/locales/puppet.pot +197 -160
- data/man/man5/puppet.conf.5 +12 -1
- data/man/man8/puppet.8 +1 -1
- data/spec/integration/application/apply_spec.rb +4 -1
- data/spec/integration/util/windows/adsi_spec.rb +2 -1
- data/spec/unit/application/apply_spec.rb +14 -0
- data/spec/unit/configurer_spec.rb +11 -0
- data/spec/unit/etc_spec.rb +25 -0
- data/spec/unit/indirector/catalog/json_spec.rb +9 -3
- data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +22 -4
- data/spec/unit/pops/loaders/loader_spec.rb +3 -10
- data/spec/unit/pops/loaders/loaders_spec.rb +30 -0
- data/spec/unit/pops/loaders/module_loaders_spec.rb +7 -7
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
- data/spec/unit/pops/serialization/to_from_hr_spec.rb +9 -0
- data/spec/unit/pops/types/task_spec.rb +42 -116
- data/spec/unit/provider/group/aix_spec.rb +0 -19
- 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/service/launchd_spec.rb +19 -0
- data/spec/unit/provider/user/aix_spec.rb +43 -2
- data/spec/unit/provider/user/windows_adsi_spec.rb +1 -4
- data/spec/unit/puppet_pal_2pec.rb +6 -6
- data/spec/unit/puppet_pal_catalog_spec.rb +58 -0
- data/spec/unit/task_spec.rb +50 -5
- data/spec/unit/type/group_spec.rb +111 -13
- data/spec/unit/util/execution_spec.rb +59 -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 +100 -5
- data/spec/unit/util/windows/service_spec.rb +100 -43
- metadata +2 -2
data/lib/puppet/provider/exec.rb
CHANGED
@@ -4,71 +4,71 @@ require 'puppet/util/execution'
|
|
4
4
|
class Puppet::Provider::Exec < Puppet::Provider
|
5
5
|
include Puppet::Util::Execution
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
sensitive = resource.parameters[:command].sensitive
|
7
|
+
def environment
|
8
|
+
env = {}
|
10
9
|
|
11
|
-
|
10
|
+
if (path = resource[:path])
|
11
|
+
env[:PATH] = path.join(File::PATH_SEPARATOR)
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
return env unless (envlist = resource[:environment])
|
15
|
+
|
16
|
+
envlist = [envlist] unless envlist.is_a? Array
|
17
|
+
envlist.each do |setting|
|
18
|
+
unless (match = /^(\w+)=((.|\n)+)$/.match(setting))
|
19
|
+
warning _("Cannot understand environment setting %{setting}") % { setting: setting.inspect }
|
20
|
+
next
|
21
|
+
end
|
22
|
+
var = match[1]
|
23
|
+
value = match[2]
|
24
|
+
|
25
|
+
if env.include?(var) || env.include?(var.to_sym)
|
26
|
+
warning _("Overriding environment setting '%{var}' with '%{value}'") % { var: var, value: value }
|
20
27
|
end
|
28
|
+
|
29
|
+
env[var] = value
|
21
30
|
end
|
22
31
|
|
23
|
-
|
32
|
+
env
|
33
|
+
end
|
34
|
+
|
35
|
+
def run(command, check = false)
|
36
|
+
output = nil
|
37
|
+
sensitive = resource.parameters[:command].sensitive
|
38
|
+
|
39
|
+
checkexe(command)
|
24
40
|
|
25
41
|
debug "Executing#{check ? " check": ""} '#{sensitive ? '[redacted]' : command}'"
|
26
|
-
begin
|
27
|
-
# Do our chdir
|
28
|
-
Dir.chdir(dir) do
|
29
|
-
environment = {}
|
30
|
-
|
31
|
-
environment[:PATH] = resource[:path].join(File::PATH_SEPARATOR) if resource[:path]
|
32
|
-
|
33
|
-
if envlist = resource[:environment]
|
34
|
-
envlist = [envlist] unless envlist.is_a? Array
|
35
|
-
envlist.each do |setting|
|
36
|
-
if setting =~ /^(\w+)=((.|\n)+)$/
|
37
|
-
env_name = $1
|
38
|
-
value = $2
|
39
|
-
if environment.include?(env_name) || environment.include?(env_name.to_sym)
|
40
|
-
warning _("Overriding environment setting '%{env_name}' with '%{value}'") % { env_name: env_name, value: value }
|
41
|
-
end
|
42
|
-
environment[env_name] = value
|
43
|
-
else
|
44
|
-
warning _("Cannot understand environment setting %{setting}") % { setting: setting.inspect }
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Ruby 2.1 and later interrupt execution in a way that bypasses error
|
50
|
-
# handling by default. Passing Timeout::Error causes an exception to be
|
51
|
-
# raised that can be rescued inside of the block by cleanup routines.
|
52
|
-
#
|
53
|
-
# This is backwards compatible all the way to Ruby 1.8.7.
|
54
|
-
Timeout::timeout(resource[:timeout], Timeout::Error) do
|
55
|
-
# note that we are passing "false" for the "override_locale" parameter, which ensures that the user's
|
56
|
-
# default/system locale will be respected. Callers may override this behavior by setting locale-related
|
57
|
-
# environment variables (LANG, LC_ALL, etc.) in their 'environment' configuration.
|
58
|
-
output = Puppet::Util::Execution.execute(command, :failonfail => false, :combine => true,
|
59
|
-
:uid => resource[:user], :gid => resource[:group],
|
60
|
-
:override_locale => false,
|
61
|
-
:custom_environment => environment,
|
62
|
-
:sensitive => sensitive)
|
63
|
-
end
|
64
|
-
# The shell returns 127 if the command is missing.
|
65
|
-
if output.exitstatus == 127
|
66
|
-
raise ArgumentError, output
|
67
|
-
end
|
68
42
|
|
69
|
-
|
70
|
-
|
71
|
-
|
43
|
+
# Ruby 2.1 and later interrupt execution in a way that bypasses error
|
44
|
+
# handling by default. Passing Timeout::Error causes an exception to be
|
45
|
+
# raised that can be rescued inside of the block by cleanup routines.
|
46
|
+
#
|
47
|
+
# This is backwards compatible all the way to Ruby 1.8.7.
|
48
|
+
Timeout::timeout(resource[:timeout], Timeout::Error) do
|
49
|
+
# If we're running a command that's meant to be a check on whether we should run
|
50
|
+
# our actual command (e.g. like a command passed to the :onlyif or :unless properties),
|
51
|
+
# then we should not set the cwd when executing the check's corresponding command.
|
52
|
+
cwd = check ? nil : resource[:cwd]
|
53
|
+
cwd ||= Dir.pwd
|
54
|
+
|
55
|
+
# note that we are passing "false" for the "override_locale" parameter, which ensures that the user's
|
56
|
+
# default/system locale will be respected. Callers may override this behavior by setting locale-related
|
57
|
+
# environment variables (LANG, LC_ALL, etc.) in their 'environment' configuration.
|
58
|
+
output = Puppet::Util::Execution.execute(
|
59
|
+
command,
|
60
|
+
:failonfail => false,
|
61
|
+
:combine => true,
|
62
|
+
:cwd => cwd,
|
63
|
+
:uid => resource[:user], :gid => resource[:group],
|
64
|
+
:override_locale => false,
|
65
|
+
:custom_environment => environment(),
|
66
|
+
:sensitive => sensitive
|
67
|
+
)
|
68
|
+
end
|
69
|
+
# The shell returns 127 if the command is missing.
|
70
|
+
if output.exitstatus == 127
|
71
|
+
raise ArgumentError, output
|
72
72
|
end
|
73
73
|
|
74
74
|
# Return output twice as processstatus was returned before, but only exitstatus was ever called.
|
@@ -53,24 +53,10 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
|
|
53
53
|
|
54
54
|
group_hash
|
55
55
|
end
|
56
|
-
|
57
|
-
# Define some Puppet Property => AIX Attribute (and vice versa)
|
58
|
-
# conversion functions here. This is so we can unit test them.
|
59
|
-
|
60
|
-
def members_to_users(members)
|
61
|
-
return members unless members.is_a?(Array)
|
62
|
-
members.join(',')
|
63
|
-
end
|
64
|
-
|
65
|
-
def users_to_members(users)
|
66
|
-
users.split(',')
|
67
|
-
end
|
68
56
|
end
|
69
57
|
|
70
58
|
mapping puppet_property: :members,
|
71
|
-
aix_attribute: :users
|
72
|
-
property_to_attribute: method(:members_to_users),
|
73
|
-
attribute_to_property: method(:users_to_members)
|
59
|
+
aix_attribute: :users
|
74
60
|
|
75
61
|
numeric_mapping puppet_property: :gid,
|
76
62
|
aix_attribute: :id
|
@@ -9,7 +9,10 @@ Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService:
|
|
9
9
|
defaultfor :operatingsystem => [:freebsd, :dragonfly]
|
10
10
|
confine :operatingsystem => [:freebsd, :dragonfly]
|
11
11
|
|
12
|
-
options :members,
|
12
|
+
options :members,
|
13
|
+
:flag => "-M",
|
14
|
+
:method => :mem,
|
15
|
+
:unmunge => proc { |members| members.join(',') }
|
13
16
|
|
14
17
|
verify :gid, _("GID must be an integer") do |value|
|
15
18
|
value.is_a? Integer
|
@@ -26,9 +29,6 @@ Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService:
|
|
26
29
|
|
27
30
|
if members = @resource.should(:members)
|
28
31
|
unless members == :absent
|
29
|
-
if members.is_a?(Array)
|
30
|
-
members = members.join(",")
|
31
|
-
end
|
32
32
|
cmd << "-M" << members
|
33
33
|
end
|
34
34
|
end
|
@@ -39,10 +39,6 @@ Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService:
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def modifycmd(param, value)
|
42
|
-
# members may be an array, need a comma separated list
|
43
|
-
if param == :members and value.is_a?(Array)
|
44
|
-
value = value.join(",")
|
45
|
-
end
|
46
42
|
super(param, value)
|
47
43
|
end
|
48
44
|
end
|
@@ -22,10 +22,12 @@ Puppet::Type.type(:group).provide :windows_adsi do
|
|
22
22
|
|
23
23
|
# Cannot use munge of the group property to canonicalize @should
|
24
24
|
# since the default array_matching comparison is not commutative
|
25
|
-
|
26
|
-
current_sids = current.map(&:sid)
|
27
25
|
# dupes automatically weeded out when hashes built
|
28
|
-
|
26
|
+
current_members = Puppet::Util::Windows::ADSI::User.name_sid_hash(current)
|
27
|
+
specified_members = Puppet::Util::Windows::ADSI::User.name_sid_hash(should)
|
28
|
+
|
29
|
+
current_sids = current_members.keys.to_a
|
30
|
+
specified_sids = specified_members.keys.to_a
|
29
31
|
|
30
32
|
if @resource[:auth_membership]
|
31
33
|
current_sids.sort == specified_sids.sort
|
@@ -63,7 +65,8 @@ Puppet::Type.type(:group).provide :windows_adsi do
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def members
|
66
|
-
group.members
|
68
|
+
@members ||= Puppet::Util::Windows::ADSI::User.name_sid_hash(group.members)
|
69
|
+
@members.keys
|
67
70
|
end
|
68
71
|
|
69
72
|
def members=(members)
|
@@ -247,31 +247,7 @@ class Puppet::Provider::NameService < Puppet::Provider
|
|
247
247
|
# The list of all groups the user is a member of. Different
|
248
248
|
# user mgmt systems will need to override this method.
|
249
249
|
def groups
|
250
|
-
|
251
|
-
|
252
|
-
# Reset our group list
|
253
|
-
Puppet::Etc.setgrent
|
254
|
-
|
255
|
-
user = @resource[:name]
|
256
|
-
|
257
|
-
# Now iterate across all of the groups, adding each one our
|
258
|
-
# user is a member of
|
259
|
-
while group = Puppet::Etc.getgrent
|
260
|
-
members = group.mem
|
261
|
-
|
262
|
-
groups << group.name if members.include? user
|
263
|
-
end
|
264
|
-
|
265
|
-
# We have to close the file, so each listing is a separate
|
266
|
-
# reading of the file.
|
267
|
-
Puppet::Etc.endgrent
|
268
|
-
|
269
|
-
uniq_groups = groups.uniq
|
270
|
-
if groups != uniq_groups
|
271
|
-
debug("Removing any duplicate group entries")
|
272
|
-
end
|
273
|
-
# remove any double listed groups
|
274
|
-
uniq_groups.join(",")
|
250
|
+
Puppet::Util::POSIX.groups_of(@resource[:name]).join(',')
|
275
251
|
end
|
276
252
|
|
277
253
|
# Convert the Etc struct into a hash.
|
@@ -116,7 +116,7 @@ class Puppet::Provider::NameService::DirectoryService < Puppet::Provider::NameSe
|
|
116
116
|
ds_value = input_hash[key]
|
117
117
|
case ds_to_ns_attribute_map[ds_attribute]
|
118
118
|
when :members
|
119
|
-
ds_value = ds_value
|
119
|
+
ds_value = ds_value.join(',')
|
120
120
|
when :gid, :uid
|
121
121
|
# OS X stores objects like uid/gid as strings.
|
122
122
|
# Try casting to an integer for these cases to be
|
@@ -344,8 +344,10 @@ class Puppet::Provider::NameService::DirectoryService < Puppet::Provider::NameSe
|
|
344
344
|
|
345
345
|
def set(param, value)
|
346
346
|
self.class.validate(param, value)
|
347
|
-
current_members = @property_value_cache_hash[:members]
|
348
347
|
if param == :members
|
348
|
+
current_members = @property_value_cache_hash[:members].split(',')
|
349
|
+
value = value.split(',')
|
350
|
+
|
349
351
|
# If we are meant to be authoritative for the group membership
|
350
352
|
# then remove all existing members who haven't been specified
|
351
353
|
# in the manifest.
|
@@ -409,7 +411,7 @@ class Puppet::Provider::NameService::DirectoryService < Puppet::Provider::NameSe
|
|
409
411
|
end
|
410
412
|
if value != "" and not value.nil?
|
411
413
|
if property == :members
|
412
|
-
add_members(nil, value)
|
414
|
+
add_members(nil, value.split(','))
|
413
415
|
else
|
414
416
|
exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
|
415
417
|
exec_arg_vector << ns_to_ds_attribute_map[property.intern]
|
@@ -117,7 +117,7 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa
|
|
117
117
|
if match
|
118
118
|
result_fields.zip(match.captures) do |field, value|
|
119
119
|
# some fields can be empty or (null) (if we are not passed a category in the package name for instance)
|
120
|
-
if value == '(null)'
|
120
|
+
if value == '(null)' || value == '<unset>'
|
121
121
|
package_info[field] = nil
|
122
122
|
elsif !value or value.empty?
|
123
123
|
package_info[field] = nil
|
@@ -133,7 +133,7 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def qatom_output_format
|
136
|
-
'"[%
|
136
|
+
'"[%[CATEGORY]] [%[PN]] [%[PV]] [%[PR]] [%[SLOT]] [%[pfx]] [%[sfx]]"'
|
137
137
|
end
|
138
138
|
|
139
139
|
def qatom_result_format
|
@@ -196,6 +196,22 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
|
|
196
196
|
Puppet::Util::Plist.read_plist_file(path)
|
197
197
|
end
|
198
198
|
|
199
|
+
# Read overrides plist, retrying if necessary
|
200
|
+
def self.read_overrides
|
201
|
+
i = 1
|
202
|
+
overrides = nil
|
203
|
+
loop do
|
204
|
+
Puppet.debug(_("Reading overrides plist, attempt %{i}") % {i: i}) if i > 1
|
205
|
+
overrides = read_plist(launchd_overrides)
|
206
|
+
break unless overrides.nil?
|
207
|
+
raise Puppet::Error.new(_('Unable to read overrides plist, too many attempts')) if i == 20
|
208
|
+
Puppet.info(_('Overrides file could not be read, trying again.'))
|
209
|
+
Kernel.sleep(0.1)
|
210
|
+
i += 1
|
211
|
+
end
|
212
|
+
overrides
|
213
|
+
end
|
214
|
+
|
199
215
|
# Clean out the @property_hash variable containing the cached list of services
|
200
216
|
def flush
|
201
217
|
@property_hash.clear
|
@@ -300,7 +316,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
|
|
300
316
|
_, job_plist = plist_from_label(resource[:name])
|
301
317
|
job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled")
|
302
318
|
|
303
|
-
if FileTest.file?(self.class.launchd_overrides) and overrides = self.class.
|
319
|
+
if FileTest.file?(self.class.launchd_overrides) and overrides = self.class.read_overrides
|
304
320
|
if overrides.has_key?(resource[:name])
|
305
321
|
if self.class.get_os_version < 14
|
306
322
|
overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")
|
@@ -324,7 +340,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
|
|
324
340
|
# rather than dealing with launchctl as it is unable to change the Disabled flag
|
325
341
|
# without actually loading/unloading the job.
|
326
342
|
def enable
|
327
|
-
overrides = self.class.
|
343
|
+
overrides = self.class.read_overrides
|
328
344
|
if self.class.get_os_version < 14
|
329
345
|
overrides[resource[:name]] = { "Disabled" => false }
|
330
346
|
else
|
@@ -334,7 +350,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
|
|
334
350
|
end
|
335
351
|
|
336
352
|
def disable
|
337
|
-
overrides = self.class.
|
353
|
+
overrides = self.class.read_overrides
|
338
354
|
if self.class.get_os_version < 14
|
339
355
|
overrides[resource[:name]] = { "Disabled" => true }
|
340
356
|
else
|
@@ -10,6 +10,7 @@
|
|
10
10
|
# See https://puppet.com/docs/puppet/latest/provider_development.html
|
11
11
|
# for more information
|
12
12
|
require 'puppet/provider/aix_object'
|
13
|
+
require 'puppet/util/posix'
|
13
14
|
require 'tempfile'
|
14
15
|
require 'date'
|
15
16
|
|
@@ -76,13 +77,23 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
|
|
76
77
|
# a String, etc. in the property. This routine does a final check to
|
77
78
|
# ensure our value doesn't have whitespace before we convert it to
|
78
79
|
# an attribute.
|
79
|
-
def
|
80
|
+
def groups_property_to_attribute(groups)
|
80
81
|
if groups =~ /\s/
|
81
82
|
raise ArgumentError, _("Invalid value %{groups}: Groups must be comma separated!") % { groups: groups }
|
82
83
|
end
|
83
84
|
|
84
85
|
groups
|
85
86
|
end
|
87
|
+
|
88
|
+
# We do not directly use the groups attribute value because that will
|
89
|
+
# always include the primary group, even if our user is not one of its
|
90
|
+
# members. Instead, we retrieve our property value by parsing the etc/group file,
|
91
|
+
# which matches what we do on our other POSIX platforms like Linux and Solaris.
|
92
|
+
#
|
93
|
+
# See https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.files/group_security.htm
|
94
|
+
def groups_attribute_to_property(provider, _groups)
|
95
|
+
Puppet::Util::POSIX.groups_of(provider.resource[:name]).join(',')
|
96
|
+
end
|
86
97
|
end
|
87
98
|
|
88
99
|
mapping puppet_property: :comment,
|
@@ -99,7 +110,8 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
|
|
99
110
|
attribute_to_property: method(:pgrp_to_gid)
|
100
111
|
|
101
112
|
mapping puppet_property: :groups,
|
102
|
-
property_to_attribute: method(:
|
113
|
+
property_to_attribute: method(:groups_property_to_attribute),
|
114
|
+
attribute_to_property: method(:groups_attribute_to_property)
|
103
115
|
|
104
116
|
mapping puppet_property: :home
|
105
117
|
mapping puppet_property: :shell
|
@@ -121,6 +133,24 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
|
|
121
133
|
# properties + a getter for the attributes property).
|
122
134
|
mk_resource_methods
|
123
135
|
|
136
|
+
# Setting the primary group (pgrp attribute) on AIX causes both the
|
137
|
+
# current and new primary groups to be included in our user's groups,
|
138
|
+
# which is undesirable behavior. Thus, this custom setter resets the
|
139
|
+
# 'groups' property back to its previous value after setting the primary
|
140
|
+
# group.
|
141
|
+
def gid=(value)
|
142
|
+
old_pgrp = gid
|
143
|
+
cur_groups = groups
|
144
|
+
|
145
|
+
set(:gid, value)
|
146
|
+
|
147
|
+
begin
|
148
|
+
self.groups = cur_groups
|
149
|
+
rescue Puppet::Error => detail
|
150
|
+
raise Puppet::Error, _("Could not reset the groups property back to %{cur_groups} after setting the primary group on %{resource}[%{name}]. This means that the previous primary group of %{old_pgrp} and the new primary group of %{new_pgrp} have been added to %{cur_groups}. You will need to manually reset the groups property if this is undesirable behavior. Detail: %{detail}") % { cur_groups: cur_groups, resource: @resource.class.name, name: @resource.name, old_pgrp: old_pgrp, new_pgrp: value, detail: detail }, detail.backtrace
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
124
154
|
# Helper function that parses the password from the given
|
125
155
|
# password filehandle. This is here to make testing easier
|
126
156
|
# for #password since we cannot configure Mocha to mock out
|
@@ -213,6 +243,22 @@ Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
|
|
213
243
|
def create
|
214
244
|
super
|
215
245
|
|
246
|
+
# We specify the 'groups' AIX attribute in AixObject's create method
|
247
|
+
# when creating our user. However, this does not always guarantee that
|
248
|
+
# our 'groups' property is set to the right value. For example, the
|
249
|
+
# primary group will always be included in the 'groups' property. This is
|
250
|
+
# bad if we're explicitly managing the 'groups' property under inclusive
|
251
|
+
# membership, and we are not specifying the primary group in the 'groups'
|
252
|
+
# property value.
|
253
|
+
#
|
254
|
+
# Setting the groups property here a second time will ensure that our user is
|
255
|
+
# created and in the right state. Note that this is an idempotent operation,
|
256
|
+
# so if AixObject's create method already set it to the right value, then this
|
257
|
+
# will noop.
|
258
|
+
if (groups = @resource.should(:groups))
|
259
|
+
self.groups = groups
|
260
|
+
end
|
261
|
+
|
216
262
|
if (password = @resource.should(:password))
|
217
263
|
self.password = password
|
218
264
|
end
|
data/lib/puppet/type/group.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'etc'
|
2
2
|
require 'facter'
|
3
3
|
require 'puppet/property/keyvalue'
|
4
|
+
require 'puppet/property/list'
|
4
5
|
require 'puppet/parameter/boolean'
|
5
6
|
|
6
7
|
module Puppet
|
@@ -81,41 +82,84 @@ module Puppet
|
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
84
|
-
newproperty(:members, :
|
85
|
+
newproperty(:members, :parent => Puppet::Property::List, :required_features => :manages_members) do
|
85
86
|
desc "The members of the group. For platforms or directory services where group
|
86
87
|
membership is stored in the group objects, not the users. This parameter's
|
87
88
|
behavior can be configured with `auth_membership`."
|
88
89
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
validate do |value|
|
91
|
+
unless value.is_a?(String)
|
92
|
+
raise ArgumentError, _("The members property must be specified as either an array of strings, or as a single string consisting of a comma-separated list of members")
|
93
|
+
end
|
94
|
+
|
95
|
+
if value.is_a?(Integer) || value =~ /^\d+$/
|
96
|
+
raise ArgumentError, _("User names must be provided, not UID numbers.")
|
97
|
+
end
|
98
|
+
|
99
|
+
if value.empty?
|
100
|
+
raise ArgumentError, _("User names must not be empty. If you want to specify \"no users\" pass an empty array")
|
101
|
+
end
|
102
|
+
|
103
|
+
if provider.respond_to?(:member_valid?)
|
104
|
+
return provider.member_valid?(value)
|
105
|
+
end
|
93
106
|
end
|
94
107
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
108
|
+
def inclusive?
|
109
|
+
@resource[:auth_membership]
|
110
|
+
end
|
111
|
+
|
112
|
+
def change_to_s(currentvalue, newvalue)
|
113
|
+
newvalue = newvalue.split(",") if newvalue != :absent
|
114
|
+
|
115
|
+
if provider.respond_to?(:members_to_s)
|
116
|
+
# for Windows ADSI
|
117
|
+
# de-dupe the "newvalue" when the sync event message is generated,
|
118
|
+
# due to final retrieve called after the resource has been modified
|
119
|
+
newvalue = provider.members_to_s(newvalue).split(',').uniq
|
98
120
|
end
|
99
121
|
|
100
|
-
super(
|
122
|
+
super(currentvalue, newvalue)
|
101
123
|
end
|
102
124
|
|
103
|
-
|
125
|
+
# override Puppet::Property::List#retrieve
|
126
|
+
def retrieve
|
104
127
|
if provider.respond_to?(:members_to_s)
|
105
|
-
|
106
|
-
|
128
|
+
# Windows ADSI members returns SIDs, but retrieve needs names
|
129
|
+
# must return qualified names for SIDs for "is" value and puppet resource
|
130
|
+
return provider.members_to_s(provider.members).split(',')
|
131
|
+
end
|
132
|
+
|
133
|
+
super
|
134
|
+
end
|
107
135
|
|
108
|
-
|
136
|
+
# The members property should also accept a comma separated
|
137
|
+
# list of members (a String parameter) for backwards
|
138
|
+
# compatibility. Unfortunately, the List property would treat
|
139
|
+
# our comma separated list of members as a single-element Array.
|
140
|
+
# This override of should= ensures that a comma separated list of
|
141
|
+
# members is munged to an array of members, which is what we want.
|
142
|
+
# Note that we cannot use `munge` because that will pass in each
|
143
|
+
# array element instead of the entire array if the members property
|
144
|
+
# is specified as an array of members, which would cause each member
|
145
|
+
# to be munged into an array for that case. This is undesirable
|
146
|
+
# behavior.
|
147
|
+
def should=(values)
|
148
|
+
super(values)
|
149
|
+
|
150
|
+
if @should.length == 1 && @should.first.include?(delimiter)
|
151
|
+
@should = @should.first.split(delimiter)
|
109
152
|
end
|
110
153
|
|
111
|
-
|
154
|
+
@should
|
112
155
|
end
|
113
|
-
alias :should_to_s :is_to_s
|
114
156
|
|
115
|
-
|
116
|
-
if provider.respond_to?(:
|
117
|
-
return provider.
|
157
|
+
def insync?(current)
|
158
|
+
if provider.respond_to?(:members_insync?)
|
159
|
+
return provider.members_insync?(current, @should)
|
118
160
|
end
|
161
|
+
|
162
|
+
super(current)
|
119
163
|
end
|
120
164
|
end
|
121
165
|
|