choria-mcorpc-support 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/mco +64 -0
- data/lib/mcollective.rb +63 -0
- data/lib/mcollective/agent.rb +5 -0
- data/lib/mcollective/agents.rb +149 -0
- data/lib/mcollective/aggregate.rb +85 -0
- data/lib/mcollective/aggregate/average.ddl +33 -0
- data/lib/mcollective/aggregate/average.rb +29 -0
- data/lib/mcollective/aggregate/base.rb +40 -0
- data/lib/mcollective/aggregate/result.rb +9 -0
- data/lib/mcollective/aggregate/result/base.rb +25 -0
- data/lib/mcollective/aggregate/result/collection_result.rb +19 -0
- data/lib/mcollective/aggregate/result/numeric_result.rb +13 -0
- data/lib/mcollective/aggregate/sum.ddl +33 -0
- data/lib/mcollective/aggregate/sum.rb +18 -0
- data/lib/mcollective/aggregate/summary.ddl +33 -0
- data/lib/mcollective/aggregate/summary.rb +53 -0
- data/lib/mcollective/application.rb +365 -0
- data/lib/mcollective/application/completion.rb +104 -0
- data/lib/mcollective/application/describe_filter.rb +87 -0
- data/lib/mcollective/application/facts.rb +62 -0
- data/lib/mcollective/application/find.rb +23 -0
- data/lib/mcollective/application/help.rb +28 -0
- data/lib/mcollective/application/inventory.rb +344 -0
- data/lib/mcollective/application/ping.rb +82 -0
- data/lib/mcollective/application/plugin.rb +369 -0
- data/lib/mcollective/application/rpc.rb +111 -0
- data/lib/mcollective/applications.rb +134 -0
- data/lib/mcollective/cache.rb +145 -0
- data/lib/mcollective/client.rb +353 -0
- data/lib/mcollective/config.rb +245 -0
- data/lib/mcollective/connector.rb +18 -0
- data/lib/mcollective/connector/base.rb +26 -0
- data/lib/mcollective/data.rb +91 -0
- data/lib/mcollective/data/agent_data.ddl +22 -0
- data/lib/mcollective/data/agent_data.rb +17 -0
- data/lib/mcollective/data/base.rb +67 -0
- data/lib/mcollective/data/collective_data.ddl +20 -0
- data/lib/mcollective/data/collective_data.rb +9 -0
- data/lib/mcollective/data/fact_data.ddl +28 -0
- data/lib/mcollective/data/fact_data.rb +55 -0
- data/lib/mcollective/data/fstat_data.ddl +89 -0
- data/lib/mcollective/data/fstat_data.rb +56 -0
- data/lib/mcollective/data/result.rb +45 -0
- data/lib/mcollective/ddl.rb +113 -0
- data/lib/mcollective/ddl/agentddl.rb +253 -0
- data/lib/mcollective/ddl/base.rb +217 -0
- data/lib/mcollective/ddl/dataddl.rb +56 -0
- data/lib/mcollective/ddl/discoveryddl.rb +52 -0
- data/lib/mcollective/ddl/validatorddl.rb +6 -0
- data/lib/mcollective/discovery.rb +143 -0
- data/lib/mcollective/discovery/flatfile.ddl +11 -0
- data/lib/mcollective/discovery/flatfile.rb +48 -0
- data/lib/mcollective/discovery/mc.ddl +11 -0
- data/lib/mcollective/discovery/mc.rb +30 -0
- data/lib/mcollective/discovery/stdin.ddl +11 -0
- data/lib/mcollective/discovery/stdin.rb +68 -0
- data/lib/mcollective/exceptions.rb +28 -0
- data/lib/mcollective/facts.rb +39 -0
- data/lib/mcollective/facts/base.rb +100 -0
- data/lib/mcollective/facts/yaml_facts.rb +65 -0
- data/lib/mcollective/generators.rb +7 -0
- data/lib/mcollective/generators/agent_generator.rb +51 -0
- data/lib/mcollective/generators/base.rb +46 -0
- data/lib/mcollective/generators/data_generator.rb +51 -0
- data/lib/mcollective/generators/templates/action_snippet.erb +13 -0
- data/lib/mcollective/generators/templates/data_input_snippet.erb +7 -0
- data/lib/mcollective/generators/templates/ddl.erb +8 -0
- data/lib/mcollective/generators/templates/plugin.erb +7 -0
- data/lib/mcollective/log.rb +118 -0
- data/lib/mcollective/logger.rb +5 -0
- data/lib/mcollective/logger/base.rb +77 -0
- data/lib/mcollective/logger/console_logger.rb +61 -0
- data/lib/mcollective/logger/file_logger.rb +53 -0
- data/lib/mcollective/logger/syslog_logger.rb +53 -0
- data/lib/mcollective/matcher.rb +224 -0
- data/lib/mcollective/matcher/parser.rb +128 -0
- data/lib/mcollective/matcher/scanner.rb +241 -0
- data/lib/mcollective/message.rb +248 -0
- data/lib/mcollective/monkey_patches.rb +152 -0
- data/lib/mcollective/optionparser.rb +197 -0
- data/lib/mcollective/pluginmanager.rb +180 -0
- data/lib/mcollective/pluginpackager.rb +98 -0
- data/lib/mcollective/pluginpackager/agent_definition.rb +94 -0
- data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
- data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
- data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
- data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
- data/lib/mcollective/pluginpackager/standard_definition.rb +69 -0
- data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
- data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
- data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
- data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
- data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
- data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
- data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
- data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
- data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
- data/lib/mcollective/registration/base.rb +91 -0
- data/lib/mcollective/rpc.rb +182 -0
- data/lib/mcollective/rpc/actionrunner.rb +158 -0
- data/lib/mcollective/rpc/agent.rb +374 -0
- data/lib/mcollective/rpc/audit.rb +38 -0
- data/lib/mcollective/rpc/client.rb +1066 -0
- data/lib/mcollective/rpc/helpers.rb +321 -0
- data/lib/mcollective/rpc/progress.rb +63 -0
- data/lib/mcollective/rpc/reply.rb +87 -0
- data/lib/mcollective/rpc/request.rb +86 -0
- data/lib/mcollective/rpc/result.rb +90 -0
- data/lib/mcollective/rpc/stats.rb +294 -0
- data/lib/mcollective/runnerstats.rb +90 -0
- data/lib/mcollective/security.rb +26 -0
- data/lib/mcollective/security/base.rb +244 -0
- data/lib/mcollective/shell.rb +126 -0
- data/lib/mcollective/ssl.rb +285 -0
- data/lib/mcollective/util.rb +579 -0
- data/lib/mcollective/validator.rb +85 -0
- data/lib/mcollective/validator/array_validator.ddl +7 -0
- data/lib/mcollective/validator/array_validator.rb +9 -0
- data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
- data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
- data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
- data/lib/mcollective/validator/length_validator.ddl +7 -0
- data/lib/mcollective/validator/length_validator.rb +11 -0
- data/lib/mcollective/validator/regex_validator.ddl +7 -0
- data/lib/mcollective/validator/regex_validator.rb +9 -0
- data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
- data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
- data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
- data/lib/mcollective/validator/typecheck_validator.rb +28 -0
- metadata +215 -0
@@ -0,0 +1 @@
|
|
1
|
+
7
|
@@ -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,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
|