# class MCollective::DDL::Base

The base class for all kinds of DDL files. DDL files when run gets parsed and builds up a hash of the basic primitive types, ideally restricted so it can be converted to JSON though today there are some Ruby Symbols in them which might be fixed laster on.

The Hash being built should be stored in @entities, the format is generally not prescribed but there’s a definite feel to how DDL files look so study the agent and discovery ones to see how the structure applies to very different use cases.

For every plugin type you should have a single word name - that corresponds to the directory in the libdir where these plugins live. If you need anything above and beyond ‘metadata’ in your plugin DDL then add a PlugintypeDDL class here and add your specific behaviors to those.

### Attributes

entities[R]
meta[R]
pluginname[R]
plugintype[R]
requirements[R]
usage[R]

### Public Class Methods

new(plugin, plugintype=:agent, loadddl=true) click to toggle source

    # File lib/mcollective/ddl/base.rb, line 22
    def initialize(plugin, plugintype=:agent, loadddl=true)
      @entities = {}
      @meta = {}
      @usage = ""
      @config = Config.instance
      @pluginname = plugin
      @plugintype = plugintype.to_sym
      @requirements = {}

      loadddlfile if loadddl
    end

### Public Instance Methods

findddlfile(ddlname=nil, ddltype=nil) click to toggle source

    # File lib/mcollective/ddl/base.rb, line 86
    def findddlfile(ddlname=nil, ddltype=nil)
      ddlname = @pluginname unless ddlname
      ddltype = @plugintype unless ddltype

      @config.libdir.each do |libdir|
        ddlfile = File.join([libdir, "mcollective", ddltype.to_s, "#{ddlname}.ddl"])
        if File.exist?(ddlfile)
          Log.debug("Found #{ddlname} ddl at #{ddlfile}")
          return ddlfile
        end
      end
      return false
    end

help(template=nil) click to toggle source

Generates help using the template based on the data created with metadata and input.

If no template name is provided one will be chosen based on the plugin type. If the provided template path is not absolute then the template will be loaded relative to helptemplatedir configuration parameter

    # File lib/mcollective/ddl/base.rb, line 41
    def help(template=nil)
      template = template_for_plugintype unless template
      template = File.join(@config.helptemplatedir, template) unless template.start_with?(File::SEPARATOR)

      template = File.read(template)
      meta = @meta
      entities = @entities

      unless template == "metadata-help.erb"
        metadata_template = File.join(@config.helptemplatedir, "metadata-help.erb")
        metadata_template = File.read(metadata_template)
        metastring = ERB.new(metadata_template, 0, '%')
        metastring = metastring.result(binding)
      end

      erb = ERB.new(template, 0, '%')
      erb.result(binding)
    end

input(argument, properties) click to toggle source

Registers an input argument for a given action

See the documentation for action for how to use this

    # File lib/mcollective/ddl/base.rb, line 150
    def input(argument, properties)
      raise "Cannot figure out what entity input #{argument} belongs to" unless @current_entity

      entity = @current_entity

      [:prompt, :description, :type].each do |arg|
        raise "Input needs a :#{arg} property" unless properties.include?(arg)
      end

      @entities[entity][:input][argument] = {:prompt => properties[:prompt],
                                             :description => properties[:description],
                                             :type => properties[:type],
                                             :optional => properties[:optional]}

      case properties[:type]
        when :string
          raise "Input type :string needs a :validation argument" unless properties.include?(:validation)
          raise "Input type :string needs a :maxlength argument" unless properties.include?(:maxlength)

          @entities[entity][:input][argument][:validation] = properties[:validation]
          @entities[entity][:input][argument][:maxlength] = properties[:maxlength]

        when :list
          raise "Input type :list needs a :list argument" unless properties.include?(:list)

          @entities[entity][:input][argument][:list] = properties[:list]
      end
    end

loadddlfile() click to toggle source

    # File lib/mcollective/ddl/base.rb, line 78
    def loadddlfile
      if ddlfile = findddlfile
        instance_eval(File.read(ddlfile), ddlfile, 1)
      else
        raise("Can't find DDL for #{@plugintype} plugin '#{@pluginname}'")
      end
    end

metadata(meta) click to toggle source

Registers meta data for the introspection hash

    # File lib/mcollective/ddl/base.rb, line 211
    def metadata(meta)
      [:name, :description, :author, :license, :version, :url, :timeout].each do |arg|
        raise "Metadata needs a :#{arg} property" unless meta.include?(arg)
      end

      @meta = meta
    end

output(argument, properties) click to toggle source

Registers an output argument for a given action

See the documentation for action for how to use this

    # File lib/mcollective/ddl/base.rb, line 182
    def output(argument, properties)
      raise "Cannot figure out what action input #{argument} belongs to" unless @current_entity
      raise "Output #{argument} needs a description argument" unless properties.include?(:description)
      raise "Output #{argument} needs a display_as argument" unless properties.include?(:display_as)

      action = @current_entity

      @entities[action][:output][argument] = {:description => properties[:description],
                                              :display_as  => properties[:display_as],
                                              :default     => properties[:default]}
    end

requires(requirement) click to toggle source

    # File lib/mcollective/ddl/base.rb, line 194
    def requires(requirement)
      raise "Requirement should be a hash in the form :item => 'requirement'" unless requirement.is_a?(Hash)

      valid_requirements = [:mcollective]

      requirement.keys.each do |key|
        unless valid_requirements.include?(key)
          raise "Requirement %s is not a valid requirement, only %s is supported" % [key, valid_requirements.join(", ")]
        end

        @requirements[key] = requirement[key]
      end

      validate_requirements
    end

template_for_plugintype() click to toggle source

    # File lib/mcollective/ddl/base.rb, line 64
    def template_for_plugintype
      case @plugintype
      when :agent
        return "rpc-help.erb"
      else
        if File.exists?(File.join(@config.helptemplatedir,"#{@plugintype}-help.erb"))
          return "#{@plugintype}-help.erb"
        else
          # Default help template gets loaded if plugintype-help does not exist.
          return "metadata-help.erb"
        end
      end
    end

validate_input_argument(input, key, argument) click to toggle source

validate strings, lists and booleans, we’ll add more types of validators when all the use cases are clear

only does validation for arguments actually given, since some might be optional. We validate the presense of the argument earlier so this is a safe assumption, just to skip them.

:string can have maxlength and regex. A maxlength of 0 will bypasss checks :list has a array of valid values

    # File lib/mcollective/ddl/base.rb, line 124
    def validate_input_argument(input, key, argument)
      Validator.load_validators

      case input[key][:type]
      when :string
        Validator.validate(argument, :string)

        Validator.length(argument, input[key][:maxlength].to_i)

        Validator.validate(argument, input[key][:validation])

      when :list
        Validator.validate(argument, input[key][:list])

      else
        Validator.validate(argument, input[key][:type])
      end

      return true
    rescue => e
      raise DDLValidationError, "Cannot validate input %s: %s" % [key, e.to_s]
    end

validate_requirements() click to toggle source

    # File lib/mcollective/ddl/base.rb, line 100
    def validate_requirements
      if requirement = @requirements[:mcollective]
        if Util.mcollective_version == "@DEVELOPMENT_VERSION@"
          Log.warn("DDL requirements validation being skipped in development")
          return true
        end

        if Util.versioncmp(Util.mcollective_version, requirement) < 0
          raise DDLValidationError, "%s plugin '%s' requires MCollective version %s or newer" % [@plugintype.to_s.capitalize, @pluginname, requirement]
        end
      end

      true
    end