Module: OmfRc::ResourceProxyDSL::ClassMethods

Included in:
OmfRc::ResourceProxy::Application, OmfRc::ResourceProxy::Net, OmfRc::ResourceProxy::Node, OmfRc::ResourceProxy::Wlan, Util::Hostapd, Util::Ip, Util::Iw, Util::Mod, Util::Sysfs, Util::Wpa
Defined in:
omf_rc/lib/omf_rc/resource_proxy_dsl.rb

Overview

Methods defined here will be available in resource/utility definition files

Instance Method Summary (collapse)

Instance Method Details

- (Object) call_hook(hook_name, context, *params)



150
151
152
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 150

def call_hook(hook_name, context, *params)
  context.send(hook_name, *params) if context.respond_to? hook_name
end

- (Object) configure(name, opts = {}) {|resource, value| ... }

Register a configurable property

Please note that the result of the last line in the configure block will be returned via 'inform' message. If you want to make sure that user get a proper notification about the configure operation, simply use the last line to return such notification

Examples:

suppose we define a utility for iw command interaction


module OmfRc::Util::Iw
  include OmfRc::ResourceProxyDSL

  configure :freq do |resource, value|
    `iw #{resource.hrn} set freq #{value}`
    "Frequency set to #{value}"
  end

  # or use iterator to define multiple properties
  %w(freq channel type).each do |p|
    configure p do |resource, value|
      `iw #{resource.hrn} set freq #{value}`
    end
  end

  # or we can try to parse iw's help page to extract valid properties and then automatically register them
  `iw help`.chomp.gsub(/^\t/, '').split("\n").map {|v| v.match(/[phy|dev] <.+> set (\w+) .*/) && $1 }.compact.uniq.each do |p|
    configure p do |resource, value|
      `iw #{resource.hrn} set #{p} #{value}`
    end
  end
end

Parameters:

  • name (Symbol)

    of the property

Yield Parameters:

  • resource (AbstractResource)

    pass the current resource object to the block

  • value (Object)

    pass the value to be configured



220
221
222
223
224
225
226
227
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 220

def configure(name, opts = {}, &register_block)
  unless opts[:if] && !opts[:if].call
    define_method("configure_#{name.to_s}") do |*args, &block|
      args[0] = Hashie::Mash.new(args[0]) if args[0].class == Hash
      register_block.call(self, *args, block) if register_block
    end
  end
end

- (Object) configure_all(&register_block)

Configure multiple properties when operations need to be completed in order, or the all operations are transactional

Examples:


configure_all do |resource, configure_properties, result|
  # Execute property one first, and make sure it is successful before attending property two
  if resource.some_operation(configure_properties[:property_one])
    if resource.other_operation(configure_properties[:property_two])
      result[:property_one] = 'GOOD'
      result[:property_two] = 'GREAT'
    else
      raise "Some errors"
    end
  else
    raise "Some errors"
  end
end


246
247
248
249
250
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 246

def configure_all(&register_block)
  define_method("configure_all") do |*args, &block|
    register_block.call(self, *args, block) if register_block
  end
end

- (Object) extend_configure(configure_name)

Extend existing configure definition

Slightly different to extend_hook, the actual method_name defined by a configure property is “configure_

Examples:

to extend a configurable property


configure :bob do |resource, value|
  resource.property.bob = value
end

# To extend this, simply do

extend_configure :bob

configure :bob do |resource, value|
  resource.orig_configure_bob(value)
  resource.property.bob = "New value: #{value}"
end

Parameters:

  • configure_name (#to_s)

    name of existing configurable property

See Also:



366
367
368
369
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 366

def extend_configure(configure_name)
  configure_name = configure_name.to_s
  alias_method "orig_configure_#{configure_name}", "configure_#{configure_name}"
end

- (Object) extend_hook(hook_name)

Extend existing hook definition by alias existing method name as “orig_

Examples:

extend a hook definition


# suppose existing hook defined as this:
hook :before_ready do |resource|
  logger.info "I am ready"
end

# now in a new proxy where we want to extend this hook, add more functionality:

extend_hook :before_ready

hook :before_ready do |resource|
  resource.orig_before_ready

  logger.info "Now I am really ready"
end

# if we simply want to overwrite the existing hook, just define the same hook without using extend_hook

hook :before_ready do |resource|
  logger.info "Not sure if I am ready or not"
end

Parameters:

  • hook_name (#to_s)

    name of existing hook



329
330
331
332
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 329

def extend_hook(hook_name)
  hook_name = hook_name.to_s
  alias_method "orig_#{hook_name}", hook_name
end

- (Object) extend_request(request_name)

Extend existing request definition



375
376
377
378
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 375

def extend_request(request_name)
  request_name = request_name.to_s
  alias_method "orig_request_#{request_name}", "request_#{request_name}"
end

- (Object) extend_work(work_name)

Extend existing work definition by alias existing method name as “orig_

See Also:



338
339
340
341
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 338

def extend_work(work_name)
  work_name = work_name.to_s
  alias_method "orig_#{work_name}", work_name
end

- (Object) hook(name) {|resource| ... }

Register some hooks which can be called at certain stage of the operation

Currently the system supports these hooks:

  • before_ready, called when a resource created, before creating an associated pubsub topic

  • before_release, called before a resource released

  • before_create, called before parent creates the child resource. (in the context of parent resource)

  • after_create, called after parent creates the child resource.

  • after_initial_configured, called after child resource created, and initial set of properties have been configured.

The sequence of execution is:

  • before_create

  • before_ready

  • after_create

  • after_initial_configured

  • before_release

Examples:


module OmfRc::ResourceProxy::Node
 include OmfRc::ResourceProxyDSL

 register_proxy :node

 # before_create hook
 #
 # the optional block will have access to three variables:
 # * resource: the parent resource itself
 # * new_resource_type: a string or symbol represents the new resource to be created
 # * new_resource_options: the options hash to be passed to the new resource
 #
 # this hook enable us to do things like:
 # * validating child resources: e.g. if parent could create this new resource
 # * setting up default child properties based on parent's property value
 hook :before_create do |resource, new_resource_type, new_resource_options|
   if new_resource_type.to_sym == :wifi
     logger.info "Resource type wifi is allowed"
   else
     raise "Go away, I can't create #{new_resource_type}"
   end
   new_resource_options.property ||= Hashie::Mash.new
   new_resource_options.property.node_info = "Node #{resource.uid}"
 end

 # after_create hook
 #
 # the optional block will have access to these variables:
 # * resource: the parent resource itself
 # * new_resource: the child resource instance
 hook :after_create do |resource, new_resource|
   logger.info "#{resource.uid} created #{new_resource.uid}"
 end

 # before_ready hook
 #
 # the optional block will have access to resource instance. Useful to initialise resource
 hook :before_ready do |resource|
   logger.info "#{resource.uid} is now ready"
 end

 # before_release hook
 #
 # the optional block will have access to resource instance. Useful to clean up resource before release it.
 hook :before_release do |resource|
   logger.info "#{resource.uid} is now released"
 end

 # after_initial_configured hook
 #
 # the optional block will have access to resource instance. Useful for actions depends on certain configured property values.
 hook :after_initial_configured do |resource|
   logger.info "#{resource.uid} has an IP address" unless resource.request_ip_addr.nil?
 end
end

Parameters:

  • name (Symbol)

    hook name. :before_create or :before_release

Yield Parameters:

  • resource (AbstractResource)

    pass the current resource object to the block



143
144
145
146
147
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 143

def hook(name, &register_block)
  define_method(name) do |*args, &block|
    register_block.call(self, *args, block) if register_block
  end
end

- (Object) namespace(ns_prefix, ns_href) Also known as: ns



380
381
382
383
384
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 380

def namespace(ns_prefix, ns_href)
  define_method("namespace") do
    { ns_prefix => ns_href }
  end
end

- (Object) property(name, opts = {})

Define internal property. Refer to options section to see supported options.

Examples:

# Read-only property, i.e. could not be modified through FRCP protocol
property :bob, default: 1, access: :read_only

# Read & Write property, i.e. could be modified through FRCP protocol
property :bob, default: 1, access: :configure

# Read & could be modified ONLY through FRCP CREATE message
property :bob, default: 1, access: :init_only

Parameters:

  • name (Symbol)

    of the property

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :default (Object)

    default value of the property

  • :access (Array<Symbol>, Symbol)

    defines access to the property it could be defined as an array, listing access rights, which by default is [:configure, :request] or it could be defined as one of the predefined symbols :configure, :read_only, or :init_only



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 406

def property(name, opts = {})
  opts = Hashie::Mash.new(opts)

  define_method("default_property_#{name}") do |*args, &block|
    self.property[name] ||= opts[:default]
  end

  if opts.access.instance_of? Array
    access = opts.access
  elsif opts.access.instance_of? Symbol
    access = case opts.access
             when :configure
               [:configure, :request]
             when :init_only
               [:init, :request]
             when :read_only
               [:request]
             else
               raise ArgumentError, "Unknown property access mode '#{opts.access}'"
             end
  end

  access ||= DEFAULT_PROP_ACCESS

  access.each do |a|
    case a
    when :configure
      define_method("configure_#{name}") do |val|
        self.property[name] = val
      end
    when :init
      define_method("initialise_#{name}") do |val|
        self.property[name] = val
      end
    when :request
      define_method("request_#{name}") do
        self.property[name]
      end
    else
      raise ArgumentError, "Unnown access type '#{a}'"
    end
  end
end

- (Object) register_proxy(name, opts = {})

Register a named proxy entry with factory class, normally this should be done in the proxy module

Examples:

suppose we define a module for wifi


module OmfRc::ResourceProxy::Wifi
  include OmfRc::ResourceProxyDSL

  # Let the factory know it is available
  register_proxy :wifi

  # or use option :create_by
  register_proxy :wifi, :create_by => :node
end

Parameters:

  • name (Symbol)

    of the resource proxy

  • opts (Hash) (defaults to: {})

    options to be passed to proxy registration

Options Hash (opts):

  • :create_by (String, Array)

    resource can only be created by these resources.



57
58
59
60
61
62
63
64
65
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 57

def register_proxy(name, opts = {})
  name = name.to_sym
  opts = Hashie::Mash.new(opts)
  if opts[:create_by] && !opts[:create_by].kind_of?(Array)
    opts[:create_by] = [opts[:create_by]]
  end
  opts[:proxy_module] = self
  OmfRc::ResourceFactory.register_proxy(name => opts)
end

- (Object) request(name, opts = {}) {|resource| ... }

Register a property that could be requested

Examples:

suppose we define a utility for iw command interaction

module OmfRc::Util::Iw
  include OmfRc::ResourceProxyDSL

  request :freq do |resource|
    `iw #{resource.hrn} link`.match(/^(freq):\W*(.+)$/) && $2
  end

  # or we can grab everything from output of iw link command and return as a hash(mash)
  `iw #{resource.hrn} link`.chomp.gsub(/^\t/, '').split("\n").drop(1).each do |v|
    v.match(/^(.+):\W*(.+)$/).tap do |m|
      m && known_properties[m[1].downcase.gsub(/\W+/, '_')] = m[2].gsub(/^\W+/, '')
    end
  end
end

Parameters:

  • name (Symbol)

    of the property

Yield Parameters:

  • resource (AbstractResource)

    pass the current resource object to the block



272
273
274
275
276
277
278
279
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 272

def request(name, opts = {}, &register_block)
  unless opts[:if] && !opts[:if].call
    define_method("request_#{name.to_s}") do |*args, &block|
      args[0] = Hashie::Mash.new(args[0]) if args[0].class == Hash
      register_block.call(self, *args, block) if register_block
    end
  end
end

- (Object) utility(name)

Include the utility by providing a name

The utility file can be added to the default utility directory UTIL_DIR, or defined inline.

Examples:

assume we have a module called iw.rb in the omf_rc/util directory, providing a module named OmfRc::Util::Iw with functionalities based on iw cli


module OmfRc::ResourceProxy::Wifi
  include OmfRc::ResourceProxyDSL

  # Simply include this util module
  utility :iw
end

Parameters:

  • name (Symbol)

    of the utility



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 168

def utility(name)
  name = name.to_s
  begin
    # In case of module defined inline
    include "OmfRc::Util::#{name.camelize}".constantize
    extend "OmfRc::Util::#{name.camelize}".constantize
  rescue NameError
    begin
      # Then we try to require the file and include the module
      require "#{UTIL_DIR}/#{name}"
      include "OmfRc::Util::#{name.camelize}".constantize
      extend "OmfRc::Util::#{name.camelize}".constantize
    rescue LoadError => le
      logger.error le.message
    rescue NameError => ne
      logger.error ne.message
    end
  end
end

- (Object) work(name) {|resource| ... }

Define an arbitrary method to do some work, can be included in configure & request block

Examples:

suppose we define a simple os checking method


work :os do
  `uname`
end

# then this os method will be available in all proxy definitions which includes this work method definition.
# if for some reason you need to call 'os' method within the same module, you need to access it via the resource instance.

work :install_software do |resource|
  raise 'Can not support non-linux distro yet' if resource.os == 'Linux'
end

Parameters:

  • name (Symbol)

    of the property

Yield Parameters:

  • resource (AbstractResource)

    pass the current resource object to the block



297
298
299
300
301
# File 'omf_rc/lib/omf_rc/resource_proxy_dsl.rb', line 297

def work(name, &register_block)
  define_method(name) do |*args, &block|
    register_block.call(self, *args, block) if register_block
  end
end