mcollective-client 2.0.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mcollective-client might be problematic. Click here for more details.

Files changed (140) hide show
  1. data/lib/mcollective.rb +32 -23
  2. data/lib/mcollective/agent.rb +5 -0
  3. data/lib/mcollective/agents.rb +5 -16
  4. data/lib/mcollective/aggregate.rb +61 -0
  5. data/lib/mcollective/aggregate/base.rb +40 -0
  6. data/lib/mcollective/aggregate/result.rb +9 -0
  7. data/lib/mcollective/aggregate/result/base.rb +25 -0
  8. data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
  9. data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
  10. data/lib/mcollective/application.rb +7 -4
  11. data/lib/mcollective/applications.rb +3 -14
  12. data/lib/mcollective/cache.rb +145 -0
  13. data/lib/mcollective/client.rb +10 -87
  14. data/lib/mcollective/config.rb +22 -8
  15. data/lib/mcollective/data.rb +87 -0
  16. data/lib/mcollective/data/base.rb +67 -0
  17. data/lib/mcollective/data/result.rb +40 -0
  18. data/lib/mcollective/ddl.rb +113 -0
  19. data/lib/mcollective/ddl/agentddl.rb +185 -0
  20. data/lib/mcollective/ddl/base.rb +220 -0
  21. data/lib/mcollective/ddl/dataddl.rb +56 -0
  22. data/lib/mcollective/ddl/discoveryddl.rb +52 -0
  23. data/lib/mcollective/ddl/validatorddl.rb +6 -0
  24. data/lib/mcollective/discovery.rb +143 -0
  25. data/lib/mcollective/generators.rb +7 -0
  26. data/lib/mcollective/generators/agent_generator.rb +51 -0
  27. data/lib/mcollective/generators/base.rb +46 -0
  28. data/lib/mcollective/generators/data_generator.rb +51 -0
  29. data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
  30. data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
  31. data/lib/mcollective/generators/templates/ddl.erb +8 -0
  32. data/lib/mcollective/generators/templates/plugin.erb +7 -0
  33. data/lib/mcollective/logger/console_logger.rb +15 -15
  34. data/lib/mcollective/matcher.rb +167 -0
  35. data/lib/mcollective/matcher/parser.rb +60 -25
  36. data/lib/mcollective/matcher/scanner.rb +156 -78
  37. data/lib/mcollective/message.rb +47 -6
  38. data/lib/mcollective/monkey_patches.rb +17 -0
  39. data/lib/mcollective/optionparser.rb +18 -1
  40. data/lib/mcollective/pluginmanager.rb +3 -3
  41. data/lib/mcollective/pluginpackager.rb +10 -3
  42. data/lib/mcollective/pluginpackager/agent_definition.rb +28 -20
  43. data/lib/mcollective/pluginpackager/standard_definition.rb +11 -9
  44. data/lib/mcollective/registration/base.rb +3 -1
  45. data/lib/mcollective/rpc.rb +18 -24
  46. data/lib/mcollective/rpc/agent.rb +37 -113
  47. data/lib/mcollective/rpc/client.rb +186 -64
  48. data/lib/mcollective/rpc/helpers.rb +42 -80
  49. data/lib/mcollective/rpc/progress.rb +3 -3
  50. data/lib/mcollective/rpc/reply.rb +37 -13
  51. data/lib/mcollective/rpc/request.rb +17 -6
  52. data/lib/mcollective/rpc/result.rb +9 -5
  53. data/lib/mcollective/rpc/stats.rb +71 -24
  54. data/lib/mcollective/security/base.rb +41 -34
  55. data/lib/mcollective/shell.rb +1 -1
  56. data/lib/mcollective/ssl.rb +34 -0
  57. data/lib/mcollective/util.rb +194 -23
  58. data/lib/mcollective/validator.rb +80 -0
  59. data/spec/fixtures/util/1.in +10 -0
  60. data/spec/fixtures/util/1.out +10 -0
  61. data/spec/fixtures/util/2.in +1 -0
  62. data/spec/fixtures/util/2.out +1 -0
  63. data/spec/fixtures/util/3.in +1 -0
  64. data/spec/fixtures/util/3.out +2 -0
  65. data/spec/fixtures/util/4.in +5 -0
  66. data/spec/fixtures/util/4.out +9 -0
  67. data/spec/spec.opts +1 -1
  68. data/spec/spec_helper.rb +2 -0
  69. data/spec/unit/agents_spec.rb +34 -19
  70. data/spec/unit/aggregate/base_spec.rb +57 -0
  71. data/spec/unit/aggregate/result/base_spec.rb +28 -0
  72. data/spec/unit/aggregate/result/collection_result_spec.rb +18 -0
  73. data/spec/unit/aggregate/result/numeric_result_spec.rb +22 -0
  74. data/spec/unit/aggregate_spec.rb +110 -0
  75. data/spec/unit/application_spec.rb +8 -3
  76. data/spec/unit/applications_spec.rb +2 -2
  77. data/spec/unit/cache_spec.rb +115 -0
  78. data/spec/unit/client_spec.rb +78 -0
  79. data/spec/unit/config_spec.rb +32 -34
  80. data/spec/unit/data/base_spec.rb +90 -0
  81. data/spec/unit/data/result_spec.rb +64 -0
  82. data/spec/unit/data_spec.rb +158 -0
  83. data/spec/unit/ddl/agentddl_spec.rb +217 -0
  84. data/spec/unit/{rpc/ddl_spec.rb → ddl/base_spec.rb} +238 -224
  85. data/spec/unit/ddl/dataddl_spec.rb +65 -0
  86. data/spec/unit/ddl/discoveryddl_spec.rb +58 -0
  87. data/spec/unit/ddl_spec.rb +84 -0
  88. data/spec/unit/discovery_spec.rb +196 -0
  89. data/spec/unit/facts/base_spec.rb +1 -1
  90. data/spec/unit/generators/agent_generator_spec.rb +72 -0
  91. data/spec/unit/generators/base_spec.rb +83 -0
  92. data/spec/unit/generators/data_generator_spec.rb +37 -0
  93. data/spec/unit/generators/snippets/agent_ddl +19 -0
  94. data/spec/unit/generators/snippets/data_ddl +20 -0
  95. data/spec/unit/logger/console_logger_spec.rb +76 -0
  96. data/spec/unit/logger/syslog_logger_spec.rb +2 -2
  97. data/spec/unit/matcher/parser_spec.rb +27 -10
  98. data/spec/unit/matcher/scanner_spec.rb +108 -5
  99. data/spec/unit/matcher_spec.rb +260 -0
  100. data/spec/unit/message_spec.rb +35 -13
  101. data/spec/unit/optionparser_spec.rb +2 -2
  102. data/spec/unit/pluginpackager/agent_definition_spec.rb +59 -42
  103. data/spec/unit/pluginpackager/standard_definition_spec.rb +10 -8
  104. data/spec/unit/pluginpackager_spec.rb +131 -0
  105. data/spec/unit/plugins/mcollective/aggregate/average_spec.rb +45 -0
  106. data/spec/unit/plugins/mcollective/aggregate/sum_spec.rb +31 -0
  107. data/spec/unit/plugins/mcollective/aggregate/summary_spec.rb +45 -0
  108. data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +1 -1
  109. data/spec/unit/plugins/mcollective/connector/rabbitmq_spec.rb +478 -0
  110. data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +2 -0
  111. data/spec/unit/plugins/mcollective/data/agent_data_spec.rb +43 -0
  112. data/spec/unit/plugins/mcollective/data/fstat_data_spec.rb +135 -0
  113. data/spec/unit/plugins/mcollective/discovery/flatfile_spec.rb +48 -0
  114. data/spec/unit/plugins/mcollective/discovery/mc_spec.rb +40 -0
  115. data/spec/unit/plugins/mcollective/packagers/debpackage_packager_spec.rb +41 -15
  116. data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +1 -1
  117. data/spec/unit/plugins/mcollective/packagers/rpmpackage_packager_spec.rb +22 -38
  118. data/spec/unit/plugins/mcollective/validator/array_validator_spec.rb +19 -0
  119. data/spec/unit/plugins/mcollective/validator/ipv4address_validator_spec.rb +19 -0
  120. data/spec/unit/plugins/mcollective/validator/ipv6address_validator_spec.rb +19 -0
  121. data/spec/unit/plugins/mcollective/validator/length_validator_spec.rb +19 -0
  122. data/spec/unit/plugins/mcollective/validator/regex_validator_spec.rb +19 -0
  123. data/spec/unit/plugins/mcollective/validator/shellsafe_validator_spec.rb +21 -0
  124. data/spec/unit/plugins/mcollective/validator/typecheck_validator_spec.rb +23 -0
  125. data/spec/unit/registration/base_spec.rb +1 -1
  126. data/spec/unit/rpc/actionrunner_spec.rb +2 -2
  127. data/spec/unit/rpc/agent_spec.rb +41 -65
  128. data/spec/unit/rpc/client_spec.rb +430 -134
  129. data/spec/unit/rpc/reply_spec.rb +31 -1
  130. data/spec/unit/rpc/request_spec.rb +33 -12
  131. data/spec/unit/rpc/result_spec.rb +7 -0
  132. data/spec/unit/rpc/stats_spec.rb +14 -14
  133. data/spec/unit/rpc_spec.rb +16 -0
  134. data/spec/unit/security/base_spec.rb +8 -8
  135. data/spec/unit/ssl_spec.rb +20 -2
  136. data/spec/unit/string_spec.rb +15 -0
  137. data/spec/unit/util_spec.rb +141 -21
  138. data/spec/unit/validator_spec.rb +67 -0
  139. metadata +145 -7
  140. data/lib/mcollective/rpc/ddl.rb +0 -258
@@ -0,0 +1,185 @@
1
+ module MCollective
2
+ module DDL
3
+ # A DDL class specific to agent plugins.
4
+ #
5
+ # A full DDL can be seen below with all the possible bells and whistles present.
6
+ #
7
+ # metadata :name => "Utilities and Helpers for SimpleRPC Agents",
8
+ # :description => "General helpful actions that expose stats and internals to SimpleRPC clients",
9
+ # :author => "R.I.Pienaar <rip@devco.net>",
10
+ # :license => "Apache License, Version 2.0",
11
+ # :version => "1.0",
12
+ # :url => "http://marionette-collective.org/",
13
+ # :timeout => 10
14
+ #
15
+ # action "get_fact", :description => "Retrieve a single fact from the fact store" do
16
+ # display :always
17
+ #
18
+ # input :fact,
19
+ # :prompt => "The name of the fact",
20
+ # :description => "The fact to retrieve",
21
+ # :type => :string,
22
+ # :validation => '^[\w\-\.]+$',
23
+ # :optional => false,
24
+ # :maxlength => 40
25
+ #
26
+ # output :fact,
27
+ # :description => "The name of the fact being returned",
28
+ # :display_as => "Fact"
29
+ #
30
+ # output :value,
31
+ # :description => "The value of the fact",
32
+ # :display_as => "Value",
33
+ # :default => ""
34
+ #
35
+ # summarize do
36
+ # aggregate summary(:value)
37
+ # end
38
+ # end
39
+ class AgentDDL<Base
40
+ def initialize(plugin, plugintype=:agent, loadddl=true)
41
+ @process_aggregate_functions = nil
42
+
43
+ super
44
+ end
45
+
46
+ def input(argument, properties)
47
+ raise "Input needs a :optional property" unless properties.include?(:optional)
48
+
49
+ super
50
+ end
51
+
52
+ # Calls the summarize block defined in the ddl. Block will not be called
53
+ # if the ddl is getting processed on the server side. This means that
54
+ # aggregate plugins only have to be present on the client side.
55
+ #
56
+ # The @process_aggregate_functions variable is used by the method_missing
57
+ # block to determine if it should kick in, this way we very tightly control
58
+ # where we activate the method_missing behavior turning it into a noop
59
+ # otherwise to maximise the chance of providing good user feedback
60
+ def summarize(&block)
61
+ unless @config.mode == :server
62
+ @process_aggregate_functions = true
63
+ block.call
64
+ @process_aggregate_functions = nil
65
+ end
66
+ end
67
+
68
+ # Sets the aggregate array for the given action
69
+ def aggregate(function, format = {:format => nil})
70
+ raise(DDLValidationError, "Formats supplied to aggregation functions should be a hash") unless format.is_a?(Hash)
71
+ raise(DDLValidationError, "Formats supplied to aggregation functions must have a :format key") unless format.keys.include?(:format)
72
+ raise(DDLValidationError, "Functions supplied to aggregate should be a hash") unless function.is_a?(Hash)
73
+
74
+ unless (function.keys.include?(:args)) && function[:args]
75
+ raise DDLValidationError, "aggregate method for action '%s' missing a function parameter" % entities[@current_entity][:action]
76
+ end
77
+
78
+ entities[@current_entity][:aggregate] ||= []
79
+ entities[@current_entity][:aggregate] << (format[:format].nil? ? function : function.merge(format))
80
+ end
81
+
82
+ # Sets the display preference to either :ok, :failed, :flatten or :always
83
+ # operates on action level
84
+ def display(pref)
85
+ # defaults to old behavior, complain if its supplied and invalid
86
+ unless [:ok, :failed, :flatten, :always].include?(pref)
87
+ raise "Display preference #{pref} is not valid, should be :ok, :failed, :flatten or :always"
88
+ end
89
+
90
+ action = @current_entity
91
+ @entities[action][:display] = pref
92
+ end
93
+
94
+ # Creates the definition for an action, you can nest input definitions inside the
95
+ # action to attach inputs and validation to the actions
96
+ #
97
+ # action "status", :description => "Restarts a Service" do
98
+ # display :always
99
+ #
100
+ # input "service",
101
+ # :prompt => "Service Action",
102
+ # :description => "The action to perform",
103
+ # :type => :list,
104
+ # :optional => true,
105
+ # :list => ["start", "stop", "restart", "status"]
106
+ #
107
+ # output "status",
108
+ # :description => "The status of the service after the action"
109
+ #
110
+ # end
111
+ def action(name, input, &block)
112
+ raise "Action needs a :description property" unless input.include?(:description)
113
+
114
+ unless @entities.include?(name)
115
+ @entities[name] = {}
116
+ @entities[name][:action] = name
117
+ @entities[name][:input] = {}
118
+ @entities[name][:output] = {}
119
+ @entities[name][:display] = :failed
120
+ @entities[name][:description] = input[:description]
121
+ end
122
+
123
+ # if a block is passed it might be creating input methods, call it
124
+ # we set @current_entity so the input block can know what its talking
125
+ # to, this is probably an epic hack, need to improve.
126
+ @current_entity = name
127
+ block.call if block_given?
128
+ @current_entity = nil
129
+ end
130
+
131
+ # If the method name matches a # aggregate function, we return the function
132
+ # with args as a hash. This will only be active if the @process_aggregate_functions
133
+ # is set to true which only happens in the #summarize block
134
+ def method_missing(name, *args, &block)
135
+ unless @process_aggregate_functions || is_function?(name)
136
+ raise NoMethodError, "undefined local variable or method `#{name}'", caller
137
+ end
138
+
139
+ return {:function => name, :args => args}
140
+ end
141
+
142
+ # Checks if a method name matches a aggregate plugin.
143
+ # This is used by method missing so that we dont greedily assume that
144
+ # every method_missing call in an agent ddl has hit a aggregate function.
145
+ def is_function?(method_name)
146
+ PluginManager.find("aggregate").include?(method_name.to_s)
147
+ end
148
+
149
+ # Helper to use the DDL to figure out if the remote call to an
150
+ # agent should be allowed based on action name and inputs.
151
+ def validate_rpc_request(action, arguments)
152
+ # is the action known?
153
+ unless actions.include?(action)
154
+ raise DDLValidationError, "Attempted to call action #{action} for #{@pluginname} but it's not declared in the DDL"
155
+ end
156
+
157
+ input = action_interface(action)[:input] || {}
158
+
159
+ input.keys.each do |key|
160
+ unless input[key][:optional]
161
+ unless arguments.keys.include?(key)
162
+ raise DDLValidationError, "Action #{action} needs a #{key} argument"
163
+ end
164
+ end
165
+
166
+ if arguments.keys.include?(key)
167
+ validate_input_argument(input, key, arguments[key])
168
+ end
169
+ end
170
+
171
+ true
172
+ end
173
+
174
+ # Returns the interface for a specific action
175
+ def action_interface(name)
176
+ @entities[name] || {}
177
+ end
178
+
179
+ # Returns an array of actions this agent support
180
+ def actions
181
+ @entities.keys
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,220 @@
1
+ module MCollective
2
+ module DDL
3
+ # The base class for all kinds of DDL files. DDL files when
4
+ # run gets parsed and builds up a hash of the basic primitive
5
+ # types, ideally restricted so it can be converted to JSON though
6
+ # today there are some Ruby Symbols in them which might be fixed
7
+ # laster on.
8
+ #
9
+ # The Hash being built should be stored in @entities, the format
10
+ # is generally not prescribed but there's a definite feel to how
11
+ # DDL files look so study the agent and discovery ones to see how
12
+ # the structure applies to very different use cases.
13
+ #
14
+ # For every plugin type you should have a single word name - that
15
+ # corresponds to the directory in the libdir where these plugins
16
+ # live. If you need anything above and beyond 'metadata' in your
17
+ # plugin DDL then add a PlugintypeDDL class here and add your
18
+ # specific behaviors to those.
19
+ class Base
20
+ attr_reader :meta, :entities, :pluginname, :plugintype, :usage, :requirements
21
+
22
+ def initialize(plugin, plugintype=:agent, loadddl=true)
23
+ @entities = {}
24
+ @meta = {}
25
+ @usage = ""
26
+ @config = Config.instance
27
+ @pluginname = plugin
28
+ @plugintype = plugintype.to_sym
29
+ @requirements = {}
30
+
31
+ loadddlfile if loadddl
32
+ end
33
+
34
+ # Generates help using the template based on the data
35
+ # created with metadata and input.
36
+ #
37
+ # If no template name is provided one will be chosen based
38
+ # on the plugin type. If the provided template path is
39
+ # not absolute then the template will be loaded relative to
40
+ # helptemplatedir configuration parameter
41
+ def help(template=nil)
42
+ template = template_for_plugintype unless template
43
+ template = File.join(@config.helptemplatedir, template) unless template.start_with?(File::SEPARATOR)
44
+
45
+ template = File.read(template)
46
+ meta = @meta
47
+ entities = @entities
48
+
49
+ unless template == "metadata-help.erb"
50
+ metadata_template = File.join(@config.helptemplatedir, "metadata-help.erb")
51
+ metadata_template = File.read(metadata_template)
52
+ metastring = ERB.new(metadata_template, 0, '%')
53
+ metastring = metastring.result(binding)
54
+ end
55
+
56
+ erb = ERB.new(template, 0, '%')
57
+ erb.result(binding)
58
+ end
59
+
60
+ def usage(usage_text)
61
+ @usage = usage_text
62
+ end
63
+
64
+ def template_for_plugintype
65
+ case @plugintype
66
+ when :agent
67
+ return "rpc-help.erb"
68
+ else
69
+ if File.exists?(File.join(@config.helptemplatedir,"#{@plugintype}-help.erb"))
70
+ return "#{@plugintype}-help.erb"
71
+ else
72
+ # Default help template gets loaded if plugintype-help does not exist.
73
+ return "metadata-help.erb"
74
+ end
75
+ end
76
+ end
77
+
78
+ def loadddlfile
79
+ if ddlfile = findddlfile
80
+ instance_eval(File.read(ddlfile), ddlfile, 1)
81
+ else
82
+ raise("Can't find DDL for #{@plugintype} plugin '#{@pluginname}'")
83
+ end
84
+ end
85
+
86
+ def findddlfile(ddlname=nil, ddltype=nil)
87
+ ddlname = @pluginname unless ddlname
88
+ ddltype = @plugintype unless ddltype
89
+
90
+ @config.libdir.each do |libdir|
91
+ ddlfile = File.join([libdir, "mcollective", ddltype.to_s, "#{ddlname}.ddl"])
92
+ if File.exist?(ddlfile)
93
+ Log.debug("Found #{ddlname} ddl at #{ddlfile}")
94
+ return ddlfile
95
+ end
96
+ end
97
+ return false
98
+ end
99
+
100
+ def validate_requirements
101
+ if requirement = @requirements[:mcollective]
102
+ if Util.mcollective_version == "@DEVELOPMENT_VERSION@"
103
+ Log.warn("DDL requirements validation being skipped in development")
104
+ return true
105
+ end
106
+
107
+ if Util.versioncmp(Util.mcollective_version, requirement) < 0
108
+ raise DDLValidationError, "%s plugin '%s' requires MCollective version %s or newer" % [@plugintype.to_s.capitalize, @pluginname, requirement]
109
+ end
110
+ end
111
+
112
+ true
113
+ end
114
+
115
+ # validate strings, lists and booleans, we'll add more types of validators when
116
+ # all the use cases are clear
117
+ #
118
+ # only does validation for arguments actually given, since some might
119
+ # be optional. We validate the presense of the argument earlier so
120
+ # this is a safe assumption, just to skip them.
121
+ #
122
+ # :string can have maxlength and regex. A maxlength of 0 will bypasss checks
123
+ # :list has a array of valid values
124
+ def validate_input_argument(input, key, argument)
125
+ Validator.load_validators
126
+
127
+ case input[key][:type]
128
+ when :string
129
+ Validator.validate(argument, :string)
130
+
131
+ Validator.length(argument, input[key][:maxlength].to_i)
132
+
133
+ Validator.validate(argument, input[key][:validation])
134
+
135
+ when :list
136
+ Validator.validate(argument, input[key][:list])
137
+
138
+ else
139
+ Validator.validate(argument, input[key][:type])
140
+ end
141
+
142
+ return true
143
+ rescue => e
144
+ raise DDLValidationError, "Cannot validate input: %s" % e.to_s
145
+ end
146
+
147
+ # Registers an input argument for a given action
148
+ #
149
+ # See the documentation for action for how to use this
150
+ def input(argument, properties)
151
+ raise "Cannot figure out what entity input #{argument} belongs to" unless @current_entity
152
+
153
+ entity = @current_entity
154
+
155
+ [:prompt, :description, :type].each do |arg|
156
+ raise "Input needs a :#{arg} property" unless properties.include?(arg)
157
+ end
158
+
159
+ @entities[entity][:input][argument] = {:prompt => properties[:prompt],
160
+ :description => properties[:description],
161
+ :type => properties[:type],
162
+ :optional => properties[:optional]}
163
+
164
+ case properties[:type]
165
+ when :string
166
+ raise "Input type :string needs a :validation argument" unless properties.include?(:validation)
167
+ raise "Input type :string needs a :maxlength argument" unless properties.include?(:maxlength)
168
+
169
+ @entities[entity][:input][argument][:validation] = properties[:validation]
170
+ @entities[entity][:input][argument][:maxlength] = properties[:maxlength]
171
+
172
+ when :list
173
+ raise "Input type :list needs a :list argument" unless properties.include?(:list)
174
+
175
+ @entities[entity][:input][argument][:list] = properties[:list]
176
+ end
177
+ end
178
+
179
+ # Registers an output argument for a given action
180
+ #
181
+ # See the documentation for action for how to use this
182
+ def output(argument, properties)
183
+ raise "Cannot figure out what action input #{argument} belongs to" unless @current_entity
184
+ raise "Output #{argument} needs a description argument" unless properties.include?(:description)
185
+ raise "Output #{argument} needs a display_as argument" unless properties.include?(:display_as)
186
+
187
+ action = @current_entity
188
+
189
+ @entities[action][:output][argument] = {:description => properties[:description],
190
+ :display_as => properties[:display_as],
191
+ :default => properties[:default]}
192
+ end
193
+
194
+ def requires(requirement)
195
+ raise "Requirement should be a hash in the form :item => 'requirement'" unless requirement.is_a?(Hash)
196
+
197
+ valid_requirements = [:mcollective]
198
+
199
+ requirement.keys.each do |key|
200
+ unless valid_requirements.include?(key)
201
+ raise "Requirement %s is not a valid requirement, only %s is supported" % [key, valid_requirements.join(", ")]
202
+ end
203
+
204
+ @requirements[key] = requirement[key]
205
+ end
206
+
207
+ validate_requirements
208
+ end
209
+
210
+ # Registers meta data for the introspection hash
211
+ def metadata(meta)
212
+ [:name, :description, :author, :license, :version, :url, :timeout].each do |arg|
213
+ raise "Metadata needs a :#{arg} property" unless meta.include?(arg)
214
+ end
215
+
216
+ @meta = meta
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,56 @@
1
+ module MCollective
2
+ module DDL
3
+ # A DDL file for the data query plugins.
4
+ #
5
+ # Query plugins can today take only one input by convention in the DDL that
6
+ # is called :query, otherwise the input is identical to the standard input.
7
+ #
8
+ # metadata :name => "Agent",
9
+ # :description => "Meta data about installed MColletive Agents",
10
+ # :author => "R.I.Pienaar <rip@devco.net>",
11
+ # :license => "ASL 2.0",
12
+ # :version => "1.0",
13
+ # :url => "http://marionette-collective.org/",
14
+ # :timeout => 1
15
+ #
16
+ # dataquery :description => "Agent Meta Data" do
17
+ # input :query,
18
+ # :prompt => "Agent Name",
19
+ # :description => "Valid agent name",
20
+ # :type => :string,
21
+ # :validation => /^[\w\_]+$/,
22
+ # :maxlength => 20
23
+ #
24
+ # [:license, :timeout, :description, :url, :version, :author].each do |item|
25
+ # output item,
26
+ # :description => "Agent #{item}",
27
+ # :display_as => item.to_s.capitalize
28
+ # end
29
+ # end
30
+ class DataDDL<Base
31
+ def dataquery(input, &block)
32
+ raise "Data queries need a :description" unless input.include?(:description)
33
+ raise "Data queries can only have one definition" if @entities[:data]
34
+
35
+ @entities[:data] = {:description => input[:description],
36
+ :input => {},
37
+ :output => {}}
38
+
39
+ @current_entity = :data
40
+ block.call if block_given?
41
+ @current_entity = nil
42
+ end
43
+
44
+ def input(argument, properties)
45
+ raise "The only valid input name for a data query is 'query'" if argument != :query
46
+
47
+ super
48
+ end
49
+
50
+ # Returns the interface for the data query
51
+ def dataquery_interface
52
+ @entities[:data] || {}
53
+ end
54
+ end
55
+ end
56
+ end