wavefront-client 3.5.3 → 3.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -2
  3. data/README-cli.md +84 -60
  4. data/bin/wavefront +84 -69
  5. data/lib/wavefront/alerting.rb +14 -3
  6. data/lib/wavefront/batch_writer.rb +7 -0
  7. data/lib/wavefront/cli.rb +15 -17
  8. data/lib/wavefront/cli/alerts.rb +15 -10
  9. data/lib/wavefront/cli/batch_write.rb +12 -3
  10. data/lib/wavefront/cli/events.rb +19 -3
  11. data/lib/wavefront/cli/sources.rb +22 -12
  12. data/lib/wavefront/cli/ts.rb +9 -1
  13. data/lib/wavefront/cli/write.rb +7 -0
  14. data/lib/wavefront/client.rb +9 -5
  15. data/lib/wavefront/client/version.rb +1 -1
  16. data/lib/wavefront/constants.rb +20 -0
  17. data/lib/wavefront/events.rb +26 -4
  18. data/lib/wavefront/metadata.rb +23 -6
  19. data/lib/wavefront/opt_handler.rb +61 -0
  20. data/spec/cli_spec.rb +584 -0
  21. data/spec/spec_helper.rb +42 -0
  22. data/spec/wavefront/alerting_spec.rb +8 -9
  23. data/spec/wavefront/batch_writer_spec.rb +1 -1
  24. data/spec/wavefront/cli/alerts_spec.rb +5 -4
  25. data/spec/wavefront/cli/batch_write_spec.rb +4 -2
  26. data/spec/wavefront/cli/events_spec.rb +3 -2
  27. data/spec/wavefront/cli/sources_spec.rb +3 -2
  28. data/spec/wavefront/cli/write_spec.rb +4 -2
  29. data/spec/wavefront/cli_spec.rb +11 -43
  30. data/spec/wavefront/client_spec.rb +2 -2
  31. data/spec/wavefront/events_spec.rb +1 -1
  32. data/spec/wavefront/metadata_spec.rb +1 -1
  33. data/spec/wavefront/mixins_spec.rb +1 -1
  34. data/spec/wavefront/opt_handler_spec.rb +89 -0
  35. data/spec/wavefront/resources/conf.yaml +10 -0
  36. data/spec/wavefront/response_spec.rb +3 -3
  37. data/spec/wavefront/validators_spec.rb +1 -1
  38. data/spec/wavefront/writer_spec.rb +1 -1
  39. metadata +9 -3
  40. data/.ruby-version +0 -1
@@ -17,6 +17,7 @@ See the License for the specific language governing permissions and
17
17
  require "wavefront/client/version"
18
18
  require "wavefront/constants"
19
19
  require 'wavefront/mixins'
20
+ require 'wavefront/validators'
20
21
  require 'rest_client'
21
22
  require 'uri'
22
23
  require 'logger'
@@ -28,11 +29,18 @@ module Wavefront
28
29
  include Wavefront::Mixins
29
30
  DEFAULT_PATH = '/api/alert/'
30
31
 
31
- attr_reader :token
32
+ attr_reader :token, :noop, :verbose, :endpoint
32
33
 
33
- def initialize(token, debug=false)
34
+ def initialize(token, host = DEFAULT_HOST, debug=false, options = {})
35
+ #
36
+ # Following existing convention, 'host' is the Wavefront API endpoint.
37
+ #
38
+ @headers = { :'X-AUTH-TOKEN' => token }
39
+ @endpoint = host
34
40
  @token = token
35
41
  debug(debug)
42
+ @noop = options[:noop]
43
+ @verbose = options[:verbose]
36
44
  end
37
45
 
38
46
  def active(options={})
@@ -76,7 +84,7 @@ module Wavefront
76
84
  end
77
85
 
78
86
  def get_alerts(path, options={})
79
- options[:host] ||= DEFAULT_HOST
87
+ options[:host] ||= endpoint
80
88
  options[:path] ||= DEFAULT_PATH
81
89
 
82
90
  uri = URI::HTTPS.build(
@@ -85,6 +93,9 @@ module Wavefront
85
93
  query: mk_qs(options),
86
94
  )
87
95
 
96
+ puts "GET #{uri.to_s}" if (verbose || noop)
97
+ return if noop
98
+
88
99
  RestClient.get(uri.to_s)
89
100
  end
90
101
 
@@ -66,12 +66,15 @@ module Wavefront
66
66
  rejected: 0,
67
67
  unsent: 0,
68
68
  }
69
+
69
70
  @opts = setup_options(options, defaults)
70
71
 
71
72
  if opts[:tags]
72
73
  valid_tags?(opts[:tags])
73
74
  @global_tags = opts[:tags]
74
75
  end
76
+
77
+ debug(options[:debug])
75
78
  end
76
79
 
77
80
  def setup_options(user, defaults)
@@ -210,5 +213,9 @@ module Wavefront
210
213
  puts 'Closing connection to proxy.' if opts[:verbose]
211
214
  sock.close
212
215
  end
216
+
217
+ def debug(enabled)
218
+ RestClient.log = 'stdout' if enabled
219
+ end
213
220
  end
214
221
  end
@@ -14,16 +14,19 @@ See the License for the specific language governing permissions and
14
14
 
15
15
  =end
16
16
 
17
- require 'inifile'
17
+ require 'wavefront/constants'
18
18
 
19
19
  module Wavefront
20
+ #
21
+ # Parent of all the CLI classes.
22
+ #
20
23
  class Cli
21
-
22
- attr_accessor :options, :arguments
24
+ attr_accessor :options, :arguments, :noop
23
25
 
24
26
  def initialize(options, arguments)
25
27
  @options = options
26
28
  @arguments = arguments
29
+ @noop = options[:noop]
27
30
 
28
31
  if options.include?(:help) && options[:help]
29
32
  puts options
@@ -31,22 +34,17 @@ module Wavefront
31
34
  end
32
35
  end
33
36
 
34
- def load_profile
37
+ def validate_opts
35
38
  #
36
- # Load in configuration options from the (optionally) given
37
- # section of an ini-style configuration file. If the file's
38
- # not there, we don't consider that an error.
39
+ # There are things we need to have. If we don't have them,
40
+ # stop the user right now. Also, if we're in debug mode, print
41
+ # out a hash of options, which can be very useful when doing
42
+ # actual debugging. Some classes may have to override this
43
+ # method. The writer, for instance, uses a proxy and has no
44
+ # token.
39
45
  #
40
- return unless options[:config].is_a?(String)
41
- cf = Pathname.new(options[:config])
42
- return unless cf.exist?
43
-
44
- pf = options[:profile] || 'default'
45
- puts "using #{pf} profile from #{cf}" if options[:debug]
46
-
47
- IniFile.load(cf)[pf].each_with_object({}) do |(k, v), memo|
48
- memo[k.to_sym] = v
49
- end
46
+ raise 'Please supply an API token.' unless options[:token]
47
+ raise 'Please supply an API endpoint.' unless options[:endpoint]
50
48
  end
51
49
  end
52
50
  end
@@ -28,9 +28,11 @@ class Wavefront::Cli::Alerts < Wavefront::Cli
28
28
  raise 'Missing query.' if arguments.empty?
29
29
  query = arguments[0].to_sym
30
30
 
31
- wfa = Wavefront::Alerting.new(@options[:token])
31
+ wfa = Wavefront::Alerting.new(@options[:token], @options[:endpoint],
32
+ @options[:debug], {
33
+ noop: @options[:noop], verbose: @options[:verbose]})
32
34
  valid_state?(wfa, query)
33
- valid_format?(@options[:format].to_sym)
35
+ valid_format?(@options[:alertformat].to_sym)
34
36
  options = { host: @options[:endpoint] }
35
37
 
36
38
  if @options[:shared]
@@ -43,11 +45,12 @@ class Wavefront::Cli::Alerts < Wavefront::Cli
43
45
 
44
46
  begin
45
47
  result = wfa.send(query, options)
46
- rescue
48
+ rescue => e
49
+ puts e if @options[:debug]
47
50
  raise 'Unable to execute query.'
48
51
  end
49
52
 
50
- format_result(result, @options[:format].to_sym)
53
+ format_result(result, @options[:alertformat].to_sym)
51
54
  exit
52
55
  end
53
56
 
@@ -56,6 +59,8 @@ class Wavefront::Cli::Alerts < Wavefront::Cli
56
59
  # Call a suitable method to display the output of the API call,
57
60
  # which is JSON.
58
61
  #
62
+ return if noop
63
+
59
64
  case format
60
65
  when :ruby
61
66
  pp result
@@ -83,11 +88,10 @@ class Wavefront::Cli::Alerts < Wavefront::Cli
83
88
  # Check the alert type we've been given is valid. There needs to
84
89
  # be a public method in the 'alerting' class for every one.
85
90
  #
86
- s = wfa.public_methods(false).sort
87
- s.delete(:token)
88
- unless s.include?(state)
89
- raise 'State must be one of: ' + s.each { |q| q.to_s }.join(', ') +
90
- '.'
91
+ states = %w(active affected_by_maintenance all invalid snoozed)
92
+
93
+ unless states.include?(state.to_s)
94
+ raise "State must be one of: #{states.join(', ')}."
91
95
  end
92
96
  true
93
97
  end
@@ -120,7 +124,7 @@ class Wavefront::Cli::Alerts < Wavefront::Cli
120
124
  else
121
125
  human_line(key, alert[key])
122
126
  end
123
- end
127
+ end.<< ''
124
128
  end
125
129
  end
126
130
 
@@ -166,6 +170,7 @@ class Wavefront::Cli::Alerts < Wavefront::Cli
166
170
  #
167
171
  # hanging indent long lines to fit in an 80-column terminal
168
172
  #
173
+ return unless line
169
174
  line.gsub(/(.{1,#{cols - offset}})(\s+|\Z)/, "\\1\n#{' ' *
170
175
  offset}").rstrip
171
176
  end
@@ -12,14 +12,23 @@ class Wavefront::Cli::BatchWrite < Wavefront::Cli
12
12
  include Wavefront::Constants
13
13
  include Wavefront::Mixins
14
14
 
15
+ def validate_opts
16
+ #
17
+ # Unlike all the API methods, we don't need a token here
18
+ #
19
+ abort 'Please supply a proxy endpoint.' unless options[:proxy]
20
+ end
21
+
15
22
  def run
16
- raise 'Invalid format string.' unless valid_format?(options[:format])
23
+ unless valid_format?(options[:infileformat])
24
+ raise 'Invalid format string.'
25
+ end
17
26
 
18
27
  file = options[:'<file>']
19
28
  setup_opts(options)
20
29
 
21
- if options.key?(:format)
22
- setup_fmt(options[:format])
30
+ if options.key?(:infileformat)
31
+ setup_fmt(options[:infileformat])
23
32
  else
24
33
  setup_fmt
25
34
  end
@@ -27,7 +27,8 @@ require 'socket'
27
27
  # in a timeseries API call.
28
28
  #
29
29
  class Wavefront::Cli::Events < Wavefront::Cli
30
- attr_accessor :state_dir, :hosts, :hostname, :t_start, :t_end, :wf_event
30
+ attr_accessor :state_dir, :hosts, :hostname, :t_start, :t_end,
31
+ :wf_event
31
32
 
32
33
  include Wavefront::Constants
33
34
  include Wavefront::Mixins
@@ -43,8 +44,11 @@ class Wavefront::Cli::Events < Wavefront::Cli
43
44
  @hosts = prep_hosts(options[:host])
44
45
  @t_start = prep_time(:start)
45
46
  @t_end = prep_time(:end)
47
+ @noop = options[:noop]
46
48
 
47
- @wf_event = Wavefront::Events.new(options[:token])
49
+ @wf_event = Wavefront::Events.new(
50
+ options[:token], options[:endpoint], options[:debug],
51
+ { verbose: options[:verbose], noop: options[:noop]})
48
52
 
49
53
  if options[:create]
50
54
  create_event_handler
@@ -77,7 +81,7 @@ class Wavefront::Cli::Events < Wavefront::Cli
77
81
  raise 'Cannot delete event.'
78
82
  end
79
83
 
80
- puts 'Deleted event.'
84
+ puts 'Deleted event.' unless noop
81
85
  end
82
86
 
83
87
  def prep_time(t)
@@ -104,6 +108,8 @@ class Wavefront::Cli::Events < Wavefront::Cli
104
108
  #
105
109
  output = create_event
106
110
 
111
+ return if noop
112
+
107
113
  unless options[:end] || options[:instant]
108
114
  create_state_dir
109
115
  create_state_file(output) unless options[:nostate]
@@ -211,6 +217,7 @@ class Wavefront::Cli::Events < Wavefront::Cli
211
217
  #
212
218
  # Returns an array of [timestamp, event_name]
213
219
  #
220
+ return false unless state_dir.exist?
214
221
  list = state_dir.children
215
222
  list.select! { |f| f.basename.to_s.split('::').last == name } if name
216
223
  return false if list.length == 0
@@ -249,4 +256,13 @@ class Wavefront::Cli::Events < Wavefront::Cli
249
256
 
250
257
  puts "Event state recorded at #{fname}."
251
258
  end
259
+
260
+ def validate_opts
261
+ #
262
+ # the 'show' sub-command does not make an API call
263
+ #
264
+ return true if options[:show]
265
+ abort 'Please supply an API token.' unless options[:token]
266
+ abort 'Please supply an API endpoint.' unless options[:endpoint]
267
+ end
252
268
  end
@@ -7,18 +7,21 @@ require 'pp'
7
7
  # Turn CLI input, from the 'sources' command, into metadata API calls
8
8
  #
9
9
  class Wavefront::Cli::Sources < Wavefront::Cli
10
- attr_accessor :wf, :out_format, :show_hidden, :show_tags
10
+ attr_accessor :wf, :out_format, :show_hidden, :show_tags, :verbose
11
11
 
12
12
  def setup_wf
13
13
  @wf = Wavefront::Metadata.new(options[:token], options[:endpoint],
14
- false, { verbose: options[:verbose] })
14
+ options[:debug],
15
+ { verbose: options[:verbose],
16
+ noop: options[:noop]})
15
17
  end
16
18
 
17
19
  def run
18
20
  setup_wf
19
- @out_format = options[:format]
21
+ @out_format = options[:sourceformat].to_s
20
22
  @show_hidden = options[:all]
21
23
  @show_tags = options[:tags]
24
+ @verbose = options[:verbose]
22
25
 
23
26
  begin
24
27
  if options[:list]
@@ -49,17 +52,20 @@ class Wavefront::Cli::Sources < Wavefront::Cli
49
52
 
50
53
  q = {
51
54
  desc: false,
52
- limit: limit,
55
+ limit: limit.to_i,
53
56
  pattern: pattern
54
57
  }
55
58
 
56
59
  q[:lastEntityId] = start if start
57
60
 
58
- display_data(wf.show_sources(q), 'list_source')
61
+ res = wf.show_sources(q)
62
+ return if noop
63
+ display_data(res, 'list_source')
59
64
  end
60
65
 
61
66
  def describe_handler(hosts, desc)
62
67
  hosts = [Socket.gethostname] if hosts.empty?
68
+ hosts = [hosts] if hosts.is_a?(String)
63
69
 
64
70
  hosts.each do |h|
65
71
  if desc.empty?
@@ -77,20 +83,22 @@ class Wavefront::Cli::Sources < Wavefront::Cli
77
83
  end
78
84
 
79
85
  def untag_handler(hosts)
80
- hosts ||= [Socket.gethostname]
86
+ hosts ||= Socket.gethostname
87
+ hosts = [hosts] if hosts.is_a?(String)
81
88
 
82
89
  hosts.each do |h|
83
- puts "Removing all tags from '#{h}'"
90
+ puts "Removing all tags from '#{h}'" if verbose
84
91
  wf.delete_tags(h)
85
92
  end
86
93
  end
87
94
 
88
95
  def add_tag_handler(hosts, tags)
89
- hosts ||= [Socket.gethostname]
96
+ hosts ||= Socket.gethostname
97
+ hosts = [hosts] if hosts.is_a?(String)
90
98
 
91
99
  hosts.each do |h|
92
100
  tags.each do |t|
93
- puts "Tagging '#{h}' with '#{t}'"
101
+ puts "Tagging '#{h}' with '#{t}'" if verbose
94
102
  begin
95
103
  wf.set_tag(h, t)
96
104
  rescue Wavefront::Exception::InvalidString
@@ -101,11 +109,12 @@ class Wavefront::Cli::Sources < Wavefront::Cli
101
109
  end
102
110
 
103
111
  def delete_tag_handler(hosts, tags)
104
- hosts ||= [Socket.gethostname]
112
+ hosts ||= Socket.gethostname
113
+ hosts = [hosts] if hosts.is_a?(String)
105
114
 
106
115
  hosts.each do |h|
107
116
  tags.each do |t|
108
- puts "Removing tag '#{t}' from '#{h}'"
117
+ puts "Removing tag '#{t}' from '#{h}'" if verbose
109
118
  wf.delete_tag(h, t)
110
119
  end
111
120
  end
@@ -125,6 +134,7 @@ class Wavefront::Cli::Sources < Wavefront::Cli
125
134
  end
126
135
 
127
136
  def display_data(result, method)
137
+ return if noop
128
138
  if out_format == 'human'
129
139
  puts public_send('humanize_' + method, result)
130
140
  elsif out_format == 'json'
@@ -146,7 +156,7 @@ class Wavefront::Cli::Sources < Wavefront::Cli
146
156
  if options[:tagged]
147
157
  skip = false
148
158
  options[:tagged].each do |t|
149
- unless s['userTags'].include?(t)
159
+ unless s.key?('userTags') && s['userTags'].include?(t)
150
160
  skip = true
151
161
  break
152
162
  end
@@ -55,8 +55,16 @@ class Wavefront::Cli::Ts < Wavefront::Cli
55
55
  options[:end_time] = Time.at(parse_time(@options[:end]))
56
56
  end
57
57
 
58
- wave = Wavefront::Client.new(@options[:token], @options[:endpoint], @options[:debug])
58
+ wave = Wavefront::Client.new(@options[:token], @options[:endpoint], @options[:debug], { noop: @options[:noop], verbose: @options[:verbose]})
59
+
60
+ if noop
61
+ wave.query(query, granularity, options)
62
+ return
63
+ end
64
+
59
65
  case options[:response_format]
66
+ when :json
67
+ pp wave.query(query, granularity, options)
60
68
  when :raw
61
69
  puts wave.query(query, granularity, options)
62
70
  when :graphite
@@ -12,6 +12,13 @@ class Wavefront::Cli::Write < Wavefront::Cli
12
12
  include Wavefront::Constants
13
13
  include Wavefront::Mixins
14
14
 
15
+ def validate_opts
16
+ #
17
+ # Unlike all the API methods, we don't need a token here
18
+ #
19
+ abort 'Please supply a proxy endpoint.' unless options[:proxy]
20
+ end
21
+
15
22
  def run
16
23
  valid_value?(options[:'<value>'])
17
24
  valid_metric?(options[:'<metric>'])
@@ -28,16 +28,17 @@ module Wavefront
28
28
  include Wavefront::Constants
29
29
  DEFAULT_PATH = '/chart/api'
30
30
 
31
- attr_reader :headers, :base_uri
31
+ attr_reader :headers, :base_uri, :noop, :verbose
32
32
 
33
- def initialize(token, host=DEFAULT_HOST, debug=false)
33
+ def initialize(token, host=DEFAULT_HOST, debug=false, options = {})
34
+ @verbose = options[:verbose]
35
+ @noop = options[:noop]
34
36
  @headers = {'X-AUTH-TOKEN' => token}
35
37
  @base_uri = URI::HTTPS.build(:host => host, :path => DEFAULT_PATH)
36
38
  debug(debug)
37
39
  end
38
40
 
39
41
  def query(query, granularity='m', options={})
40
-
41
42
  options[:end_time] ||= Time.now.utc
42
43
  options[:start_time] ||= options[:end_time] - DEFAULT_PERIOD_SECONDS
43
44
  options[:response_format] ||= DEFAULT_FORMAT
@@ -48,7 +49,7 @@ module Wavefront
48
49
  [ options[:start_time], options[:end_time] ].each { |o| raise Wavefront::Exception::InvalidTimeFormat unless o.is_a?(Time) }
49
50
  raise Wavefront::Exception::InvalidGranularity unless GRANULARITIES.include?(granularity)
50
51
  raise Wavefront::Exception::InvalidResponseFormat unless FORMATS.include?(options[:response_format])
51
- raise InvalidPrefixLength unless options[:prefix_length].is_a?(Fixnum)
52
+ raise InvalidPrefixLength unless options[:prefix_length].is_a?(Integer)
52
53
 
53
54
  args = {:params =>
54
55
  {:q => query, :g => granularity, :n => 'Unknown',
@@ -62,11 +63,14 @@ module Wavefront
62
63
  args[:params].merge!(options[:passthru])
63
64
  end
64
65
 
66
+ puts "GET #{@base_uri.to_s}\nPARAMS #{args.to_s}" if (verbose || noop)
67
+
68
+ return if noop
69
+
65
70
  response = RestClient.get @base_uri.to_s, args
66
71
 
67
72
  klass = Object.const_get('Wavefront').const_get('Response').const_get(options[:response_format].to_s.capitalize)
68
73
  return klass.new(response, options)
69
-
70
74
  end
71
75
 
72
76
  private