Class: Puppet::Provider::NameService

Inherits:
Puppet::Provider show all
Defined in:
lib/puppet/provider/nameservice.rb,
lib/puppet/provider/nameservice/pw.rb,
lib/puppet/provider/nameservice/objectadd.rb

Overview

This is the parent class of all NSS classes. They’re very different in their backend, but they’re pretty similar on the front-end. This class provides a way for them all to be as similar as possible.

API:

  • public

Direct Known Subclasses

DirectoryService, ObjectAdd

Defined Under Namespace

Classes: DirectoryService, ObjectAdd, PW

Constant Summary

Constants inherited from Puppet::Provider

Confine

Constants included from Util

Util::ALNUM, Util::ALPHA, Util::AbsolutePathPosix, Util::AbsolutePathWindows, Util::DEFAULT_POSIX_MODE, Util::DEFAULT_WINDOWS_MODE, Util::ESCAPED, Util::HEX, Util::HttpProxy, Util::PUPPET_STACK_INSERTION_FRAME, Util::RESERVED, Util::RFC_3986_URI_REGEX, Util::UNRESERVED, Util::UNSAFE

Constants included from Util::POSIX

Util::POSIX::LOCALE_ENV_VARS, Util::POSIX::USER_ENV_VARS

Constants included from Util::SymbolicFileMode

Util::SymbolicFileMode::SetGIDBit, Util::SymbolicFileMode::SetUIDBit, Util::SymbolicFileMode::StickyBit, Util::SymbolicFileMode::SymbolicMode, Util::SymbolicFileMode::SymbolicSpecialToBit

Constants included from Util::Docs

Util::Docs::HEADER_LEVELS

Instance Attribute Summary

Attributes inherited from Puppet::Provider

#resource

Attributes included from Util::Docs

#doc, #nodoc

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Puppet::Provider

#<=>, #clear, command, #command, commands, declared_feature?, default?, default_match, defaultfor, execpipe, #execpipe, execute, #execute, fact_match, feature_match, #flush, has_command, #inspect, mk_resource_methods, #name, notdefaultfor, optional_commands, post_resource_eval, prefetch, some_default_match, specificity, supports_parameter?, #to_s

Methods included from Util::Logging

#clear_deprecation_warnings, #debug, #deprecation_warning, #format_backtrace, #format_exception, #get_deprecation_offender, #log_and_raise, #log_deprecations_to_file, #log_exception, #puppet_deprecation_warning, #send_log, setup_facter_logging!, #warn_once

Methods included from Util

absolute_path?, benchmark, chuser, clear_environment, create_erb, default_env, deterministic_rand, deterministic_rand_int, exit_on_fail, format_backtrace_array, format_puppetstack_frame, get_env, get_environment, logmethods, merge_environment, path_to_uri, pretty_backtrace, replace_file, resolve_stackframe, rfc2396_escape, safe_posix_fork, set_env, skip_external_facts, symbolizehash, thinmark, uri_encode, uri_query_encode, uri_to_path, uri_unescape, which, withenv, withumask

Methods included from Util::POSIX

#get_posix_field, #gid, groups_of, #idfield, #methodbyid, #methodbyname, #search_posix_field, #uid

Methods included from Util::SymbolicFileMode

#display_mode, #normalize_symbolic_mode, #symbolic_mode_to_int, #valid_symbolic_mode?

Methods included from Util::Docs

#desc, #dochook, #doctable, #markdown_definitionlist, #markdown_header, #nodoc?, #pad, scrub

Methods included from Util::Warnings

clear_warnings, debug_once, maybe_log, notice_once, warnonce

Methods included from Confiner

#confine, #confine_collection, #suitable?

Methods included from Util::Errors

#adderrorcontext, #devfail, #error_context, error_location, error_location_with_space, error_location_with_unknowns, #exceptwrap, #fail

Constructor Details

#initialize(resource) ⇒ NameService

Returns a new instance of NameService.

API:

  • public



251
252
253
254
255
256
257
258
259
260
# File 'lib/puppet/provider/nameservice.rb', line 251

def initialize(resource)
  super
  @custom_environment = {}
  @objectinfo = nil
  if resource.is_a?(Hash) && !resource[:canonical_name].nil?
    @canonical_name = resource[:canonical_name]
  else
    @canonical_name = resource[:name]
  end
end

Class Method Details

.autogen_default(param) ⇒ Object

API:

  • public



9
10
11
# File 'lib/puppet/provider/nameservice.rb', line 9

def autogen_default(param)
  defined?(@autogen_defaults) ? @autogen_defaults[param.intern] : nil
end

.autogen_defaults(hash) ⇒ Object

API:

  • public



13
14
15
16
17
18
# File 'lib/puppet/provider/nameservice.rb', line 13

def autogen_defaults(hash)
  @autogen_defaults ||= {}
  hash.each do |param, value|
    @autogen_defaults[param.intern] = value
  end
end

.autogen_id(field, resource_type) ⇒ Object

Autogenerate either a uid or a gid. This is not very flexible: we can only generate one field type per class, and get kind of confused if asked for both.

API:

  • public



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/puppet/provider/nameservice.rb', line 124

def self.autogen_id(field, resource_type)
  # Figure out what sort of value we want to generate.
  case resource_type
  when :user;   database = :passwd;  method = :uid
  when :group;  database = :group;   method = :gid
  else
    #TRANSLATORS "autogen_id()" is a method name and should not be translated
    raise Puppet::DevError, _("autogen_id() does not support auto generation of id for resource type %{resource_type}") % { resource_type: resource_type }
  end

  # Initialize from the data set, if needed.
  unless @prevauto
    # Sadly, Etc doesn't return an enumerator, it just invokes the block
    # given, or returns the first record from the database.  There is no
    # other, more convenient enumerator for these, so we fake one with this
    # loop.  Thanks, Ruby, for your awesome abstractions. --daniel 2012-03-23
    highest = []
    Puppet::Etc.send(database) {|entry| highest << entry.send(method) }
    highest = highest.reject {|x| x > 65000 }.max

    @prevauto = highest || 1000
  end

  # ...and finally increment and return the next value.
  @prevauto += 1
end

.initvarsObject

API:

  • public



20
21
22
23
24
# File 'lib/puppet/provider/nameservice.rb', line 20

def initvars
  @checks = {}
  @options = {}
  super
end

.instancesObject

API:

  • public



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/puppet/provider/nameservice.rb', line 26

def instances
  objects = []
  begin
    method = Puppet::Etc.method(:"get#{section}ent")
    while ent = method.call #rubocop:disable Lint/AssignmentInCondition
      objects << new(:name => ent.name, :canonical_name => ent.canonical_name, :ensure => :present)
    end
  ensure
    Puppet::Etc.send("end#{section}ent")
  end
  objects
end

.option(name, option) ⇒ Object

API:

  • public



39
40
41
42
# File 'lib/puppet/provider/nameservice.rb', line 39

def option(name, option)
  name = name.intern if name.is_a? String
  (defined?(@options) and @options.include? name and @options[name].include? option) ? @options[name][option] : nil
end

.options(name, hash) ⇒ Object

API:

  • public



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/puppet/provider/nameservice.rb', line 44

def options(name, hash)
  unless resource_type.valid_parameter?(name)
    raise Puppet::DevError, _("%{name} is not a valid attribute for %{resource_type}") % { name: name, resource_type: resource_type.name }
  end
  @options ||= {}
  @options[name] ||= {}

  # Set options individually, so we can call the options method
  # multiple times.
  hash.each do |param, value|
    @options[name][param] = value
  end
end

.resource_type=(resource_type) ⇒ Object

API:

  • public



58
59
60
61
62
63
64
65
# File 'lib/puppet/provider/nameservice.rb', line 58

def resource_type=(resource_type)
  super
  @resource_type.validproperties.each do |prop|
    next if prop == :ensure
    define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
    define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
  end
end

.sectionObject

This is annoying, but there really aren’t that many options, and this is built into Ruby.

API:

  • public



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/puppet/provider/nameservice.rb', line 69

def section
  unless resource_type
    raise Puppet::DevError,
      "Cannot determine Etc section without a resource type"
  end

  if @resource_type.name == :group
    "gr"
  else
    "pw"
  end
end

.validate(name, value) ⇒ Object

API:

  • public



82
83
84
85
86
87
88
# File 'lib/puppet/provider/nameservice.rb', line 82

def validate(name, value)
  name = name.intern if name.is_a? String
  if @checks.include? name
    block = @checks[name][:block]
    raise ArgumentError, _("Invalid value %{value}: %{error}") % { value: value, error: @checks[name][:error] } unless block.call(value)
  end
end

.verify(name, error, &block) ⇒ Object

API:

  • public



90
91
92
93
# File 'lib/puppet/provider/nameservice.rb', line 90

def verify(name, error, &block)
  name = name.intern if name.is_a? String
  @checks[name] = {:error => error, :block => block}
end

Instance Method Details

#autogen(field) ⇒ Object

Autogenerate a value. Mostly used for uid/gid, but also used heavily with DirectoryServices

API:

  • public



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/puppet/provider/nameservice.rb', line 104

def autogen(field)
  field = field.intern
  id_generators = {:user => :uid, :group => :gid}
  if id_generators[@resource.class.name] == field
    return self.class.autogen_id(field, @resource.class.name)
  else
    value = self.class.autogen_default(field)
    if value
      return value
    elsif respond_to?("autogen_#{field}")
      return send("autogen_#{field}")
    else
      return nil
    end
  end
end

#comments_insync?(current, should) ⇒ Boolean

From overriding Puppet::Property#insync? Ruby Etc::getpwnam < 2.1.0 always returns a struct with binary encoded string values, and >= 2.1.0 will return binary encoded strings for values incompatible with current locale charset, or Encoding.default_external if compatible. Compare a “should” value with encoding of “current” value, to avoid unnecessary property syncs and comparison of strings with different encodings. (PUP-6777)

return basic string comparison after re-encoding (same as Puppet::Property#property_matches)

Returns:

API:

  • public



288
289
290
291
292
# File 'lib/puppet/provider/nameservice.rb', line 288

def comments_insync?(current, should)
  # we're only doing comparison here so don't mutate the string
  desired = should[0].to_s.dup
  current == desired.force_encoding(current.encoding)
end

#createObject

API:

  • public



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/puppet/provider/nameservice.rb', line 151

def create
  if exists?
    info _("already exists")
    # The object already exists
    return nil
  end

  begin
    sensitive = has_sensitive_data?
    execute(self.addcmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
    if feature?(:manages_password_age) && (cmd = passcmd)
      execute(cmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
    end
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, _("Could not create %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
  end
end

#deleteObject

API:

  • public



169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/puppet/provider/nameservice.rb', line 169

def delete
  unless exists?
    info _("already absent")
    # the object already doesn't exist
    return nil
  end

  begin
    execute(self.deletecmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment})
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, _("Could not delete %{resource} %{name}: %{detail}") % { resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
  end
end

#ensureObject

API:

  • public



183
184
185
186
187
188
189
# File 'lib/puppet/provider/nameservice.rb', line 183

def ensure
  if exists?
    :present
  else
    :absent
  end
end

#exists?Boolean

Does our object exist?

Returns:

API:

  • public



192
193
194
# File 'lib/puppet/provider/nameservice.rb', line 192

def exists?
  !!getinfo(true)
end

#get(param) ⇒ Object

Retrieve a specific value by name.

API:

  • public



197
198
199
# File 'lib/puppet/provider/nameservice.rb', line 197

def get(param)
  (hash = getinfo(false)) ? unmunge(param, hash[param]) : nil
end

#getinfo(refresh) ⇒ Object

Retrieve what we can about our object

API:

  • public



220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/puppet/provider/nameservice.rb', line 220

def getinfo(refresh)
  if @objectinfo.nil? or refresh == true
    @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
    begin
      @objectinfo = Puppet::Etc.send(@etcmethod, @canonical_name)
    rescue ArgumentError
      @objectinfo = nil
    end
  end

  # Now convert our Etc struct into a hash.
  @objectinfo ? info2hash(@objectinfo) : nil
end

#groupsObject

The list of all groups the user is a member of. Different user mgmt systems will need to override this method.

API:

  • public



236
237
238
# File 'lib/puppet/provider/nameservice.rb', line 236

def groups
  Puppet::Util::POSIX.groups_of(@resource[:name]).join(',')
end

#has_sensitive_data?(property = nil) ⇒ Boolean

Derived classes can override to declare sensitive data so a flag can be passed to execute

Returns:

API:

  • public



275
276
277
# File 'lib/puppet/provider/nameservice.rb', line 275

def has_sensitive_data?(property = nil)
  false
end

#info2hash(info) ⇒ Object

Convert the Etc struct into a hash.

API:

  • public



241
242
243
244
245
246
247
248
249
# File 'lib/puppet/provider/nameservice.rb', line 241

def info2hash(info)
  hash = {}
  self.class.resource_type.validproperties.each do |param|
    method = posixmethod(param)
    hash[param] = info.send(posixmethod(param)) if info.respond_to? method
  end

  hash
end

#munge(name, value) ⇒ Object

API:

  • public



201
202
203
204
205
206
207
208
# File 'lib/puppet/provider/nameservice.rb', line 201

def munge(name, value)
  block = self.class.option(name, :munge)
  if block and block.is_a? Proc
    block.call(value)
  else
    value
  end
end

#set(param, value) ⇒ Object

Raises:

API:

  • public



262
263
264
265
266
267
268
269
270
271
272
# File 'lib/puppet/provider/nameservice.rb', line 262

def set(param, value)
  self.class.validate(param, value)
  cmd = modifycmd(param, munge(param, value))
  raise Puppet::DevError, _("Nameservice command must be an array") unless cmd.is_a?(Array)
  sensitive = has_sensitive_data?(param)
  begin
    execute(cmd, {:failonfail => true, :combine => true, :custom_environment => @custom_environment, :sensitive => sensitive})
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, _("Could not set %{param} on %{resource}[%{name}]: %{detail}") % { param: param, resource: @resource.class.name, name: @resource.name, detail: detail }, detail.backtrace
  end
end

#unmunge(name, value) ⇒ Object

API:

  • public



210
211
212
213
214
215
216
217
# File 'lib/puppet/provider/nameservice.rb', line 210

def unmunge(name, value)
  block = self.class.option(name, :unmunge)
  if block and block.is_a? Proc
    block.call(value)
  else
    value
  end
end