mcollective-client 1.3.3

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 (103) hide show
  1. data/bin/mc-call-agent +54 -0
  2. data/bin/mco +27 -0
  3. data/lib/mcollective.rb +70 -0
  4. data/lib/mcollective/agents.rb +160 -0
  5. data/lib/mcollective/application.rb +354 -0
  6. data/lib/mcollective/applications.rb +145 -0
  7. data/lib/mcollective/client.rb +292 -0
  8. data/lib/mcollective/config.rb +202 -0
  9. data/lib/mcollective/connector.rb +18 -0
  10. data/lib/mcollective/connector/base.rb +24 -0
  11. data/lib/mcollective/facts.rb +39 -0
  12. data/lib/mcollective/facts/base.rb +86 -0
  13. data/lib/mcollective/log.rb +103 -0
  14. data/lib/mcollective/logger.rb +5 -0
  15. data/lib/mcollective/logger/base.rb +73 -0
  16. data/lib/mcollective/logger/console_logger.rb +61 -0
  17. data/lib/mcollective/logger/file_logger.rb +46 -0
  18. data/lib/mcollective/logger/syslog_logger.rb +53 -0
  19. data/lib/mcollective/matcher.rb +16 -0
  20. data/lib/mcollective/matcher/parser.rb +93 -0
  21. data/lib/mcollective/matcher/scanner.rb +123 -0
  22. data/lib/mcollective/message.rb +201 -0
  23. data/lib/mcollective/monkey_patches.rb +104 -0
  24. data/lib/mcollective/optionparser.rb +164 -0
  25. data/lib/mcollective/pluginmanager.rb +180 -0
  26. data/lib/mcollective/pluginpackager.rb +26 -0
  27. data/lib/mcollective/pluginpackager/agent_definition.rb +79 -0
  28. data/lib/mcollective/pluginpackager/standard_definition.rb +59 -0
  29. data/lib/mcollective/registration.rb +16 -0
  30. data/lib/mcollective/registration/base.rb +75 -0
  31. data/lib/mcollective/rpc.rb +188 -0
  32. data/lib/mcollective/rpc/actionrunner.rb +142 -0
  33. data/lib/mcollective/rpc/agent.rb +441 -0
  34. data/lib/mcollective/rpc/audit.rb +38 -0
  35. data/lib/mcollective/rpc/client.rb +793 -0
  36. data/lib/mcollective/rpc/ddl.rb +258 -0
  37. data/lib/mcollective/rpc/helpers.rb +339 -0
  38. data/lib/mcollective/rpc/progress.rb +63 -0
  39. data/lib/mcollective/rpc/reply.rb +61 -0
  40. data/lib/mcollective/rpc/request.rb +51 -0
  41. data/lib/mcollective/rpc/result.rb +41 -0
  42. data/lib/mcollective/rpc/stats.rb +185 -0
  43. data/lib/mcollective/runnerstats.rb +90 -0
  44. data/lib/mcollective/security.rb +26 -0
  45. data/lib/mcollective/security/base.rb +237 -0
  46. data/lib/mcollective/shell.rb +87 -0
  47. data/lib/mcollective/ssl.rb +246 -0
  48. data/lib/mcollective/unix_daemon.rb +37 -0
  49. data/lib/mcollective/util.rb +274 -0
  50. data/lib/mcollective/vendor.rb +41 -0
  51. data/lib/mcollective/vendor/require_vendored.rb +2 -0
  52. data/lib/mcollective/windows_daemon.rb +25 -0
  53. data/spec/Rakefile +16 -0
  54. data/spec/fixtures/application/test.rb +7 -0
  55. data/spec/fixtures/test-cert.pem +15 -0
  56. data/spec/fixtures/test-private.pem +15 -0
  57. data/spec/fixtures/test-public.pem +6 -0
  58. data/spec/monkey_patches/instance_variable_defined.rb +7 -0
  59. data/spec/spec.opts +1 -0
  60. data/spec/spec_helper.rb +25 -0
  61. data/spec/unit/agents_spec.rb +280 -0
  62. data/spec/unit/application_spec.rb +636 -0
  63. data/spec/unit/applications_spec.rb +155 -0
  64. data/spec/unit/array.rb +30 -0
  65. data/spec/unit/config_spec.rb +148 -0
  66. data/spec/unit/facts/base_spec.rb +118 -0
  67. data/spec/unit/facts_spec.rb +39 -0
  68. data/spec/unit/log_spec.rb +71 -0
  69. data/spec/unit/logger/base_spec.rb +110 -0
  70. data/spec/unit/logger/syslog_logger_spec.rb +86 -0
  71. data/spec/unit/matcher/parser_spec.rb +106 -0
  72. data/spec/unit/matcher/scanner_spec.rb +71 -0
  73. data/spec/unit/message_spec.rb +401 -0
  74. data/spec/unit/optionparser_spec.rb +113 -0
  75. data/spec/unit/pluginmanager_spec.rb +173 -0
  76. data/spec/unit/pluginpackager/agent_definition_spec.rb +130 -0
  77. data/spec/unit/pluginpackager/standard_definition_spec.rb +75 -0
  78. data/spec/unit/plugins/mcollective/connector/activemq_spec.rb +533 -0
  79. data/spec/unit/plugins/mcollective/connector/stomp/eventlogger_spec.rb +34 -0
  80. data/spec/unit/plugins/mcollective/connector/stomp_spec.rb +417 -0
  81. data/spec/unit/plugins/mcollective/packagers/ospackage_spec.rb +229 -0
  82. data/spec/unit/plugins/mcollective/security/psk_spec.rb +156 -0
  83. data/spec/unit/registration/base_spec.rb +77 -0
  84. data/spec/unit/rpc/actionrunner_spec.rb +213 -0
  85. data/spec/unit/rpc/agent_spec.rb +155 -0
  86. data/spec/unit/rpc/client_spec.rb +523 -0
  87. data/spec/unit/rpc/ddl_spec.rb +388 -0
  88. data/spec/unit/rpc/helpers_spec.rb +55 -0
  89. data/spec/unit/rpc/reply_spec.rb +143 -0
  90. data/spec/unit/rpc/request_spec.rb +115 -0
  91. data/spec/unit/rpc/result_spec.rb +66 -0
  92. data/spec/unit/rpc/stats_spec.rb +288 -0
  93. data/spec/unit/runnerstats_spec.rb +40 -0
  94. data/spec/unit/security/base_spec.rb +279 -0
  95. data/spec/unit/shell_spec.rb +144 -0
  96. data/spec/unit/ssl_spec.rb +244 -0
  97. data/spec/unit/symbol.rb +11 -0
  98. data/spec/unit/unix_daemon.rb +41 -0
  99. data/spec/unit/util_spec.rb +342 -0
  100. data/spec/unit/vendor_spec.rb +34 -0
  101. data/spec/unit/windows_daemon.rb +43 -0
  102. data/spec/windows_spec.opts +1 -0
  103. metadata +242 -0
@@ -0,0 +1,26 @@
1
+ module MCollective
2
+ module PluginPackager
3
+ # Plugin definition classes
4
+ autoload :AgentDefinition, "mcollective/pluginpackager/agent_definition"
5
+ autoload :StandardDefinition, "mcollective/pluginpackager/standard_definition"
6
+
7
+ # Package implementation plugins
8
+ def self.load_packagers
9
+ PluginManager.find_and_load("pluginpackager")
10
+ end
11
+
12
+ def self.[](klass)
13
+ const_get("#{klass}")
14
+ end
15
+
16
+ def self.get_metadata(path, type)
17
+ ddl = MCollective::RPC::DDL.new("package", false)
18
+ ddl.instance_eval File.read(Dir.glob(File.join(path, type, "*.ddl")).first)
19
+ ddl.meta
20
+ end
21
+
22
+ def self.check_dir_present(path)
23
+ (File.directory?(path) && !Dir.glob(File.join(path, "*")).empty?)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,79 @@
1
+ module MCollective
2
+ module PluginPackager
3
+ # MCollective Agent Plugin package
4
+ class AgentDefinition
5
+ attr_accessor :path, :packagedata, :metadata, :target_path, :vendor, :iteration, :postinstall
6
+ attr_accessor :plugintype
7
+
8
+ def initialize(path, name, vendor, postinstall, iteration, plugintype)
9
+ @plugintype = plugintype
10
+ @path = path
11
+ @packagedata = {}
12
+ @iteration = iteration || 1
13
+ @postinstall = postinstall
14
+ @vendor = vendor || "Puppet Labs"
15
+ @target_path = File.expand_path(@path)
16
+ @metadata = PluginPackager.get_metadata(@path, "agent")
17
+ @metadata[:name] = (name || @metadata[:name]).downcase.gsub(" ", "_")
18
+ identify_packages
19
+ end
20
+
21
+ # Identify present packages and populate packagedata hash.
22
+ def identify_packages
23
+ @packagedata[:common] = common
24
+ @packagedata[:agent] = agent
25
+ @packagedata[:client] = client
26
+ end
27
+
28
+ # Obtain Agent package files and dependencies.
29
+ def agent
30
+ agent = {:files => [],
31
+ :dependencies => ["mcollective"],
32
+ :description => "Agent plugin for #{@metadata[:name]}"}
33
+
34
+ agentdir = File.join(@path, "agent")
35
+
36
+ if PluginPackager.check_dir_present agentdir
37
+ ddls = Dir.glob(File.join(agentdir, "*.ddl"))
38
+ agent[:files] = (Dir.glob(File.join(agentdir, "*")) - ddls)
39
+ implementations = Dir.glob(File.join(@metadata[:name], "**"))
40
+ agent[:files] += implementations unless implementations.empty?
41
+ else
42
+ return nil
43
+ end
44
+
45
+ agent[:dependencies] << "mcollective-#{@metadata[:name]}-common" if @packagedata[:common]
46
+ agent
47
+ end
48
+
49
+ # Obtain client package files and dependencies.
50
+ def client
51
+ client = {:files => [],
52
+ :dependencies => ["mcollective-client"],
53
+ :description => "Client plugin for #{@metadata[:name]}"}
54
+
55
+ clientdir = File.join(@path, "application")
56
+ bindir = File.join(@path, "bin")
57
+ ddldir = File.join(@path, "agent")
58
+
59
+ client[:files] += Dir.glob(File.join(clientdir, "*")) if PluginPackager.check_dir_present clientdir
60
+ client[:files] += Dir.glob(File.join(bindir,"*")) if PluginPackager.check_dir_present bindir
61
+ client[:files] += Dir.glob(File.join(ddldir, "*.ddl")) if PluginPackager.check_dir_present ddldir
62
+ client[:dependencies] << "mcollective-#{@metadata[:name]}-common" if @packagedata[:common]
63
+ client[:files].empty? ? nil : client
64
+ end
65
+
66
+ # Obtain common package files and dependencies.
67
+ def common
68
+ common = {:files =>[],
69
+ :dependencies => ["mcollective-common"],
70
+ :description => "Common libraries for #{@metadata[:name]}"}
71
+
72
+ commondir = File.join(@path, "util")
73
+ common[:files] += Dir.glob(File.join(commondir,"*")) if PluginPackager.check_dir_present commondir
74
+ common[:files].empty? ? nil : common
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,59 @@
1
+ module MCollective
2
+ module PluginPackager
3
+ class StandardDefinition
4
+ attr_accessor :path, :packagedata, :metadata, :target_path, :vendor, :iteration, :postinstall
5
+ attr_accessor :plugintype
6
+
7
+ def initialize(path, name, vendor, postinstall, iteration, plugintype)
8
+ @plugintype = plugintype
9
+ @path = path
10
+ @packagedata = {}
11
+ @iteration = iteration || 1
12
+ @postinstall = postinstall
13
+ @vendor = vendor || "Puppet Labs"
14
+ @target_path = File.expand_path(@path)
15
+ @metadata = PluginPackager.get_metadata(@path, @plugintype)
16
+ @metadata[:name] = (name || @metadata[:name]).downcase.gsub(" ", "_")
17
+ identify_packages
18
+ end
19
+
20
+ # Identify present packages and populate the packagedata hash
21
+ def identify_packages
22
+ @packagedata[:common] = common
23
+ @packagedata[@plugintype] = plugin
24
+ end
25
+
26
+ # Obtain standard plugin files and dependencies
27
+ def plugin
28
+ plugindata = {:files => [],
29
+ :dependencies => ["mcollective"],
30
+ :description => "#{@name} #{@plugintype} plugin for the Marionette Collective."}
31
+
32
+ plugindir = File.join(@path, @plugintype.to_s)
33
+ if PluginPackager.check_dir_present plugindir
34
+ plugindata[:files] = Dir.glob(File.join(plugindir, "*"))
35
+ else
36
+ return nil
37
+ end
38
+
39
+ plugindata[:dependencies] <<"mcollective-#{@metadata[:name]}-common" if @packagedata[:common]
40
+ plugindata
41
+ end
42
+
43
+ # Obtain list of common files
44
+ def common
45
+ common = {:files => [],
46
+ :dependencies => ["mcolelctive-common"],
47
+ :description => "Common libraries for #{@name} connector plugin"}
48
+
49
+ commondir = File.join(@path, "util")
50
+ if PluginPackager.check_dir_present commondir
51
+ common[:files] = Dir.glob(File.join(commondir, "*"))
52
+ return common
53
+ else
54
+ return nil
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,16 @@
1
+ module MCollective
2
+ # Registration is implimented using a module structure and installations can
3
+ # configure which module they want to use.
4
+ #
5
+ # We provide a simple one that just sends back the list of current known agents
6
+ # in MCollective::Registration::Agentlist, you can create your own:
7
+ #
8
+ # Create a module in plugins/mcollective/registration/<yourplugin>.rb
9
+ #
10
+ # You can inherit from MCollective::Registration::Base in which case you just need
11
+ # to supply a _body_ method, whatever this method returns will be send to the
12
+ # middleware connection for an agent called _registration_
13
+ module Registration
14
+ autoload :Base, "mcollective/registration/base"
15
+ end
16
+ end
@@ -0,0 +1,75 @@
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
+ loop do
24
+ begin
25
+ publish(body)
26
+
27
+ sleep interval
28
+ rescue Exception => e
29
+ Log.error("Sending registration message failed: #{e}")
30
+ sleep interval
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def config
37
+ Config.instance
38
+ end
39
+
40
+ def msg_filter
41
+ {"agent" => "registration"}
42
+ end
43
+
44
+ def target_collective
45
+ main_collective = config.main_collective
46
+
47
+ collective = config.registration_collective || main_collective
48
+
49
+ unless config.collectives.include?(collective)
50
+ Log.warn("Sending registration to #{main_collective}: #{collective} is not a valid collective")
51
+ collective = main_collective
52
+ end
53
+
54
+ return collective
55
+ end
56
+
57
+ def interval
58
+ config.registerinterval
59
+ end
60
+
61
+ def publish(message)
62
+ unless message
63
+ Log.debug("Skipping registration due to nil body")
64
+ else
65
+ req = Message.new(message, nil, {:type => :request, :agent => "registration", :collective => target_collective, :filter => msg_filter})
66
+ req.encode!
67
+
68
+ Log.debug("Sending registration #{req.requestid} to collective #{req.collective}")
69
+
70
+ req.publish
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,188 @@
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
+ autoload :Client, "mcollective/rpc/client"
9
+ autoload :Agent, "mcollective/rpc/agent"
10
+ autoload :Reply, "mcollective/rpc/reply"
11
+ autoload :Request, "mcollective/rpc/request"
12
+ autoload :Audit, "mcollective/rpc/audit"
13
+ autoload :Progress, "mcollective/rpc/progress"
14
+ autoload :Stats, "mcollective/rpc/stats"
15
+ autoload :DDL, "mcollective/rpc/ddl"
16
+ autoload :Result, "mcollective/rpc/result"
17
+ autoload :Helpers, "mcollective/rpc/helpers"
18
+ autoload :ActionRunner, "mcollective/rpc/actionrunner"
19
+
20
+ # Creates a standard options hash, pass in a block to add extra headings etc
21
+ # see Optionparser
22
+ def rpcoptions
23
+ oparser = MCollective::Optionparser.new({:verbose => false, :progress_bar => true}, "filter")
24
+
25
+ options = oparser.parse do |parser, options|
26
+ if block_given?
27
+ yield(parser, options)
28
+ end
29
+
30
+ Helpers.add_simplerpc_options(parser, options)
31
+ end
32
+
33
+ return options
34
+ end
35
+
36
+ # Wrapper to create clients, supposed to be used as
37
+ # a mixin:
38
+ #
39
+ # include MCollective::RPC
40
+ #
41
+ # exim = rpcclient("exim")
42
+ # printrpc exim.mailq
43
+ #
44
+ # or
45
+ #
46
+ # rpcclient("exim") do |exim|
47
+ # printrpc exim.mailq
48
+ # end
49
+ #
50
+ # It will take a few flags:
51
+ # :configfile => "etc/client.cfg"
52
+ # :options => options
53
+ # :exit_on_failure => true
54
+ #
55
+ # Options would be a build up options hash from the Optionparser
56
+ # you can use the rpcoptions helper to create this
57
+ #
58
+ # :exit_on_failure is true by default, and causes the application to
59
+ # exit if there is a failure constructing the RPC client. Set this flag
60
+ # to false to cause an Exception to be raised instead.
61
+ def rpcclient(agent, flags = {})
62
+ configfile = flags[:configfile] || "/etc/mcollective/client.cfg"
63
+ options = flags[:options] || nil
64
+
65
+ if flags.key?(:exit_on_failure)
66
+ exit_on_failure = flags[:exit_on_failure]
67
+ else
68
+ # We exit on failure by default for CLI-friendliness
69
+ exit_on_failure = true
70
+ end
71
+
72
+ begin
73
+ if options
74
+ rpc = Client.new(agent, :configfile => options[:config], :options => options)
75
+ @options = rpc.options
76
+ else
77
+ rpc = Client.new(agent, :configfile => configfile)
78
+ @options = rpc.options
79
+ end
80
+ rescue Exception => e
81
+ if exit_on_failure
82
+ puts("Could not create RPC client: #{e}")
83
+ exit!
84
+ else
85
+ raise e
86
+ end
87
+ end
88
+
89
+ if block_given?
90
+ yield(rpc)
91
+ else
92
+ return rpc
93
+ end
94
+ end
95
+
96
+ # means for other classes to drop stats into this module
97
+ # its a bit hacky but needed so that the mixin methods like
98
+ # printrpcstats can easily get access to it without
99
+ # users having to pass it around in params.
100
+ def self.stats(stats)
101
+ @@stats = stats
102
+ end
103
+
104
+ # means for other classes to drop discovered hosts into this module
105
+ # its a bit hacky but needed so that the mixin methods like
106
+ # printrpcstats can easily get access to it without
107
+ # users having to pass it around in params.
108
+ def self.discovered(discovered)
109
+ @@discovered = discovered
110
+ end
111
+
112
+ # Prints stats, requires stats to be saved from elsewhere
113
+ # using the MCollective::RPC.stats method.
114
+ #
115
+ # If you've passed -v on the command line a detailed stat block
116
+ # will be printed, else just a one liner.
117
+ #
118
+ # You can pass flags into it, at the moment only one flag is
119
+ # supported:
120
+ #
121
+ # printrpcstats :caption => "Foo"
122
+ #
123
+ # This will use "Foo" as the caption to the stats in verbose
124
+ # mode
125
+ def printrpcstats(flags={})
126
+ return unless @options[:output_format] == :console
127
+
128
+ verbose = @options[:verbose] rescue verbose = false
129
+ caption = flags[:caption] || "rpc stats"
130
+
131
+ begin
132
+ stats = @@stats
133
+ rescue
134
+ puts("no stats to display")
135
+ return
136
+ end
137
+
138
+ puts
139
+ puts stats.report(caption, verbose)
140
+ end
141
+
142
+ # Prints the result of an RPC call.
143
+ #
144
+ # In the default quiet mode - no flattening or verbose - only results
145
+ # that produce an error will be printed
146
+ #
147
+ # To get details of each result run with the -v command line option.
148
+ def printrpc(result, flags = {})
149
+ verbose = @options[:verbose] rescue verbose = false
150
+ verbose = flags[:verbose] || verbose
151
+ flatten = flags[:flatten] || false
152
+ format = @options[:output_format]
153
+
154
+ result_text = Helpers.rpcresults(result, {:verbose => verbose, :flatten => flatten, :format => format})
155
+
156
+ if result.is_a?(Array) && format == :console
157
+ puts "\n%s\n" % [ result_text ]
158
+ else
159
+ # when we get just one result to print dont pad them all with
160
+ # blank spaces etc, just print the individual result with no
161
+ # padding
162
+ puts result_text unless result_text == ""
163
+ end
164
+ end
165
+
166
+ # Wrapper for MCollective::Util.empty_filter? to make clients less fugly
167
+ # to write - ticket #18
168
+ def empty_filter?(options)
169
+ if options.include?(:filter)
170
+ Util.empty_filter?(options[:filter])
171
+ else
172
+ Util.empty_filter?(options)
173
+ end
174
+ end
175
+
176
+ # Factory for RPC::Request messages, only really here to make agents
177
+ # a bit easier to understand
178
+ def self.request(msg)
179
+ RPC::Request.new(msg)
180
+ end
181
+
182
+ # Factory for RPC::Reply messages, only really here to make agents
183
+ # a bit easier to understand
184
+ def self.reply
185
+ RPC::Reply.new
186
+ end
187
+ end
188
+ end