choria-mcorpc-support 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/bin/mco +64 -0
  3. data/lib/mcollective.rb +63 -0
  4. data/lib/mcollective/agent.rb +5 -0
  5. data/lib/mcollective/agents.rb +149 -0
  6. data/lib/mcollective/aggregate.rb +85 -0
  7. data/lib/mcollective/aggregate/average.ddl +33 -0
  8. data/lib/mcollective/aggregate/average.rb +29 -0
  9. data/lib/mcollective/aggregate/base.rb +40 -0
  10. data/lib/mcollective/aggregate/result.rb +9 -0
  11. data/lib/mcollective/aggregate/result/base.rb +25 -0
  12. data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
  13. data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
  14. data/lib/mcollective/aggregate/sum.ddl +33 -0
  15. data/lib/mcollective/aggregate/sum.rb +18 -0
  16. data/lib/mcollective/aggregate/summary.ddl +33 -0
  17. data/lib/mcollective/aggregate/summary.rb +53 -0
  18. data/lib/mcollective/application.rb +365 -0
  19. data/lib/mcollective/application/completion.rb +104 -0
  20. data/lib/mcollective/application/describe_filter.rb +87 -0
  21. data/lib/mcollective/application/facts.rb +62 -0
  22. data/lib/mcollective/application/find.rb +23 -0
  23. data/lib/mcollective/application/help.rb +28 -0
  24. data/lib/mcollective/application/inventory.rb +344 -0
  25. data/lib/mcollective/application/ping.rb +82 -0
  26. data/lib/mcollective/application/plugin.rb +369 -0
  27. data/lib/mcollective/application/rpc.rb +111 -0
  28. data/lib/mcollective/applications.rb +134 -0
  29. data/lib/mcollective/cache.rb +145 -0
  30. data/lib/mcollective/client.rb +353 -0
  31. data/lib/mcollective/config.rb +245 -0
  32. data/lib/mcollective/connector.rb +18 -0
  33. data/lib/mcollective/connector/base.rb +26 -0
  34. data/lib/mcollective/data.rb +91 -0
  35. data/lib/mcollective/data/agent_data.ddl +22 -0
  36. data/lib/mcollective/data/agent_data.rb +17 -0
  37. data/lib/mcollective/data/base.rb +67 -0
  38. data/lib/mcollective/data/collective_data.ddl +20 -0
  39. data/lib/mcollective/data/collective_data.rb +9 -0
  40. data/lib/mcollective/data/fact_data.ddl +28 -0
  41. data/lib/mcollective/data/fact_data.rb +55 -0
  42. data/lib/mcollective/data/fstat_data.ddl +89 -0
  43. data/lib/mcollective/data/fstat_data.rb +56 -0
  44. data/lib/mcollective/data/result.rb +45 -0
  45. data/lib/mcollective/ddl.rb +113 -0
  46. data/lib/mcollective/ddl/agentddl.rb +253 -0
  47. data/lib/mcollective/ddl/base.rb +217 -0
  48. data/lib/mcollective/ddl/dataddl.rb +56 -0
  49. data/lib/mcollective/ddl/discoveryddl.rb +52 -0
  50. data/lib/mcollective/ddl/validatorddl.rb +6 -0
  51. data/lib/mcollective/discovery.rb +143 -0
  52. data/lib/mcollective/discovery/flatfile.ddl +11 -0
  53. data/lib/mcollective/discovery/flatfile.rb +48 -0
  54. data/lib/mcollective/discovery/mc.ddl +11 -0
  55. data/lib/mcollective/discovery/mc.rb +30 -0
  56. data/lib/mcollective/discovery/stdin.ddl +11 -0
  57. data/lib/mcollective/discovery/stdin.rb +68 -0
  58. data/lib/mcollective/exceptions.rb +28 -0
  59. data/lib/mcollective/facts.rb +39 -0
  60. data/lib/mcollective/facts/base.rb +100 -0
  61. data/lib/mcollective/facts/yaml_facts.rb +65 -0
  62. data/lib/mcollective/generators.rb +7 -0
  63. data/lib/mcollective/generators/agent_generator.rb +51 -0
  64. data/lib/mcollective/generators/base.rb +46 -0
  65. data/lib/mcollective/generators/data_generator.rb +51 -0
  66. data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
  67. data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
  68. data/lib/mcollective/generators/templates/ddl.erb +8 -0
  69. data/lib/mcollective/generators/templates/plugin.erb +7 -0
  70. data/lib/mcollective/log.rb +118 -0
  71. data/lib/mcollective/logger.rb +5 -0
  72. data/lib/mcollective/logger/base.rb +77 -0
  73. data/lib/mcollective/logger/console_logger.rb +61 -0
  74. data/lib/mcollective/logger/file_logger.rb +53 -0
  75. data/lib/mcollective/logger/syslog_logger.rb +53 -0
  76. data/lib/mcollective/matcher.rb +224 -0
  77. data/lib/mcollective/matcher/parser.rb +128 -0
  78. data/lib/mcollective/matcher/scanner.rb +241 -0
  79. data/lib/mcollective/message.rb +248 -0
  80. data/lib/mcollective/monkey_patches.rb +152 -0
  81. data/lib/mcollective/optionparser.rb +197 -0
  82. data/lib/mcollective/pluginmanager.rb +180 -0
  83. data/lib/mcollective/pluginpackager.rb +98 -0
  84. data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
  85. data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
  86. data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
  87. data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
  88. data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
  89. data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
  90. data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
  91. data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
  92. data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
  93. data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
  94. data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
  95. data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
  96. data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
  97. data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
  98. data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
  99. data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
  100. data/lib/mcollective/registration/base.rb +91 -0
  101. data/lib/mcollective/rpc.rb +182 -0
  102. data/lib/mcollective/rpc/actionrunner.rb +158 -0
  103. data/lib/mcollective/rpc/agent.rb +374 -0
  104. data/lib/mcollective/rpc/audit.rb +38 -0
  105. data/lib/mcollective/rpc/client.rb +1066 -0
  106. data/lib/mcollective/rpc/helpers.rb +321 -0
  107. data/lib/mcollective/rpc/progress.rb +63 -0
  108. data/lib/mcollective/rpc/reply.rb +87 -0
  109. data/lib/mcollective/rpc/request.rb +86 -0
  110. data/lib/mcollective/rpc/result.rb +90 -0
  111. data/lib/mcollective/rpc/stats.rb +294 -0
  112. data/lib/mcollective/runnerstats.rb +90 -0
  113. data/lib/mcollective/security.rb +26 -0
  114. data/lib/mcollective/security/base.rb +244 -0
  115. data/lib/mcollective/shell.rb +126 -0
  116. data/lib/mcollective/ssl.rb +285 -0
  117. data/lib/mcollective/util.rb +579 -0
  118. data/lib/mcollective/validator.rb +85 -0
  119. data/lib/mcollective/validator/array_validator.ddl +7 -0
  120. data/lib/mcollective/validator/array_validator.rb +9 -0
  121. data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
  122. data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
  123. data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
  124. data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
  125. data/lib/mcollective/validator/length_validator.ddl +7 -0
  126. data/lib/mcollective/validator/length_validator.rb +11 -0
  127. data/lib/mcollective/validator/regex_validator.ddl +7 -0
  128. data/lib/mcollective/validator/regex_validator.rb +9 -0
  129. data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
  130. data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
  131. data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
  132. data/lib/mcollective/validator/typecheck_validator.rb +28 -0
  133. metadata +215 -0
@@ -0,0 +1,15 @@
1
+ Source: <%= @package_name %>
2
+ Homepage: <%= @plugin.metadata[:url] %>
3
+ Section: utils
4
+ Priority: extra
5
+ Build-Depends: debhelper (>= 7), cdbs, dpatch
6
+ Maintainer: <%= @plugin.metadata[:author] %>
7
+ Standards-Version: 3.9.1
8
+ <% @plugin.packagedata.each do |type, data| %>
9
+ Package: <%= "#{@package_name}-#{type}" %>
10
+ Architecture: all
11
+ Depends: <%= build_dependency_string(data) %>
12
+ Description: <%= @plugin.metadata[:description]%>
13
+ <%= data[:description]%>
14
+ .
15
+ <% end -%>
@@ -0,0 +1,8 @@
1
+ This package was generated by the MCollective plugin packager on
2
+ <%= Time.now%>
3
+
4
+ Upstream Author:
5
+ <%= @plugin.metadata[:author] %> <%= @plugin.metadata[:url] %>
6
+
7
+ License:
8
+ <%= @plugin.metadata[:license] -%>
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/make -f
2
+
3
+ include /usr/share/cdbs/1/rules/debhelper.mk
4
+ include /usr/share/cdbs/1/rules/dpatch.mk
5
+ include /usr/share/cdbs/1/class/makefile.mk
6
+ DEB_MAKE_INVOKE = $(DEB_MAKE_ENVVARS) make -f debian/Makefile -C $(DEB_BUILDDIR)
@@ -0,0 +1,5 @@
1
+ name '<%= @plugin.vendor %>-<%= @package_name %>'
2
+ version '<%= @plugin.metadata[:version] %>'
3
+ description '<%= @plugin.metadata[:description] %>'
4
+ project_page '<%= @plugin.metadata[:url]%>'
5
+ dependency 'puppetlabs/mcollective', '1.x'
@@ -0,0 +1,37 @@
1
+ # <%= @package_name %>
2
+
3
+ #### Table of Contents
4
+
5
+ 1. [Overview](#overview)
6
+ 2. [Module Description - What the module does and why it is useful](#module-description)
7
+ 3. [Setup - The basics of getting started with <%= @package_name %>](#setup)
8
+ * [What the <%= @package_name %> module affects](#what-the-<%= @package_name %>-module-affects)
9
+ * [Setup requirements](#setup-requirements)
10
+ 4. [Usage - Configuration options and additional functionality](#usage)
11
+ 5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
12
+
13
+
14
+ ## Overview
15
+
16
+ The <%= @package_name %> module is a module that wraps a source release of the
17
+ <%= @plugin.metadata[:name] %> mcollective plugin for use with the
18
+ [puppetlabs mcollective](http://forge.puppetlabs.com/puppetlabs/mcollective)
19
+ module.
20
+
21
+ ## Module description
22
+
23
+ ## Usage
24
+
25
+ <% @plugin.packagedata.keys.map { |x| x.to_s }.sort.each do |klass| -%>
26
+ <%# Don't document common class -%>
27
+ <% if klass != "common" -%>
28
+ ### class <%= @package_name %>::<%= klass %>
29
+
30
+ Installs the <%= klass %> component of the <%= @plugin.metadata[:name] %> plugin.
31
+
32
+ ```puppet
33
+ include <%= @package_name%>::<%= klass %>
34
+ ```
35
+ <% end %>
36
+ <% end %>
37
+
@@ -0,0 +1,9 @@
1
+ #
2
+ class <%= @package_name %>::<%= @klass %> {
3
+ <% if @plugin.packagedata[:common] && @klass != 'common' %>
4
+ include ::<%= @package_name %>::common
5
+ <% end %>
6
+ mcollective::plugin { '<%= @package_name %>/<%= @klass %>':
7
+ source => 'puppet:///modules/<%= @package_name %>/<%= @klass %>',
8
+ }
9
+ }
@@ -0,0 +1,63 @@
1
+ Name: <%= @package_name %>
2
+ Summary: <%= @plugin.metadata[:description] %>
3
+ Version: <%= @plugin.metadata[:version] %>
4
+ Release: <%= @plugin.revision %>%{?dist}
5
+ License: <%= @plugin.metadata[:license]%>
6
+ URL: <%= @plugin.metadata[:url]%>
7
+ Vendor: <%= @plugin.vendor%>
8
+ Packager: <%= @plugin.metadata[:author]%>
9
+ BuildArch: noarch
10
+ Group: System Tools
11
+ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
12
+ Source0: <%= @package_name_and_version%>.tgz
13
+
14
+ %description
15
+ <%= @plugin.metadata[:description] %>
16
+
17
+ %prep
18
+ %setup
19
+
20
+ %build
21
+ <% package_files = plugin_files.map{ |f| File.join(@libdir, File.expand_path(f).gsub(/#{File.expand_path(@plugin.path)}|\.\//, '')) } -%>
22
+ <% dirs = package_files.map{ |f| File.dirname(f) }.uniq -%>
23
+
24
+ %install
25
+ rm -rf %{buildroot}
26
+ <% dirs.each do |dir| -%>
27
+ %{__install} -d -m0755 %{buildroot}<%= dir%>
28
+ <% end -%>
29
+ <% package_files.each do |file| -%>
30
+ %{__install} -m0644 -v <%= (file[0].chr == '/') ? file[1..file.size-1]: file%> %{buildroot}<%=file %>
31
+ <% end -%>
32
+
33
+ <% @plugin.packagedata.each do |type, data| %>
34
+ %package <%= type %>
35
+ Summary: <%= @plugin.metadata[:description] %>
36
+ <% if data[:plugindependency] %>
37
+ Requires: <%= data[:plugindependency][:name] -%> = <%= data[:plugindependency][:version]%>-<%= data[:plugindependency][:revision]%>%{?dist}
38
+ <% end -%>
39
+ <% PluginPackager.filter_dependencies('redhat', data[:dependencies]).each do |dep|-%>
40
+ Requires: <%= dep[:name] -%> <%= ">= #{dep[:version]}" if dep[:version]%><%="-#{dep[:revision]}" if dep[:revision]%>
41
+ <% end -%>
42
+ %description <%= type %>
43
+ <%= data[:description] %>
44
+
45
+ %files <%= type %>
46
+ %defattr(-, root, root, -)
47
+ <% package_files(data[:files]).each do |file| -%>
48
+ <%= file %>
49
+ <% end -%>
50
+ <% end -%>
51
+
52
+ <% if @plugin.preinstall -%>
53
+ %pre
54
+ <%= @plugin.preinstall %>
55
+ <% end -%>
56
+ <% if @plugin.postinstall -%>
57
+ %post
58
+ <%= @plugin.postinstall%>
59
+ <% end -%>
60
+
61
+ %changelog
62
+ * <%= Time.now.strftime("%a %b %d %Y") -%> <%= @plugin.metadata[:author]%> - <%= @plugin.metadata[:version]%>-<%= @plugin.revision %>
63
+ - Built Package <%= @plugin.metadata[:name] -%>
@@ -0,0 +1,91 @@
1
+ module MCollective
2
+ module Registration
3
+ # This is a base class that other registration plugins can use
4
+ # to handle regular announcements to the mcollective
5
+ #
6
+ # The configuration file determines how often registration messages
7
+ # gets sent using the _registerinterval_ option, the plugin runs in the
8
+ # background in a thread.
9
+ class Base
10
+ # Register plugins that inherits base
11
+ def self.inherited(klass)
12
+ PluginManager << {:type => "registration_plugin", :class => klass.to_s}
13
+ end
14
+
15
+ # Creates a background thread that periodically send a registration notice.
16
+ #
17
+ # The actual registration notices comes from the 'body' method of the registration
18
+ # plugins.
19
+ def run(connection)
20
+ return false if interval == 0
21
+
22
+ Thread.new do
23
+ publish_thread(connection)
24
+ end
25
+ end
26
+
27
+ def config
28
+ Config.instance
29
+ end
30
+
31
+ def msg_filter
32
+ filter = Util.empty_filter
33
+ filter["agent"] << "registration"
34
+ filter
35
+ end
36
+
37
+ def target_collective
38
+ main_collective = config.main_collective
39
+
40
+ collective = config.registration_collective || main_collective
41
+
42
+ unless config.collectives.include?(collective)
43
+ Log.warn("Sending registration to #{main_collective}: #{collective} is not a valid collective")
44
+ collective = main_collective
45
+ end
46
+
47
+ return collective
48
+ end
49
+
50
+ def interval
51
+ config.registerinterval
52
+ end
53
+
54
+ def publish(message)
55
+ unless message
56
+ Log.debug("Skipping registration due to nil body")
57
+ else
58
+ req = Message.new(message, nil, {:type => :request, :agent => "registration", :collective => target_collective, :filter => msg_filter})
59
+ req.encode!
60
+
61
+ Log.debug("Sending registration #{req.requestid} to collective #{req.collective}")
62
+
63
+ req.publish
64
+ end
65
+ end
66
+
67
+ def body
68
+ raise "Registration Plugins must implement the #body method"
69
+ end
70
+
71
+ private
72
+ def publish_thread(connnection)
73
+ if config.registration_splay
74
+ splay_delay = rand(interval)
75
+ Log.debug("registration_splay enabled. Registration will start in #{splay_delay} seconds")
76
+ sleep splay_delay
77
+ end
78
+
79
+ loop do
80
+ begin
81
+ publish(body)
82
+ sleep interval
83
+ rescue Exception => e
84
+ Log.error("Sending registration message failed: #{e}")
85
+ sleep interval
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,182 @@
1
+ require 'pp'
2
+
3
+ module MCollective
4
+ # Toolset to create a standard interface of client and agent using
5
+ # an RPC metaphor, standard compliant agents will make it easier
6
+ # to create generic clients like web interfaces etc
7
+ module RPC
8
+ require "mcollective/rpc/actionrunner"
9
+ require "mcollective/rpc/agent"
10
+ require "mcollective/rpc/audit"
11
+ require "mcollective/rpc/client"
12
+ require "mcollective/rpc/helpers"
13
+ require "mcollective/rpc/progress"
14
+ require "mcollective/rpc/reply"
15
+ require "mcollective/rpc/request"
16
+ require "mcollective/rpc/result"
17
+ require "mcollective/rpc/stats"
18
+
19
+ # Creates a standard options hash, pass in a block to add extra headings etc
20
+ # see Optionparser
21
+ def rpcoptions
22
+ oparser = MCollective::Optionparser.new({:verbose => false, :progress_bar => true}, "filter")
23
+
24
+ options = oparser.parse do |parser, options|
25
+ if block_given?
26
+ yield(parser, options)
27
+ end
28
+
29
+ Helpers.add_simplerpc_options(parser, options)
30
+ end
31
+
32
+ return options
33
+ end
34
+
35
+ # Wrapper to create clients, supposed to be used as
36
+ # a mixin:
37
+ #
38
+ # include MCollective::RPC
39
+ #
40
+ # exim = rpcclient("exim")
41
+ # printrpc exim.mailq
42
+ #
43
+ # or
44
+ #
45
+ # rpcclient("exim") do |exim|
46
+ # printrpc exim.mailq
47
+ # end
48
+ #
49
+ # It will take a few flags:
50
+ # :configfile => "etc/client.cfg"
51
+ # :options => options
52
+ # :exit_on_failure => true
53
+ #
54
+ # Options would be a build up options hash from the Optionparser
55
+ # you can use the rpcoptions helper to create this
56
+ #
57
+ # :exit_on_failure is true by default, and causes the application to
58
+ # exit if there is a failure constructing the RPC client. Set this flag
59
+ # to false to cause an Exception to be raised instead.
60
+ def rpcclient(agent, flags = {})
61
+ configfile = flags[:configfile] || Util.config_file_for_user
62
+ options = flags[:options] || nil
63
+
64
+ if flags.key?(:exit_on_failure)
65
+ exit_on_failure = flags[:exit_on_failure]
66
+ else
67
+ # We exit on failure by default for CLI-friendliness
68
+ exit_on_failure = true
69
+ end
70
+
71
+ begin
72
+ if options
73
+ rpc = Client.new(agent, :configfile => options[:config], :options => options)
74
+ @options = rpc.options
75
+ else
76
+ rpc = Client.new(agent, :configfile => configfile)
77
+ @options = rpc.options
78
+ end
79
+ rescue Exception => e
80
+ if exit_on_failure
81
+ puts("Could not create RPC client: #{e}")
82
+ exit!
83
+ else
84
+ raise e
85
+ end
86
+ end
87
+
88
+ if block_given?
89
+ yield(rpc)
90
+ else
91
+ return rpc
92
+ end
93
+ end
94
+
95
+ # means for other classes to drop stats into this module
96
+ # its a bit hacky but needed so that the mixin methods like
97
+ # printrpcstats can easily get access to it without
98
+ # users having to pass it around in params.
99
+ def self.stats(stats)
100
+ @@stats = stats
101
+ end
102
+
103
+ # means for other classes to drop discovered hosts into this module
104
+ # its a bit hacky but needed so that the mixin methods like
105
+ # printrpcstats can easily get access to it without
106
+ # users having to pass it around in params.
107
+ def self.discovered(discovered)
108
+ @@discovered = discovered
109
+ end
110
+
111
+ # Prints stats, requires stats to be saved from elsewhere
112
+ # using the MCollective::RPC.stats method.
113
+ #
114
+ # If you've passed -v on the command line a detailed stat block
115
+ # will be printed, else just a one liner.
116
+ #
117
+ # You can pass flags into it:
118
+ #
119
+ # printrpcstats :caption => "Foo", :summarize => true
120
+ #
121
+ # This will use "Foo" as the caption to the stats in verbose
122
+ # mode and print out any aggregate summary information if present
123
+ def printrpcstats(flags={})
124
+ return unless @options[:output_format] == :console
125
+
126
+ flags = {:summarize => false, :caption => "rpc stats"}.merge(flags)
127
+
128
+ verbose = @options[:verbose] rescue verbose = false
129
+
130
+ begin
131
+ stats = @@stats
132
+ rescue
133
+ puts("no stats to display")
134
+ return
135
+ end
136
+
137
+ puts stats.report(flags[:caption], flags[:summarize], verbose)
138
+ end
139
+
140
+ # Prints the result of an RPC call.
141
+ #
142
+ # In the default quiet mode - no flattening or verbose - only results
143
+ # that produce an error will be printed
144
+ #
145
+ # To get details of each result run with the -v command line option.
146
+ def printrpc(result, flags = {})
147
+ verbose = @options[:verbose] rescue verbose = false
148
+ verbose = flags[:verbose] || verbose
149
+ flatten = flags[:flatten] || false
150
+ format = @options[:output_format]
151
+ forced_mode = @options[:force_display_mode] || false
152
+
153
+ result_text = Helpers.rpcresults(result, {:verbose => verbose, :flatten => flatten, :format => format, :force_display_mode => forced_mode})
154
+
155
+ if result.is_a?(Array) && format == :console
156
+ puts "\n%s\n" % [ result_text ]
157
+ else
158
+ # when we get just one result to print dont pad them all with
159
+ # blank spaces etc, just print the individual result with no
160
+ # padding
161
+ puts result_text unless result_text == ""
162
+ end
163
+ end
164
+
165
+ # Wrapper for MCollective::Util.empty_filter? to make clients less fugly
166
+ # to write - ticket #18
167
+ def empty_filter?(options)
168
+ if options.include?(:filter)
169
+ Util.empty_filter?(options[:filter])
170
+ else
171
+ Util.empty_filter?(options)
172
+ end
173
+ end
174
+
175
+ def self.const_missing(const_name)
176
+ super unless const_name == :DDL
177
+
178
+ Log.warn("MCollective::RPC::DDL is deprecatd, please use MCollective::DDL instead")
179
+ MCollective::DDL
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,158 @@
1
+ module MCollective
2
+ module RPC
3
+ # A helper used by RPC::Agent#implemented_by to delegate an action to
4
+ # an external script. At present only JSON based serialization is
5
+ # supported in future ones based on key=val pairs etc will be added
6
+ #
7
+ # It serializes the request object into an input file and creates an
8
+ # empty output file. It then calls the external command reading the
9
+ # output file at the end.
10
+ #
11
+ # any STDERR gets logged at error level and any STDOUT gets logged at
12
+ # info level.
13
+ #
14
+ # It will interpret the exit code from the application the same way
15
+ # RPC::Reply#fail! and #fail handles their codes creating a consistent
16
+ # interface, the message part of the fail message will come from STDERR
17
+ #
18
+ # Generally externals should just exit with code 1 on failure and print to
19
+ # STDERR, this is exactly what Perl die() does and translates perfectly
20
+ # to our model
21
+ #
22
+ # It uses the MCollective::Shell wrapper to call the external application
23
+ class ActionRunner
24
+ attr_reader :command, :agent, :action, :format, :stdout, :stderr, :request
25
+
26
+ def initialize(command, request, format=:json)
27
+ @agent = request.agent
28
+ @action = request.action
29
+ @format = format
30
+ @request = request
31
+ @command = path_to_command(command)
32
+ @stdout = ""
33
+ @stderr = ""
34
+ end
35
+
36
+ def run
37
+ unless canrun?(command)
38
+ Log.warn("Cannot run #{to_s}")
39
+ raise RPCAborted, "Cannot execute #{to_s}"
40
+ end
41
+
42
+ Log.debug("Running #{to_s}")
43
+
44
+ request_file = saverequest(request)
45
+ reply_file = tempfile("reply")
46
+ reply_file.close
47
+
48
+ runner = shell(command, request_file.path, reply_file.path)
49
+
50
+ runner.runcommand
51
+
52
+ Log.debug("#{command} exited with #{runner.status.exitstatus}")
53
+
54
+ stderr.each_line {|l| Log.error("#{to_s}: #{l.chomp}")} unless stderr.empty?
55
+ stdout.each_line {|l| Log.info("#{to_s}: #{l.chomp}")} unless stdout.empty?
56
+
57
+ {:exitstatus => runner.status.exitstatus,
58
+ :stdout => runner.stdout,
59
+ :stderr => runner.stderr,
60
+ :data => load_results(reply_file.path)}
61
+ ensure
62
+ request_file.close! if request_file.respond_to?("close!")
63
+ reply_file.close! if reply_file.respond_to?("close")
64
+ end
65
+
66
+ def shell(command, infile, outfile)
67
+ env = {"MCOLLECTIVE_REQUEST_FILE" => infile,
68
+ "MCOLLECTIVE_REPLY_FILE" => outfile}
69
+
70
+ Shell.new("#{command} #{infile} #{outfile}", :cwd => Dir.tmpdir, :stdout => stdout, :stderr => stderr, :environment => env)
71
+ end
72
+
73
+ def load_results(file)
74
+ Log.debug("Attempting to load results in #{format} format from #{file}")
75
+
76
+ data = {}
77
+
78
+ if respond_to?("load_#{format}_results")
79
+ tempdata = send("load_#{format}_results", file)
80
+
81
+ tempdata.each_pair do |k,v|
82
+ data[k.to_sym] = v
83
+ end
84
+ end
85
+
86
+ data
87
+ rescue Exception => e
88
+ {}
89
+ end
90
+
91
+ def load_json_results(file)
92
+ return {} unless File.readable?(file)
93
+
94
+ JSON.load(File.read(file)) || {}
95
+ rescue JSON::ParserError
96
+ {}
97
+ end
98
+
99
+ def saverequest(req)
100
+ Log.debug("Attempting to save request in #{format} format")
101
+
102
+ if respond_to?("save_#{format}_request")
103
+ data = send("save_#{format}_request", req)
104
+
105
+ request_file = tempfile("request")
106
+ request_file.puts data
107
+ request_file.close
108
+ end
109
+
110
+ request_file
111
+ end
112
+
113
+ def save_json_request(req)
114
+ req.to_json
115
+ end
116
+
117
+ def canrun?(command)
118
+ File.executable?(command)
119
+ end
120
+
121
+ def to_s
122
+ "%s#%s command: %s" % [ agent, action, command ]
123
+ end
124
+
125
+ def tempfile(prefix)
126
+ Tempfile.new("mcollective_#{prefix}", Dir.tmpdir)
127
+ end
128
+
129
+ def path_to_command(command)
130
+ if Util.absolute_path?(command)
131
+ return command
132
+ end
133
+
134
+ Config.instance.libdir.each do |libdir|
135
+ command_file_old = File.join(libdir, "agent", agent, command)
136
+ command_file_new = File.join(libdir, "mcollective", "agent", agent, command)
137
+ command_file_old_exists = File.exists?(command_file_old)
138
+ command_file_new_exists = File.exists?(command_file_new)
139
+
140
+ if command_file_new_exists && command_file_old_exists
141
+ Log.debug("Found 'implemented_by' scripts found in two locations #{command_file_old} and #{command_file_new}")
142
+ Log.debug("Running script: #{command_file_new}")
143
+ return command_file_new
144
+ elsif command_file_old_exists
145
+ Log.debug("Running script: #{command_file_old}")
146
+ return command_file_old
147
+ elsif command_file_new_exists
148
+ Log.debug("Running script: #{command_file_new}")
149
+ return command_file_new
150
+ end
151
+ end
152
+
153
+ Log.warn("No script found for: #{command}")
154
+ command
155
+ end
156
+ end
157
+ end
158
+ end