X-Git-Url: https://review.fuel-infra.org/gitweb?a=blobdiff_plain;f=website%2Freference%2Fplugins%2Fddl.md;fp=website%2Freference%2Fplugins%2Fddl.md;h=5d3b5e96231c417df33112e241861634c0ac2a45;hb=b87d2f4e68281062df1913440ca5753ae63314a9;hp=0000000000000000000000000000000000000000;hpb=ab0ea530b8ac956091f17b104ab2311336cfc250;p=packages%2Fprecise%2Fmcollective.git diff --git a/website/reference/plugins/ddl.md b/website/reference/plugins/ddl.md new file mode 100644 index 0000000..5d3b5e9 --- /dev/null +++ b/website/reference/plugins/ddl.md @@ -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.