Updated mcollective.init according to OSCI-658
[packages/precise/mcollective.git] / website / reference / plugins / ddl.md
diff --git a/website/reference/plugins/ddl.md b/website/reference/plugins/ddl.md
new file mode 100644 (file)
index 0000000..5d3b5e9
--- /dev/null
@@ -0,0 +1,274 @@
+---
+layout: default
+title: Data Definition Language
+---
+[WritingAgents]: /mcollective/reference/basic/basic_agent_and_client.html
+[SimpleRPCClients]: /mcollective/simplerpc/clients.html
+[ResultsandExceptions]: /mcollective/simplerpc/clients.html#results_and_exceptions
+[SimpleRPCAuditing]: /mcollective/simplerpc/auditing.html
+[SimpleRPCAuthorization]: /mcollective/simplerpc/authorization.html
+[WritingAgentsScreenCast]: http://mcollective.blip.tv/file/3808928/
+[DDLScreenCast]: http://mcollective.blip.tv/file/3799653
+[RPCUtil]: /mcollective/reference/plugins/rpcutil.html
+[ValidatorPlugins]: /mcollective/reference/plugins/validator.html
+
+As with other remote procedure invocation systems MCollective has a DDL that defines what remote methods are available, what inputs they take and what outputs they generate.
+
+In addition to the usual procedure definitions we also keep meta data about author, versions, license and other key data points.
+
+The DDL is used in various scenarios:
+
+ * The user can access it in the form of a human readable help page
+ * User interfaces can access it in a way that facilitate auto generation of user interfaces
+ * The RPC client auto configures and use appropriate timeouts in waiting for responses
+ * Before sending a call over the network inputs get validated so we do not send unexpected data to remote nodes.
+ * Module repositories can use the meta data to display a standard view of available modules to assist a user in picking the right ones.
+ * The server will validate incoming requests prior to sending it to agents
+
+We've created [a screencast showing the capabilities of the DDL][DDLScreenCast] that might help give you a better overview.
+
+**NOTE:** As of version 2.1.1 the DDL is required on all servers before an agent will be activated
+
+## Examples
+We'll start with a few examples as I think it's pretty simple what they do, and later on show what other permutations are allowed for defining inputs and outputs.
+
+A helper agent called [_rpcutil_][RPCUtil] is included that helps you gather stats, inventory etc about the running daemon.  This helper has a full DDL included, see the plugins dir for this agent.
+
+The typical service agent is a good example, it has various actions that all more or less take the same input.  All but status would have almost identical language.
+
+### Meta Data
+First we need to define the meta data for the agent itself:
+
+{% highlight ruby linenos %}
+metadata :name        => "SimpleRPC Service Agent",
+         :description => "Agent to manage services using the Puppet service provider",
+         :author      => "R.I.Pienaar",
+         :license     => "GPLv2",
+         :version     => "1.1",
+         :url         => "http://projects.puppetlabs.com/projects/mcollective-plugins/wiki",
+         :timeout     => 60
+{% endhighlight %}
+
+It's fairly obvious what these all do, *:timeout* is how long the MCollective daemon will let the threads run.
+
+## Required versions
+As of MCollective 2.1.2 you can indicate which is the lowest version of MCollective needed to use a plugin.  Plugins that do not meet the requirement can not be used.
+
+{% highlight ruby linenos %}
+requires :mcollective => "2.0.0"
+{% endhighlight %}
+
+You should add this right after the metadata section in the DDL
+
+## Actions, Input and Output
+Defining inputs and outputs is the hardest part, below first the *status* action:
+
+{% highlight ruby linenos %}
+action "status", :description => "Gets the status of a service" do
+    display :always  # supported in 0.4.7 and newer only
+
+    input :service,
+          :prompt      => "Service Name",
+          :description => "The service to get the status for",
+          :type        => :string,
+          :validation  => '^[a-zA-Z\-_\d]+$',
+          :optional    => false,
+          :default     => "mcollective",
+          :maxlength   => 30
+
+    output :status,
+           :description => "The status of service",
+           :display_as  => "Service Status",
+           :default     => "unknown status"
+end
+{% endhighlight %}
+
+As you see we can define all the major components of input and output parameters.  *:type* can be one of various values and each will have different parameters, more on that later.
+
+As of version 2.1.1 the outputs can define a default value.  For agents the reply structures are pre-populated with all the defined outputs, if no default is supplied a default of nil will be set.
+
+As of version 2.3.1 the inputs can also define default values, this is only processed and applied for non optional inputs.
+
+By default mcollective only show data from actions that failed, the *display* line above tells it to always show the results.  Possible values are *:ok*, *:failed* (the default behavior) and *:always*.
+
+Finally the service agent has 3 almost identical actions - *start*, *stop* and *restart* - below we use a simple loop to define them all in one go.
+
+{% highlight ruby linenos %}
+["start", "stop", "restart"].each do |act|
+    action act, :description => "#{act.capitalize} a service" do
+        input :service,
+              :prompt      => "Service Name",
+              :description => "The service to #{act}",
+              :type        => :string,
+              :validation  => '^[a-zA-Z\-_\d]+$',
+              :optional    => false,
+              :maxlength   => 30
+
+        output :status,
+               :description => "The status of service after #{act}",
+               :display_as  => "Service Status",
+               :default     => "unknown status"
+    end
+end
+{% endhighlight %}
+
+All of this code just goes into a file, no special class or module bits needed, just save it as *service.ddl* in the same location as the *service.rb*.
+
+Importantly you do not need to have the *service.rb* on a machine to use the DDL, this means on machines that are just used for running client programs you can just drop the *.ddl* files into the agents directory.
+
+You can view a human readable version of this using *mco plugin doc <agent>* command:
+
+{% highlight console %}
+% mco plugin doc service
+SimpleRPC Service Agent
+=======================
+
+Agent to manage services using the Puppet service provider
+
+      Author: R.I.Pienaar
+     Version: 1.1
+     License: GPLv2
+     Timeout: 60
+   Home Page: http://projects.puppetlabs.com/projects/mcollective-plugins/wiki
+
+
+
+ACTIONS:
+========
+   restart, start, status, stop
+
+   restart action:
+   ---------------
+       Restart a service
+
+       INPUT:
+           service:
+              Description: The service to restart
+                   Prompt: Service Name
+                     Type: string
+               Validation: ^[a-zA-Z\-_\d]+$
+                   Length: 30
+
+
+       OUTPUT:
+           status:
+              Description: The status of service after restart
+               Display As: Service Status
+{% endhighlight %}
+
+### Optional Inputs
+The input block has a mandatory *:optional* field, when true it would be ok if a client attempts to call the agent without this input supplied.  If it is supplied though it will be validated.
+
+### Types of Input
+As you see above the input block has *:type* option, types can be *:string*, *:list*, *:boolean*, *:integer*, *:float* or *:number*
+
+#### :string type
+The string type validates initially that the input is infact a String, then it validates the length of the input and finally matches the supplied Regular Expression.
+
+Both *:validation* and *:maxlength* are required arguments for the string type of input.
+
+If you want to allow unlimited length text you can make *:maxlength => 0* but use this with care.
+
+As of version 2.2.0 a new plugin type called [Validator Plugins][ValidatorPlugins] exist that allow you to supply your own validations for *:string* types.
+
+#### :list type
+List types provide a list of valid options and only those will be allowed, see an example below:
+
+{% highlight ruby linenos %}
+input :action,
+      :prompt      => "Service Action",
+      :description => "The action to perform",
+      :type        => :list,
+      :optional    => false,
+      :list        => ["stop", "start", "restart"]
+{% endhighlight %}
+
+In user interfaces this might be displayed as a drop down list selector or another kind of menu.
+
+#### :boolean type
+
+The value input should be either _true_ or _false_ actual boolean values.  This feature was introduced in version _0.4.9_.
+
+#### :integer type
+
+The value input should be an integer number like _1_ or _100_ but not _1.1_.  This feature was introduced in version _1.3.2_
+
+#### :float type
+
+The value input should be a floating point number like _1.0_ but not _1_.  This feature was introduced in version _1.3.2_
+
+#### :number type
+
+The value input should be an integer or a floating point number. This feature was introduced in version _1.3.2_
+
+#### :any type
+
+The value input can be any type, this allows you to send rich objects like arrays of hashes around, it effectively disables validation of the type of input.
+
+The :any type is deprecated and will be removed after version 2.2.x.
+
+### Accessing the DDL
+While programming client applications or web apps you can gain access to the DDL for any agent in several ways:
+
+{% highlight ruby linenos %}
+require 'mcollective'
+
+config = MCollective::Config.instance
+config.loadconfig(options[:config])
+
+ddl = MCollective::DDL.new("service")
+puts ddl.help("#{config.configdir}/rpc-help.erb")
+{% endhighlight %}
+
+This will produce the text help output from the above example, you can supply any ERB template to format the output however you want.
+
+You can also access the data structures directly:
+
+{% highlight ruby linenos %}
+ddl = MCollective::DDL.new("service")
+puts "Meta Data:"
+pp ddl.meta
+
+puts
+puts "Status Action:"
+pp ddl.action_interface("status")
+{% endhighlight %}
+
+{% highlight ruby linenos %}
+Meta Data:
+{:license=>"GPLv2",
+ :author=>"R.I.Pienaar",
+ :name=>"SimpleRPC Service Agent",
+ :timeout=>60,
+ :version=>"1.1",
+ :url=>"http://projects.puppetlabs.com/projects/mcollective-plugins/wiki",
+ :description=>"Agent to manage services using the Puppet service provider"}
+
+Status Action:
+{:action=>"status",
+ :input=>
+  {:service=>
+    {:validation=>"^[a-zA-Z\\-_\\d]+$",
+     :maxlength=>30,
+     :prompt=>"Service Name",
+     :type=>:string,
+     :optional=>false,
+     :description=>"The service to get the status for"}},
+ :output=>
+  {"status"=>
+    {:display_as=>"Service Status", :description=>"The status of service"}},
+ :description=>"Gets the status of a service"}
+
+{% endhighlight %}
+
+The ddl object is also available on any *rpcclient*:
+
+{% highlight ruby linenos %}
+service = rpcclient("service")
+pp service.ddl.meta
+{% endhighlight %}
+
+In the case of accessing it through the service as in this example, if there was no DDL file on the machine for the service agent you'd get a *nil* back from the ddl accessor.
+
+### Input Validation
+As mentioned earlier the client does automatic input validation using the DDL, if validation fails you will get an *MCollective::DDLValidationError* exception thrown with an appropriate message.