choria-mcorpc-support 2.21.1 → 2.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mcollective.rb +1 -2
  3. data/lib/mcollective/agent/bolt_tasks.ddl +253 -0
  4. data/lib/mcollective/agent/bolt_tasks.json +365 -0
  5. data/lib/mcollective/agent/bolt_tasks.rb +178 -0
  6. data/lib/mcollective/agent/choria_util.ddl +152 -0
  7. data/lib/mcollective/agent/choria_util.json +244 -0
  8. data/lib/mcollective/agent/rpcutil.ddl +8 -4
  9. data/lib/mcollective/agent/rpcutil.json +333 -0
  10. data/lib/mcollective/agent/scout.ddl +169 -0
  11. data/lib/mcollective/agent/scout.json +224 -0
  12. data/lib/mcollective/agents.rb +7 -6
  13. data/lib/mcollective/aggregate.rb +4 -4
  14. data/lib/mcollective/aggregate/average.rb +2 -2
  15. data/lib/mcollective/aggregate/base.rb +2 -2
  16. data/lib/mcollective/aggregate/result.rb +3 -3
  17. data/lib/mcollective/aggregate/result/collection_result.rb +2 -2
  18. data/lib/mcollective/aggregate/result/numeric_result.rb +2 -2
  19. data/lib/mcollective/aggregate/sum.rb +2 -2
  20. data/lib/mcollective/aggregate/summary.rb +3 -4
  21. data/lib/mcollective/application.rb +57 -21
  22. data/lib/mcollective/application/choria.rb +189 -0
  23. data/lib/mcollective/application/completion.rb +6 -6
  24. data/lib/mcollective/application/facts.rb +11 -11
  25. data/lib/mcollective/application/federation.rb +237 -0
  26. data/lib/mcollective/application/find.rb +4 -4
  27. data/lib/mcollective/application/help.rb +3 -3
  28. data/lib/mcollective/application/inventory.rb +3 -341
  29. data/lib/mcollective/application/ping.rb +5 -51
  30. data/lib/mcollective/application/playbook.rb +207 -0
  31. data/lib/mcollective/application/plugin.rb +106 -106
  32. data/lib/mcollective/application/rpc.rb +3 -108
  33. data/lib/mcollective/application/tasks.rb +425 -0
  34. data/lib/mcollective/applications.rb +11 -10
  35. data/lib/mcollective/audit/choria.rb +33 -0
  36. data/lib/mcollective/cache.rb +2 -4
  37. data/lib/mcollective/client.rb +11 -10
  38. data/lib/mcollective/config.rb +21 -34
  39. data/lib/mcollective/connector/base.rb +2 -1
  40. data/lib/mcollective/connector/nats.ddl +9 -0
  41. data/lib/mcollective/connector/nats.rb +450 -0
  42. data/lib/mcollective/data.rb +8 -3
  43. data/lib/mcollective/data/agent_data.rb +1 -1
  44. data/lib/mcollective/data/base.rb +6 -5
  45. data/lib/mcollective/data/bolt_task_data.ddl +90 -0
  46. data/lib/mcollective/data/bolt_task_data.rb +32 -0
  47. data/lib/mcollective/data/collective_data.rb +1 -1
  48. data/lib/mcollective/data/fact_data.rb +6 -6
  49. data/lib/mcollective/data/fstat_data.rb +2 -4
  50. data/lib/mcollective/data/result.rb +7 -2
  51. data/lib/mcollective/ddl/agentddl.rb +5 -17
  52. data/lib/mcollective/ddl/base.rb +10 -13
  53. data/lib/mcollective/discovery.rb +24 -39
  54. data/lib/mcollective/discovery/choria.ddl +11 -0
  55. data/lib/mcollective/discovery/choria.rb +223 -0
  56. data/lib/mcollective/discovery/flatfile.rb +7 -8
  57. data/lib/mcollective/discovery/mc.rb +2 -2
  58. data/lib/mcollective/discovery/stdin.rb +17 -18
  59. data/lib/mcollective/exceptions.rb +13 -0
  60. data/lib/mcollective/facts/base.rb +9 -9
  61. data/lib/mcollective/facts/yaml_facts.rb +12 -12
  62. data/lib/mcollective/generators.rb +3 -3
  63. data/lib/mcollective/generators/agent_generator.rb +3 -4
  64. data/lib/mcollective/generators/base.rb +14 -15
  65. data/lib/mcollective/generators/data_generator.rb +5 -6
  66. data/lib/mcollective/log.rb +2 -2
  67. data/lib/mcollective/logger/base.rb +3 -2
  68. data/lib/mcollective/logger/console_logger.rb +10 -10
  69. data/lib/mcollective/logger/file_logger.rb +7 -7
  70. data/lib/mcollective/logger/syslog_logger.rb +11 -15
  71. data/lib/mcollective/message.rb +8 -39
  72. data/lib/mcollective/monkey_patches.rb +2 -4
  73. data/lib/mcollective/optionparser.rb +2 -1
  74. data/lib/mcollective/pluginmanager.rb +3 -5
  75. data/lib/mcollective/pluginpackager.rb +1 -3
  76. data/lib/mcollective/pluginpackager/agent_definition.rb +3 -8
  77. data/lib/mcollective/pluginpackager/forge_packager.rb +7 -9
  78. data/lib/mcollective/pluginpackager/standard_definition.rb +1 -2
  79. data/lib/mcollective/registration/base.rb +18 -16
  80. data/lib/mcollective/rpc.rb +2 -4
  81. data/lib/mcollective/rpc/actionrunner.rb +16 -18
  82. data/lib/mcollective/rpc/agent.rb +26 -43
  83. data/lib/mcollective/rpc/audit.rb +1 -0
  84. data/lib/mcollective/rpc/client.rb +67 -85
  85. data/lib/mcollective/rpc/helpers.rb +55 -62
  86. data/lib/mcollective/rpc/progress.rb +2 -2
  87. data/lib/mcollective/rpc/reply.rb +17 -19
  88. data/lib/mcollective/rpc/request.rb +7 -5
  89. data/lib/mcollective/rpc/result.rb +6 -8
  90. data/lib/mcollective/rpc/stats.rb +49 -58
  91. data/lib/mcollective/security/base.rb +13 -56
  92. data/lib/mcollective/security/choria.rb +765 -0
  93. data/lib/mcollective/shell.rb +9 -4
  94. data/lib/mcollective/signer/base.rb +28 -0
  95. data/lib/mcollective/signer/choria.rb +185 -0
  96. data/lib/mcollective/ssl.rb +8 -6
  97. data/lib/mcollective/util.rb +58 -55
  98. data/lib/mcollective/util/bolt_support.rb +176 -0
  99. data/lib/mcollective/util/bolt_support/plan_runner.rb +167 -0
  100. data/lib/mcollective/util/bolt_support/task_result.rb +94 -0
  101. data/lib/mcollective/util/bolt_support/task_results.rb +128 -0
  102. data/lib/mcollective/util/choria.rb +946 -0
  103. data/lib/mcollective/util/indifferent_hash.rb +12 -0
  104. data/lib/mcollective/util/natswrapper.rb +242 -0
  105. data/lib/mcollective/util/playbook.rb +435 -0
  106. data/lib/mcollective/util/playbook/data_stores.rb +201 -0
  107. data/lib/mcollective/util/playbook/data_stores/base.rb +99 -0
  108. data/lib/mcollective/util/playbook/data_stores/consul_data_store.rb +88 -0
  109. data/lib/mcollective/util/playbook/data_stores/environment_data_store.rb +33 -0
  110. data/lib/mcollective/util/playbook/data_stores/etcd_data_store.rb +42 -0
  111. data/lib/mcollective/util/playbook/data_stores/file_data_store.rb +106 -0
  112. data/lib/mcollective/util/playbook/data_stores/shell_data_store.rb +103 -0
  113. data/lib/mcollective/util/playbook/inputs.rb +265 -0
  114. data/lib/mcollective/util/playbook/nodes.rb +207 -0
  115. data/lib/mcollective/util/playbook/nodes/mcollective_nodes.rb +86 -0
  116. data/lib/mcollective/util/playbook/nodes/pql_nodes.rb +40 -0
  117. data/lib/mcollective/util/playbook/nodes/shell_nodes.rb +55 -0
  118. data/lib/mcollective/util/playbook/nodes/terraform_nodes.rb +65 -0
  119. data/lib/mcollective/util/playbook/nodes/yaml_nodes.rb +47 -0
  120. data/lib/mcollective/util/playbook/playbook_logger.rb +47 -0
  121. data/lib/mcollective/util/playbook/puppet_logger.rb +51 -0
  122. data/lib/mcollective/util/playbook/report.rb +152 -0
  123. data/lib/mcollective/util/playbook/task_result.rb +55 -0
  124. data/lib/mcollective/util/playbook/tasks.rb +196 -0
  125. data/lib/mcollective/util/playbook/tasks/base.rb +45 -0
  126. data/lib/mcollective/util/playbook/tasks/graphite_event_task.rb +64 -0
  127. data/lib/mcollective/util/playbook/tasks/mcollective_task.rb +356 -0
  128. data/lib/mcollective/util/playbook/tasks/shell_task.rb +93 -0
  129. data/lib/mcollective/util/playbook/tasks/slack_task.rb +105 -0
  130. data/lib/mcollective/util/playbook/tasks/webhook_task.rb +136 -0
  131. data/lib/mcollective/util/playbook/template_util.rb +98 -0
  132. data/lib/mcollective/util/playbook/uses.rb +169 -0
  133. data/lib/mcollective/util/tasks_support.rb +751 -0
  134. data/lib/mcollective/util/tasks_support/cli.rb +260 -0
  135. data/lib/mcollective/util/tasks_support/default_formatter.rb +138 -0
  136. data/lib/mcollective/util/tasks_support/json_formatter.rb +108 -0
  137. data/lib/mcollective/validator.rb +6 -1
  138. data/lib/mcollective/validator/bolt_task_name_validator.ddl +7 -0
  139. data/lib/mcollective/validator/bolt_task_name_validator.rb +11 -0
  140. data/lib/mcollective/validator/length_validator.rb +1 -3
  141. metadata +65 -6
  142. data/lib/mcollective/application/describe_filter.rb +0 -87
  143. data/lib/mcollective/matcher.rb +0 -220
  144. data/lib/mcollective/matcher/parser.rb +0 -128
  145. data/lib/mcollective/matcher/scanner.rb +0 -241
@@ -38,18 +38,22 @@ module MCollective
38
38
  case opt.to_s
39
39
  when "stdout"
40
40
  raise "stdout should support <<" unless val.respond_to?("<<")
41
+
41
42
  @stdout = val
42
43
 
43
44
  when "stderr"
44
45
  raise "stderr should support <<" unless val.respond_to?("<<")
46
+
45
47
  @stderr = val
46
48
 
47
49
  when "stdin"
48
50
  raise "stdin should be a String" unless val.is_a?(String)
51
+
49
52
  @stdin = val
50
53
 
51
54
  when "cwd"
52
55
  raise "Directory #{val} does not exist" unless File.directory?(val)
56
+
53
57
  @cwd = val
54
58
 
55
59
  when "environment"
@@ -62,6 +66,7 @@ module MCollective
62
66
 
63
67
  when "timeout"
64
68
  raise "timeout should be a positive integer or the symbol :on_thread_exit symbol" unless val.eql?(:on_thread_exit) || (val.is_a?(Integer) && val > 0)
69
+
65
70
  @timeout = val
66
71
  end
67
72
  end
@@ -69,10 +74,10 @@ module MCollective
69
74
 
70
75
  # Actually does the systemu call passing in the correct environment, stdout and stderr
71
76
  def runcommand
72
- opts = {"env" => @environment,
77
+ opts = {"env" => @environment,
73
78
  "stdout" => @stdout,
74
79
  "stderr" => @stderr,
75
- "cwd" => @cwd}
80
+ "cwd" => @cwd}
76
81
 
77
82
  opts["stdin"] = @stdin if @stdin
78
83
 
@@ -108,8 +113,8 @@ module MCollective
108
113
  # only wait if the parent thread is dead
109
114
  Process.waitpid(cid) unless thread.alive?
110
115
  end
111
- rescue SystemExit # rubocop:disable Lint/HandleExceptions
112
- rescue Errno::ESRCH # rubocop:disable Lint/HandleExceptions
116
+ rescue SystemExit # rubocop:disable Lint/SuppressedException
117
+ rescue Errno::ESRCH # rubocop:disable Lint/SuppressedException
113
118
  rescue Errno::ECHILD
114
119
  Log.warn("Could not reap process '#{cid}'.")
115
120
  rescue Exception => e # rubocop:disable Lint/RescueException
@@ -0,0 +1,28 @@
1
+ module MCollective
2
+ module Signer
3
+ class Base
4
+ # Register plugins that inherits base
5
+ def self.inherited(klass)
6
+ PluginManager << {:type => "choria_signer_plugin", :class => klass.to_s}
7
+ super
8
+ end
9
+
10
+ def initialize
11
+ @config = Config.instance
12
+ @log = Log
13
+ end
14
+
15
+ # Signs a secure request
16
+ #
17
+ # Generally for local mode this would just use the users own certificate but if you have a
18
+ # remote signer this might use a token to speak to a remote API, by default Choria supports
19
+ # a standard web service for remote signatures
20
+ #
21
+ # @param secure_request [Hash] a choria:secure:request:1 hash
22
+ # @raise [StandardError] when signing fails
23
+ def sign_secure_request!(secure_request)
24
+ raise(NoMethodError, "undefined method `sign_secure_request!' for %s" % inspect)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,185 @@
1
+ require_relative "base"
2
+
3
+ module MCollective
4
+ module Signer
5
+ # This is a Secure Request Signer that allows either local signing of requests using the users
6
+ # own certificate or delegation based signing via a webservice
7
+ #
8
+ # This allows one to integrate the Choria CLI into a centralised authentication, authorization and
9
+ # auditing system
10
+ #
11
+ # Available settings:
12
+ #
13
+ # choria.security.request_signer.plugin - the plugin to use, `choria` for this one - the default.
14
+ # choria.security.request_signer.token_file - a file holding a token like a JWT or similar
15
+ # choria.security.request_signer.token_environment - a ENV key holding a token like a JWT or similar
16
+ # choria.security.request_signer.url - a endpoint that implements the v1 signer protocol
17
+ #
18
+ # The webservice has to support the specification found at https://choria.io/schemas/choria/signer/v1/service.json
19
+ class Choria < Base
20
+ # Retrieves the token from either a local file or the users environment
21
+ #
22
+ # @return [String, nil]
23
+ def token
24
+ file = @config.pluginconf["choria.security.request_signer.token_file"]
25
+ env = @config.pluginconf["choria.security.request_signer.token_environment"]
26
+
27
+ if file
28
+ file = File.expand_path(file)
29
+
30
+ raise("No token found in %s, please authenticate using your configured authentication service" % file) unless File.exist?(file)
31
+
32
+ return File.read(file).chomp
33
+ end
34
+
35
+ raise("could not find token in environment variable %s" % env) unless ENV[env]
36
+
37
+ ENV[env].chomp
38
+ end
39
+
40
+ # Signs the secure request
41
+ #
42
+ # Signing supports either local mode using local certificates or delegating to a remote
43
+ # signer that is written in conformance with the signer specification version 1
44
+ #
45
+ # @param secure_request [Hash] a v1 secure request
46
+ def sign_secure_request!(secure_request)
47
+ return if $choria_unsafe_disable_protocol_security # rubocop:disable Style/GlobalVars
48
+
49
+ if remote_signer?
50
+ remote_sign!(secure_request)
51
+ else
52
+ local_sign!(secure_request)
53
+ end
54
+ end
55
+
56
+ # Determines the callerid for this client
57
+ #
58
+ # When a remote signer is enabled the caller is extracted from the JWT
59
+ # otherwise a choria=user style ID is generated
60
+ #
61
+ # @return [String]
62
+ # @raise [Exception] when the JWT is invalid
63
+ def callerid
64
+ if remote_signer?
65
+ parts = token.split(".")
66
+
67
+ raise("Invalid JWT token") unless parts.length == 3
68
+
69
+ claims = JSON.parse(Base64.decode64(parts[1]))
70
+
71
+ raise("Invalid JWT token") unless claims.include?("callerid")
72
+ raise("Invalid JWT token") unless claims["callerid"].is_a?(String)
73
+ raise("Invalid JWT token") if claims["callerid"].empty?
74
+
75
+ claims["callerid"]
76
+ else
77
+ "choria=%s" % choria.certname
78
+ end
79
+ end
80
+
81
+ # The body that would be submitted to the remote service
82
+ #
83
+ # @param secure_request [Hash] a v1 secure request
84
+ # @return [Hash]
85
+ def sign_request_body(secure_request)
86
+ {
87
+ "token" => token,
88
+ "request" => Base64.encode64(secure_request["message"])
89
+ }
90
+ end
91
+
92
+ # Performs a remote sign operation against a configured web service
93
+ #
94
+ # @param secure_request [Hash] a v1 secure request
95
+ # @raise [StandardError] on signing error
96
+ def remote_sign!(secure_request)
97
+ Log.info("Signing secure request using remote signer %s" % remote_signer_url)
98
+
99
+ uri = remote_signer_url
100
+ post = choria.http_post(uri.request_uri)
101
+ post.body = sign_request_body(secure_request).to_json
102
+ post["Content-type"] = "application/json"
103
+
104
+ http = choria.https(:target => uri.host, :port => uri.port)
105
+ http.use_ssl = false if uri.scheme == "http"
106
+
107
+ # While this might appear alarming it's expected that the clients
108
+ # in this situation will not have any Choria CA issued certificates
109
+ # and so wish to use a remote signer - the certificate management woes
110
+ # being one of the main reasons for centralised AAA.
111
+ #
112
+ # So there is no realistic way to verify these requests especially in the
113
+ # event that these signers run on private IPs and such as would be typical
114
+ # so while we do this big No No of disabling verify here it really is the
115
+ # only thing that make sense.
116
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl?
117
+
118
+ resp = http.request(post)
119
+
120
+ signature = {}
121
+
122
+ if resp.code == "200"
123
+ signature = JSON.parse(resp.body)
124
+ else
125
+ raise("Could not get remote signature: %s: %s" % [resp.code, resp.body])
126
+ end
127
+
128
+ raise("Could not get remote signature: %s" % signature["error"]) if signature["error"]
129
+
130
+ signed_request = JSON.parse(Base64.decode64(signature["secure_request"]))
131
+ signed_request.each do |k, v|
132
+ secure_request[k] = v
133
+ end
134
+ end
135
+
136
+ # Signs using local certificates
137
+ #
138
+ # @param secure_request [Hash] a v1 secure request
139
+ # @raise [StandardError] on signing error
140
+ def local_sign!(secure_request)
141
+ Log.info("Signing secure request using local credentials")
142
+
143
+ secure_request["signature"] = sign(secure_request["message"])
144
+ secure_request["pubcert"] = File.read(client_public_cert).chomp
145
+
146
+ nil
147
+ end
148
+
149
+ # (see Security::Choria#sign)
150
+ def sign(string, id=nil)
151
+ security.sign(string, id)
152
+ end
153
+
154
+ # (see Security::Choria#client_public_cert)
155
+ def client_public_cert
156
+ security.client_public_cert
157
+ end
158
+
159
+ # Determines if a remote signer is configured
160
+ #
161
+ # @return [Boolean]
162
+ def remote_signer?
163
+ !!(remote_signer_url == "" || remote_signer_url)
164
+ end
165
+
166
+ # Determines the remote url to submit standard signing requests to
167
+ #
168
+ # @return [URI, Nil]
169
+ def remote_signer_url
170
+ return nil unless @config.pluginconf["choria.security.request_signer.url"]
171
+ return nil if @config.pluginconf["choria.security.request_signer.url"] == ""
172
+
173
+ URI.parse(@config.pluginconf["choria.security.request_signer.url"])
174
+ end
175
+
176
+ def security
177
+ @security ||= PluginManager["security_plugin"]
178
+ end
179
+
180
+ def choria
181
+ @choria ||= security.choria
182
+ end
183
+ end
184
+ end
185
+ end
@@ -166,7 +166,7 @@ module MCollective
166
166
 
167
167
  # Signs a string using the private key
168
168
  def sign(string, base64=false)
169
- sig = @private_key.sign(OpenSSL::Digest::SHA1.new, string)
169
+ sig = @private_key.sign(OpenSSL::Digest.new("SHA1"), string)
170
170
 
171
171
  base64 ? base64_encode(sig) : sig
172
172
  end
@@ -175,7 +175,7 @@ module MCollective
175
175
  def verify_signature(signature, string, base64=false)
176
176
  signature = base64_decode(signature) if base64
177
177
 
178
- @public_key.verify(OpenSSL::Digest::SHA1.new, signature, string)
178
+ @public_key.verify(OpenSSL::Digest.new("SHA1"), signature, string)
179
179
  end
180
180
 
181
181
  # base 64 encode a string
@@ -196,6 +196,7 @@ module MCollective
196
196
  # The Base 64 character set is A-Z a-z 0-9 + / =
197
197
  # Also allow for whitespace, but raise if we get anything else
198
198
  raise(ArgumentError, "invalid base64") if string !~ /^[A-Za-z0-9+\/=\s]+$/
199
+
199
200
  Base64.decode64(string)
200
201
  end
201
202
 
@@ -248,7 +249,8 @@ module MCollective
248
249
  raise "Could not find key #{key}" unless File.exist?(key)
249
250
  raise "#{type} key file '#{key}' is empty" if File.zero?(key)
250
251
 
251
- if type == :public
252
+ case type
253
+ when :public
252
254
  begin
253
255
  key = OpenSSL::PKey::RSA.new(File.read(key))
254
256
  rescue OpenSSL::PKey::RSAError
@@ -271,9 +273,9 @@ module MCollective
271
273
  # See http://bugs.ruby-lang.org/issues/4550
272
274
  OpenSSL.errors if Util.ruby_version =~ /^1.8/
273
275
 
274
- return key
275
- elsif type == :private
276
- return OpenSSL::PKey::RSA.new(File.read(key), passphrase)
276
+ key
277
+ when :private
278
+ OpenSSL::PKey::RSA.new(File.read(key), passphrase)
277
279
  else
278
280
  raise "Can only load :public or :private keys"
279
281
  end
@@ -10,12 +10,12 @@ module MCollective
10
10
 
11
11
  if agent.is_a?(Regexp)
12
12
  if !Agents.agentlist.grep(agent).empty?
13
- return true
13
+ true
14
14
  else
15
- return false
15
+ false
16
16
  end
17
17
  else
18
- return Agents.agentlist.include?(agent)
18
+ Agents.agentlist.include?(agent)
19
19
  end
20
20
  end
21
21
 
@@ -41,9 +41,10 @@ module MCollective
41
41
 
42
42
  begin
43
43
  File.readlines(cfile).each do |k|
44
- if klass.is_a?(Regexp)
44
+ case klass
45
+ when Regexp
45
46
  return true if k.chomp.match(klass)
46
- elsif k.chomp == klass
47
+ when k.chomp
47
48
  return true
48
49
  end
49
50
  end
@@ -74,11 +75,11 @@ module MCollective
74
75
  fact = fact.clone
75
76
  case fact
76
77
  when Array
77
- return fact.any? { |element| test_fact_value(element, value, operator)}
78
+ fact.any? { |element| test_fact_value(element, value, operator)}
78
79
  when Hash
79
- return fact.keys.any? { |element| test_fact_value(element, value, operator)}
80
+ fact.keys.any? { |element| test_fact_value(element, value, operator)}
80
81
  else
81
- return test_fact_value(fact, value, operator)
82
+ test_fact_value(fact, value, operator)
82
83
  end
83
84
  end
84
85
 
@@ -104,7 +105,7 @@ module MCollective
104
105
  value = Float(value) # rubocop:disable Lint/UselessAssignment
105
106
  end
106
107
 
107
- return true if eval("fact #{operator} value") # rubocop:disable Security/Eval
108
+ return true if eval("fact #{operator} value") # rubocop:disable Security/Eval, Style/EvalWithLocation
108
109
  end
109
110
 
110
111
  false
@@ -118,9 +119,10 @@ module MCollective
118
119
  def self.has_identity?(identity)
119
120
  identity = Regexp.new(identity.gsub("\/", "")) if identity.start_with?("/")
120
121
 
121
- if identity.is_a?(Regexp)
122
+ case identity
123
+ when Regexp
122
124
  return Config.instance.identity.match(identity)
123
- elsif Config.instance.identity == identity
125
+ when Config.instance.identity
124
126
  return true
125
127
  end
126
128
 
@@ -135,9 +137,9 @@ module MCollective
135
137
  # Creates an empty filter
136
138
  def self.empty_filter
137
139
  {
138
- "fact" => [],
140
+ "fact" => [],
139
141
  "cf_class" => [],
140
- "agent" => [],
142
+ "agent" => [],
141
143
  "identity" => [],
142
144
  "compound" => []
143
145
  }
@@ -146,7 +148,7 @@ module MCollective
146
148
  # Returns the PuppetLabs mcollective path for windows
147
149
  def self.windows_prefix
148
150
  require "win32/dir"
149
- File.join(Dir::COMMON_APPDATA, "PuppetLabs", "mcollective")
151
+ File.join(Dir::COMMON_APPDATA, "PuppetLabs", "choria")
150
152
  end
151
153
 
152
154
  def self.choria_windows_prefix
@@ -161,7 +163,7 @@ module MCollective
161
163
  # File.expand_path will raise if HOME isn't set, catch it
162
164
  user_path = File.expand_path("~/.mcollective")
163
165
  config_paths << user_path
164
- rescue Exception # rubocop:disable Lint/RescueException, Lint/HandleExceptions
166
+ rescue Exception # rubocop:disable Lint/RescueException, Lint/SuppressedException
165
167
  end
166
168
 
167
169
  if windows?
@@ -169,6 +171,7 @@ module MCollective
169
171
  else
170
172
  config_paths << "/etc/puppetlabs/mcollective/client.cfg"
171
173
  config_paths << "/etc/mcollective/client.cfg"
174
+ config_paths << "/usr/local/etc/mcollective/client.cfg"
172
175
  end
173
176
 
174
177
  config_paths
@@ -181,29 +184,32 @@ module MCollective
181
184
  # File.expand_path will raise if HOME isn't set, catch it
182
185
  user_path = File.expand_path("~/.choriarc")
183
186
  config_paths << user_path
184
- rescue Exception # rubocop:disable Lint/RescueException, Lint/HandleExceptions
187
+ rescue Exception # rubocop:disable Lint/RescueException, Lint/SuppressedException
185
188
  end
186
189
 
187
190
  if windows?
188
191
  config_paths << File.join(choria_windows_prefix, "etc", "client.conf")
189
192
  else
190
193
  config_paths << "/etc/choria/client.conf"
194
+ config_paths << "/usr/local/etc/choria/client.conf"
191
195
  end
192
196
 
193
197
  config_paths
194
198
  end
195
199
 
196
- # Picks the default user config file, pririties are first Choria ones then old MCollective ones
200
+ # Picks the default user config file, priorities are first Choria ones then old MCollective ones
197
201
  #
198
202
  # In roughly this order, first to exist is used:
199
203
  #
200
204
  # - ~/.choriarc
201
205
  # - APPData/ChoriaIO/choria/etc/client.conf on windows
202
- # - /etc/choria/client.conf on unix
206
+ # - /etc/choria/client.conf then
207
+ # - /usr/local/etc/choria/client.conf on unix
203
208
  # - ~/.mcollective
204
209
  # - APPData/PuppetLabs/mcollective/etc/client.cfg on windows
205
210
  # - /etc/puppetlabs/mcollective/client.cfg
206
211
  # - /etc/mcollective/client.cfg
212
+ # - /usr/local/etc/mcollective/client.cfg
207
213
  def self.config_file_for_user
208
214
  config_paths = choria_config_paths_for_user + mcollective_config_paths_for_user
209
215
  found = config_paths.find_index { |file| File.readable?(file) } || 0
@@ -213,14 +219,14 @@ module MCollective
213
219
  # Creates a standard options hash
214
220
  def self.default_options
215
221
  {
216
- :verbose => false,
217
- :disctimeout => nil,
218
- :timeout => 5,
219
- :config => config_file_for_user,
220
- :collective => nil,
221
- :discovery_method => nil,
222
+ :verbose => false,
223
+ :disctimeout => nil,
224
+ :timeout => 5,
225
+ :config => config_file_for_user,
226
+ :collective => nil,
227
+ :discovery_method => nil,
222
228
  :discovery_options => Config.instance.default_discovery_options,
223
- :filter => empty_filter
229
+ :filter => empty_filter
224
230
  }
225
231
  end
226
232
 
@@ -269,15 +275,16 @@ module MCollective
269
275
 
270
276
  # Parse a fact filter string like foo=bar into the tuple hash thats needed
271
277
  def self.parse_fact_string(fact)
272
- if fact =~ /^([^ ]+?)[ ]*=>[ ]*(.+)/
278
+ case fact
279
+ when /^([^ ]+?) *=> *(.+)/
273
280
  {:fact => $1, :value => $2, :operator => ">="}
274
- elsif fact =~ /^([^ ]+?)[ ]*=<[ ]*(.+)/
281
+ when /^([^ ]+?) *=< *(.+)/
275
282
  {:fact => $1, :value => $2, :operator => "<="}
276
- elsif fact =~ /^([^ ]+?)[ ]*(<=|>=|<|>|!=|==|=~)[ ]*(.+)/
283
+ when /^([^ ]+?) *(<=|>=|<|>|!=|==|=~) *(.+)/
277
284
  {:fact => $1, :value => $3, :operator => $2}
278
- elsif fact =~ /^(.+?)[ ]*=[ ]*\/(.+)\/$/
285
+ when /^(.+?) *= *\/(.+)\/$/
279
286
  {:fact => $1, :value => "/#{$2}/", :operator => "=~"}
280
- elsif fact =~ /^([^= ]+?)[ ]*=[ ]*(.+)/
287
+ when /^([^= ]+?) *= *(.+)/
281
288
  {:fact => $1, :value => $2, :operator => "=="}
282
289
  else
283
290
  raise "Could not parse fact #{fact} it does not appear to be in a valid format"
@@ -322,9 +329,9 @@ module MCollective
322
329
  }
323
330
 
324
331
  if colorize
325
- return colors[code] || ""
332
+ colors[code] || ""
326
333
  else
327
- return ""
334
+ ""
328
335
  end
329
336
  end
330
337
 
@@ -375,9 +382,7 @@ module MCollective
375
382
  text.each_with_index do |line, i|
376
383
  whitespace = 0
377
384
 
378
- while whitespace < line.length && line[whitespace].chr == " "
379
- whitespace += 1
380
- end
385
+ whitespace += 1 while whitespace < line.length && line[whitespace].chr == " "
381
386
 
382
387
  # If the current line is empty, indent it so that a snippet
383
388
  # from the previous line is aligned correctly.
@@ -431,21 +436,21 @@ module MCollective
431
436
  #
432
437
  # Returns [0, 0] if it can't figure it out or if you're
433
438
  # not running on a tty
434
- def self.terminal_dimensions(stdout=STDOUT, environment=ENV)
439
+ def self.terminal_dimensions(stdout=$stdout, environment=ENV)
435
440
  return [0, 0] unless stdout.tty?
436
441
 
437
442
  return [80, 40] if Util.windows?
438
443
 
439
444
  if environment["COLUMNS"] && environment["LINES"]
440
- return [environment["COLUMNS"].to_i, environment["LINES"].to_i]
445
+ [environment["COLUMNS"].to_i, environment["LINES"].to_i]
441
446
 
442
447
  elsif environment["TERM"] && command_in_path?("tput")
443
- return [`tput cols`.to_i, `tput lines`.to_i]
448
+ [`tput cols`.to_i, `tput lines`.to_i]
444
449
 
445
450
  elsif command_in_path?("stty")
446
- return `stty size`.scan(/\d+/).map(&:to_i)
451
+ `stty size`.scan(/\d+/).map(&:to_i)
447
452
  else
448
- return [0, 0]
453
+ [0, 0]
449
454
  end
450
455
  rescue
451
456
  [0, 0]
@@ -486,6 +491,7 @@ module MCollective
486
491
  elsif b == "." then return 1
487
492
  elsif a =~ /^\d+$/ && b =~ /^\d+$/
488
493
  return a.to_s.upcase <=> b.to_s.upcase if a =~ /^0/ || b =~ /^0/
494
+
489
495
  return a.to_i <=> b.to_i
490
496
  else
491
497
  return a.upcase <=> b.upcase
@@ -512,10 +518,11 @@ module MCollective
512
518
  # Any other value will return FalseClass
513
519
  def self.str_to_bool(val)
514
520
  clean_val = val.to_s.strip
515
- if clean_val =~ /^(1|yes|true|y|t)$/i
516
- return true
517
- elsif clean_val =~ /^(0|no|false|n|f)$/i
518
- return false
521
+ case clean_val
522
+ when /^(1|yes|true|y|t)$/i
523
+ true
524
+ when /^(0|no|false|n|f)$/i
525
+ false
519
526
  else
520
527
  raise("Cannot convert string value '#{clean_val}' into a boolean.")
521
528
  end
@@ -527,8 +534,7 @@ module MCollective
527
534
  template_path = File.join(config_dir, template_file)
528
535
  return template_path if File.exist?(template_path)
529
536
 
530
- template_path = File.join("/etc/mcollective", template_file)
531
- template_path
537
+ File.join("/etc/mcollective", template_file)
532
538
  end
533
539
 
534
540
  # subscribe to the direct addressing queue
@@ -559,6 +565,7 @@ module MCollective
559
565
 
560
566
  while char = Win32API.new("crtdll", "_getch", [], "I").Call
561
567
  break if [10, 13].include?(char) # return or newline
568
+
562
569
  if [127, 8].include?(char) # backspace and delete
563
570
  input.slice!(-1, 1) unless input.empty?
564
571
  else
@@ -570,17 +577,13 @@ module MCollective
570
577
  end
571
578
 
572
579
  def self.get_hidden_input_on_unix # rubocop:disable Naming/AccessorMethodName
573
- unless $stdin.tty?
574
- raise "Could not hook to stdin to hide input. If using SSH, try using -t flag while connecting to server."
575
- end
576
- unless system "stty -echo -icanon"
577
- raise "Could not hide input using stty command."
578
- end
580
+ raise "Could not hook to stdin to hide input. If using SSH, try using -t flag while connecting to server." unless $stdin.tty?
581
+ raise "Could not hide input using stty command." unless system "stty -echo -icanon"
582
+
579
583
  input = $stdin.gets
580
584
  ensure
581
- unless system "stty echo icanon"
582
- raise "Could not enable echoing of input. Try executing `stty echo icanon` to debug."
583
- end
585
+ raise "Could not enable echoing of input. Try executing `stty echo icanon` to debug." unless system "stty echo icanon"
586
+
584
587
  input
585
588
  end
586
589