wavefront-client 3.5.3 → 3.5.4

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 (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