sensu-cli-compat 0.6.3.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 93c6437ccfa0bfec4c2ef12ae2fc7f795da9ea2f
4
+ data.tar.gz: 8d1b4470a3bb9248737fb91dc76eb9abcd106b00
5
+ SHA512:
6
+ metadata.gz: ba28bd44a8487cf939f6f23892b6af8bb0186ee0cd790a6d230f5d30fcd6a3a15555961deb92c59ef9e67df9dde32fa617002c97d224bb635028c09458b8e9f0
7
+ data.tar.gz: a45e1623c30498a7114ab72194b87c6bb3ea826a439bb7a8607158e25593a1bb4cf72d8f6bc412218c1ca12a8355c83d0d0070b208b01ca4813028be4c057e4d
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ sensu-cli
2
+ =========
3
+ ```
4
+ #
5
+ # Welcome to the sensu-cli.
6
+ # ______
7
+ # .-' '-.
8
+ # .' __ '.
9
+ # / / \ \
10
+ # ------------------
11
+ # /\
12
+ # '--'
13
+ # SENSU-CLI
14
+ #
15
+ ```
16
+ A sensu-cli for interacting with the sensu api.
17
+
18
+ What is Sensu? http://sensuapp.org/
19
+
20
+ Features
21
+ --------
22
+ * API interaction with info, health, stashes, events, clients, aggregates and checks
23
+ * Resolve Events
24
+ * Silence clients and checks
25
+ * Get Requests (get clients, stashes, events, etc.)
26
+ * Delete Requests (delete clients, stashes, aggregates and events)
27
+
28
+
29
+ Usage and Configuration
30
+ -----------------------
31
+ * gem install sensu-cli
32
+
33
+ * There is one settings file for host, port, ssl, and HTTP timeout that lives in your user directory ~/.sensu/settings.rb. You can alternatively place this in /etc/sensu/sensu-cli/settings.rb.
34
+
35
+ ````
36
+ host "127.0.0.1"
37
+ port "4567"
38
+ ssl false
39
+ read_timeout 20
40
+ open_timeout 20
41
+ ````
42
+ This format was chosen so you can do some ENV magic via your profile and setting up an alias. For details see the [wiki](https://github.com/agent462/sensu-cli/wiki)
43
+
44
+ * All Configuration Settings
45
+ `host` String - Required
46
+ `port` String/Integer - Required
47
+ `ssl` Boolean - Optional - Defaults False
48
+ `read_timeout` Integer - Optional - Default 15 (seconds)
49
+ `open_timeout` Integer - Optional - Default 5 (seconds)
50
+ `pretty_colors` Boolean - Optional - Default True
51
+ `proxy_address` String - Optional
52
+ `proxy_port` Integer - Optional
53
+ `user` String - Optional
54
+ `password` String - Optional
55
+
56
+ Examples
57
+ -----------
58
+ ````
59
+ Available subcommands: (for details, sensu SUB-COMMAND --help)
60
+
61
+ ** Aggregate Commands **
62
+ sensu-cli aggregate list (OPTIONS)
63
+ sensu-cli aggregate show CHECK (OPTIONS)
64
+ sensu-cli aggregate delete CHECK
65
+
66
+ ** Check Commands **
67
+ sensu-cli check list
68
+ sensu-cli check show CHECK
69
+ sensu-cli check request CHECK SUB1,SUB2
70
+
71
+ ** Client Commands **
72
+ sensu-cli client list (OPTIONS)
73
+ sensu-cli client show NODE
74
+ sensu-cli client delete NODE
75
+ sensu-cli client history NODE
76
+
77
+ ** Event Commands **
78
+ sensu-cli event list
79
+ sensu-cli event show NODE (OPTIONS)
80
+ sensu-cli event delete NODE CHECK
81
+
82
+ ** Health Commands **
83
+ sensu-cli health (OPTIONS)
84
+
85
+ ** Info Commands **
86
+ sensu-cli info
87
+
88
+ ** Silence Commands **
89
+ sensu-cli silence NODE (OPTIONS)
90
+
91
+ ** Stash Commands **
92
+ sensu-cli stash list (OPTIONS)
93
+ sensu-cli stash show STASHPATH
94
+ sensu-cli stash delete STASHPATH
95
+ sensu-cli stash create PATH
96
+
97
+ ** Resolve Commands **
98
+ sensu-cli resolve NODE CHECK
99
+
100
+ --version, -v: Print version and exit
101
+ --help, -h: Show this message
102
+ ````
103
+
104
+ Contributions
105
+ -------------
106
+ Please provide a pull request. I'm an ops guy, not a developer, so if you're submitting code cleanup, all I ask is that you explain the improvement so I can learn.
107
+
108
+
109
+ License and Author
110
+ ==================
111
+ I'm releasing this under the MIT or Apache 2.0 license. You pick.
112
+
113
+ Author:: Bryan Brandau <agent462@gmail.com>
114
+
115
+ Copyright:: 2013, Bryan Brandau
116
+
117
+ Licensed under the Apache License, Version 2.0 (the "License");
118
+ you may not use this file except in compliance with the License.
119
+ You may obtain a copy of the License at
120
+
121
+ http://www.apache.org/licenses/LICENSE-2.0
122
+
123
+ Unless required by applicable law or agreed to in writing, software
124
+ distributed under the License is distributed on an "AS IS" BASIS,
125
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
126
+ See the License for the specific language governing permissions and
127
+ limitations under the License.
data/bin/sensu ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.dirname(__FILE__) + '/../lib' unless $LOAD_PATH.include?(File.dirname(__FILE__) + '/../lib/')
3
+
4
+ require 'sensu-cli'
5
+ sensu = SensuCli::Base.new
6
+ sensu.setup
data/bin/sensu-cli ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.dirname(__FILE__) + '/../lib' unless $LOAD_PATH.include?(File.dirname(__FILE__) + '/../lib/')
3
+
4
+ require 'sensu-cli'
5
+ sensu = SensuCli::Base.new
6
+ sensu.setup
data/lib/sensu-cli.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'sensu-cli/settings'
2
+ require 'sensu-cli/cli'
3
+ require 'sensu-cli/editor'
4
+ require 'sensu-cli/pretty'
5
+ require 'sensu-cli/path.rb'
6
+ require 'sensu-cli/api.rb'
7
+ require 'sensu-cli/base.rb'
8
+ require 'sensu-cli/version.rb'
9
+ require 'sensu-cli/filter.rb'
10
+
11
+ module SensuCli
12
+ def self.die(code = 0, msg = nil)
13
+ at_exit { puts msg }
14
+ Kernel.exit(code)
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ require 'net/https'
2
+ require 'json'
3
+ require 'rainbow/ext/string'
4
+
5
+ module SensuCli
6
+ class Api
7
+ def request(opts)
8
+ http = Net::HTTP.new(opts[:host], opts[:port], opts[:proxy_address],
9
+ opts[:proxy_port])
10
+ http.read_timeout = opts[:read_timeout]
11
+ http.open_timeout = opts[:open_timeout]
12
+ if opts[:ssl]
13
+ http.use_ssl = true
14
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
15
+ end
16
+ proxy_header = { 'api-proxy' => 'true' }
17
+ case opts[:method]
18
+ when 'Get'
19
+ req = Net::HTTP::Get.new(opts[:path], proxy_header)
20
+ when 'Delete'
21
+ req = Net::HTTP::Delete.new(opts[:path], proxy_header)
22
+ when 'Post'
23
+ req = Net::HTTP::Post.new(opts[:path], proxy_header.merge!('Content-Type' => 'application/json'))
24
+ req.body = opts[:payload]
25
+ end
26
+ req.basic_auth(opts[:user], opts[:password]) if opts[:user] && opts[:password]
27
+ begin
28
+ http.request(req)
29
+ rescue Timeout::Error
30
+ SensuCli::die(1, 'HTTP request has timed out.'.color(:red))
31
+ rescue StandardError => e
32
+ SensuCli::die(1, "An HTTP error occurred. Check your settings. #{e}".color(:red))
33
+ end
34
+ end
35
+
36
+ def response(code, body, command = nil)
37
+ case code
38
+ when '200'
39
+ JSON.parse(body)
40
+ when '201'
41
+ puts 'The stash has been created.' if command == 'stashes' || command == 'silence'
42
+ when '202'
43
+ puts 'The item was submitted for processing.'
44
+ when '204'
45
+ puts 'Sensu is healthy' if command == 'health'
46
+ puts 'The item was successfully deleted.' if command == 'aggregates' || command == 'stashes'
47
+ when '400'
48
+ puts 'The payload is malformed.'.color(:red)
49
+ when '401'
50
+ puts 'The request requires user authentication.'.color(:red)
51
+ when '404'
52
+ puts 'The item did not exist.'.color(:cyan)
53
+ else
54
+ if command == 'health'
55
+ puts 'Sensu is not healthy.'.color(:red)
56
+ else
57
+ puts "There was an error while trying to complete your request. Response code: #{code}".color(:red)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,66 @@
1
+ module SensuCli
2
+ class Base
3
+ def setup
4
+ @cli = Cli.new.global
5
+ settings
6
+ api_path(@cli)
7
+ make_call
8
+ end
9
+
10
+ def settings
11
+ directory = "#{Dir.home}/.sensu"
12
+ file = "#{directory}/settings.rb"
13
+ alt = '/etc/sensu/sensu-cli/settings.rb'
14
+ settings = Settings.new
15
+ if settings.file?(file)
16
+ SensuCli::Config.from_file(file)
17
+ elsif settings.file?(alt)
18
+ SensuCli::Config.from_file(alt)
19
+ else
20
+ settings.create(directory, file)
21
+ end
22
+ Rainbow.enabled = Config.pretty_colors == false ? false : true
23
+ end
24
+
25
+ def api_path(cli)
26
+ p = PathCreator.new
27
+ p.respond_to?(cli[:command]) ? path = p.send(cli[:command], cli) : SensuCli::die(1, 'Something Bad Happened')
28
+ @api = { :path => path[:path], :method => cli[:method], :command => cli[:command], :payload => (path[:payload] || false) }
29
+ end
30
+
31
+ def make_call
32
+ opts = {
33
+ :path => @api[:path],
34
+ :method => @api[:method],
35
+ :payload => @api[:payload],
36
+ :host => Config.host,
37
+ :port => Config.port,
38
+ :ssl => Config.ssl || false,
39
+ :user => Config.user || nil,
40
+ :read_timeout => Config.read_timeout || 15,
41
+ :open_timeout => Config.open_timeout || 5,
42
+ :password => Config.password || nil,
43
+ :proxy_address => Config.proxy_address || nil,
44
+ :proxy_port => Config.proxy_port || nil
45
+ }
46
+ api = Api.new
47
+ res = api.request(opts)
48
+ msg = api.response(res.code, res.body, @api[:command])
49
+ msg = Filter.new(@cli[:fields][:filter]).process(msg) if @cli[:fields][:filter]
50
+ endpoint = @api[:command]
51
+ if res.code != '200'
52
+ SensuCli::die(0)
53
+ elsif @cli[:fields][:format] == 'single'
54
+ Pretty.single(msg, endpoint)
55
+ elsif @cli[:fields][:format] == 'table'
56
+ fields = nil || @cli[:fields][:fields]
57
+ Pretty.table(msg, endpoint, fields)
58
+ elsif @cli[:fields][:format] == 'json'
59
+ Pretty.json(msg)
60
+ else
61
+ Pretty.print(msg, endpoint)
62
+ end
63
+ Pretty.count(msg) unless @cli[:fields][:format] == 'table' or @cli[:fields][:format] == 'json'
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,313 @@
1
+ require 'trollop'
2
+ require 'sensu-cli/version'
3
+ require 'rainbow/ext/string'
4
+
5
+ module SensuCli
6
+ class Cli # rubocop:disable ClassLength
7
+ SUB_COMMANDS = %w(info client check event stash aggregate silence resolve health)
8
+ CLIENT_COMMANDS = %w(list show delete history)
9
+ CHECK_COMMANDS = %w(list show request)
10
+ EVENT_COMMANDS = %w(list show delete)
11
+ STASH_COMMANDS = %w(list show delete create)
12
+ AGG_COMMANDS = %w(list show delete)
13
+ SIL_COMMANDS = ''
14
+ RES_COMMANDS = ''
15
+ INFO_COMMANDS = ''
16
+ HEALTH_COMMANDS = ''
17
+
18
+ CLIENT_BANNER = <<-EOS.gsub(/^ {10}/, '')
19
+ ** Client Commands **
20
+ sensu-cli client list (OPTIONS)
21
+ sensu-cli client show NODE
22
+ sensu-cli client delete NODE
23
+ sensu-cli client history NODE\n\r
24
+ EOS
25
+ INFO_BANNER = <<-EOS.gsub(/^ {10}/, '')
26
+ ** Info Commands **
27
+ sensu-cli info\n\r
28
+ EOS
29
+ HEALTH_BANNER = <<-EOS.gsub(/^ {10}/, '')
30
+ ** Health Commands **
31
+ sensu-cli health (OPTIONS)\n\r
32
+ EOS
33
+ CHECK_BANNER = <<-EOS.gsub(/^ {10}/, '')
34
+ ** Check Commands **
35
+ sensu-cli check list
36
+ sensu-cli check show CHECK
37
+ sensu-cli check request CHECK SUB1,SUB2\n\r
38
+ EOS
39
+ EVENT_BANNER = <<-EOS.gsub(/^ {10}/, '')
40
+ ** Event Commands **
41
+ sensu-cli event list (OPTIONS)
42
+ sensu-cli event show NODE (OPTIONS)
43
+ sensu-cli event delete NODE CHECK\n\r
44
+ EOS
45
+ STASH_BANNER = <<-EOS.gsub(/^ {10}/, '')
46
+ ** Stash Commands **
47
+ sensu-cli stash list (OPTIONS)
48
+ sensu-cli stash show STASHPATH
49
+ sensu-cli stash delete STASHPATH
50
+ sensu-cli stash create PATH\n\r
51
+ EOS
52
+ AGG_BANNER = <<-EOS.gsub(/^ {10}/, '')
53
+ ** Aggregate Commands **
54
+ sensu-cli aggregate list (OPTIONS)
55
+ sensu-cli aggregate show CHECK (OPTIONS)
56
+ sensu-cli aggregate delete CHECK\n\r
57
+ EOS
58
+ SIL_BANNER = <<-EOS.gsub(/^ {10}/, '')
59
+ ** Silence Commands **
60
+ sensu-cli silence NODE (OPTIONS)\n\r
61
+ EOS
62
+ RES_BANNER = <<-EOS.gsub(/^ {10}/, '')
63
+ ** Resolve Commands **
64
+ sensu-cli resolve NODE CHECK\n\r
65
+ EOS
66
+
67
+ def global
68
+ global_opts = Trollop::Parser.new do
69
+ version "sensu-cli version: #{SensuCli::VERSION}"
70
+ banner <<-'EOS'.gsub(/^ {10}/, '')
71
+ #
72
+ # Welcome to the sensu-cli.
73
+ # ______
74
+ # .-' '-.
75
+ # .' __ '.
76
+ # / / \ \
77
+ # ------------------
78
+ # /\
79
+ # '--'
80
+ # SENSU-CLI
81
+ #
82
+ EOS
83
+ banner "\n\rAvailable subcommands: (for details, sensu-cli SUB-COMMAND --help)\n\r"
84
+ banner AGG_BANNER
85
+ banner CHECK_BANNER
86
+ banner CLIENT_BANNER
87
+ banner EVENT_BANNER
88
+ banner HEALTH_BANNER
89
+ banner INFO_BANNER
90
+ banner SIL_BANNER
91
+ banner STASH_BANNER
92
+ banner RES_BANNER
93
+ stop_on SUB_COMMANDS
94
+ end
95
+
96
+ Trollop::with_standard_exception_handling global_opts do
97
+ global_opts.parse ARGV
98
+ raise Trollop::HelpNeeded if ARGV.empty? # show help screen
99
+ end
100
+
101
+ cmd = next_argv
102
+ self.respond_to?(cmd) ? send(cmd) : explode(global_opts)
103
+ end
104
+
105
+ def explode(opts)
106
+ Trollop::with_standard_exception_handling opts do
107
+ raise Trollop::HelpNeeded # show help screen
108
+ end
109
+ end
110
+
111
+ def deep_merge(hash_one, hash_two)
112
+ hash_one.merge(hash_two) { |_key, hash_one_item, hash_two_item| deep_merge(hash_one_item, hash_two_item) }
113
+ end
114
+
115
+ def parser(cli)
116
+ Trollop::Parser.new do
117
+ banner Cli.const_get("#{cli}_BANNER")
118
+ stop_on Cli.const_get("#{cli}_COMMANDS")
119
+ end
120
+ end
121
+
122
+ def explode_if_empty(opts, command)
123
+ explode(opts) if ARGV.empty? && command != 'list'
124
+ end
125
+
126
+ def next_argv
127
+ ARGV.shift
128
+ end
129
+
130
+ def client # rubocop:disable MethodLength
131
+ opts = parser('CLIENT')
132
+ command = next_argv
133
+ explode_if_empty(opts, command)
134
+ case command
135
+ when 'list'
136
+ p = Trollop::options do
137
+ opt :limit, 'The number if clients to return', :short => 'l', :type => :string
138
+ opt :offset, 'The number of clients to offset before returning', :short => 'o', :type => :string
139
+ opt :format, 'Available formats; single, table, json', :short => 'f', :type => :string
140
+ opt :fields, 'Fields for table ouput: -F name,address,subscriptions', :short => 'F', :type => :string
141
+ opt :filter, 'Field and value to filter on: name,graphite', :type => :string
142
+ end
143
+ Trollop::die :format, 'Available optional formats: single, table, json'.color(:red) if p[:format] != 'table' && p[:format] != 'single' && p[:format] != 'json' && p[:format]
144
+ Trollop::die :fields, 'Fields must be used in conjunction with --format table'.color(:red) if p[:format] != 'table' && p[:fields]
145
+ Trollop::die :offset, 'Offset depends on the limit option --limit ( -l )'.color(:red) if p[:offset] && !p[:limit]
146
+ { :command => 'clients', :method => 'Get', :fields => p }
147
+ when 'delete'
148
+ p = Trollop::options
149
+ item = next_argv # the ARGV.shift needs to happen after Trollop::options to catch --help
150
+ deep_merge({ :command => 'clients', :method => 'Delete', :fields => { :name => item } }, { :fields => p })
151
+ when 'show'
152
+ p = Trollop::options
153
+ item = next_argv
154
+ deep_merge({ :command => 'clients', :method => 'Get', :fields => { :name => item } }, { :fields => p })
155
+ when 'history'
156
+ p = Trollop::options
157
+ item = next_argv
158
+ deep_merge({ :command => 'clients', :method => 'Get', :fields => { :name => item, :history => true } }, { :fields => p })
159
+ else
160
+ explode(opts)
161
+ end
162
+ end
163
+
164
+ def info
165
+ parser('INFO')
166
+ p = Trollop::options
167
+ { :command => 'info', :method => 'Get', :fields => p }
168
+ end
169
+
170
+ def health
171
+ parser('HEALTH')
172
+ p = Trollop::options do
173
+ opt :consumers, 'The minimum number of consumers', :short => 'c', :type => :string, :required => true
174
+ opt :messages, 'The maximum number of messages', :short => 'm', :type => :string, :required => true
175
+ end
176
+ { :command => 'health', :method => 'Get', :fields => p }
177
+ end
178
+
179
+ def check
180
+ opts = parser('CHECK')
181
+ command = next_argv
182
+ explode_if_empty(opts, command)
183
+ item = next_argv
184
+ case command
185
+ when 'list'
186
+ p = Trollop::options do
187
+ opt :filter, 'Field and value to filter on: command,procs', :type => :string
188
+ end
189
+ { :command => 'checks', :method => 'Get', :fields => p }
190
+ when 'show'
191
+ p = Trollop::options
192
+ deep_merge({ :command => 'checks', :method => 'Get', :fields => { :name => item } }, { :fields => p })
193
+ when 'request'
194
+ p = Trollop::options
195
+ ARGV.empty? ? explode(opts) : subscribers = next_argv.split(',')
196
+ deep_merge({ :command => 'checks', :method => 'Post', :fields => { :check => item, :subscribers => subscribers } }, { :fields => p })
197
+ else
198
+ explode(opts)
199
+ end
200
+ end
201
+
202
+ def event
203
+ opts = parser('EVENT')
204
+ command = next_argv
205
+ explode_if_empty(opts, command)
206
+ case command
207
+ when 'list'
208
+ p = Trollop::options do
209
+ opt :filter, 'Field and value to filter on: client,graphite (use "name" as field for client or event name)', :type => :string
210
+ opt :format, 'Available formats; single, table, json', :short => 'f', :type => :string
211
+ end
212
+ Trollop::die :format, 'Available optional formats: single, table, json'.color(:red) if p[:format] != 'table' && p[:format] != 'single' && p[:format] != 'json' && p[:format]
213
+ { :command => 'events', :method => 'Get', :fields => p }
214
+ when 'show'
215
+ p = Trollop::options do
216
+ opt :check, 'Returns the check associated with the client', :short => 'k', :type => :string
217
+ end
218
+ item = next_argv
219
+ deep_merge({ :command => 'events', :method => 'Get', :fields => { :client => item } }, { :fields => p })
220
+ when 'delete'
221
+ p = Trollop::options
222
+ item = next_argv
223
+ check = next_argv
224
+ explode(opts) if check.nil?
225
+ deep_merge({ :command => 'events', :method => 'Delete', :fields => { :client => item, :check => check } }, { :fields => p })
226
+ else
227
+ explode(opts)
228
+ end
229
+ end
230
+
231
+ def stash
232
+ opts = parser('STASH')
233
+ command = next_argv
234
+ explode_if_empty(opts, command)
235
+ case command
236
+ when 'list'
237
+ p = Trollop::options do
238
+ opt :limit, 'The number of stashes to return', :short => 'l', :type => :string
239
+ opt :offset, 'The number of stashes to offset before returning', :short => 'o', :type => :string
240
+ opt :format, 'Available formats; single, table, json', :short => 'f', :type => :string
241
+ opt :filter, 'Field and value to filter on: path,graphite', :type => :string
242
+ end
243
+ Trollop::die :offset, 'Offset depends on the limit option --limit ( -l )'.color(:red) if p[:offset] && !p[:limit]
244
+ Trollop::die :format, 'Available optional formats: single, table, json'.color(:red) if p[:format] != 'table' && p[:format] != 'single' && p[:format] != 'json' && p[:format]
245
+ { :command => 'stashes', :method => 'Get', :fields => p }
246
+ when 'show'
247
+ p = Trollop::options
248
+ item = next_argv
249
+ deep_merge({ :command => 'stashes', :method => 'Get', :fields => { :path => item } }, { :fields => p })
250
+ when 'delete'
251
+ p = Trollop::options
252
+ item = next_argv
253
+ deep_merge({ :command => 'stashes', :method => 'Delete', :fields => { :path => item } }, { :fields => p })
254
+ when 'create'
255
+ p = Trollop::options
256
+ item = next_argv
257
+ deep_merge({ :command => 'stashes', :method => 'Post', :fields => { :create => true, :create_path => item } }, { :fields => p })
258
+ else
259
+ explode(opts)
260
+ end
261
+ end
262
+
263
+ def aggregate
264
+ opts = parser('AGG')
265
+ command = next_argv
266
+ explode_if_empty(opts, command)
267
+ case command
268
+ when 'list'
269
+ p = Trollop::options do
270
+ opt :filter, 'Field and value to filter on: issued,1399505890', :type => :string
271
+ end
272
+ { :command => 'aggregates', :method => 'Get', :fields => p }
273
+ when 'show'
274
+ p = Trollop::options do
275
+ opt :id, 'The id of the check issued.', :short => 'i', :type => :integer
276
+ opt :limit, 'The number of aggregates to return', :short => 'l', :type => :string
277
+ opt :offset, 'The number of aggregates to offset before returning', :short => 'o', :type => :string
278
+ # opt :results, 'Include the check results', :short => 'r', :type => :boolean
279
+ end
280
+ Trollop::die :offset, 'Offset depends on the limit option --limit ( -l )'.color(:red) if p[:offset] && !p[:limit]
281
+ item = next_argv
282
+ deep_merge({ :command => 'aggregates', :method => 'Get', :fields => { :check => item } }, { :fields => p })
283
+ when 'delete'
284
+ p = Trollop::options
285
+ item = next_argv
286
+ deep_merge({ :command => 'aggregates', :method => 'Delete', :fields => { :check => item } }, { :fields => p })
287
+ else
288
+ explode(opts)
289
+ end
290
+ end
291
+
292
+ def silence
293
+ opts = parser('SIL')
294
+ p = Trollop::options do
295
+ opt :check, 'The check to silence', :short => 'k', :type => :string
296
+ opt :owner, 'The owner of the stash', :short => 'o', :type => :string
297
+ opt :reason, 'The reason this check/node is being silenced', :short => 'r', :type => :string
298
+ opt :expire, 'The number of seconds the silenced event is valid', :short => 'e', :type => :integer
299
+ end
300
+ command = next_argv
301
+ explode(opts) if command.nil?
302
+ deep_merge({ :command => 'silence', :method => 'Post', :fields => { :client => command } }, { :fields => p })
303
+ end
304
+
305
+ def resolve
306
+ opts = parser('RES')
307
+ command = next_argv
308
+ p = Trollop::options
309
+ ARGV.empty? ? explode(opts) : check = next_argv
310
+ deep_merge({ :command => 'resolve', :method => 'Post', :fields => { :client => command, :check => check } }, { :fields => p })
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,28 @@
1
+ require 'json'
2
+ require 'tempfile'
3
+
4
+ module SensuCli
5
+ class Editor
6
+ def create_stash(create_path)
7
+ file = temp_file(:path => create_path, :content => { :timestamp => Time.now.to_i })
8
+ edit(file)
9
+ end
10
+
11
+ def edit(file)
12
+ editor = ENV['EDITOR'] ? ENV['EDITOR'] : 'vi'
13
+ system("#{editor} #{file}")
14
+ begin
15
+ JSON.parse(File.read(file))
16
+ rescue JSON::ParserError
17
+ SensuCli::die(1, 'The stash you created has invalid JSON.')
18
+ end
19
+ end
20
+
21
+ def temp_file(template)
22
+ file = Tempfile.new('sensu')
23
+ file.write(JSON.pretty_generate(template))
24
+ file.close
25
+ file.path
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module SensuCli
2
+ class Filter
3
+ attr_reader :filter
4
+
5
+ def initialize(filter_data)
6
+ filter_split(filter_data)
7
+ end
8
+
9
+ def filter_split(filter)
10
+ @filter = filter.sub(' ', '').split(',')
11
+ end
12
+
13
+ def match?(data)
14
+ data.to_s.include? filter[1]
15
+ end
16
+
17
+ def inspect_hash(data)
18
+ data.any? do |key, value|
19
+ if value.is_a?(Array)
20
+ match?(value) if key == filter[0]
21
+ elsif value.is_a?(Hash)
22
+ process(value)
23
+ else
24
+ match?(value) if key == filter[0]
25
+ end
26
+ end
27
+ end
28
+
29
+ def process(data)
30
+ if data.is_a?(Array)
31
+ data.select do |value|
32
+ process(value)
33
+ end
34
+ elsif data.is_a?(Hash)
35
+ inspect_hash(data)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,96 @@
1
+ module SensuCli
2
+ class PathCreator
3
+ def clients(cli)
4
+ path = '/clients'
5
+ path << "/#{cli[:fields][:name]}" if cli[:fields][:name]
6
+ path << '/history' if cli[:fields][:history]
7
+ path << pagination(cli)
8
+ respond(path)
9
+ end
10
+
11
+ def info(*)
12
+ path = '/info'
13
+ respond(path)
14
+ end
15
+
16
+ def health(cli)
17
+ path = "/health?consumers=#{cli[:fields][:consumers]}&messages=#{cli[:fields][:messages]}"
18
+ respond(path)
19
+ end
20
+
21
+ def stashes(cli)
22
+ if cli[:fields][:create]
23
+ e = Editor.new
24
+ payload = e.create_stash(cli[:fields][:create_path]).to_json
25
+ end
26
+ path = '/stashes'
27
+ path << "/#{cli[:fields][:path]}" if cli[:fields][:path]
28
+ path << pagination(cli)
29
+ respond(path, payload)
30
+ end
31
+
32
+ def checks(cli)
33
+ if cli[:fields][:name]
34
+ path = "/check/#{cli[:fields][:name]}"
35
+ elsif cli[:fields][:subscribers]
36
+ payload = { :check => cli[:fields][:check], :subscribers => cli[:fields][:subscribers] }.to_json
37
+ path = '/request'
38
+ else
39
+ path = '/checks'
40
+ end
41
+ respond(path, payload)
42
+ end
43
+
44
+ def events(cli)
45
+ path = '/events'
46
+ path << "/#{cli[:fields][:client]}" if cli[:fields][:client]
47
+ path << "/#{cli[:fields][:check]}" if cli[:fields][:check]
48
+ respond(path)
49
+ end
50
+
51
+ def resolve(cli)
52
+ payload = { :client => cli[:fields][:client], :check => cli[:fields][:check] }.to_json
53
+ path = '/resolve'
54
+ respond(path, payload)
55
+ end
56
+
57
+ def silence(cli)
58
+ content = { :timestamp => Time.now.to_i }
59
+ content.merge!(:owner => cli[:fields][:owner]) if cli[:fields][:owner]
60
+ content.merge!(:reason => cli[:fields][:reason]) if cli[:fields][:reason]
61
+ payload = { :content => content }
62
+ payload.merge!(:expire => cli[:fields][:expire].to_i) if cli[:fields][:expire]
63
+ silence_path = 'silence'
64
+ silence_path << "/#{cli[:fields][:client]}" if cli[:fields][:client]
65
+ silence_path << "/#{cli[:fields][:check]}" if cli[:fields][:check]
66
+ payload = payload.merge!(:path => silence_path).to_json
67
+ respond('/stashes', payload)
68
+ end
69
+
70
+ def aggregates(cli)
71
+ path = '/aggregates'
72
+ path << "/#{cli[:fields][:check]}" if cli[:fields][:check]
73
+ path << "/#{cli[:fields][:id]}" if cli[:fields][:id]
74
+ path << pagination(cli)
75
+ respond(path)
76
+ end
77
+
78
+ def pagination(cli)
79
+ if cli[:fields].key?(:limit) && cli[:fields].key?(:offset)
80
+ "?limit=#{cli[:fields][:limit]}&offset=#{cli[:fields][:offset]}"
81
+ elsif cli[:fields].key?(:limit)
82
+ "?limit=#{cli[:fields][:limit]}"
83
+ else
84
+ ''
85
+ end
86
+ end
87
+
88
+ def method_missing(method_name, *_args)
89
+ puts "Path method: #{method_name} does not exist. "
90
+ end
91
+
92
+ def respond(path, payload = false)
93
+ { :path => path, :payload => payload }
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,136 @@
1
+ require 'rainbow/ext/string'
2
+ require 'hirb'
3
+ require 'json'
4
+ require 'erubis'
5
+
6
+ module SensuCli
7
+ class Pretty
8
+ class << self
9
+ def print(res, endpoint = nil)
10
+ return no_values if res.empty?
11
+ case endpoint
12
+ when 'events'
13
+ template = File.read(File.expand_path(File.join(File.dirname(__FILE__), 'templates/event.erb')))
14
+ renderer = Erubis::Eruby.new(template)
15
+ res.each do |event|
16
+ puts renderer.result(event)
17
+ end
18
+ return
19
+ end
20
+ if res.is_a?(Hash)
21
+ res.each do |key, value|
22
+ puts "#{key}: ".color(:cyan) + "#{value}".color(:green)
23
+ end
24
+ elsif res.is_a?(Array)
25
+ res.each do |item|
26
+ puts '-------'.color(:yellow)
27
+ if item.is_a?(Hash)
28
+ item.each do |key, value|
29
+ puts "#{key}: ".color(:cyan) + "#{value}".color(:green)
30
+ end
31
+ else
32
+ puts item.to_s.color(:cyan)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def json(res)
39
+ puts JSON.pretty_generate(res)
40
+ end
41
+
42
+ def count(res)
43
+ res.is_a?(Hash) ? count = res.length : count = res.count
44
+ puts "#{count} total items".color(:yellow) if count
45
+ end
46
+
47
+ def clean(thing)
48
+ thing = thing.gsub("\n", '/\n') if thing.is_a?(String)
49
+ thing
50
+ end
51
+
52
+ def no_values
53
+ puts 'no values for this request'.color(:cyan)
54
+ end
55
+
56
+ def single(res, endpoint = nil)
57
+ return no_values if res.empty?
58
+ case endpoint
59
+ when 'events'
60
+ res = event_data(res)
61
+ end
62
+ keys = res.map { |item| item.keys }.flatten.uniq.sort
63
+
64
+ # Remove fields with spaces (breaks awkage)
65
+ keys.select! do |key|
66
+ res.none? { |item| item[key].to_s.include?(' ') }
67
+ end
68
+
69
+ # Find max value lengths
70
+ value_lengths = {}
71
+ keys.each do |key|
72
+ max_value_length = res.map { |item| item[key].to_s.length }.max
73
+ value_lengths[key] = [max_value_length, key.length].max
74
+ end
75
+
76
+ # Print header
77
+ lengths = keys.map { |key| "%-#{value_lengths[key]}s" }.join(' ')
78
+ puts format(lengths, *keys)
79
+
80
+ # Print value rows
81
+ res.each do |item|
82
+ if item.is_a?(Hash)
83
+ values = keys.map { |key| item[key] }
84
+ puts format(lengths, *values)
85
+ else
86
+ puts item.to_s.color(:cyan)
87
+ end
88
+ end
89
+ end
90
+
91
+ def parse_fields(fields)
92
+ fields.split(',')
93
+ end
94
+
95
+ def event_data(res)
96
+ events = []
97
+ res.each do |event|
98
+ events << {
99
+ 'client' => event['client']['name'],
100
+ 'address' => event['client']['address'],
101
+ 'check' => event['check']['name'],
102
+ 'interval' => event['check']['interval'],
103
+ 'occurrences' => event['occurrences'],
104
+ 'status' => event['check']['status'],
105
+ 'handlers' => event['check']['handlers'],
106
+ 'issued' => event['check']['issued'],
107
+ 'executed' => event['check']['executed'],
108
+ 'output' => event['check']['output'].rstrip
109
+ }
110
+ end
111
+ events
112
+ end
113
+
114
+ def table(res, endpoint = nil, fields = nil)
115
+ return no_values if res.empty?
116
+ case endpoint
117
+ when 'events'
118
+ keys = %w(check client address interval occurrences status handlers issued executed output)
119
+ render_table(event_data(res), keys)
120
+ else
121
+ if fields
122
+ keys = parse_fields(fields)
123
+ else
124
+ keys = res.map { |item| item.keys }.flatten.uniq
125
+ end
126
+ render_table(res, keys)
127
+ end
128
+ end
129
+
130
+ def render_table(data, keys)
131
+ terminal_size = Hirb::Util.detect_terminal_size
132
+ puts Hirb::Helpers::AutoTable.render(data, :max_width => terminal_size[0], :fields => keys)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,21 @@
1
+ require 'fileutils'
2
+ require 'mixlib/config'
3
+ require 'rainbow/ext/string'
4
+
5
+ module SensuCli
6
+ class Settings
7
+ def file?(file)
8
+ !File.readable?(file) ? false : true # rubocop:disable FavorUnlessOverNegatedIf
9
+ end
10
+
11
+ def create(directory, file)
12
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
13
+ FileUtils.cp(File.join(File.dirname(__FILE__), '../../settings.example.rb'), file)
14
+ SensuCli::die(0, "We created the configuration file for you at #{file}. You can also place this in /etc/sensu/sensu-cli/settings.rb. Edit the settings as needed.".color(:red))
15
+ end
16
+ end
17
+
18
+ class Config
19
+ extend(Mixlib::Config)
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ <%= "-------".color(:yellow) %>
2
+ <%= "id:".color(:blue).bright %> <%= id.to_s.color(:green) %>
3
+ <%= "client name:".color(:blue).bright %> <%= client['name'].to_s.color(:green) %>
4
+ <%= "address:".color(:cyan) %> <%= client['address'].to_s.color(:green) %>
5
+ <%= "subscriptions:".color(:cyan) %> <%= client['subscriptions'].to_s.color(:green) %>
6
+ <%= "version:".color(:cyan) %> <%= client['version'].to_s.color(:green) %>
7
+ <%= "timestamp:".color(:cyan) %> <%= client['timestamp'].to_s.color(:green) %>
8
+ <%= "check name:".color(:blue).bright %> <%= check['name'].to_s.color(:green) %>
9
+ <%= "command:".color(:cyan) %> <%= check['command'].to_s.color(:green) %>
10
+ <%= "handlers:".color(:cyan) %> <%= check['handlers'].to_s.color(:green) %>
11
+ <%= "interval:".color(:cyan) %> <%= check['interval'].to_s.color(:green) %>
12
+ <%= "subscribers:".color(:cyan) %> <%= check['subscribers'].to_s.color(:green) %>
13
+ <%= "issued:".color(:cyan) %> <%= check['issued'].to_s.color(:green) %>
14
+ <%= "executed:".color(:cyan) %> <%= check['executed'].to_s.color(:green) %>
15
+ <%= "duration:".color(:cyan) %> <%= check['duration'].to_s.color(:green) %>
16
+ <%= "output:".color(:cyan) %> <%= check['output'].rstrip.to_s.color(:green) %>
17
+ <%= "status:".color(:cyan) %> <%= check['status'].to_s.color(:green) %>
18
+ <%= "history:".color(:cyan) %> <%= check['history'].to_s.color(:green) %>
19
+ <%= "occurrences:".color(:blue).bright %> <%= occurrences.to_s.color(:green) %>
20
+ <%= "action:".color(:blue).bright %> <%= action.to_s.color(:green) %>
@@ -0,0 +1,3 @@
1
+ module SensuCli
2
+ VERSION = '0.6.3.2'
3
+ end
data/sensu-cli.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), 'lib', 'sensu-cli', 'version')
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'sensu-cli-compat'
5
+ s.version = SensuCli::VERSION
6
+ s.platform = Gem::Platform::RUBY
7
+ s.summary = 'A command line utility for Sensu.'
8
+ s.description = 'A command line utility for interacting with the Sensu api.'
9
+ s.authors = ['Bryan Brandau', 'Rob Thomas']
10
+ s.email = ['agent462@gmail.com', 'xrobau@gmail.com']
11
+ s.has_rdoc = false
12
+ s.licenses = %w(MIT APACHE)
13
+ s.homepage = 'http://github.com/xrobau/sensu-cli'
14
+
15
+ s.add_dependency('rainbow', '1.99.2')
16
+ s.add_dependency('trollop', '2.0')
17
+ s.add_dependency('mixlib-config', '2.1.0')
18
+ s.add_dependency('hirb', '0.7.1')
19
+ s.add_dependency('erubis', '2.7.0')
20
+ s.add_dependency('json', '1.8.1')
21
+
22
+ s.add_development_dependency('rspec')
23
+ s.add_development_dependency('rubocop')
24
+
25
+ s.files = Dir.glob('{bin,lib}/**/*') + %w(sensu-cli.gemspec README.md settings.example.rb)
26
+ s.executables = Dir.glob('bin/**/*').map { |file| File.basename(file) }
27
+ s.require_paths = ['lib']
28
+ end
@@ -0,0 +1,3 @@
1
+ host '127.0.0.1'
2
+ port '4567'
3
+ ssl false
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sensu-cli-compat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.3.2
5
+ platform: ruby
6
+ authors:
7
+ - Bryan Brandau
8
+ - Rob Thomas
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2014-12-04 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rainbow
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.99.2
23
+ type: :runtime
24
+ version_requirements: *id001
25
+ - !ruby/object:Gem::Dependency
26
+ name: trollop
27
+ prerelease: false
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "="
31
+ - !ruby/object:Gem::Version
32
+ version: "2.0"
33
+ type: :runtime
34
+ version_requirements: *id002
35
+ - !ruby/object:Gem::Dependency
36
+ name: mixlib-config
37
+ prerelease: false
38
+ requirement: &id003 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "="
41
+ - !ruby/object:Gem::Version
42
+ version: 2.1.0
43
+ type: :runtime
44
+ version_requirements: *id003
45
+ - !ruby/object:Gem::Dependency
46
+ name: hirb
47
+ prerelease: false
48
+ requirement: &id004 !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.7.1
53
+ type: :runtime
54
+ version_requirements: *id004
55
+ - !ruby/object:Gem::Dependency
56
+ name: erubis
57
+ prerelease: false
58
+ requirement: &id005 !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "="
61
+ - !ruby/object:Gem::Version
62
+ version: 2.7.0
63
+ type: :runtime
64
+ version_requirements: *id005
65
+ - !ruby/object:Gem::Dependency
66
+ name: json
67
+ prerelease: false
68
+ requirement: &id006 !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.8.1
73
+ type: :runtime
74
+ version_requirements: *id006
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ prerelease: false
78
+ requirement: &id007 !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - &id008
81
+ - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ type: :development
85
+ version_requirements: *id007
86
+ - !ruby/object:Gem::Dependency
87
+ name: rubocop
88
+ prerelease: false
89
+ requirement: &id009 !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - *id008
92
+ type: :development
93
+ version_requirements: *id009
94
+ description: A command line utility for interacting with the Sensu api.
95
+ email:
96
+ - agent462@gmail.com
97
+ - xrobau@gmail.com
98
+ executables:
99
+ - sensu
100
+ - sensu-cli
101
+ extensions: []
102
+
103
+ extra_rdoc_files: []
104
+
105
+ files:
106
+ - README.md
107
+ - bin/sensu
108
+ - bin/sensu-cli
109
+ - lib/sensu-cli.rb
110
+ - lib/sensu-cli/api.rb
111
+ - lib/sensu-cli/base.rb
112
+ - lib/sensu-cli/cli.rb
113
+ - lib/sensu-cli/editor.rb
114
+ - lib/sensu-cli/filter.rb
115
+ - lib/sensu-cli/path.rb
116
+ - lib/sensu-cli/pretty.rb
117
+ - lib/sensu-cli/settings.rb
118
+ - lib/sensu-cli/templates/event.erb
119
+ - lib/sensu-cli/version.rb
120
+ - sensu-cli.gemspec
121
+ - settings.example.rb
122
+ homepage: http://github.com/xrobau/sensu-cli
123
+ licenses:
124
+ - MIT
125
+ - APACHE
126
+ metadata: {}
127
+
128
+ post_install_message:
129
+ rdoc_options: []
130
+
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - *id008
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - *id008
139
+ requirements: []
140
+
141
+ rubyforge_project:
142
+ rubygems_version: 2.4.5
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: A command line utility for Sensu.
146
+ test_files: []
147
+