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.
- data/lib/mcollective/agent/discovery.rb +37 -0
- data/lib/mcollective/agent/rpcutil.ddl +220 -0
- data/lib/mcollective/agent/rpcutil.rb +108 -0
- data/lib/mcollective/aggregate/average.ddl +33 -0
- data/lib/mcollective/aggregate/average.rb +29 -0
- data/lib/mcollective/aggregate/result.rb +3 -3
- 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/aggregate.rb +2 -2
- data/lib/mcollective/application/completion.rb +104 -0
- data/lib/mcollective/application/facts.rb +62 -0
- data/lib/mcollective/application/find.rb +21 -0
- data/lib/mcollective/application/help.rb +28 -0
- data/lib/mcollective/application/inventory.rb +344 -0
- data/lib/mcollective/application/ping.rb +77 -0
- data/lib/mcollective/application/plugin.rb +369 -0
- data/lib/mcollective/application/rpc.rb +121 -0
- data/lib/mcollective/application.rb +2 -0
- data/lib/mcollective/audit/logfile.rb +26 -0
- data/lib/mcollective/config.rb +16 -9
- data/lib/mcollective/connector/activemq.ddl +9 -0
- data/lib/mcollective/connector/activemq.rb +572 -0
- data/lib/mcollective/connector/rabbitmq.ddl +9 -0
- data/lib/mcollective/connector/rabbitmq.rb +484 -0
- data/lib/mcollective/connector.rb +1 -1
- data/lib/mcollective/data/agent_data.ddl +22 -0
- data/lib/mcollective/data/agent_data.rb +17 -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.rb +2 -2
- data/lib/mcollective/ddl.rb +4 -4
- 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 +66 -0
- data/lib/mcollective/facts/yaml_facts.rb +61 -0
- data/lib/mcollective/facts.rb +1 -1
- data/lib/mcollective/generators.rb +3 -3
- data/lib/mcollective/logger.rb +1 -1
- data/lib/mcollective/matcher/scanner.rb +1 -1
- data/lib/mcollective/matcher.rb +2 -2
- 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/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/pluginpackager.rb +2 -2
- data/lib/mcollective/registration/agentlist.rb +10 -0
- data/lib/mcollective/registration.rb +1 -1
- data/lib/mcollective/rpc/stats.rb +0 -1
- data/lib/mcollective/rpc.rb +11 -11
- data/lib/mcollective/security/aes_security.rb +394 -0
- data/lib/mcollective/security/psk.rb +117 -0
- data/lib/mcollective/security/ssl.rb +328 -0
- data/lib/mcollective/security.rb +1 -1
- data/lib/mcollective/util.rb +18 -18
- 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
- data/lib/mcollective.rb +31 -31
- data/spec/spec_helper.rb +0 -5
- data/spec/unit/{plugins/mcollective → mcollective}/agent/rpcutil_spec.rb +1 -1
- data/spec/unit/{agents_spec.rb → mcollective/agents_spec.rb} +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/aggregate/average_spec.rb +1 -1
- data/spec/unit/{aggregate → mcollective/aggregate}/base_spec.rb +0 -0
- data/spec/unit/{aggregate → mcollective/aggregate}/result/base_spec.rb +0 -0
- data/spec/unit/{aggregate → mcollective/aggregate}/result/collection_result_spec.rb +0 -0
- data/spec/unit/{aggregate → mcollective/aggregate}/result/numeric_result_spec.rb +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/aggregate/sum_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/aggregate/summary_spec.rb +1 -1
- data/spec/unit/{aggregate_spec.rb → mcollective/aggregate_spec.rb} +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/application/plugin_spec.rb +1 -1
- data/spec/unit/{application_spec.rb → mcollective/application_spec.rb} +0 -0
- data/spec/unit/{applications_spec.rb → mcollective/applications_spec.rb} +1 -1
- data/spec/unit/{array_spec.rb → mcollective/array_spec.rb} +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/audit/logfile_spec.rb +1 -1
- data/spec/unit/{cache_spec.rb → mcollective/cache_spec.rb} +0 -0
- data/spec/unit/{client_spec.rb → mcollective/client_spec.rb} +0 -0
- data/spec/unit/{config_spec.rb → mcollective/config_spec.rb} +12 -7
- data/spec/unit/{plugins/mcollective → mcollective}/connector/activemq_spec.rb +1 -1
- data/spec/unit/{connector → mcollective/connector}/base_spec.rb +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/connector/rabbitmq_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/data/agent_data_spec.rb +1 -1
- data/spec/unit/{data → mcollective/data}/base_spec.rb +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/data/collective_data_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/data/fact_data_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/data/fstat_data_spec.rb +1 -1
- data/spec/unit/{data → mcollective/data}/result_spec.rb +0 -0
- data/spec/unit/{data_spec.rb → mcollective/data_spec.rb} +0 -0
- data/spec/unit/{ddl → mcollective/ddl}/agentddl_spec.rb +0 -0
- data/spec/unit/{ddl → mcollective/ddl}/base_spec.rb +0 -0
- data/spec/unit/{ddl → mcollective/ddl}/dataddl_spec.rb +0 -0
- data/spec/unit/{ddl → mcollective/ddl}/discoveryddl_spec.rb +0 -0
- data/spec/unit/{ddl_spec.rb → mcollective/ddl_spec.rb} +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/discovery/flatfile_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/discovery/mc_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/discovery/stdin_spec.rb +1 -1
- data/spec/unit/{discovery_spec.rb → mcollective/discovery_spec.rb} +0 -0
- data/spec/unit/{facts → mcollective/facts}/base_spec.rb +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/facts/yaml_facts_spec.rb +1 -1
- data/spec/unit/{facts_spec.rb → mcollective/facts_spec.rb} +0 -0
- data/spec/unit/{generators → mcollective/generators}/agent_generator_spec.rb +0 -0
- data/spec/unit/{generators → mcollective/generators}/base_spec.rb +0 -0
- data/spec/unit/{generators → mcollective/generators}/data_generator_spec.rb +0 -0
- data/spec/unit/{generators → mcollective/generators}/snippets/agent_ddl +0 -0
- data/spec/unit/{generators → mcollective/generators}/snippets/data_ddl +0 -0
- data/spec/unit/{log_spec.rb → mcollective/log_spec.rb} +0 -0
- data/spec/unit/{logger → mcollective/logger}/base_spec.rb +0 -0
- data/spec/unit/{logger → mcollective/logger}/console_logger_spec.rb +0 -0
- data/spec/unit/{logger → mcollective/logger}/file_logger_spec.rb +0 -0
- data/spec/unit/{logger → mcollective/logger}/syslog_logger_spec.rb +0 -0
- data/spec/unit/{matcher → mcollective/matcher}/parser_spec.rb +0 -0
- data/spec/unit/{matcher → mcollective/matcher}/scanner_spec.rb +0 -0
- data/spec/unit/{matcher_spec.rb → mcollective/matcher_spec.rb} +0 -0
- data/spec/unit/{message_spec.rb → mcollective/message_spec.rb} +0 -0
- data/spec/unit/{monkey_patches_spec.rb → mcollective/monkey_patches_spec.rb} +0 -0
- data/spec/unit/{optionparser_spec.rb → mcollective/optionparser_spec.rb} +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/packagers/debpackage_packager_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/packagers/modulepackage_packager_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/packagers/ospackage_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/packagers/rpmpackage_packager_spec.rb +1 -1
- data/spec/unit/{pluginmanager_spec.rb → mcollective/pluginmanager_spec.rb} +0 -0
- data/spec/unit/{pluginpackager → mcollective/pluginpackager}/agent_definition_spec.rb +0 -0
- data/spec/unit/{pluginpackager → mcollective/pluginpackager}/standard_definition_spec.rb +0 -0
- data/spec/unit/{pluginpackager_spec.rb → mcollective/pluginpackager_spec.rb} +0 -0
- data/spec/unit/{registration → mcollective/registration}/base_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/actionrunner_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/agent_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/client_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/helpers_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/reply_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/request_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/result_spec.rb +0 -0
- data/spec/unit/{rpc → mcollective/rpc}/stats_spec.rb +0 -0
- data/spec/unit/{rpc_spec.rb → mcollective/rpc_spec.rb} +0 -0
- data/spec/unit/{runner_spec.rb → mcollective/runner_spec.rb} +0 -0
- data/spec/unit/{runnerstats_spec.rb → mcollective/runnerstats_spec.rb} +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/security/aes_security_spec.rb +1 -1
- data/spec/unit/{security → mcollective/security}/base_spec.rb +0 -0
- data/spec/unit/{plugins/mcollective → mcollective}/security/psk_spec.rb +1 -1
- data/spec/unit/{shell_spec.rb → mcollective/shell_spec.rb} +0 -0
- data/spec/unit/{ssl_spec.rb → mcollective/ssl_spec.rb} +12 -12
- data/spec/unit/{string_spec.rb → mcollective/string_spec.rb} +0 -0
- data/spec/unit/{symbol_spec.rb → mcollective/symbol_spec.rb} +0 -0
- data/spec/unit/{unix_daemon_spec.rb → mcollective/unix_daemon_spec.rb} +0 -0
- data/spec/unit/{util_spec.rb → mcollective/util_spec.rb} +28 -6
- data/spec/unit/{plugins/mcollective → mcollective}/validator/array_validator_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/validator/ipv4address_validator_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/validator/ipv6address_validator_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/validator/length_validator_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/validator/regex_validator_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/validator/shellsafe_validator_spec.rb +1 -1
- data/spec/unit/{plugins/mcollective → mcollective}/validator/typecheck_validator_spec.rb +1 -1
- data/spec/unit/{validator_spec.rb → mcollective/validator_spec.rb} +1 -1
- data/spec/unit/{vendor_spec.rb → mcollective/vendor_spec.rb} +2 -2
- data/spec/unit/{windows_daemon_spec.rb → mcollective/windows_daemon_spec.rb} +0 -0
- metadata +361 -284
- checksums.yaml +0 -7
@@ -0,0 +1,484 @@
|
|
1
|
+
require 'stomp'
|
2
|
+
|
3
|
+
module MCollective
|
4
|
+
module Connector
|
5
|
+
class Rabbitmq<Base
|
6
|
+
attr_reader :connection
|
7
|
+
|
8
|
+
class EventLogger
|
9
|
+
def on_connecting(params=nil)
|
10
|
+
Log.info("TCP Connection attempt %d to %s" % [params[:cur_conattempts], stomp_url(params)])
|
11
|
+
rescue
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_connected(params=nil)
|
15
|
+
Log.info("Connected to #{stomp_url(params)}")
|
16
|
+
rescue
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_disconnect(params=nil)
|
20
|
+
Log.info("Disconnected from #{stomp_url(params)}")
|
21
|
+
rescue
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_connectfail(params=nil)
|
25
|
+
Log.info("TCP Connection to #{stomp_url(params)} failed on attempt #{params[:cur_conattempts]}")
|
26
|
+
rescue
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_miscerr(params, errstr)
|
30
|
+
Log.error("Unexpected error on connection #{stomp_url(params)}: #{errstr}")
|
31
|
+
rescue
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_ssl_connecting(params)
|
35
|
+
Log.info("Establishing SSL session with #{stomp_url(params)}")
|
36
|
+
rescue
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_ssl_connected(params)
|
40
|
+
Log.info("SSL session established with #{stomp_url(params)}")
|
41
|
+
rescue
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_ssl_connectfail(params)
|
45
|
+
Log.error("SSL session creation with #{stomp_url(params)} failed: #{params[:ssl_exception]}")
|
46
|
+
end
|
47
|
+
|
48
|
+
# Stomp 1.1+ - heart beat read (receive) failed.
|
49
|
+
def on_hbread_fail(params, ticker_data)
|
50
|
+
if ticker_data["lock_fail"]
|
51
|
+
if params[:max_hbrlck_fails] == 0
|
52
|
+
# failure is disabled
|
53
|
+
Log.debug("Heartbeat failed to acquire readlock for '%s': %s" % [stomp_url(params), ticker_data.inspect])
|
54
|
+
elsif ticker_data['lock_fail_count'] >= params[:max_hbrlck_fails]
|
55
|
+
# we're about to force a disconnect
|
56
|
+
Log.error("Heartbeat failed to acquire readlock for '%s': %s" % [stomp_url(params), ticker_data.inspect])
|
57
|
+
else
|
58
|
+
Log.warn("Heartbeat failed to acquire readlock for '%s': %s" % [stomp_url(params), ticker_data.inspect])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
if params[:max_hbread_fails] == 0
|
62
|
+
# failure is disabled
|
63
|
+
Log.debug("Heartbeat read failed from '%s': %s" % [stomp_url(params), ticker_data.inspect])
|
64
|
+
elsif ticker_data['read_fail_count'] >= params[:max_hbread_fails]
|
65
|
+
# we're about to force a reconnect
|
66
|
+
Log.error("Heartbeat read failed from '%s': %s" % [stomp_url(params), ticker_data.inspect])
|
67
|
+
else
|
68
|
+
Log.warn("Heartbeat read failed from '%s': %s" % [stomp_url(params), ticker_data.inspect])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
rescue Exception => e
|
72
|
+
end
|
73
|
+
|
74
|
+
# Stomp 1.1+ - heart beat send (transmit) failed.
|
75
|
+
def on_hbwrite_fail(params, ticker_data)
|
76
|
+
Log.error("Heartbeat write failed from '%s': %s" % [stomp_url(params), ticker_data.inspect])
|
77
|
+
rescue Exception => e
|
78
|
+
end
|
79
|
+
|
80
|
+
# Log heart beat fires
|
81
|
+
def on_hbfire(params, srind, curt)
|
82
|
+
case srind
|
83
|
+
when "receive_fire"
|
84
|
+
Log.debug("Received heartbeat from %s: %s, %s" % [stomp_url(params), srind, curt])
|
85
|
+
when "send_fire"
|
86
|
+
Log.debug("Publishing heartbeat to %s: %s, %s" % [stomp_url(params), srind, curt])
|
87
|
+
end
|
88
|
+
rescue Exception => e
|
89
|
+
end
|
90
|
+
|
91
|
+
def stomp_url(params)
|
92
|
+
"%s://%s@%s:%d" % [ params[:cur_ssl] ? "stomp+ssl" : "stomp", params[:cur_login], params[:cur_host], params[:cur_port]]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def initialize
|
97
|
+
@config = Config.instance
|
98
|
+
@subscriptions = []
|
99
|
+
@base64 = false
|
100
|
+
@use_exponential_back_off = get_bool_option("rabbitmq.use_exponential_back_off", "true")
|
101
|
+
@initial_reconnect_delay = Float(get_option("rabbitmq.initial_reconnect_delay", 0.01))
|
102
|
+
@back_off_multiplier = Integer(get_option("rabbitmq.back_off_multiplier", 2))
|
103
|
+
@max_reconnect_delay = Float(get_option("rabbitmq.max_reconnect_delay", 30.0))
|
104
|
+
@reconnect_delay = @initial_reconnect_delay
|
105
|
+
|
106
|
+
Log.info("RabbitMQ connector initialized. Using stomp-gem #{stomp_version}")
|
107
|
+
end
|
108
|
+
|
109
|
+
# Connects to the RabbitMQ middleware
|
110
|
+
def connect(connector = ::Stomp::Connection)
|
111
|
+
if @connection
|
112
|
+
Log.debug("Already connection, not re-initializing connection")
|
113
|
+
return
|
114
|
+
end
|
115
|
+
|
116
|
+
begin
|
117
|
+
@base64 = get_bool_option("rabbitmq.base64", "false")
|
118
|
+
|
119
|
+
pools = Integer(get_option("rabbitmq.pool.size"))
|
120
|
+
hosts = []
|
121
|
+
|
122
|
+
1.upto(pools) do |poolnum|
|
123
|
+
host = {}
|
124
|
+
|
125
|
+
host[:host] = get_option("rabbitmq.pool.#{poolnum}.host")
|
126
|
+
host[:port] = get_option("rabbitmq.pool.#{poolnum}.port", 61613).to_i
|
127
|
+
host[:login] = get_env_or_option("STOMP_USER", "rabbitmq.pool.#{poolnum}.user", '')
|
128
|
+
host[:passcode] = get_env_or_option("STOMP_PASSWORD", "rabbitmq.pool.#{poolnum}.password", '')
|
129
|
+
host[:ssl] = get_bool_option("rabbitmq.pool.#{poolnum}.ssl", "false")
|
130
|
+
|
131
|
+
# if ssl is enabled set :ssl to the hash of parameters
|
132
|
+
if host[:ssl]
|
133
|
+
host[:ssl] = ssl_parameters(poolnum, get_bool_option("rabbitmq.pool.#{poolnum}.ssl.fallback", "false"))
|
134
|
+
end
|
135
|
+
|
136
|
+
Log.debug("Adding #{host[:host]}:#{host[:port]} to the connection pool")
|
137
|
+
hosts << host
|
138
|
+
end
|
139
|
+
|
140
|
+
raise "No hosts found for the RabbitMQ connection pool" if hosts.size == 0
|
141
|
+
|
142
|
+
connection = {:hosts => hosts}
|
143
|
+
|
144
|
+
# Various STOMP gem options, defaults here matches defaults for 1.1.6 the meaning of
|
145
|
+
# these can be guessed, the documentation isn't clear
|
146
|
+
connection[:use_exponential_back_off] = @use_exponential_back_off
|
147
|
+
connection[:initial_reconnect_delay] = @initial_reconnect_delay
|
148
|
+
connection[:back_off_multiplier] = @back_off_multiplier
|
149
|
+
connection[:max_reconnect_delay] = @max_reconnect_delay
|
150
|
+
connection[:max_reconnect_attempts] = Integer(get_option("rabbitmq.max_reconnect_attempts", 0))
|
151
|
+
connection[:randomize] = get_bool_option("rabbitmq.randomize", "false")
|
152
|
+
connection[:backup] = get_bool_option("rabbitmq.backup", "false")
|
153
|
+
|
154
|
+
connection[:timeout] = Integer(get_option("rabbitmq.timeout", -1))
|
155
|
+
connection[:connect_timeout] = Integer(get_option("rabbitmq.connect_timeout", 30))
|
156
|
+
connection[:reliable] = true
|
157
|
+
connection[:max_hbrlck_fails] = Integer(get_option("rabbitmq.max_hbrlck_fails", 0))
|
158
|
+
connection[:max_hbread_fails] = Integer(get_option("rabbitmq.max_hbread_fails", 2))
|
159
|
+
|
160
|
+
connection[:connect_headers] = connection_headers
|
161
|
+
|
162
|
+
connection[:logger] = EventLogger.new
|
163
|
+
|
164
|
+
@connection = connector.new(connection)
|
165
|
+
|
166
|
+
rescue ClientTimeoutError => e
|
167
|
+
raise e
|
168
|
+
rescue Exception => e
|
169
|
+
raise("Could not connect to RabbitMQ Server: #{e}")
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def connection_headers
|
174
|
+
headers = {:"accept-version" => "1.0"}
|
175
|
+
|
176
|
+
heartbeat_interval = Integer(get_option("rabbitmq.heartbeat_interval", 0))
|
177
|
+
stomp_1_0_fallback = get_bool_option("rabbitmq.stomp_1_0_fallback", true)
|
178
|
+
|
179
|
+
headers[:host] = get_option("rabbitmq.vhost", "/")
|
180
|
+
|
181
|
+
if heartbeat_interval > 0
|
182
|
+
unless stomp_version_supports_heartbeat?
|
183
|
+
raise("Setting STOMP 1.1 properties like heartbeat intervals require at least version 1.2.10 of the STOMP gem")
|
184
|
+
end
|
185
|
+
|
186
|
+
if heartbeat_interval < 30
|
187
|
+
Log.warn("Connection heartbeat is set to %d, forcing to minimum value of 30s")
|
188
|
+
heartbeat_interval = 30
|
189
|
+
end
|
190
|
+
|
191
|
+
heartbeat_interval = heartbeat_interval * 1000
|
192
|
+
headers[:"heart-beat"] = "%d,%d" % [heartbeat_interval + 500, heartbeat_interval - 500]
|
193
|
+
|
194
|
+
if stomp_1_0_fallback
|
195
|
+
headers[:"accept-version"] = "1.1,1.0"
|
196
|
+
else
|
197
|
+
headers[:"accept-version"] = "1.1"
|
198
|
+
end
|
199
|
+
else
|
200
|
+
if stomp_version_supports_heartbeat?
|
201
|
+
Log.info("Connecting without STOMP 1.1 heartbeats, consider setting plugin.rabbitmq.heartbeat_interval")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
headers
|
206
|
+
end
|
207
|
+
|
208
|
+
def stomp_version
|
209
|
+
::Stomp::Version::STRING
|
210
|
+
end
|
211
|
+
|
212
|
+
def stomp_version_supports_heartbeat?
|
213
|
+
return Util.versioncmp(stomp_version, "1.2.10") >= 0
|
214
|
+
end
|
215
|
+
|
216
|
+
# Sets the SSL paramaters for a specific connection
|
217
|
+
def ssl_parameters(poolnum, fallback)
|
218
|
+
params = {
|
219
|
+
:cert_file => get_cert_file(poolnum),
|
220
|
+
:key_file => get_key_file(poolnum),
|
221
|
+
:ts_files => get_option("rabbitmq.pool.#{poolnum}.ssl.ca", false),
|
222
|
+
:ciphers => get_option("rabbitmq.pool.#{poolnum}.ssl.ciphers", false),
|
223
|
+
}
|
224
|
+
|
225
|
+
raise "cert, key and ca has to be supplied for verified SSL mode" unless params[:cert_file] && params[:key_file] && params[:ts_files]
|
226
|
+
|
227
|
+
raise "Cannot find certificate file #{params[:cert_file]}" unless File.exist?(params[:cert_file])
|
228
|
+
raise "Cannot find key file #{params[:key_file]}" unless File.exist?(params[:key_file])
|
229
|
+
|
230
|
+
params[:ts_files].split(",").each do |ca|
|
231
|
+
raise "Cannot find CA file #{ca}" unless File.exist?(ca)
|
232
|
+
end
|
233
|
+
|
234
|
+
begin
|
235
|
+
::Stomp::SSLParams.new(params)
|
236
|
+
rescue NameError
|
237
|
+
raise "Stomp gem >= 1.2.2 is needed"
|
238
|
+
end
|
239
|
+
|
240
|
+
rescue Exception => e
|
241
|
+
if fallback
|
242
|
+
Log.warn("Failed to set full SSL verified mode, falling back to unverified: #{e.class}: #{e}")
|
243
|
+
return true
|
244
|
+
else
|
245
|
+
Log.error("Failed to set full SSL verified mode: #{e.class}: #{e}")
|
246
|
+
raise(e)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# Returns the name of the private key file used by RabbitMQ
|
251
|
+
# Will first check if an environment variable MCOLLECTIVE_RABBITMQ_POOLX_SSL_KEY exists,
|
252
|
+
# where X is the RabbitMQ pool number.
|
253
|
+
# If the environment variable doesn't exist, it will try and load the value from the config.
|
254
|
+
def get_key_file(poolnum)
|
255
|
+
ENV["MCOLLECTIVE_RABBITMQ_POOL%s_SSL_KEY" % poolnum] || get_option("rabbitmq.pool.#{poolnum}.ssl.key", false)
|
256
|
+
end
|
257
|
+
|
258
|
+
# Returns the name of the certificate file used by RabbitMQ
|
259
|
+
# Will first check if an environment variable MCOLLECTIVE_RABBITMQ_POOLX_SSL_CERT exists,
|
260
|
+
# where X is the RabbitMQ pool number.
|
261
|
+
# If the environment variable doesn't exist, it will try and load the value from the config.
|
262
|
+
def get_cert_file(poolnum)
|
263
|
+
ENV["MCOLLECTIVE_RABBITMQ_POOL%s_SSL_CERT" % poolnum] || get_option("rabbitmq.pool.#{poolnum}.ssl.cert", false)
|
264
|
+
end
|
265
|
+
|
266
|
+
# Calculate the exponential backoff needed
|
267
|
+
def exponential_back_off
|
268
|
+
if !@use_exponential_back_off
|
269
|
+
return nil
|
270
|
+
end
|
271
|
+
|
272
|
+
backoff = @reconnect_delay
|
273
|
+
|
274
|
+
# calculate next delay
|
275
|
+
@reconnect_delay = @reconnect_delay * @back_off_multiplier
|
276
|
+
|
277
|
+
# cap at max reconnect delay
|
278
|
+
if @reconnect_delay > @max_reconnect_delay
|
279
|
+
@reconnect_delay = @max_reconnect_delay
|
280
|
+
end
|
281
|
+
|
282
|
+
return backoff
|
283
|
+
end
|
284
|
+
|
285
|
+
# Receives a message from the RabbitMQ connection
|
286
|
+
def receive
|
287
|
+
Log.debug("Waiting for a message from RabbitMQ")
|
288
|
+
|
289
|
+
# When the Stomp library > 1.2.0 is mid reconnecting due to its reliable connection
|
290
|
+
# handling it sets the connection to closed. If we happen to be receiving at just
|
291
|
+
# that time we will get an exception warning about the closed connection so handling
|
292
|
+
# that here with a sleep and a retry.
|
293
|
+
begin
|
294
|
+
msg = @connection.receive
|
295
|
+
rescue ::Stomp::Error::NoCurrentConnection
|
296
|
+
sleep 1
|
297
|
+
retry
|
298
|
+
end
|
299
|
+
|
300
|
+
# In older stomp gems an attempt to receive after failed authentication can return nil
|
301
|
+
if msg.nil?
|
302
|
+
raise MessageNotReceived.new(exponential_back_off), "No message received from RabbitMQ."
|
303
|
+
end
|
304
|
+
|
305
|
+
raise "Received a processing error from RabbitMQ: '%s'" % msg.body.chomp if msg.body =~ /Processing error/
|
306
|
+
|
307
|
+
# We expect all messages we get to be of STOMP frame type MESSAGE, raise on unexpected types
|
308
|
+
if msg.command != 'MESSAGE'
|
309
|
+
Log.debug("Unexpected '#{msg.command}' frame. Headers: #{msg.headers.inspect} Body: #{msg.body.inspect}")
|
310
|
+
raise UnexpectedMessageType.new(exponential_back_off),
|
311
|
+
"Received frame of type '#{msg.command}' expected 'MESSAGE'"
|
312
|
+
end
|
313
|
+
|
314
|
+
Message.new(msg.body, msg, :base64 => @base64, :headers => msg.headers)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Sends a message to the RabbitMQ connection
|
318
|
+
def publish(msg)
|
319
|
+
msg.base64_encode! if @base64
|
320
|
+
|
321
|
+
if msg.type == :direct_request
|
322
|
+
msg.discovered_hosts.each do |node|
|
323
|
+
target = target_for(msg, node)
|
324
|
+
|
325
|
+
Log.debug("Sending a direct message to RabbitMQ target '#{target[:name]}' with headers '#{target[:headers].inspect}'")
|
326
|
+
|
327
|
+
@connection.publish(target[:name], msg.payload, target[:headers])
|
328
|
+
end
|
329
|
+
else
|
330
|
+
target = target_for(msg)
|
331
|
+
|
332
|
+
Log.debug("Sending a broadcast message to RabbitMQ target '#{target[:name]}' with headers '#{target[:headers].inspect}'")
|
333
|
+
|
334
|
+
@connection.publish(target[:name], msg.payload, target[:headers])
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def target_for(msg, node=nil)
|
339
|
+
if msg.type == :reply
|
340
|
+
target = {:name => msg.request.headers["reply-to"], :headers => {}, :id => ""}
|
341
|
+
|
342
|
+
elsif [:request, :direct_request].include?(msg.type)
|
343
|
+
target = make_target(msg.agent, msg.type, msg.collective, msg.reply_to, node)
|
344
|
+
|
345
|
+
else
|
346
|
+
raise "Don't now how to create a target for message type #{msg.type}"
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
# marks messages as valid for ttl + 10 seconds, we do this here
|
351
|
+
# rather than in make_target as this should only be set on publish
|
352
|
+
target[:headers]["expiration"] = ((msg.ttl + 10) * 1000).to_s
|
353
|
+
|
354
|
+
target[:headers]["mc_sender"] = Config.instance.identity
|
355
|
+
|
356
|
+
return target
|
357
|
+
end
|
358
|
+
|
359
|
+
def make_target(agent, type, collective, reply_to=nil, node=nil)
|
360
|
+
raise("Unknown target type #{type}") unless [:directed, :broadcast, :reply, :request, :direct_request].include?(type)
|
361
|
+
raise("Unknown collective '#{collective}' known collectives are '#{@config.collectives.join ', '}'") unless @config.collectives.include?(collective)
|
362
|
+
|
363
|
+
target = {:name => "", :headers => {}, :id => nil}
|
364
|
+
|
365
|
+
if reply_to
|
366
|
+
reply_path = reply_to
|
367
|
+
elsif get_bool_option("rabbitmq.use_reply_exchange", false)
|
368
|
+
reply_path = "/exchange/mcollective_reply/%s_%s_%s" % [ @config.identity, $$, Client.request_sequence ]
|
369
|
+
else
|
370
|
+
reply_path = "/temp-queue/mcollective_reply_%s" % agent
|
371
|
+
end
|
372
|
+
case type
|
373
|
+
when :reply # receiving replies on a temp queue
|
374
|
+
target[:name] = reply_path
|
375
|
+
target[:id] = "mcollective_%s_replies" % agent
|
376
|
+
|
377
|
+
when :broadcast, :request # publishing a request to all nodes with an agent
|
378
|
+
target[:name] = "/exchange/%s_broadcast/%s" % [collective, agent]
|
379
|
+
if reply_to
|
380
|
+
target[:headers]["reply-to"] = reply_to
|
381
|
+
else
|
382
|
+
target[:headers]["reply-to"] = reply_path
|
383
|
+
end
|
384
|
+
target[:id] = "%s_broadcast_%s" % [collective, agent]
|
385
|
+
|
386
|
+
when :direct_request # a request to a specific node
|
387
|
+
raise "Directed requests need to have a node identity" unless node
|
388
|
+
|
389
|
+
target[:name] = "/exchange/%s_directed/%s" % [ collective, node]
|
390
|
+
target[:headers]["reply-to"] = reply_path
|
391
|
+
|
392
|
+
when :directed # subscribing to directed messages
|
393
|
+
target[:name] = "/exchange/%s_directed/%s" % [ collective, @config.identity ]
|
394
|
+
target[:id] = "%s_%s_directed_to_identity" % [ collective, @config.identity ]
|
395
|
+
end
|
396
|
+
|
397
|
+
target
|
398
|
+
end
|
399
|
+
|
400
|
+
# Subscribe to a topic or queue
|
401
|
+
def subscribe(agent, type, collective)
|
402
|
+
if type == :reply
|
403
|
+
# On rabbitmq if you send a message with a reply-to: header set to
|
404
|
+
# '/temp-queue/*' it automatically creates a private queue, munges
|
405
|
+
# the reply-to: header to point to this private queue, and
|
406
|
+
# subscribes you to it. As such you should never attempt to
|
407
|
+
# SUBSCRIBE or UNSUBSCRIBE to '/temp-queue/*' directly as that'll
|
408
|
+
# cause great pain and suffering.
|
409
|
+
# https://www.rabbitmq.com/stomp.html#d.tqd
|
410
|
+
|
411
|
+
# The exception to this is in 'use_reply_exchange' mode, when the
|
412
|
+
# reply-to will be set to a queue in an explicit exchange.
|
413
|
+
if !get_bool_option("rabbitmq.use_reply_exchange", false)
|
414
|
+
# We aren't in 'use_reply_exchange' mode, don't subscribe.
|
415
|
+
return
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
source = make_target(agent, type, collective)
|
420
|
+
|
421
|
+
unless @subscriptions.include?(source[:id])
|
422
|
+
Log.debug("Subscribing to #{source[:name]} with headers #{source[:headers].inspect.chomp}")
|
423
|
+
@connection.subscribe(source[:name], source[:headers], source[:id])
|
424
|
+
@subscriptions << source[:id]
|
425
|
+
end
|
426
|
+
rescue ::Stomp::Error::DuplicateSubscription
|
427
|
+
Log.error("Received subscription request for #{source.inspect.chomp} but already had a matching subscription, ignoring")
|
428
|
+
end
|
429
|
+
|
430
|
+
# Subscribe to a topic or queue
|
431
|
+
def unsubscribe(agent, type, collective)
|
432
|
+
if type == :reply
|
433
|
+
# For a more detailed discussion of this logic, please see #subscribe
|
434
|
+
if !get_bool_option("rabbitmq.use_reply_exchange", false)
|
435
|
+
# We shouldn't try to unsubscribe from a '/temp-queue/*' queue.
|
436
|
+
return
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
source = make_target(agent, type, collective)
|
441
|
+
|
442
|
+
Log.debug("Unsubscribing from #{source[:name]}")
|
443
|
+
@connection.unsubscribe(source[:name], source[:headers], source[:id])
|
444
|
+
@subscriptions.delete(source[:id])
|
445
|
+
end
|
446
|
+
|
447
|
+
# Disconnects from the RabbitMQ connection
|
448
|
+
def disconnect
|
449
|
+
Log.debug("Disconnecting from RabbitMQ")
|
450
|
+
@connection.disconnect
|
451
|
+
@connection = nil
|
452
|
+
end
|
453
|
+
|
454
|
+
# looks in the environment first then in the config file
|
455
|
+
# for a specific option, accepts an optional default.
|
456
|
+
#
|
457
|
+
# raises an exception when it cant find a value anywhere
|
458
|
+
def get_env_or_option(env, opt, default=nil)
|
459
|
+
return ENV[env] if ENV.include?(env)
|
460
|
+
return @config.pluginconf[opt] if @config.pluginconf.include?(opt)
|
461
|
+
return default if default
|
462
|
+
|
463
|
+
raise("No #{env} environment or plugin.#{opt} configuration option given")
|
464
|
+
end
|
465
|
+
|
466
|
+
# looks for a config option, accepts an optional default
|
467
|
+
#
|
468
|
+
# raises an exception when it cant find a value anywhere
|
469
|
+
def get_option(opt, default=nil)
|
470
|
+
return @config.pluginconf[opt] if @config.pluginconf.include?(opt)
|
471
|
+
return default unless default.nil?
|
472
|
+
|
473
|
+
raise("No plugin.#{opt} configuration option given")
|
474
|
+
end
|
475
|
+
|
476
|
+
# looks up a boolean value in the config
|
477
|
+
def get_bool_option(val, default)
|
478
|
+
Util.str_to_bool(@config.pluginconf.fetch(val, default))
|
479
|
+
end
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
# vi:tabstop=4:expandtab:ai
|
@@ -0,0 +1,22 @@
|
|
1
|
+
metadata :name => "Agent",
|
2
|
+
:description => "Meta data about installed MColletive Agents",
|
3
|
+
:author => "R.I.Pienaar <rip@devco.net>",
|
4
|
+
:license => "ASL 2.0",
|
5
|
+
:version => "1.0",
|
6
|
+
:url => "http://marionette-collective.org/",
|
7
|
+
:timeout => 1
|
8
|
+
|
9
|
+
dataquery :description => "Agent Meta Data" do
|
10
|
+
input :query,
|
11
|
+
:prompt => "Agent Name",
|
12
|
+
:description => "Valid agent name",
|
13
|
+
:type => :string,
|
14
|
+
:validation => /^[\w\_]+$/,
|
15
|
+
:maxlength => 20
|
16
|
+
|
17
|
+
[:license, :timeout, :description, :url, :version, :author].each do |item|
|
18
|
+
output item,
|
19
|
+
:description => "Agent #{item}",
|
20
|
+
:display_as => item.to_s.capitalize
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Data
|
3
|
+
class Agent_data<Base
|
4
|
+
query do |plugin|
|
5
|
+
raise "No agent called #{plugin} found" unless PluginManager.include?("#{plugin}_agent")
|
6
|
+
|
7
|
+
agent = PluginManager["#{plugin}_agent"]
|
8
|
+
|
9
|
+
result[:agent] = plugin
|
10
|
+
|
11
|
+
[:license, :timeout, :description, :url, :version, :author].each do |item|
|
12
|
+
result[item] = agent.meta[item]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
metadata :name => "Collective",
|
2
|
+
:description => "Collective membership",
|
3
|
+
:author => "Puppet Labs",
|
4
|
+
:license => "ASL 2.0",
|
5
|
+
:version => "1.0",
|
6
|
+
:url => "http://marionette-collective.org/",
|
7
|
+
:timeout => 1
|
8
|
+
|
9
|
+
dataquery :description => "Collective" do
|
10
|
+
input :query,
|
11
|
+
:prompt => 'Collective',
|
12
|
+
:description => 'Collective name to ask about, eg mcollective',
|
13
|
+
:type => :string,
|
14
|
+
:validation => /./,
|
15
|
+
:maxlength => 256
|
16
|
+
|
17
|
+
output :member,
|
18
|
+
:description => 'Node is a member of the named collective',
|
19
|
+
:display_as => 'member'
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
metadata :name => "Fact",
|
2
|
+
:description => "Structured fact query",
|
3
|
+
:author => "Puppet Labs",
|
4
|
+
:license => "ASL 2.0",
|
5
|
+
:version => "1.0",
|
6
|
+
:url => "http://marionette-collective.org/",
|
7
|
+
:timeout => 1
|
8
|
+
|
9
|
+
dataquery :description => "Fact" do
|
10
|
+
input :query,
|
11
|
+
:prompt => 'Fact Path',
|
12
|
+
:description => 'Path to a fact, eg network.eth0.address',
|
13
|
+
:type => :string,
|
14
|
+
:validation => /./,
|
15
|
+
:maxlength => 256
|
16
|
+
|
17
|
+
output :exists,
|
18
|
+
:description => 'Fact is present',
|
19
|
+
:display_as => 'exists'
|
20
|
+
|
21
|
+
output :value,
|
22
|
+
:description => 'Fact value',
|
23
|
+
:display_as => 'value'
|
24
|
+
|
25
|
+
output :value_encoding,
|
26
|
+
:description => 'Encoding of the fact value (text/plain or application/json)',
|
27
|
+
:display_as => 'value_encoding'
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module MCollective
|
2
|
+
module Data
|
3
|
+
class Fact_data<Base
|
4
|
+
query do |path|
|
5
|
+
parts = path.split /\./
|
6
|
+
walk_path(parts)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def walk_path(path)
|
12
|
+
# Set up results as though we didn't find the value
|
13
|
+
result[:exists] = false
|
14
|
+
result[:value] = false
|
15
|
+
result[:value_encoding] = false
|
16
|
+
|
17
|
+
facts = PluginManager['facts_plugin'].get_facts
|
18
|
+
|
19
|
+
path.each do |level|
|
20
|
+
case facts
|
21
|
+
when Array
|
22
|
+
level = Integer(level)
|
23
|
+
if level >= facts.size
|
24
|
+
# array index out would be out of bounds, so we don't have the value
|
25
|
+
return
|
26
|
+
end
|
27
|
+
when Hash
|
28
|
+
if !facts.include?(level)
|
29
|
+
# we don't have the key for the next level, so give up
|
30
|
+
return
|
31
|
+
end
|
32
|
+
else
|
33
|
+
# this isn't a container data type, so we can't walk into it
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
facts = facts[level]
|
38
|
+
end
|
39
|
+
|
40
|
+
result[:exists] = true
|
41
|
+
case facts
|
42
|
+
when Array, Hash
|
43
|
+
# Currently data plugins cannot return structured data, so until
|
44
|
+
# this is fixed flatten the data with json and flag that we have
|
45
|
+
# munged the data
|
46
|
+
result[:value] = facts.to_json
|
47
|
+
result[:value_encoding] = 'application/json'
|
48
|
+
else
|
49
|
+
result[:value] = facts
|
50
|
+
result[:value_encoding] = 'text/plain'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|