mcollective-client 2.7.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. data/lib/mcollective/agent/discovery.rb +37 -0
  2. data/lib/mcollective/agent/rpcutil.ddl +220 -0
  3. data/lib/mcollective/agent/rpcutil.rb +108 -0
  4. data/lib/mcollective/aggregate/average.ddl +33 -0
  5. data/lib/mcollective/aggregate/average.rb +29 -0
  6. data/lib/mcollective/aggregate/result.rb +3 -3
  7. data/lib/mcollective/aggregate/sum.ddl +33 -0
  8. data/lib/mcollective/aggregate/sum.rb +18 -0
  9. data/lib/mcollective/aggregate/summary.ddl +33 -0
  10. data/lib/mcollective/aggregate/summary.rb +53 -0
  11. data/lib/mcollective/aggregate.rb +2 -2
  12. data/lib/mcollective/application/completion.rb +104 -0
  13. data/lib/mcollective/application/facts.rb +62 -0
  14. data/lib/mcollective/application/find.rb +21 -0
  15. data/lib/mcollective/application/help.rb +28 -0
  16. data/lib/mcollective/application/inventory.rb +344 -0
  17. data/lib/mcollective/application/ping.rb +77 -0
  18. data/lib/mcollective/application/plugin.rb +369 -0
  19. data/lib/mcollective/application/rpc.rb +121 -0
  20. data/lib/mcollective/application.rb +2 -0
  21. data/lib/mcollective/audit/logfile.rb +26 -0
  22. data/lib/mcollective/config.rb +16 -9
  23. data/lib/mcollective/connector/activemq.ddl +9 -0
  24. data/lib/mcollective/connector/activemq.rb +572 -0
  25. data/lib/mcollective/connector/rabbitmq.ddl +9 -0
  26. data/lib/mcollective/connector/rabbitmq.rb +484 -0
  27. data/lib/mcollective/connector.rb +1 -1
  28. data/lib/mcollective/data/agent_data.ddl +22 -0
  29. data/lib/mcollective/data/agent_data.rb +17 -0
  30. data/lib/mcollective/data/collective_data.ddl +20 -0
  31. data/lib/mcollective/data/collective_data.rb +9 -0
  32. data/lib/mcollective/data/fact_data.ddl +28 -0
  33. data/lib/mcollective/data/fact_data.rb +55 -0
  34. data/lib/mcollective/data/fstat_data.ddl +89 -0
  35. data/lib/mcollective/data/fstat_data.rb +56 -0
  36. data/lib/mcollective/data.rb +2 -2
  37. data/lib/mcollective/ddl.rb +4 -4
  38. data/lib/mcollective/discovery/flatfile.ddl +11 -0
  39. data/lib/mcollective/discovery/flatfile.rb +48 -0
  40. data/lib/mcollective/discovery/mc.ddl +11 -0
  41. data/lib/mcollective/discovery/mc.rb +30 -0
  42. data/lib/mcollective/discovery/stdin.ddl +11 -0
  43. data/lib/mcollective/discovery/stdin.rb +66 -0
  44. data/lib/mcollective/facts/yaml_facts.rb +61 -0
  45. data/lib/mcollective/facts.rb +1 -1
  46. data/lib/mcollective/generators.rb +3 -3
  47. data/lib/mcollective/logger.rb +1 -1
  48. data/lib/mcollective/matcher/scanner.rb +1 -1
  49. data/lib/mcollective/matcher.rb +2 -2
  50. data/lib/mcollective/pluginpackager/debpackage_packager.rb +237 -0
  51. data/lib/mcollective/pluginpackager/modulepackage_packager.rb +127 -0
  52. data/lib/mcollective/pluginpackager/ospackage_packager.rb +59 -0
  53. data/lib/mcollective/pluginpackager/rpmpackage_packager.rb +180 -0
  54. data/lib/mcollective/pluginpackager/templates/debian/Makefile.erb +7 -0
  55. data/lib/mcollective/pluginpackager/templates/debian/changelog.erb +5 -0
  56. data/lib/mcollective/pluginpackager/templates/debian/compat.erb +1 -0
  57. data/lib/mcollective/pluginpackager/templates/debian/control.erb +15 -0
  58. data/lib/mcollective/pluginpackager/templates/debian/copyright.erb +8 -0
  59. data/lib/mcollective/pluginpackager/templates/debian/rules.erb +6 -0
  60. data/lib/mcollective/pluginpackager/templates/module/Modulefile.erb +5 -0
  61. data/lib/mcollective/pluginpackager/templates/module/README.md.erb +37 -0
  62. data/lib/mcollective/pluginpackager/templates/module/_manifest.pp.erb +9 -0
  63. data/lib/mcollective/pluginpackager/templates/redhat/rpm_spec.erb +63 -0
  64. data/lib/mcollective/pluginpackager.rb +2 -2
  65. data/lib/mcollective/registration/agentlist.rb +10 -0
  66. data/lib/mcollective/registration.rb +1 -1
  67. data/lib/mcollective/rpc/stats.rb +0 -1
  68. data/lib/mcollective/rpc.rb +11 -11
  69. data/lib/mcollective/security/aes_security.rb +394 -0
  70. data/lib/mcollective/security/psk.rb +117 -0
  71. data/lib/mcollective/security/ssl.rb +328 -0
  72. data/lib/mcollective/security.rb +1 -1
  73. data/lib/mcollective/util.rb +18 -18
  74. data/lib/mcollective/validator/array_validator.ddl +7 -0
  75. data/lib/mcollective/validator/array_validator.rb +9 -0
  76. data/lib/mcollective/validator/ipv4address_validator.ddl +7 -0
  77. data/lib/mcollective/validator/ipv4address_validator.rb +16 -0
  78. data/lib/mcollective/validator/ipv6address_validator.ddl +7 -0
  79. data/lib/mcollective/validator/ipv6address_validator.rb +16 -0
  80. data/lib/mcollective/validator/length_validator.ddl +7 -0
  81. data/lib/mcollective/validator/length_validator.rb +11 -0
  82. data/lib/mcollective/validator/regex_validator.ddl +7 -0
  83. data/lib/mcollective/validator/regex_validator.rb +9 -0
  84. data/lib/mcollective/validator/shellsafe_validator.ddl +7 -0
  85. data/lib/mcollective/validator/shellsafe_validator.rb +13 -0
  86. data/lib/mcollective/validator/typecheck_validator.ddl +7 -0
  87. data/lib/mcollective/validator/typecheck_validator.rb +28 -0
  88. data/lib/mcollective.rb +31 -31
  89. data/spec/spec_helper.rb +0 -5
  90. data/spec/unit/{plugins/mcollective → mcollective}/agent/rpcutil_spec.rb +1 -1
  91. data/spec/unit/{agents_spec.rb → mcollective/agents_spec.rb} +0 -0
  92. data/spec/unit/{plugins/mcollective → mcollective}/aggregate/average_spec.rb +1 -1
  93. data/spec/unit/{aggregate → mcollective/aggregate}/base_spec.rb +0 -0
  94. data/spec/unit/{aggregate → mcollective/aggregate}/result/base_spec.rb +0 -0
  95. data/spec/unit/{aggregate → mcollective/aggregate}/result/collection_result_spec.rb +0 -0
  96. data/spec/unit/{aggregate → mcollective/aggregate}/result/numeric_result_spec.rb +0 -0
  97. data/spec/unit/{plugins/mcollective → mcollective}/aggregate/sum_spec.rb +1 -1
  98. data/spec/unit/{plugins/mcollective → mcollective}/aggregate/summary_spec.rb +1 -1
  99. data/spec/unit/{aggregate_spec.rb → mcollective/aggregate_spec.rb} +0 -0
  100. data/spec/unit/{plugins/mcollective → mcollective}/application/plugin_spec.rb +1 -1
  101. data/spec/unit/{application_spec.rb → mcollective/application_spec.rb} +0 -0
  102. data/spec/unit/{applications_spec.rb → mcollective/applications_spec.rb} +1 -1
  103. data/spec/unit/{array_spec.rb → mcollective/array_spec.rb} +0 -0
  104. data/spec/unit/{plugins/mcollective → mcollective}/audit/logfile_spec.rb +1 -1
  105. data/spec/unit/{cache_spec.rb → mcollective/cache_spec.rb} +0 -0
  106. data/spec/unit/{client_spec.rb → mcollective/client_spec.rb} +0 -0
  107. data/spec/unit/{config_spec.rb → mcollective/config_spec.rb} +12 -7
  108. data/spec/unit/{plugins/mcollective → mcollective}/connector/activemq_spec.rb +1 -1
  109. data/spec/unit/{connector → mcollective/connector}/base_spec.rb +0 -0
  110. data/spec/unit/{plugins/mcollective → mcollective}/connector/rabbitmq_spec.rb +1 -1
  111. data/spec/unit/{plugins/mcollective → mcollective}/data/agent_data_spec.rb +1 -1
  112. data/spec/unit/{data → mcollective/data}/base_spec.rb +0 -0
  113. data/spec/unit/{plugins/mcollective → mcollective}/data/collective_data_spec.rb +1 -1
  114. data/spec/unit/{plugins/mcollective → mcollective}/data/fact_data_spec.rb +1 -1
  115. data/spec/unit/{plugins/mcollective → mcollective}/data/fstat_data_spec.rb +1 -1
  116. data/spec/unit/{data → mcollective/data}/result_spec.rb +0 -0
  117. data/spec/unit/{data_spec.rb → mcollective/data_spec.rb} +0 -0
  118. data/spec/unit/{ddl → mcollective/ddl}/agentddl_spec.rb +0 -0
  119. data/spec/unit/{ddl → mcollective/ddl}/base_spec.rb +0 -0
  120. data/spec/unit/{ddl → mcollective/ddl}/dataddl_spec.rb +0 -0
  121. data/spec/unit/{ddl → mcollective/ddl}/discoveryddl_spec.rb +0 -0
  122. data/spec/unit/{ddl_spec.rb → mcollective/ddl_spec.rb} +0 -0
  123. data/spec/unit/{plugins/mcollective → mcollective}/discovery/flatfile_spec.rb +1 -1
  124. data/spec/unit/{plugins/mcollective → mcollective}/discovery/mc_spec.rb +1 -1
  125. data/spec/unit/{plugins/mcollective → mcollective}/discovery/stdin_spec.rb +1 -1
  126. data/spec/unit/{discovery_spec.rb → mcollective/discovery_spec.rb} +0 -0
  127. data/spec/unit/{facts → mcollective/facts}/base_spec.rb +0 -0
  128. data/spec/unit/{plugins/mcollective → mcollective}/facts/yaml_facts_spec.rb +1 -1
  129. data/spec/unit/{facts_spec.rb → mcollective/facts_spec.rb} +0 -0
  130. data/spec/unit/{generators → mcollective/generators}/agent_generator_spec.rb +0 -0
  131. data/spec/unit/{generators → mcollective/generators}/base_spec.rb +0 -0
  132. data/spec/unit/{generators → mcollective/generators}/data_generator_spec.rb +0 -0
  133. data/spec/unit/{generators → mcollective/generators}/snippets/agent_ddl +0 -0
  134. data/spec/unit/{generators → mcollective/generators}/snippets/data_ddl +0 -0
  135. data/spec/unit/{log_spec.rb → mcollective/log_spec.rb} +0 -0
  136. data/spec/unit/{logger → mcollective/logger}/base_spec.rb +0 -0
  137. data/spec/unit/{logger → mcollective/logger}/console_logger_spec.rb +0 -0
  138. data/spec/unit/{logger → mcollective/logger}/file_logger_spec.rb +0 -0
  139. data/spec/unit/{logger → mcollective/logger}/syslog_logger_spec.rb +0 -0
  140. data/spec/unit/{matcher → mcollective/matcher}/parser_spec.rb +0 -0
  141. data/spec/unit/{matcher → mcollective/matcher}/scanner_spec.rb +0 -0
  142. data/spec/unit/{matcher_spec.rb → mcollective/matcher_spec.rb} +0 -0
  143. data/spec/unit/{message_spec.rb → mcollective/message_spec.rb} +0 -0
  144. data/spec/unit/{monkey_patches_spec.rb → mcollective/monkey_patches_spec.rb} +0 -0
  145. data/spec/unit/{optionparser_spec.rb → mcollective/optionparser_spec.rb} +0 -0
  146. data/spec/unit/{plugins/mcollective → mcollective}/packagers/debpackage_packager_spec.rb +1 -1
  147. data/spec/unit/{plugins/mcollective → mcollective}/packagers/modulepackage_packager_spec.rb +1 -1
  148. data/spec/unit/{plugins/mcollective → mcollective}/packagers/ospackage_spec.rb +1 -1
  149. data/spec/unit/{plugins/mcollective → mcollective}/packagers/rpmpackage_packager_spec.rb +1 -1
  150. data/spec/unit/{pluginmanager_spec.rb → mcollective/pluginmanager_spec.rb} +0 -0
  151. data/spec/unit/{pluginpackager → mcollective/pluginpackager}/agent_definition_spec.rb +0 -0
  152. data/spec/unit/{pluginpackager → mcollective/pluginpackager}/standard_definition_spec.rb +0 -0
  153. data/spec/unit/{pluginpackager_spec.rb → mcollective/pluginpackager_spec.rb} +0 -0
  154. data/spec/unit/{registration → mcollective/registration}/base_spec.rb +0 -0
  155. data/spec/unit/{rpc → mcollective/rpc}/actionrunner_spec.rb +0 -0
  156. data/spec/unit/{rpc → mcollective/rpc}/agent_spec.rb +0 -0
  157. data/spec/unit/{rpc → mcollective/rpc}/client_spec.rb +0 -0
  158. data/spec/unit/{rpc → mcollective/rpc}/helpers_spec.rb +0 -0
  159. data/spec/unit/{rpc → mcollective/rpc}/reply_spec.rb +0 -0
  160. data/spec/unit/{rpc → mcollective/rpc}/request_spec.rb +0 -0
  161. data/spec/unit/{rpc → mcollective/rpc}/result_spec.rb +0 -0
  162. data/spec/unit/{rpc → mcollective/rpc}/stats_spec.rb +0 -0
  163. data/spec/unit/{rpc_spec.rb → mcollective/rpc_spec.rb} +0 -0
  164. data/spec/unit/{runner_spec.rb → mcollective/runner_spec.rb} +0 -0
  165. data/spec/unit/{runnerstats_spec.rb → mcollective/runnerstats_spec.rb} +0 -0
  166. data/spec/unit/{plugins/mcollective → mcollective}/security/aes_security_spec.rb +1 -1
  167. data/spec/unit/{security → mcollective/security}/base_spec.rb +0 -0
  168. data/spec/unit/{plugins/mcollective → mcollective}/security/psk_spec.rb +1 -1
  169. data/spec/unit/{shell_spec.rb → mcollective/shell_spec.rb} +0 -0
  170. data/spec/unit/{ssl_spec.rb → mcollective/ssl_spec.rb} +12 -12
  171. data/spec/unit/{string_spec.rb → mcollective/string_spec.rb} +0 -0
  172. data/spec/unit/{symbol_spec.rb → mcollective/symbol_spec.rb} +0 -0
  173. data/spec/unit/{unix_daemon_spec.rb → mcollective/unix_daemon_spec.rb} +0 -0
  174. data/spec/unit/{util_spec.rb → mcollective/util_spec.rb} +28 -6
  175. data/spec/unit/{plugins/mcollective → mcollective}/validator/array_validator_spec.rb +1 -1
  176. data/spec/unit/{plugins/mcollective → mcollective}/validator/ipv4address_validator_spec.rb +1 -1
  177. data/spec/unit/{plugins/mcollective → mcollective}/validator/ipv6address_validator_spec.rb +1 -1
  178. data/spec/unit/{plugins/mcollective → mcollective}/validator/length_validator_spec.rb +1 -1
  179. data/spec/unit/{plugins/mcollective → mcollective}/validator/regex_validator_spec.rb +1 -1
  180. data/spec/unit/{plugins/mcollective → mcollective}/validator/shellsafe_validator_spec.rb +1 -1
  181. data/spec/unit/{plugins/mcollective → mcollective}/validator/typecheck_validator_spec.rb +1 -1
  182. data/spec/unit/{validator_spec.rb → mcollective/validator_spec.rb} +1 -1
  183. data/spec/unit/{vendor_spec.rb → mcollective/vendor_spec.rb} +2 -2
  184. data/spec/unit/{windows_daemon_spec.rb → mcollective/windows_daemon_spec.rb} +0 -0
  185. metadata +361 -284
  186. checksums.yaml +0 -7
@@ -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] -%>
@@ -1,8 +1,8 @@
1
1
  module MCollective
2
2
  module PluginPackager
3
3
  # Plugin definition classes
4
- autoload :AgentDefinition, "mcollective/pluginpackager/agent_definition"
5
- autoload :StandardDefinition, "mcollective/pluginpackager/standard_definition"
4
+ require "mcollective/pluginpackager/agent_definition"
5
+ require "mcollective/pluginpackager/standard_definition"
6
6
 
7
7
  # Package implementation plugins
8
8
  def self.load_packagers
@@ -0,0 +1,10 @@
1
+ module MCollective
2
+ module Registration
3
+ # A registration plugin that simply sends in the list of agents we have
4
+ class Agentlist<Base
5
+ def body
6
+ Agents.agentlist
7
+ end
8
+ end
9
+ end
10
+ end
@@ -11,6 +11,6 @@ module MCollective
11
11
  # to supply a _body_ method, whatever this method returns will be send to the
12
12
  # middleware connection for an agent called _registration_
13
13
  module Registration
14
- autoload :Base, "mcollective/registration/base"
14
+ require "mcollective/registration/base"
15
15
  end
16
16
  end
@@ -39,7 +39,6 @@ module MCollective
39
39
  :totaltime => @totaltime,
40
40
  :discovered => @discovered,
41
41
  :discovered_nodes => @discovered_nodes,
42
- :noresponsefrom => @noresponsefrom,
43
42
  :okcount => @okcount,
44
43
  :requestid => @requestid,
45
44
  :failcount => @failcount,
@@ -5,16 +5,16 @@ module MCollective
5
5
  # an RPC metaphor, standard compliant agents will make it easier
6
6
  # to create generic clients like web interfaces etc
7
7
  module RPC
8
- autoload :ActionRunner, "mcollective/rpc/actionrunner"
9
- autoload :Agent, "mcollective/rpc/agent"
10
- autoload :Audit, "mcollective/rpc/audit"
11
- autoload :Client, "mcollective/rpc/client"
12
- autoload :Helpers, "mcollective/rpc/helpers"
13
- autoload :Progress, "mcollective/rpc/progress"
14
- autoload :Reply, "mcollective/rpc/reply"
15
- autoload :Request, "mcollective/rpc/request"
16
- autoload :Result, "mcollective/rpc/result"
17
- autoload :Stats, "mcollective/rpc/stats"
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
18
 
19
19
  # Creates a standard options hash, pass in a block to add extra headings etc
20
20
  # see Optionparser
@@ -58,7 +58,7 @@ module MCollective
58
58
  # exit if there is a failure constructing the RPC client. Set this flag
59
59
  # to false to cause an Exception to be raised instead.
60
60
  def rpcclient(agent, flags = {})
61
- configfile = flags[:configfile] || "/etc/mcollective/client.cfg"
61
+ configfile = flags[:configfile] || Util.config_file_for_user
62
62
  options = flags[:options] || nil
63
63
 
64
64
  if flags.key?(:exit_on_failure)
@@ -0,0 +1,394 @@
1
+ module MCollective
2
+ module Security
3
+ # Impliments a security system that encrypts payloads using AES and secures
4
+ # the AES encrypted data using RSA public/private key encryption.
5
+ #
6
+ # The design goals of this plugin are:
7
+ #
8
+ # - Each actor - clients and servers - can have their own set of public and
9
+ # private keys
10
+ # - All actors are uniquely and cryptographically identified
11
+ # - Requests are encrypted using the clients private key and anyone that has
12
+ # the public key can see the request. Thus an atacker may see the requests
13
+ # given access to network or machine due to the broadcast nature of mcollective
14
+ # - The message time and TTL of messages are cryptographically secured making the
15
+ # ensuring messages can not be replayed with fake TTLs or times
16
+ # - Replies are encrypted using the calling clients public key. Thus no-one but
17
+ # the caller can view the contents of replies.
18
+ # - Servers can all have their own RSA keys, or share one, or reuse keys created
19
+ # by other PKI using software like Puppet
20
+ # - Requests from servers - like registration data - can be secured even to external
21
+ # eaves droppers depending on the level of configuration you are prepared to do
22
+ # - Given a network where you can ensure third parties are not able to access the
23
+ # middleware public key distribution can happen automatically
24
+ #
25
+ # Configuration Options:
26
+ # ======================
27
+ #
28
+ # Common Options:
29
+ #
30
+ # # Enable this plugin
31
+ # securityprovider = aes_security
32
+ #
33
+ # # Use YAML as serializer
34
+ # plugin.aes.serializer = yaml
35
+ #
36
+ # # Send our public key with every request so servers can learn it
37
+ # plugin.aes.send_pubkey = 1
38
+ #
39
+ # Clients:
40
+ #
41
+ # # The clients public and private keys
42
+ # plugin.aes.client_private = /home/user/.mcollective.d/user-private.pem
43
+ # plugin.aes.client_public = /home/user/.mcollective.d/user.pem
44
+ #
45
+ # Servers:
46
+ #
47
+ # # Where to cache client keys or find manually distributed ones
48
+ # plugin.aes.client_cert_dir = /etc/mcollective/ssl/clients
49
+ #
50
+ # # Cache public keys promiscuously from the network (this requires either a ca_cert to be set
51
+ # or insecure_learning to be enabled)
52
+ # plugin.aes.learn_pubkeys = 1
53
+ #
54
+ # # Do not check if client certificate can be verified by a CA
55
+ # plugin.aes.insecure_learning = 1
56
+ #
57
+ # # CA cert used to verify public keys when in learning mode
58
+ # plugin.aes.ca_cert = /etc/mcollective/ssl/ca.cert
59
+ #
60
+ # # Log but accept messages that may have been tampered with
61
+ # plugin.aes.enforce_ttl = 0
62
+ #
63
+ # # The servers public and private keys
64
+ # plugin.aes.server_private = /etc/mcollective/ssl/server-private.pem
65
+ # plugin.aes.server_public = /etc/mcollective/ssl/server-public.pem
66
+ #
67
+ class Aes_security<Base
68
+ def decodemsg(msg)
69
+ body = deserialize(msg.payload)
70
+
71
+ should_process_msg?(msg, body[:requestid])
72
+ # if we get a message that has a pubkey attached and we're set to learn
73
+ # then add it to the client_cert_dir this should only happen on servers
74
+ # since clients will get replies using their own pubkeys
75
+ if Util.str_to_bool(@config.pluginconf.fetch("aes.learn_pubkeys", false)) && body.include?(:sslpubkey)
76
+ certname = certname_from_callerid(body[:callerid])
77
+ certfile = "#{client_cert_dir}/#{certname}.pem"
78
+ if !File.exist?(certfile)
79
+ if !Util.str_to_bool(@config.pluginconf.fetch("aes.insecure_learning", false))
80
+ if !@config.pluginconf.fetch("aes.ca_cert", nil)
81
+ raise "Cannot verify certificate for '#{certname}'. No CA certificate specified."
82
+ end
83
+
84
+ if !validate_certificate(body[:sslpubkey], certname)
85
+ raise "Unable to validate certificate '#{certname}' against CA"
86
+ end
87
+
88
+ Log.debug("Verified certificate '#{certname}' against CA")
89
+ else
90
+ Log.warn("Insecure key learning is not a secure method of key distribution. Do NOT use this mode in sensitive environments.")
91
+ end
92
+
93
+ Log.debug("Caching client cert in #{certfile}")
94
+ File.open(certfile, "w") {|f| f.print body[:sslpubkey]}
95
+ else
96
+ Log.debug("Not caching client cert. File #{certfile} already exists.")
97
+ end
98
+ end
99
+
100
+ cryptdata = {:key => body[:sslkey], :data => body[:body]}
101
+
102
+ if @initiated_by == :client
103
+ body[:body] = deserialize(decrypt(cryptdata, nil))
104
+ else
105
+ certname = certname_from_callerid(body[:callerid])
106
+ certfile = "#{client_cert_dir}/#{certname}.pem"
107
+ # if aes.ca_cert is set every certificate is validated before we try and use it
108
+ if @config.pluginconf.fetch("aes.ca_cert", nil) && !validate_certificate(File.read(certfile), certname)
109
+ raise "Unable to validate certificate '#{certname}' against CA"
110
+ end
111
+ body[:body] = deserialize(decrypt(cryptdata, body[:callerid]))
112
+
113
+ # If we got a hash it's possible that this is a message with secure
114
+ # TTL and message time, attempt to decode that and transform into a
115
+ # traditional message.
116
+ #
117
+ # If it's not a hash it might be a old style message like old discovery
118
+ # ones that would just be a string so we allow that unaudited but only
119
+ # if enforce_ttl is disabled. This is primarly to allow a mixed old and
120
+ # new plugin infrastructure to work
121
+ if body[:body].is_a?(Hash)
122
+ update_secure_property(body, :aes_ttl, :ttl, "TTL")
123
+ update_secure_property(body, :aes_msgtime, :msgtime, "Message Time")
124
+
125
+ body[:body] = body[:body][:aes_msg] if body[:body].include?(:aes_msg)
126
+ else
127
+ unless @config.pluginconf["aes.enforce_ttl"] == "0"
128
+ raise "Message %s is in an unknown or older security protocol, ignoring" % [request_description(body)]
129
+ end
130
+ end
131
+ end
132
+
133
+ return body
134
+ rescue MsgDoesNotMatchRequestID
135
+ raise
136
+
137
+ rescue OpenSSL::PKey::RSAError
138
+ raise MsgDoesNotMatchRequestID, "Could not decrypt message using our key, possibly directed at another client"
139
+
140
+ rescue Exception => e
141
+ Log.warn("Could not decrypt message from client: #{e.class}: #{e}")
142
+ raise SecurityValidationFailed, "Could not decrypt message"
143
+ end
144
+
145
+ # To avoid tampering we turn the origin body into a hash and copy some of the protocol keys
146
+ # like :ttl and :msg_time into the hash before encrypting it.
147
+ #
148
+ # This function compares and updates the unencrypted ones based on the encrypted ones. By
149
+ # default it enforces matching and presense by raising exceptions, if aes.enforce_ttl is set
150
+ # to 0 it will only log warnings about violations
151
+ def update_secure_property(msg, secure_property, property, description)
152
+ req = request_description(msg)
153
+
154
+ unless @config.pluginconf["aes.enforce_ttl"] == "0"
155
+ raise "Request #{req} does not have a secure #{description}" unless msg[:body].include?(secure_property)
156
+ raise "Request #{req} #{description} does not match encrypted #{description} - possible tampering" unless msg[:body][secure_property] == msg[property]
157
+ else
158
+ if msg[:body].include?(secure_property)
159
+ Log.warn("Request #{req} #{description} does not match encrypted #{description} - possible tampering") unless msg[:body][secure_property] == msg[property]
160
+ else
161
+ Log.warn("Request #{req} does not have a secure #{description}") unless msg[:body].include?(secure_property)
162
+ end
163
+ end
164
+
165
+ msg[property] = msg[:body][secure_property] if msg[:body].include?(secure_property)
166
+ msg[:body].delete(secure_property)
167
+ end
168
+
169
+ # Encodes a reply
170
+ def encodereply(sender, msg, requestid, requestcallerid)
171
+ crypted = encrypt(serialize(msg), requestcallerid)
172
+
173
+ req = create_reply(requestid, sender, crypted[:data])
174
+ req[:sslkey] = crypted[:key]
175
+
176
+ serialize(req)
177
+ end
178
+
179
+ # Encodes a request msg
180
+ def encoderequest(sender, msg, requestid, filter, target_agent, target_collective, ttl=60)
181
+ req = create_request(requestid, filter, nil, @initiated_by, target_agent, target_collective, ttl)
182
+
183
+ # embed the ttl and msgtime in the crypted data later we will use these in
184
+ # the decoding of a message to set the message ones from secure sources. this
185
+ # is to ensure messages are not tampered with to facility replay attacks etc
186
+ aes_msg = {:aes_msg => msg,
187
+ :aes_ttl => ttl,
188
+ :aes_msgtime => req[:msgtime]}
189
+
190
+ crypted = encrypt(serialize(aes_msg), callerid)
191
+
192
+ req[:body] = crypted[:data]
193
+ req[:sslkey] = crypted[:key]
194
+
195
+ if @config.pluginconf.include?("aes.send_pubkey") && @config.pluginconf["aes.send_pubkey"] == "1"
196
+ if @initiated_by == :client
197
+ req[:sslpubkey] = File.read(client_public_key)
198
+ else
199
+ req[:sslpubkey] = File.read(server_public_key)
200
+ end
201
+ end
202
+
203
+ serialize(req)
204
+ end
205
+
206
+ # Serializes a message using the configured encoder
207
+ def serialize(msg)
208
+ serializer = @config.pluginconf["aes.serializer"] || "marshal"
209
+
210
+ Log.debug("Serializing using #{serializer}")
211
+
212
+ case serializer
213
+ when "yaml"
214
+ return YAML.dump(msg)
215
+ else
216
+ return Marshal.dump(msg)
217
+ end
218
+ end
219
+
220
+ # De-Serializes a message using the configured encoder
221
+ def deserialize(msg)
222
+ serializer = @config.pluginconf["aes.serializer"] || "marshal"
223
+
224
+ Log.debug("De-Serializing using #{serializer}")
225
+
226
+ case serializer
227
+ when "yaml"
228
+ return YAML.load(msg)
229
+ else
230
+ return Marshal.load(msg)
231
+ end
232
+ end
233
+
234
+ # sets the caller id to the md5 of the public key
235
+ def callerid
236
+ if @initiated_by == :client
237
+ key = client_public_key
238
+ else
239
+ key = server_public_key
240
+ end
241
+
242
+ # First try and create a X509 certificate object. If that is possible,
243
+ # we lift the callerid from the cert
244
+ begin
245
+ ssl_cert = OpenSSL::X509::Certificate.new(File.read(key))
246
+ id = "cert=#{certname_from_certificate(ssl_cert)}"
247
+ rescue
248
+ # If the public key is not a certificate, use the file name as callerid
249
+ id = "cert=#{File.basename(key).gsub(/\.pem$/, '')}"
250
+ end
251
+
252
+ return id
253
+ end
254
+
255
+ def encrypt(string, certid)
256
+ if @initiated_by == :client
257
+ @ssl ||= SSL.new(client_public_key, client_private_key)
258
+
259
+ Log.debug("Encrypting message using private key")
260
+ return @ssl.encrypt_with_private(string)
261
+ else
262
+ # when the server is initating requests like for registration
263
+ # then the certid will be our callerid
264
+ if certid == callerid
265
+ Log.debug("Encrypting message using private key #{server_private_key}")
266
+
267
+ ssl = SSL.new(server_public_key, server_private_key)
268
+ return ssl.encrypt_with_private(string)
269
+ else
270
+ Log.debug("Encrypting message using public key for #{certid}")
271
+
272
+ ssl = SSL.new(public_key_path_for_client(certid))
273
+ return ssl.encrypt_with_public(string)
274
+ end
275
+ end
276
+ end
277
+
278
+ def decrypt(string, certid)
279
+ if @initiated_by == :client
280
+ @ssl ||= SSL.new(client_public_key, client_private_key)
281
+
282
+ Log.debug("Decrypting message using private key")
283
+ return @ssl.decrypt_with_private(string)
284
+ else
285
+ Log.debug("Decrypting message using public key for #{certid}")
286
+ ssl = SSL.new(public_key_path_for_client(certid))
287
+ return ssl.decrypt_with_public(string)
288
+ end
289
+ end
290
+
291
+ def validate_certificate(client_cert, certid)
292
+ cert_file = @config.pluginconf.fetch("aes.ca_cert", nil)
293
+
294
+ begin
295
+ ssl_cert = OpenSSL::X509::Certificate.new(client_cert)
296
+ rescue OpenSSL::X509::CertificateError
297
+ Log.warn("Received public key that is not a X509 certficate")
298
+ return false
299
+ end
300
+
301
+ ssl_certname = certname_from_certificate(ssl_cert)
302
+
303
+ if certid != ssl_certname
304
+ Log.warn("certname '#{certid}' doesn't match certificate '#{ssl_certname}'")
305
+ return false
306
+ end
307
+
308
+ Log.debug("Loading CA Cert for verification")
309
+ ca_cert = OpenSSL::X509::Store.new
310
+ ca_cert.add_file cert_file
311
+
312
+ if ca_cert.verify(ssl_cert)
313
+ Log.debug("Verified certificate '#{ssl_certname}' against CA")
314
+ else
315
+ # TODO add cert id
316
+ Log.warn("Unable to validate certificate '#{ssl_certname}'' against CA")
317
+ return false
318
+ end
319
+ return true
320
+ end
321
+
322
+ # On servers this will look in the aes.client_cert_dir for public
323
+ # keys matching the clientid, clientid is expected to be in the format
324
+ # set by callerid
325
+ def public_key_path_for_client(clientid)
326
+ raise "Unknown callerid format in '#{clientid}'" unless clientid.match(/^cert=(.+)$/)
327
+
328
+ clientid = $1
329
+
330
+ client_cert_dir + "/#{clientid}.pem"
331
+ end
332
+
333
+ # Figures out the client private key either from MCOLLECTIVE_AES_PRIVATE or the
334
+ # plugin.aes.client_private config option
335
+ def client_private_key
336
+ return ENV["MCOLLECTIVE_AES_PRIVATE"] if ENV.include?("MCOLLECTIVE_AES_PRIVATE")
337
+
338
+ raise("No plugin.aes.client_private configuration option specified") unless @config.pluginconf.include?("aes.client_private")
339
+
340
+ return @config.pluginconf["aes.client_private"]
341
+ end
342
+
343
+ # Figures out the client public key either from MCOLLECTIVE_AES_PUBLIC or the
344
+ # plugin.aes.client_public config option
345
+ def client_public_key
346
+ return ENV["MCOLLECTIVE_AES_PUBLIC"] if ENV.include?("MCOLLECTIVE_AES_PUBLIC")
347
+
348
+ raise("No plugin.aes.client_public configuration option specified") unless @config.pluginconf.include?("aes.client_public")
349
+
350
+ return @config.pluginconf["aes.client_public"]
351
+ end
352
+
353
+ # Figures out the server public key from the plugin.aes.server_public config option
354
+ def server_public_key
355
+ raise("No aes.server_public configuration option specified") unless @config.pluginconf.include?("aes.server_public")
356
+ return @config.pluginconf["aes.server_public"]
357
+ end
358
+
359
+ # Figures out the server private key from the plugin.aes.server_private config option
360
+ def server_private_key
361
+ raise("No plugin.aes.server_private configuration option specified") unless @config.pluginconf.include?("aes.server_private")
362
+ @config.pluginconf["aes.server_private"]
363
+ end
364
+
365
+ # Figures out where to get client public certs from the plugin.aes.client_cert_dir config option
366
+ def client_cert_dir
367
+ raise("No plugin.aes.client_cert_dir configuration option specified") unless @config.pluginconf.include?("aes.client_cert_dir")
368
+ @config.pluginconf["aes.client_cert_dir"]
369
+ end
370
+
371
+ def request_description(msg)
372
+ "%s from %s@%s" % [msg[:requestid], msg[:callerid], msg[:senderid]]
373
+ end
374
+
375
+ # Takes our cert=foo callerids and return the foo bit else nil
376
+ def certname_from_callerid(id)
377
+ if id =~ /^cert=([\w\.\-]+)/
378
+ return $1
379
+ else
380
+ raise("Received a callerid in an unexpected format: '#{id}', ignoring")
381
+ end
382
+ end
383
+
384
+ def certname_from_certificate(cert)
385
+ id = cert.subject
386
+ if id.to_s =~ /^\/CN=([\w\.\-]+)/
387
+ return $1
388
+ else
389
+ raise("Received a callerid in an unexpected format in an SSL certificate: '#{id}', ignoring")
390
+ end
391
+ end
392
+ end
393
+ end
394
+ end