wavefront-cli 0.0.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 +7 -0
- data/.codeclimate.yml +20 -0
- data/.gitignore +4 -0
- data/.travis.yml +16 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +65 -0
- data/README.md +221 -0
- data/Rakefile +18 -0
- data/bin/wavefront +14 -0
- data/lib/wavefront-cli/alert.rb +60 -0
- data/lib/wavefront-cli/base.rb +320 -0
- data/lib/wavefront-cli/cloudintegration.rb +12 -0
- data/lib/wavefront-cli/commands/alert.rb +38 -0
- data/lib/wavefront-cli/commands/base.rb +105 -0
- data/lib/wavefront-cli/commands/dashboard.rb +29 -0
- data/lib/wavefront-cli/commands/event.rb +44 -0
- data/lib/wavefront-cli/commands/integration.rb +33 -0
- data/lib/wavefront-cli/commands/link.rb +34 -0
- data/lib/wavefront-cli/commands/message.rb +23 -0
- data/lib/wavefront-cli/commands/metric.rb +20 -0
- data/lib/wavefront-cli/commands/proxy.rb +25 -0
- data/lib/wavefront-cli/commands/query.rb +32 -0
- data/lib/wavefront-cli/commands/savedsearch.rb +32 -0
- data/lib/wavefront-cli/commands/source.rb +27 -0
- data/lib/wavefront-cli/commands/user.rb +24 -0
- data/lib/wavefront-cli/commands/webhook.rb +25 -0
- data/lib/wavefront-cli/commands/window.rb +33 -0
- data/lib/wavefront-cli/commands/write.rb +35 -0
- data/lib/wavefront-cli/constants.rb +17 -0
- data/lib/wavefront-cli/controller.rb +134 -0
- data/lib/wavefront-cli/dashboard.rb +27 -0
- data/lib/wavefront-cli/display/alert.rb +44 -0
- data/lib/wavefront-cli/display/base.rb +304 -0
- data/lib/wavefront-cli/display/cloudintegration.rb +18 -0
- data/lib/wavefront-cli/display/dashboard.rb +21 -0
- data/lib/wavefront-cli/display/event.rb +19 -0
- data/lib/wavefront-cli/display/externallink.rb +13 -0
- data/lib/wavefront-cli/display/maintenancewindow.rb +19 -0
- data/lib/wavefront-cli/display/message.rb +8 -0
- data/lib/wavefront-cli/display/metric.rb +22 -0
- data/lib/wavefront-cli/display/proxy.rb +13 -0
- data/lib/wavefront-cli/display/query.rb +69 -0
- data/lib/wavefront-cli/display/savedsearch.rb +17 -0
- data/lib/wavefront-cli/display/source.rb +26 -0
- data/lib/wavefront-cli/display/user.rb +16 -0
- data/lib/wavefront-cli/display/webhook.rb +24 -0
- data/lib/wavefront-cli/display/write.rb +19 -0
- data/lib/wavefront-cli/event.rb +162 -0
- data/lib/wavefront-cli/exception.rb +5 -0
- data/lib/wavefront-cli/externallink.rb +16 -0
- data/lib/wavefront-cli/maintenancewindow.rb +16 -0
- data/lib/wavefront-cli/message.rb +19 -0
- data/lib/wavefront-cli/metric.rb +24 -0
- data/lib/wavefront-cli/opt_handler.rb +62 -0
- data/lib/wavefront-cli/proxy.rb +22 -0
- data/lib/wavefront-cli/query.rb +74 -0
- data/lib/wavefront-cli/savedsearch.rb +24 -0
- data/lib/wavefront-cli/source.rb +20 -0
- data/lib/wavefront-cli/user.rb +25 -0
- data/lib/wavefront-cli/version.rb +1 -0
- data/lib/wavefront-cli/webhook.rb +8 -0
- data/lib/wavefront-cli/write.rb +244 -0
- data/spec/spec_helper.rb +197 -0
- data/spec/wavefront-cli/alert_spec.rb +44 -0
- data/spec/wavefront-cli/base_spec.rb +47 -0
- data/spec/wavefront-cli/cli_help_spec.rb +47 -0
- data/spec/wavefront-cli/cloudintegration_spec.rb +24 -0
- data/spec/wavefront-cli/dashboard_spec.rb +37 -0
- data/spec/wavefront-cli/event_spec.rb +19 -0
- data/spec/wavefront-cli/externallink_spec.rb +18 -0
- data/spec/wavefront-cli/maintanancewindow_spec.rb +19 -0
- data/spec/wavefront-cli/message_spec.rb +28 -0
- data/spec/wavefront-cli/metric_spec.rb +22 -0
- data/spec/wavefront-cli/proxy_spec.rb +26 -0
- data/spec/wavefront-cli/query_spec.rb +63 -0
- data/spec/wavefront-cli/resources/conf.yaml +10 -0
- data/spec/wavefront-cli/savedsearch_spec.rb +18 -0
- data/spec/wavefront-cli/source_spec.rb +18 -0
- data/spec/wavefront-cli/user_spec.rb +31 -0
- data/spec/wavefront-cli/webhook_spec.rb +17 -0
- data/wavefront-cli.gemspec +36 -0
- metadata +279 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for cloud integrations.
|
6
|
+
#
|
7
|
+
class CloudIntegration < Base
|
8
|
+
def do_list_brief
|
9
|
+
terse_output(:id, :service)
|
10
|
+
end
|
11
|
+
|
12
|
+
def do_describe
|
13
|
+
readable_time(:lastReceivedDataPointMs, :lastProcessingTimestamp)
|
14
|
+
drop_fields(:forceSave)
|
15
|
+
long_output
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for dashboards.
|
6
|
+
#
|
7
|
+
class Dashboard < Base
|
8
|
+
def do_list
|
9
|
+
long_output [:id, :minutes, :target, :status, :tags, :hostsUsed,
|
10
|
+
:condition, :displayExpression, :severity,
|
11
|
+
:additionalInformation]
|
12
|
+
end
|
13
|
+
|
14
|
+
def do_describe
|
15
|
+
drop_fields(:parameterDetails)
|
16
|
+
readable_time(:updatedEpochMillis)
|
17
|
+
data[:sections] = data[:sections].map { |s| s[:name] }
|
18
|
+
long_output
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'date'
|
2
|
+
require_relative './base'
|
3
|
+
|
4
|
+
module WavefrontDisplay
|
5
|
+
#
|
6
|
+
# Format human-readable output for events.
|
7
|
+
#
|
8
|
+
class Event < Base
|
9
|
+
def do_describe
|
10
|
+
readable_time(:startTime, :endTime, :updatedAt, :createdAt,
|
11
|
+
:createdEpochMillis, :updatedEpochMillis)
|
12
|
+
long_output
|
13
|
+
end
|
14
|
+
|
15
|
+
def do_list_brief
|
16
|
+
terse_output(:id, :runningState)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for maintenance windows.
|
6
|
+
#
|
7
|
+
class MaintenanceWindow < Base
|
8
|
+
def do_describe
|
9
|
+
readable_time(:startTimeInSeconds, :endTimeInSeconds,
|
10
|
+
:createdEpochMillis, :updatedEpochMillis)
|
11
|
+
drop_fields(:hostTagGroupHostNamesGroupAnded, :relevantHostTagsAnded)
|
12
|
+
long_output
|
13
|
+
end
|
14
|
+
|
15
|
+
def do_list_brief
|
16
|
+
terse_output(:id, :title)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for metrics.
|
6
|
+
#
|
7
|
+
class Metric < Base
|
8
|
+
def do_describe
|
9
|
+
if data.hosts.empty?
|
10
|
+
puts "No matches."
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
|
14
|
+
modified_data = data['hosts'].map do |h, aggr|
|
15
|
+
{ host: h[:host],
|
16
|
+
last_update: human_time(h[:last_update]) }
|
17
|
+
end.sort_by{ |h| h[:last_update] }.reverse
|
18
|
+
|
19
|
+
terse_output(:host, :last_update, modified_data)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for queries.
|
6
|
+
#
|
7
|
+
class Query < Base
|
8
|
+
def do_default
|
9
|
+
|
10
|
+
ts = if data.key?(:timeseries)
|
11
|
+
data[:timeseries].each do |s|
|
12
|
+
s[:data] = humanize_series(s[:data])
|
13
|
+
end
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
|
18
|
+
events = if data.key?(:events)
|
19
|
+
data[:events].map { |s| humanize_event(s) }
|
20
|
+
else
|
21
|
+
[]
|
22
|
+
end
|
23
|
+
|
24
|
+
new = {
|
25
|
+
name: data.name,
|
26
|
+
query: data.query,
|
27
|
+
timeseries: ts,
|
28
|
+
events: events
|
29
|
+
}
|
30
|
+
|
31
|
+
@data = new
|
32
|
+
long_output
|
33
|
+
end
|
34
|
+
|
35
|
+
def do_raw
|
36
|
+
data.each { |ts| puts humanize_series(ts[:points]).join("\n") }
|
37
|
+
end
|
38
|
+
|
39
|
+
def do_raw_404
|
40
|
+
puts 'API 404: metric does not exist.'
|
41
|
+
end
|
42
|
+
|
43
|
+
def humanize_event(data)
|
44
|
+
data[:start] = human_time(data[:start])
|
45
|
+
data[:end] = human_time(data[:end]) if data[:end]
|
46
|
+
data.delete(:isEphemeral)
|
47
|
+
data
|
48
|
+
end
|
49
|
+
|
50
|
+
def humanize_series(data)
|
51
|
+
last_date = nil
|
52
|
+
|
53
|
+
data.map! do |row|
|
54
|
+
if row.is_a?(Hash)
|
55
|
+
ht = human_time(row[:timestamp])
|
56
|
+
val = row[:value]
|
57
|
+
else
|
58
|
+
ht = human_time(row[0])
|
59
|
+
val = row[1]
|
60
|
+
end
|
61
|
+
|
62
|
+
date, time = ht.split
|
63
|
+
ds = date == last_date ? '' : date
|
64
|
+
last_date = date
|
65
|
+
format('%12s %s %s', ds, time, val)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for saved searches.
|
6
|
+
#
|
7
|
+
class SavedSearch < Base
|
8
|
+
def do_describe
|
9
|
+
readable_time(:createdEpochMillis, :updatedEpochMillis)
|
10
|
+
long_output
|
11
|
+
end
|
12
|
+
|
13
|
+
def do_list_brief
|
14
|
+
terse_output(:id, :entityType)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for webhooks.
|
6
|
+
#
|
7
|
+
class Source < Base
|
8
|
+
def do_list
|
9
|
+
drop_cluster_sources
|
10
|
+
long_output
|
11
|
+
end
|
12
|
+
|
13
|
+
def do_list_brief
|
14
|
+
drop_cluster_sources
|
15
|
+
terse_output(:id, :description)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Filter out the Wavefront cluster sources
|
19
|
+
#
|
20
|
+
def drop_cluster_sources
|
21
|
+
data.sort_by! { |k, _v| k }
|
22
|
+
return if options[:all]
|
23
|
+
data.delete_if { |k| k.id =~ /prod-[\da-f]{2}-/ }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for user management.
|
6
|
+
#
|
7
|
+
class User < Base
|
8
|
+
def do_list_brief
|
9
|
+
data.each { |user| puts user[:identifier] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def do_delete
|
13
|
+
puts "Deleted user '#{options[:'<id>']}."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
#
|
5
|
+
# Format human-readable output for webhooks.
|
6
|
+
#
|
7
|
+
class Webhook < Base
|
8
|
+
def do_list
|
9
|
+
long_output([:id, :description, :createdEpochMillis,
|
10
|
+
:updatedEpochMillis, :updaterId, :creatorId,
|
11
|
+
:title])
|
12
|
+
end
|
13
|
+
|
14
|
+
def do_list_brief
|
15
|
+
terse_output(:id, :title)
|
16
|
+
end
|
17
|
+
|
18
|
+
def do_describe
|
19
|
+
readable_time(:createdEpochMillis, :updatedEpochMillis)
|
20
|
+
drop_fields(:template)
|
21
|
+
long_output
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module WavefrontDisplay
|
4
|
+
# Format human-readable output when writing points.
|
5
|
+
#
|
6
|
+
class Write < Base
|
7
|
+
def do_point
|
8
|
+
[:sent, :rejected, :unsent].each do |k|
|
9
|
+
puts format(' %12s %d', k.to_s, data[k])
|
10
|
+
end
|
11
|
+
|
12
|
+
exit(data.rejected.zero? && data.unsent.zero? ? 0 : 1)
|
13
|
+
end
|
14
|
+
|
15
|
+
def do_file
|
16
|
+
do_point
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'wavefront-sdk/mixins'
|
3
|
+
require_relative './base'
|
4
|
+
|
5
|
+
EVENT_STATE_DIR = Pathname.new('/var/tmp/wavefront')
|
6
|
+
|
7
|
+
module WavefrontCli
|
8
|
+
#
|
9
|
+
# CLI coverage for the v2 'event' API.
|
10
|
+
#
|
11
|
+
class Event < WavefrontCli::Base
|
12
|
+
attr_reader :state_dir
|
13
|
+
include Wavefront::Mixins
|
14
|
+
|
15
|
+
def post_initialize(_options)
|
16
|
+
begin
|
17
|
+
@state_dir = EVENT_STATE_DIR + Etc.getlogin
|
18
|
+
rescue
|
19
|
+
@state_dir = EVENT_STATE_DIR + 'notty'
|
20
|
+
end
|
21
|
+
|
22
|
+
create_state_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
def do_list
|
26
|
+
options[:start] = Time.now - 600 unless options[:start]
|
27
|
+
options[:end] = Time.now unless options[:end]
|
28
|
+
wf.list(options[:start], options[:end], options[:limit] || 100,
|
29
|
+
options[:offset] || nil)
|
30
|
+
end
|
31
|
+
|
32
|
+
def do_update
|
33
|
+
k, v = options[:'<key=value>'].split('=')
|
34
|
+
wf.update(options[:'<id>'], k => v)
|
35
|
+
end
|
36
|
+
|
37
|
+
def do_create
|
38
|
+
options[:start] = Time.now unless options[:start]
|
39
|
+
|
40
|
+
t_start = parse_time(options[:start], true)
|
41
|
+
id = [t_start, options[:'<event>']].join(':')
|
42
|
+
|
43
|
+
body = { name: options[:'<event>'],
|
44
|
+
startTime: t_start,
|
45
|
+
id: id,
|
46
|
+
annotations: {} }
|
47
|
+
|
48
|
+
body[:annotations][:details] = options[:desc] if options[:desc]
|
49
|
+
body[:annotations][:severity] = options[:severity] if options[:severity]
|
50
|
+
body[:annotations][:type] = options[:type] if options[:type]
|
51
|
+
body[:hosts] = options[:host] if options[:host]
|
52
|
+
|
53
|
+
if options[:instant]
|
54
|
+
body[:endTime] = t_start + 1
|
55
|
+
elsif options[:end]
|
56
|
+
body[:endTime] = parse_time(options[:end], true)
|
57
|
+
end
|
58
|
+
|
59
|
+
resp = wf.create(body)
|
60
|
+
|
61
|
+
unless options[:nostate] || options[:end] || options[:instant]
|
62
|
+
create_state_file(id, options[:host])
|
63
|
+
end
|
64
|
+
|
65
|
+
resp
|
66
|
+
end
|
67
|
+
|
68
|
+
# The user doesn't have to give us an event ID. If no event
|
69
|
+
# name is given, we'll pop the last event off the stack. If an
|
70
|
+
# event name is given and it doesn't look like a full WF event
|
71
|
+
# name, we'll look for something on the stack. If it does look
|
72
|
+
# like a real event, we'll make and API call straight away.
|
73
|
+
#
|
74
|
+
def do_close
|
75
|
+
ev_file = nil
|
76
|
+
|
77
|
+
ev = if options[:'<id>'] == false
|
78
|
+
pop_event
|
79
|
+
elsif options[:'<id>'] =~ /^\d{13}:.+/
|
80
|
+
ev_file = state_dir + options[:'<id>']
|
81
|
+
options[:'<id>']
|
82
|
+
else
|
83
|
+
pop_event(options[:'<id>'])
|
84
|
+
end
|
85
|
+
|
86
|
+
abort "No locally stored event matches '#{options[:'<id>']}'." unless ev
|
87
|
+
|
88
|
+
res = wf.close(ev)
|
89
|
+
ev_file.unlink if ev_file && ev_file.exist? && res.status.code == 200
|
90
|
+
res
|
91
|
+
end
|
92
|
+
|
93
|
+
def do_show
|
94
|
+
begin
|
95
|
+
events = state_dir.children
|
96
|
+
rescue Errno::ENOENT
|
97
|
+
raise 'There is no event state directory on this host.'
|
98
|
+
end
|
99
|
+
|
100
|
+
if events.size.zero?
|
101
|
+
puts 'No open events.'
|
102
|
+
else
|
103
|
+
events.sort.reverse.each { |e| puts e.basename }
|
104
|
+
end
|
105
|
+
|
106
|
+
exit
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# Write a state file. We put the hosts bound to the event into the
|
112
|
+
# file. These aren't currently used by anything in the CLI, but they
|
113
|
+
# might be useful to someone, somewhere, someday.
|
114
|
+
#
|
115
|
+
def create_state_file(id, hosts = [])
|
116
|
+
puts "statfile fir #{id}"
|
117
|
+
fname = state_dir + id
|
118
|
+
|
119
|
+
begin
|
120
|
+
File.open(fname, 'w') { hosts.to_s }
|
121
|
+
rescue
|
122
|
+
raise 'Event was created but state file was not.'
|
123
|
+
end
|
124
|
+
|
125
|
+
puts "Event state recorded at #{fname}."
|
126
|
+
end
|
127
|
+
|
128
|
+
def create_state_dir
|
129
|
+
FileUtils.mkdir_p(state_dir)
|
130
|
+
return true if state_dir.exist? && state_dir.directory? &&
|
131
|
+
state_dir.writable?
|
132
|
+
raise 'Cannot create state directory.'
|
133
|
+
end
|
134
|
+
|
135
|
+
def validate_input
|
136
|
+
validate_id if options[:'<id>'] && !options[:close]
|
137
|
+
validate_tags if options[:'<tag>']
|
138
|
+
send(:extra_validation) if respond_to?(:extra_validation)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Get the last event this script created. If you supply a name, you
|
142
|
+
# get the last event with that name. If not, you get the last event.
|
143
|
+
# Chances are you'll only ever have one in-play at once.
|
144
|
+
#
|
145
|
+
# @param name [String] name of event
|
146
|
+
# Returns an array of [timestamp, event_name]
|
147
|
+
#
|
148
|
+
def pop_event(name = false)
|
149
|
+
return false unless state_dir.exist?
|
150
|
+
|
151
|
+
list = state_dir.children
|
152
|
+
|
153
|
+
list.select! { |f| f.basename.to_s.split(':').last == name } if name
|
154
|
+
|
155
|
+
return false if list.empty?
|
156
|
+
|
157
|
+
ev_file = list.sort.last
|
158
|
+
File.unlink(ev_file)
|
159
|
+
ev_file.basename.to_s
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|