Class: Puppet::Provider::AixObject

Inherits:
Puppet::Provider show all
Defined in:
lib/puppet/provider/aixobject.rb

Overview

Common code for AIX providers. This class implements basic structure for AIX resources.

Author

Hector Rivas Gandara <[email protected]>

Constant Summary

Constants inherited from Puppet::Provider

Confine

Constants included from Util::Logging

Util::Logging::FILE_AND_LINE, Util::Logging::FILE_NO_LINE, Util::Logging::MM, Util::Logging::NO_FILE_LINE, Util::Logging::SUPPRESS_FILE_LINE

Constants included from Util

Util::AbsolutePathPosix, Util::AbsolutePathWindows, Util::DEFAULT_POSIX_MODE, Util::DEFAULT_WINDOWS_MODE

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

Class Attribute Summary collapse

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, execfail, #execfail, execpipe, #execpipe, execute, #execute, fact_match, feature_match, has_command, initvars, #inspect, #name, optional_commands, post_resource_eval, prefetch, specificity, supports_parameter?, #to_s

Methods included from Util::Logging

#clear_deprecation_warnings, #debug, #deprecation_warning, #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, default_env, deterministic_rand, deterministic_rand_int, exit_on_fail, get_env, get_environment, logmethods, merge_environment, path_to_uri, pretty_backtrace, replace_file, safe_posix_fork, set_env, symbolizehash, thinmark, uri_encode, uri_query_encode, uri_to_path, which, withenv, withumask

Methods included from Util::POSIX

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

Methods included from Util::SymbolicFileMode

#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, notice_once, warnonce

Methods included from Confiner

#confine, #confine_collection, #suitable?

Methods included from Util::Errors

#adderrorcontext, #devfail, #error_context, #exceptwrap, #fail

Constructor Details

#initialize(resource) ⇒ AixObject

Returns a new instance of AixObject.



387
388
389
390
391
# File 'lib/puppet/provider/aixobject.rb', line 387

def initialize(resource)
  super
  @objectinfo = nil
  @objectosinfo = nil
end

Class Attribute Details

.attribute_mappingObject



33
34
35
# File 'lib/puppet/provider/aixobject.rb', line 33

def attribute_mapping
  @attribute_mapping
end

Class Method Details

.attribute_mapping_fromObject

Mapping from AIX attribute to Puppet property.



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/puppet/provider/aixobject.rb', line 51

def self.attribute_mapping_from
  if ! @attribute_mapping_from
    @attribute_mapping_from = {}
    attribute_mapping.each { |elem|
      attribute_mapping_from[elem[:aix_attr]] = {
        :key => elem[:puppet_prop],
        :method => elem[:from]
      }
    }
  end
  @attribute_mapping_from
end

.attribute_mapping_toObject

Mapping from Puppet property to AIX attribute.



37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/puppet/provider/aixobject.rb', line 37

def self.attribute_mapping_to
  if ! @attribute_mapping_to
    @attribute_mapping_to = {}
    attribute_mapping.each { |elem|
      attribute_mapping_to[elem[:puppet_prop]] = {
        :key => elem[:aix_attr],
        :method => elem[:to]
      }
    }
  end
  @attribute_mapping_to
end

.instancesObject

Return all existing instances The method for returning a list of provider instances. Note that it returns providers, preferably with values already filled in, not resources.



289
290
291
292
293
294
295
# File 'lib/puppet/provider/aixobject.rb', line 289

def self.instances
  objects=[]
  list_all.each { |entry|
    objects << new(:name => entry, :ensure => :present)
  }
  objects
end

.list_allObject

List all elements of given type. It works for colon separated commands and list commands. It returns a list of names.



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/puppet/provider/aixobject.rb', line 252

def self.list_all
  names = []
  begin
    output = execute([self.command(:list), 'ALL'])

    output = output.split("\n").select{ |line| line != /^#/ }

    output.each do |line|
      name = line.split(/[ :]/)[0]
      names << name if not name.empty?
    end
  rescue Puppet::ExecutionFailure => detail
    # Print error if needed
    Puppet.debug "aix.list_all(): Could not get all resources of type #{@resource.class.name}: #{detail}"
  end
  names
end

.mk_resource_methodsObject


Call this method when the object is initialized. It creates getter/setter methods for each property our resource type supports. If setter or getter already defined it will not be overwritten



343
344
345
346
347
348
349
# File 'lib/puppet/provider/aixobject.rb', line 343

def self.mk_resource_methods
  [resource_type.validproperties, resource_type.parameters].flatten.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

.resource_type=(resource_type) ⇒ Object

Define the needed getters and setters as soon as we know the resource type



352
353
354
355
# File 'lib/puppet/provider/aixobject.rb', line 352

def self.resource_type=(resource_type)
  super
  mk_resource_methods
end

Instance Method Details

#addcmd(_extra_attrs = []) ⇒ Object

Raises:



14
15
16
# File 'lib/puppet/provider/aixobject.rb', line 14

def addcmd( _extra_attrs = [] )
  raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement addcmd"
end

#createObject

Create a new instance of the resource



310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/puppet/provider/aixobject.rb', line 310

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

  begin
    execute(self.addcmd)
  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

Delete this instance of the resource



325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/puppet/provider/aixobject.rb', line 325

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

  begin
    execute(self.deletecmd)
  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

#deletecmdObject

Raises:



22
23
24
# File 'lib/puppet/provider/aixobject.rb', line 22

def deletecmd
  raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement deletecmd"
end

#ensureObject

  • ensure

    The basic state that the object should be in.  Valid values are
    `present`, `absent`, `role`.
    

From ensurable: exists?, create, delete



301
302
303
304
305
306
307
# File 'lib/puppet/provider/aixobject.rb', line 301

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

#exists?Boolean

Check that the user exists

Returns:

  • (Boolean)


282
283
284
# File 'lib/puppet/provider/aixobject.rb', line 282

def exists?
  !!getinfo(true) # !! => converts to bool
end

#flushObject

Clear out the cached values.



276
277
278
279
# File 'lib/puppet/provider/aixobject.rb', line 276

def flush
  @property_hash.clear if @property_hash
  @objectinfo.clear if @objectinfo
end

#get(param) ⇒ Object

Retrieve a specific value by name.



358
359
360
# File 'lib/puppet/provider/aixobject.rb', line 358

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

#get_arguments(key, value, mapping, objectinfo) ⇒ Object

Gets the given command line argument for the given key and value, using the given mapping to translate key and value. All the objectinfo hash (@resource or @property_hash) is passed.

This operation works with each property one by one, and default behaviour is return the arguments as key=value pairs. Subclasses must reimplement this if more complex operations/arguments are needed



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/puppet/provider/aixobject.rb', line 109

def get_arguments(key, value, mapping, objectinfo)
  if mapping.nil?
    new_key = key
    new_value = value
  elsif mapping[key].nil?
    # is not present in mapping, ignore it.
    new_key = nil
    new_value = nil
  elsif mapping[key][:method].nil?
    new_key = mapping[key][:key]
    new_value = value
  else
    new_key = mapping[key][:key]
    new_value = method(mapping[key][:method]).call(value)
  end

  # convert it to string
  new_value = Array(new_value).join(',')

  if new_key
    return [ "#{new_key}=#{new_value}" ]
  else
    return []
  end
end

#getinfo(refresh = false) ⇒ Object

Retrieve all the information of an existing resource. It will execute ‘lscmd’ command and parse the output, using the mapping ‘attribute_mapping_from’ to translate the keys and values.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/puppet/provider/aixobject.rb', line 223

def getinfo(refresh = false)
  if @objectinfo.nil? or refresh == true
    # Execute lsuser, split all attributes and add them to a dict.
    begin
      output = execute(self.lscmd)
      @objectinfo = self.parse_command_output(output)
      # All attributes without translation
      @objectosinfo = self.parse_command_output(output, nil)
    rescue Puppet::ExecutionFailure => detail
      # Print error if needed. FIXME: Do not check the user here.
      Puppet.debug "aix.getinfo(): Could not find #{@resource.class.name} #{@resource.name}: #{detail}"
    end
  end
  @objectinfo
end

#getosinfo(refresh = false) ⇒ Object

Like getinfo, but it will not use the mapping to translate the keys and values. It might be useful to retrieve some raw information.



241
242
243
244
245
246
# File 'lib/puppet/provider/aixobject.rb', line 241

def getosinfo(refresh = false)
  if @objectosinfo.nil? or refresh == true
    getinfo(refresh)
  end
  @objectosinfo || Hash.new
end

#hash2args(hash, mapping = self.class.attribute_mapping_to) ⇒ Object

Convert the provider properties (hash) to AIX command arguments (list of strings) This function will translate each value/key and generate the argument using the get_arguments function.



139
140
141
142
143
144
145
146
# File 'lib/puppet/provider/aixobject.rb', line 139

def hash2args(hash, mapping=self.class.attribute_mapping_to)
  return "" unless hash
  arg_list = []
  hash.each {|key, val|
    arg_list += self.get_arguments(key, val, mapping, hash)
  }
  arg_list
end

#load_attribute(key, value, mapping, objectinfo) ⇒ Object

Loads an AIX attribute (key=value) and stores it in the given hash with puppet semantics. It translates the pair using the given mapping.

This operation works with each property one by one, subclasses must reimplement this if more complex operations are needed



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/puppet/provider/aixobject.rb', line 85

def load_attribute(key, value, mapping, objectinfo)
  if mapping.nil?
    objectinfo[key] = value
  elsif mapping[key].nil?
    # is not present in mapping, ignore it.
    true
  elsif mapping[key][:method].nil?
    objectinfo[mapping[key][:key]] = value
  else
    objectinfo[mapping[key][:key]] = method(mapping[key][:method]).call(value)
  end

  return objectinfo
end

#lscmd(_value = @resource[:name]) ⇒ Object

The real provider must implement these functions.

Raises:



10
11
12
# File 'lib/puppet/provider/aixobject.rb', line 10

def lscmd( _value = @resource[:name] )
  raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement lscmd"
end

#modifycmd(_attributes_hash = {}) ⇒ Object

Raises:



18
19
20
# File 'lib/puppet/provider/aixobject.rb', line 18

def modifycmd( _attributes_hash = {} )
  raise Puppet::Error, "Method not defined #{@resource.class.name} #{@resource.name}: Base AixObject provider doesn't implement modifycmd"
end

#parse_attr_list(str, mapping = self.class.attribute_mapping_from) ⇒ Object

Parse AIX command attributes from the output of an AIX command, that which format is a list of space separated of key=value pairs: “uid=100 groups=a,b,c”. It returns a hash.

If a mapping is provided, the keys are translated as defined in the mapping hash. And only values included in mapping will be added

NOTE: it will ignore the items not including ‘=’



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/puppet/provider/aixobject.rb', line 157

def parse_attr_list(str, mapping=self.class.attribute_mapping_from)
  properties = {}
  attrs = []
  if str.nil? or (attrs = str.split()).empty?
    return nil
  end

  attrs.each { |i|
    if i.include? "=" # Ignore if it does not include '='
      (key_str, val) = i.split('=')
      # Check the key
      if key_str.nil? or key_str.empty?
        info _("Empty key in string 'i'?")
        continue
      end
      key_str.strip!
      key = key_str.to_sym
      val.strip! if val

      properties = self.load_attribute(key, val, mapping, properties)
    end
  }
  properties.empty? ? nil : properties
end

#parse_colon_list(str, key_list, mapping = self.class.attribute_mapping_from) ⇒ Object

Parse AIX command output in a colon separated list of attributes, This function is useful to parse the output of commands like lsfs -c:

#MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
/:/dev/hd4:jfs2::bootfs:557056:rw:yes:no
/home:/dev/hd1:jfs2:::2129920:rw:yes:no
/usr:/dev/hd2:jfs2::bootfs:9797632:rw:yes:no

If a mapping is provided, the keys are translated as defined in the mapping hash. And only values included in mapping will be added



191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/puppet/provider/aixobject.rb', line 191

def parse_colon_list(str, key_list, mapping=self.class.attribute_mapping_from)
  properties = {}
  attrs = []
  if str.nil? or (attrs = str.split(':')).empty?
    return nil
  end

  attrs.each { |val|
    key = key_list.shift.to_sym
    properties = self.load_attribute(key, val, mapping, properties)
  }
  properties.empty? ? nil : properties
end

#parse_command_output(output, mapping = self.class.attribute_mapping_from) ⇒ Object

Default parsing function for AIX commands. It will choose the method depending of the first line. For the colon separated list it will:

1. Get keys from first line.
2. Parse next line.


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

def parse_command_output(output, mapping=self.class.attribute_mapping_from)
  lines = output.split("\n")
  # if it begins with #something:... is a colon separated list.
  if lines[0] =~ /^#.*:/
    self.parse_colon_list(lines[1], lines[0][1..-1].split(':'), mapping)
  else
    self.parse_attr_list(lines[0], mapping)
  end
end

#set(param, value) ⇒ Object

Set a property.



363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/puppet/provider/aixobject.rb', line 363

def set(param, value)
  @property_hash[param.intern] = value

  if getinfo().nil?
    # This is weird...
    raise Puppet::Error, _("Trying to update parameter '%{param}' to '%{value}' for a resource that does not exists %{resource} %{name}: %{detail}") % { param: param, value: value, resource: @resource.class.name, name: @resource.name, detail: detail }
  end
  if value == getinfo()[param.to_sym]
    return
  end

  #self.class.validate(param, value)
  if cmd = modifycmd({param =>value})
    begin
      execute(cmd)
    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

  # Refresh de info.
  getinfo(true)
end

#translate_attr(key, value, mapping) ⇒ Object

This functions translates a key and value using the given mapping. Mapping can be nil (no translation) or a hash with this format => new_key, :method => translate_method It returns a list with the pair [key, value]



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

def translate_attr(key, value, mapping)
  return [key, value] unless mapping
  return nil unless mapping[key]

  if mapping[key][:method]
    new_value = method(mapping[key][:method]).call(value)
  else
    new_value = value
  end
  [mapping[key][:key], new_value]
end