Update mcollective.init according to OSCI-855
[packages/precise/mcollective.git] / website / reference / plugins / ddl.md
1 ---
2 layout: default
3 title: Data Definition Language
4 ---
5 [WritingAgents]: /mcollective/reference/basic/basic_agent_and_client.html
6 [SimpleRPCClients]: /mcollective/simplerpc/clients.html
7 [ResultsandExceptions]: /mcollective/simplerpc/clients.html#results_and_exceptions
8 [SimpleRPCAuditing]: /mcollective/simplerpc/auditing.html
9 [SimpleRPCAuthorization]: /mcollective/simplerpc/authorization.html
10 [WritingAgentsScreenCast]: http://mcollective.blip.tv/file/3808928/
11 [DDLScreenCast]: http://mcollective.blip.tv/file/3799653
12 [RPCUtil]: /mcollective/reference/plugins/rpcutil.html
13 [ValidatorPlugins]: /mcollective/reference/plugins/validator.html
14
15 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.
16
17 In addition to the usual procedure definitions we also keep meta data about author, versions, license and other key data points.
18
19 The DDL is used in various scenarios:
20
21  * The user can access it in the form of a human readable help page
22  * User interfaces can access it in a way that facilitate auto generation of user interfaces
23  * The RPC client auto configures and use appropriate timeouts in waiting for responses
24  * Before sending a call over the network inputs get validated so we do not send unexpected data to remote nodes.
25  * Module repositories can use the meta data to display a standard view of available modules to assist a user in picking the right ones.
26  * The server will validate incoming requests prior to sending it to agents
27
28 We've created [a screencast showing the capabilities of the DDL][DDLScreenCast] that might help give you a better overview.
29
30 **NOTE:** As of version 2.1.1 the DDL is required on all servers before an agent will be activated
31
32 ## Examples
33 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.
34
35 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.
36
37 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.
38
39 ### Meta Data
40 First we need to define the meta data for the agent itself:
41
42 {% highlight ruby linenos %}
43 metadata :name        => "SimpleRPC Service Agent",
44          :description => "Agent to manage services using the Puppet service provider",
45          :author      => "R.I.Pienaar",
46          :license     => "GPLv2",
47          :version     => "1.1",
48          :url         => "http://projects.puppetlabs.com/projects/mcollective-plugins/wiki",
49          :timeout     => 60
50 {% endhighlight %}
51
52 It's fairly obvious what these all do, *:timeout* is how long the MCollective daemon will let the threads run.
53
54 ## Required versions
55 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.
56
57 {% highlight ruby linenos %}
58 requires :mcollective => "2.0.0"
59 {% endhighlight %}
60
61 You should add this right after the metadata section in the DDL
62
63 ## Actions, Input and Output
64 Defining inputs and outputs is the hardest part, below first the *status* action:
65
66 {% highlight ruby linenos %}
67 action "status", :description => "Gets the status of a service" do
68     display :always  # supported in 0.4.7 and newer only
69
70     input :service,
71           :prompt      => "Service Name",
72           :description => "The service to get the status for",
73           :type        => :string,
74           :validation  => '^[a-zA-Z\-_\d]+$',
75           :optional    => false,
76           :default     => "mcollective",
77           :maxlength   => 30
78
79     output :status,
80            :description => "The status of service",
81            :display_as  => "Service Status",
82            :default     => "unknown status"
83 end
84 {% endhighlight %}
85
86 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.
87
88 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.
89
90 As of version 2.3.1 the inputs can also define default values, this is only processed and applied for non optional inputs.
91
92 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*.
93
94 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.
95
96 {% highlight ruby linenos %}
97 ["start", "stop", "restart"].each do |act|
98     action act, :description => "#{act.capitalize} a service" do
99         input :service,
100               :prompt      => "Service Name",
101               :description => "The service to #{act}",
102               :type        => :string,
103               :validation  => '^[a-zA-Z\-_\d]+$',
104               :optional    => false,
105               :maxlength   => 30
106
107         output :status,
108                :description => "The status of service after #{act}",
109                :display_as  => "Service Status",
110                :default     => "unknown status"
111     end
112 end
113 {% endhighlight %}
114
115 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*.
116
117 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.
118
119 You can view a human readable version of this using *mco plugin doc <agent>* command:
120
121 {% highlight console %}
122 % mco plugin doc service
123 SimpleRPC Service Agent
124 =======================
125
126 Agent to manage services using the Puppet service provider
127
128       Author: R.I.Pienaar
129      Version: 1.1
130      License: GPLv2
131      Timeout: 60
132    Home Page: http://projects.puppetlabs.com/projects/mcollective-plugins/wiki
133
134
135
136 ACTIONS:
137 ========
138    restart, start, status, stop
139
140    restart action:
141    ---------------
142        Restart a service
143
144        INPUT:
145            service:
146               Description: The service to restart
147                    Prompt: Service Name
148                      Type: string
149                Validation: ^[a-zA-Z\-_\d]+$
150                    Length: 30
151
152
153        OUTPUT:
154            status:
155               Description: The status of service after restart
156                Display As: Service Status
157 {% endhighlight %}
158
159 ### Optional Inputs
160 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.
161
162 ### Types of Input
163 As you see above the input block has *:type* option, types can be *:string*, *:list*, *:boolean*, *:integer*, *:float* or *:number*
164
165 #### :string type
166 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.
167
168 Both *:validation* and *:maxlength* are required arguments for the string type of input.
169
170 If you want to allow unlimited length text you can make *:maxlength => 0* but use this with care.
171
172 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.
173
174 #### :list type
175 List types provide a list of valid options and only those will be allowed, see an example below:
176
177 {% highlight ruby linenos %}
178 input :action,
179       :prompt      => "Service Action",
180       :description => "The action to perform",
181       :type        => :list,
182       :optional    => false,
183       :list        => ["stop", "start", "restart"]
184 {% endhighlight %}
185
186 In user interfaces this might be displayed as a drop down list selector or another kind of menu.
187
188 #### :boolean type
189
190 The value input should be either _true_ or _false_ actual boolean values.  This feature was introduced in version _0.4.9_.
191
192 #### :integer type
193
194 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_
195
196 #### :float type
197
198 The value input should be a floating point number like _1.0_ but not _1_.  This feature was introduced in version _1.3.2_
199
200 #### :number type
201
202 The value input should be an integer or a floating point number. This feature was introduced in version _1.3.2_
203
204 #### :any type
205
206 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.
207
208 The :any type is deprecated and will be removed after version 2.2.x.
209
210 ### Accessing the DDL
211 While programming client applications or web apps you can gain access to the DDL for any agent in several ways:
212
213 {% highlight ruby linenos %}
214 require 'mcollective'
215
216 config = MCollective::Config.instance
217 config.loadconfig(options[:config])
218
219 ddl = MCollective::DDL.new("service")
220 puts ddl.help("#{config.configdir}/rpc-help.erb")
221 {% endhighlight %}
222
223 This will produce the text help output from the above example, you can supply any ERB template to format the output however you want.
224
225 You can also access the data structures directly:
226
227 {% highlight ruby linenos %}
228 ddl = MCollective::DDL.new("service")
229 puts "Meta Data:"
230 pp ddl.meta
231
232 puts
233 puts "Status Action:"
234 pp ddl.action_interface("status")
235 {% endhighlight %}
236
237 {% highlight ruby linenos %}
238 Meta Data:
239 {:license=>"GPLv2",
240  :author=>"R.I.Pienaar",
241  :name=>"SimpleRPC Service Agent",
242  :timeout=>60,
243  :version=>"1.1",
244  :url=>"http://projects.puppetlabs.com/projects/mcollective-plugins/wiki",
245  :description=>"Agent to manage services using the Puppet service provider"}
246
247 Status Action:
248 {:action=>"status",
249  :input=>
250   {:service=>
251     {:validation=>"^[a-zA-Z\\-_\\d]+$",
252      :maxlength=>30,
253      :prompt=>"Service Name",
254      :type=>:string,
255      :optional=>false,
256      :description=>"The service to get the status for"}},
257  :output=>
258   {"status"=>
259     {:display_as=>"Service Status", :description=>"The status of service"}},
260  :description=>"Gets the status of a service"}
261
262 {% endhighlight %}
263
264 The ddl object is also available on any *rpcclient*:
265
266 {% highlight ruby linenos %}
267 service = rpcclient("service")
268 pp service.ddl.meta
269 {% endhighlight %}
270
271 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.
272
273 ### Input Validation
274 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.