choria-mcorpc-support 2.22.1 → 2.23.3

Sign up to get free protection for your applications and to get access to all the features.
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 +3 -68
  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 -26
  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 +73 -82
  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 +752 -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
@@ -154,19 +156,23 @@ module MCollective
154
156
  File.join(Dir::COMMON_APPDATA, "ChoriaIO", "choria")
155
157
  end
156
158
 
157
- def self.mcollective_config_paths_for_user
159
+ def self.config_paths_for_user
158
160
  config_paths = []
159
161
 
160
- begin
161
- # File.expand_path will raise if HOME isn't set, catch it
162
- user_path = File.expand_path("~/.mcollective")
163
- config_paths << user_path
164
- rescue Exception # rubocop:disable Lint/RescueException, Lint/HandleExceptions
162
+ ["~/.choriarc", "~/.mcollective"].each do |f|
163
+ begin
164
+ # File.expand_path will raise if HOME isn't set, catch it
165
+ config_paths << File.expand_path(f)
166
+ rescue ArgumentError # rubocop:disable Lint/SuppressedException
167
+ end
165
168
  end
166
169
 
167
170
  if windows?
171
+ config_paths << File.join(choria_windows_prefix, "etc", "client.conf")
168
172
  config_paths << File.join(windows_prefix, "etc", "client.cfg")
169
173
  else
174
+ config_paths << "/etc/choria/client.conf"
175
+ config_paths << "/usr/local/etc/choria/client.conf"
170
176
  config_paths << "/etc/puppetlabs/mcollective/client.cfg"
171
177
  config_paths << "/etc/mcollective/client.cfg"
172
178
  config_paths << "/usr/local/etc/mcollective/client.cfg"
@@ -175,56 +181,44 @@ module MCollective
175
181
  config_paths
176
182
  end
177
183
 
178
- def self.choria_config_paths_for_user
179
- config_paths = []
180
-
181
- begin
182
- # File.expand_path will raise if HOME isn't set, catch it
183
- user_path = File.expand_path("~/.choriarc")
184
- config_paths << user_path
185
- rescue Exception # rubocop:disable Lint/RescueException, Lint/HandleExceptions
186
- end
187
-
188
- if windows?
189
- config_paths << File.join(choria_windows_prefix, "etc", "client.conf")
190
- else
191
- config_paths << "/etc/choria/client.conf"
192
- config_paths << "/usr/local/etc/choria/client.conf"
193
- end
194
-
195
- config_paths
196
- end
197
-
198
184
  # Picks the default user config file, priorities are first Choria ones then old MCollective ones
199
185
  #
200
186
  # In roughly this order, first to exist is used:
201
187
  #
202
188
  # - ~/.choriarc
203
- # - APPData/ChoriaIO/choria/etc/client.conf on windows
204
- # - /etc/choria/client.conf then
205
- # - /usr/local/etc/choria/client.conf on unix
206
189
  # - ~/.mcollective
207
- # - APPData/PuppetLabs/mcollective/etc/client.cfg on windows
190
+ #
191
+ # On Unix:
192
+ #
193
+ # - /etc/choria/client.conf
194
+ # - /usr/local/etc/choria/client.conf
208
195
  # - /etc/puppetlabs/mcollective/client.cfg
209
196
  # - /etc/mcollective/client.cfg
210
197
  # - /usr/local/etc/mcollective/client.cfg
198
+ #
199
+ # On Windows:
200
+ #
201
+ # - APPData/ChoriaIO/choria/etc/client.conf on windows
202
+ # - APPData/PuppetLabs/mcollective/etc/client.cfg on windows
211
203
  def self.config_file_for_user
212
- config_paths = choria_config_paths_for_user + mcollective_config_paths_for_user
204
+ config_paths = config_paths_for_user
205
+
213
206
  found = config_paths.find_index { |file| File.readable?(file) } || 0
207
+
214
208
  config_paths[found]
215
209
  end
216
210
 
217
211
  # Creates a standard options hash
218
212
  def self.default_options
219
213
  {
220
- :verbose => false,
221
- :disctimeout => nil,
222
- :timeout => 5,
223
- :config => config_file_for_user,
224
- :collective => nil,
225
- :discovery_method => nil,
214
+ :verbose => false,
215
+ :disctimeout => nil,
216
+ :timeout => 5,
217
+ :config => config_file_for_user,
218
+ :collective => nil,
219
+ :discovery_method => nil,
226
220
  :discovery_options => Config.instance.default_discovery_options,
227
- :filter => empty_filter
221
+ :filter => empty_filter
228
222
  }
229
223
  end
230
224
 
@@ -273,15 +267,16 @@ module MCollective
273
267
 
274
268
  # Parse a fact filter string like foo=bar into the tuple hash thats needed
275
269
  def self.parse_fact_string(fact)
276
- if fact =~ /^([^ ]+?)[ ]*=>[ ]*(.+)/
270
+ case fact
271
+ when /^([^ ]+?) *=> *(.+)/
277
272
  {:fact => $1, :value => $2, :operator => ">="}
278
- elsif fact =~ /^([^ ]+?)[ ]*=<[ ]*(.+)/
273
+ when /^([^ ]+?) *=< *(.+)/
279
274
  {:fact => $1, :value => $2, :operator => "<="}
280
- elsif fact =~ /^([^ ]+?)[ ]*(<=|>=|<|>|!=|==|=~)[ ]*(.+)/
275
+ when /^([^ ]+?) *(<=|>=|<|>|!=|==|=~) *(.+)/
281
276
  {:fact => $1, :value => $3, :operator => $2}
282
- elsif fact =~ /^(.+?)[ ]*=[ ]*\/(.+)\/$/
277
+ when /^(.+?) *= *\/(.+)\/$/
283
278
  {:fact => $1, :value => "/#{$2}/", :operator => "=~"}
284
- elsif fact =~ /^([^= ]+?)[ ]*=[ ]*(.+)/
279
+ when /^([^= ]+?) *= *(.+)/
285
280
  {:fact => $1, :value => $2, :operator => "=="}
286
281
  else
287
282
  raise "Could not parse fact #{fact} it does not appear to be in a valid format"
@@ -326,9 +321,9 @@ module MCollective
326
321
  }
327
322
 
328
323
  if colorize
329
- return colors[code] || ""
324
+ colors[code] || ""
330
325
  else
331
- return ""
326
+ ""
332
327
  end
333
328
  end
334
329
 
@@ -379,9 +374,7 @@ module MCollective
379
374
  text.each_with_index do |line, i|
380
375
  whitespace = 0
381
376
 
382
- while whitespace < line.length && line[whitespace].chr == " "
383
- whitespace += 1
384
- end
377
+ whitespace += 1 while whitespace < line.length && line[whitespace].chr == " "
385
378
 
386
379
  # If the current line is empty, indent it so that a snippet
387
380
  # from the previous line is aligned correctly.
@@ -435,21 +428,21 @@ module MCollective
435
428
  #
436
429
  # Returns [0, 0] if it can't figure it out or if you're
437
430
  # not running on a tty
438
- def self.terminal_dimensions(stdout=STDOUT, environment=ENV)
431
+ def self.terminal_dimensions(stdout=$stdout, environment=ENV)
439
432
  return [0, 0] unless stdout.tty?
440
433
 
441
434
  return [80, 40] if Util.windows?
442
435
 
443
436
  if environment["COLUMNS"] && environment["LINES"]
444
- return [environment["COLUMNS"].to_i, environment["LINES"].to_i]
437
+ [environment["COLUMNS"].to_i, environment["LINES"].to_i]
445
438
 
446
439
  elsif environment["TERM"] && command_in_path?("tput")
447
- return [`tput cols`.to_i, `tput lines`.to_i]
440
+ [`tput cols`.to_i, `tput lines`.to_i]
448
441
 
449
442
  elsif command_in_path?("stty")
450
- return `stty size`.scan(/\d+/).map(&:to_i)
443
+ `stty size`.scan(/\d+/).map(&:to_i)
451
444
  else
452
- return [0, 0]
445
+ [0, 0]
453
446
  end
454
447
  rescue
455
448
  [0, 0]
@@ -490,6 +483,7 @@ module MCollective
490
483
  elsif b == "." then return 1
491
484
  elsif a =~ /^\d+$/ && b =~ /^\d+$/
492
485
  return a.to_s.upcase <=> b.to_s.upcase if a =~ /^0/ || b =~ /^0/
486
+
493
487
  return a.to_i <=> b.to_i
494
488
  else
495
489
  return a.upcase <=> b.upcase
@@ -516,10 +510,11 @@ module MCollective
516
510
  # Any other value will return FalseClass
517
511
  def self.str_to_bool(val)
518
512
  clean_val = val.to_s.strip
519
- if clean_val =~ /^(1|yes|true|y|t)$/i
520
- return true
521
- elsif clean_val =~ /^(0|no|false|n|f)$/i
522
- return false
513
+ case clean_val
514
+ when /^(1|yes|true|y|t)$/i
515
+ true
516
+ when /^(0|no|false|n|f)$/i
517
+ false
523
518
  else
524
519
  raise("Cannot convert string value '#{clean_val}' into a boolean.")
525
520
  end
@@ -531,8 +526,7 @@ module MCollective
531
526
  template_path = File.join(config_dir, template_file)
532
527
  return template_path if File.exist?(template_path)
533
528
 
534
- template_path = File.join("/etc/mcollective", template_file)
535
- template_path
529
+ File.join("/etc/mcollective", template_file)
536
530
  end
537
531
 
538
532
  # subscribe to the direct addressing queue
@@ -563,6 +557,7 @@ module MCollective
563
557
 
564
558
  while char = Win32API.new("crtdll", "_getch", [], "I").Call
565
559
  break if [10, 13].include?(char) # return or newline
560
+
566
561
  if [127, 8].include?(char) # backspace and delete
567
562
  input.slice!(-1, 1) unless input.empty?
568
563
  else
@@ -574,17 +569,13 @@ module MCollective
574
569
  end
575
570
 
576
571
  def self.get_hidden_input_on_unix # rubocop:disable Naming/AccessorMethodName
577
- unless $stdin.tty?
578
- raise "Could not hook to stdin to hide input. If using SSH, try using -t flag while connecting to server."
579
- end
580
- unless system "stty -echo -icanon"
581
- raise "Could not hide input using stty command."
582
- end
572
+ raise "Could not hook to stdin to hide input. If using SSH, try using -t flag while connecting to server." unless $stdin.tty?
573
+ raise "Could not hide input using stty command." unless system "stty -echo -icanon"
574
+
583
575
  input = $stdin.gets
584
576
  ensure
585
- unless system "stty echo icanon"
586
- raise "Could not enable echoing of input. Try executing `stty echo icanon` to debug."
587
- end
577
+ raise "Could not enable echoing of input. Try executing `stty echo icanon` to debug." unless system "stty echo icanon"
578
+
588
579
  input
589
580
  end
590
581