wavefront-cli 2.3.1 → 2.4.0

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.
@@ -0,0 +1,20 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontOutput
4
+ #
5
+ # Display objects in an HCL-compatible way, for use with the
6
+ # Wavefront Terraform provider. We farm everything out, as
7
+ # different resource types need various amounts of massaging. Args
8
+ # are passed through to the child class.
9
+ #
10
+ class Hcl < Base
11
+ def run
12
+ require_relative File.join('hcl', options[:class])
13
+ oclass = Object.const_get(format('WavefrontHclOutput::%s',
14
+ options[:class].to_s.capitalize))
15
+ oclass.new(resp, options).run
16
+ rescue LoadError
17
+ abort "no HCL output for #{options[:class]}."
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontHclOutput
4
+ #
5
+ # Define alerts which can be understood by the Wavefront Terraform
6
+ # provider.
7
+ #
8
+ class Alert < Base
9
+ def hcl_fields
10
+ %w[name target condition additional_information display_expression
11
+ minutes resolve_after_minutes severity tags]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,92 @@
1
+ require 'securerandom'
2
+ require 'json'
3
+
4
+ module WavefrontHclOutput
5
+ class Base
6
+ attr_reader :resp, :options
7
+
8
+ def initialize(resp, options)
9
+ @resp = resp
10
+ @options = options
11
+ end
12
+
13
+ def run
14
+ puts open_output
15
+ required_fields.each { |k, v| puts handler(k, v) }
16
+ puts close_output
17
+ end
18
+
19
+ # Fields which the provider requires.
20
+ # @return [Array] of strings
21
+ #
22
+ def hcl_fields
23
+ []
24
+ end
25
+
26
+ def open_output
27
+ format('resource "wavefront_%s" "%s" {', resource_name,
28
+ SecureRandom.uuid)
29
+ end
30
+
31
+ def close_output
32
+ '}'
33
+ end
34
+
35
+ # Override this if the provider calls a resource something other
36
+ # than the name of the inheriting class
37
+ #
38
+ def resource_name
39
+ options[:class]
40
+ end
41
+
42
+ # The provider can only handle certain keys. Each class should
43
+ # provide a list of things it knows the provider requires. If it
44
+ # does not, we display everything
45
+ #
46
+ def required_fields
47
+ return resp if hcl_fields.empty?
48
+ resp.select { |k, _v| hcl_fields.include?(k) }
49
+ end
50
+
51
+ # Format each key-value pair
52
+ # @param k [String] key
53
+ # @param v [Any] value
54
+ # @return [String]
55
+ #
56
+ def handler(k, v)
57
+ key_handler = "khandle_#{k}".to_sym
58
+ value_handler = "vhandle_#{k}".to_sym
59
+ quote_handler = "qhandle_#{k}".to_sym
60
+ k = send(key_handler) if respond_to?(key_handler)
61
+ v = send(value_handler, v) if respond_to?(value_handler)
62
+
63
+ quote_handler = :quote_value unless respond_to?(quote_handler)
64
+
65
+ format(' %s = %s', k.to_snake, send(quote_handler, v))
66
+ end
67
+
68
+ # Tags need to be in an array. They aren't always called "tags"
69
+ # by the API.
70
+ # @param v [Array,Hash,String] tags
71
+ # @return [Array] of soft-quoted tags
72
+ #
73
+ def vhandle_tags(v)
74
+ v = v.values if v.is_a?(Hash)
75
+ Array(v).flatten
76
+ end
77
+
78
+ # Some values need to be quoted, some need to be escaped etc
79
+ # etc.
80
+ # @param v [Object] value
81
+ # @return [String]
82
+ #
83
+ def quote_value(v)
84
+ case v.class.to_s.to_sym
85
+ when :String
86
+ format('"%s"', v.gsub(/\"/, '\"'))
87
+ else
88
+ v
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,114 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontHclOutput
4
+ #
5
+ # This is a rather kludgy class which generates HCL output
6
+ # suitable for the Wavefront Terraform provider. It has to work
7
+ # round a number of inconsistencies and omissions in said
8
+ # provider, and will have to change as the provider improves.
9
+ #
10
+ # It works, manually, down the hierarchy described
11
+ # in https://github.com/spaceapegames/terraform-provider-wavefront/blob/master/wavefront/resource_dashboard.go
12
+ #
13
+ class Dashboard < Base
14
+
15
+ # Top-level fields
16
+ #
17
+ def hcl_fields
18
+ %w[name description url sections parameter_details tags]
19
+ end
20
+
21
+ def khandle_sections
22
+ 'section'
23
+ end
24
+
25
+ # @param vals [Array] an array of objects
26
+ # @param fn [Symbol] a method which knows how to deal with one
27
+ # of the objects in vals
28
+ # @return [String] HCL list of vals
29
+ #
30
+ def listmaker(vals, fn)
31
+ vals.each_with_object([]) { |v, a| a.<< send(fn, v) }.to_hcl_list
32
+ end
33
+
34
+ def vhandle_sections(v)
35
+ v.each_with_object([]) do |section, a|
36
+ a.<< ("name = \"#{section[:name]}\"\n row = " +
37
+ handle_rows(section[:rows])).braced(4)
38
+ end.to_hcl_list
39
+ end
40
+
41
+ def handle_rows(rows)
42
+ rows.each_with_object([]) do |row, a|
43
+ a.<< ("chart = " + handle_charts(row[:charts]).to_s).braced(8)
44
+ end.to_hcl_list
45
+ end
46
+
47
+ def handle_charts(charts)
48
+ listmaker(charts, :handle_chart)
49
+ end
50
+
51
+ def handle_chart(chart)
52
+ fields = %w[units name description]
53
+
54
+ lines = chart.each_with_object([]) do |(k, v), a|
55
+ a.<< format('%s = %s', k, quote_value(v)) if fields.include?(k)
56
+ end
57
+
58
+ lines.<< "source = #{handle_sources(chart[:sources])}"
59
+ lines.to_hcl_obj(10)
60
+ end
61
+
62
+ def handle_sources(sources)
63
+ listmaker(sources, :handle_source)
64
+ end
65
+
66
+ def handle_source(source)
67
+ fields = %w[name query disabled scatterPlotSource querybuilderEnabled
68
+ sourceDescription]
69
+
70
+ source.each_with_object([]) do |(k, v), a|
71
+ if fields.include?(k)
72
+ k = 'queryBuilderEnabled' if k == 'querybuilderEnabled'
73
+ a.<< format('%s = %s', k.to_snake, quote_value(v))
74
+ end
75
+ end.to_hcl_obj(14)
76
+ end
77
+
78
+ def qhandle_sections(v)
79
+ v
80
+ end
81
+
82
+ def quote_value(v)
83
+ v.gsub!(/\$/, '$$') if v.is_a?(String)
84
+ super
85
+ end
86
+ end
87
+ end
88
+
89
+ class String
90
+ def braced(indent = 0)
91
+ pad = ' ' * indent
92
+ "\n#{pad}{#{self}\n#{pad}}"
93
+ end
94
+ end
95
+
96
+ class Array
97
+ #
98
+ # Turn an array into a string which represents an HCL list
99
+ # @return [String]
100
+ #
101
+ def to_hcl_list
102
+ '[' + self.join(',') + ']'
103
+ end
104
+
105
+ # Turn an array into a string which represents an HCL object
106
+ # @return [String]
107
+ #
108
+ def to_hcl_obj(indent = 0)
109
+ outpad = ' ' * indent
110
+ inpad = ' ' * (indent + 2)
111
+
112
+ "\n#{outpad}{\n#{inpad}" + self.join("\n#{inpad}") + "\n#{outpad}}"
113
+ end
114
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontHclOutput
4
+ #
5
+ # Munge notificant output into something compatible with the
6
+ # Wavefront Terraform provider
7
+ #
8
+ class Notificant < Base
9
+ def hcl_fields
10
+ %w[title description triggers template method recipient emailSubject
11
+ contentType customHttpHeaders]
12
+ end
13
+
14
+ def vhandle_template(v)
15
+ v.gsub(/\s*\n/, '')
16
+ end
17
+
18
+ def resource_name
19
+ 'alert_target'
20
+ end
21
+
22
+ def khandle_title
23
+ 'name'
24
+ end
25
+
26
+ def khandle_customHttpHeaders
27
+ 'custom_headers'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontOutput
4
+ #
5
+ # Display as JSON
6
+ #
7
+ class Json < Base
8
+ def run
9
+ puts resp.to_json
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontOutput
4
+ #
5
+ # Display as a raw Ruby object
6
+ #
7
+ class Ruby < Base
8
+ def run
9
+ p resp
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,257 @@
1
+ MERP MERP
2
+ resource "wavefront_dashboard" "9f8d3f29-d965-4f7e-8473-43571e431b99" {
3
+ name = "JPC Website Host"
4
+ description = "overview of SmartOS zones"
5
+ url = "jpc-webhost"
6
+ section = [
7
+ { name = "Memory"
8
+ row = [
9
+ { chart = [
10
+ {
11
+ units = "B"
12
+ name = "Swap Free"
13
+ description = "Remember, on Solaris, \"swap\" means backing store, so this is all memory."
14
+ source = [
15
+ {
16
+ scatter_plot_source = "Y"
17
+ query_builder_enabled = false
18
+ source_description = ""
19
+ name = "New Query"
20
+ query = "ts(\"tenant.swapresv.value\", env=${env}) - ts(\"tenant.swapresv.usage\", env=${env})"
21
+ }]
22
+ },
23
+ {
24
+ units = ""
25
+ name = "Free Physical Memory"
26
+ source = [
27
+ {
28
+ scatter_plot_source = "Y"
29
+ query_builder_enabled = false
30
+ source_description = ""
31
+ name = "physical memory"
32
+ query = "ts(\"tenant.physicalmem.value\", env=${env}) - ts(\"tenant.physicalmem.usage\", env=${env})"
33
+ },
34
+ {
35
+ scatter_plot_source = "Y"
36
+ query_builder_enabled = true
37
+ source_description = ""
38
+ name = "out of memory"
39
+ query = "0"
40
+ }]
41
+ },
42
+ {
43
+ units = ""
44
+ name = "times over memory"
45
+ source = [
46
+ {
47
+ scatter_plot_source = "Y"
48
+ query_builder_enabled = false
49
+ source_description = ""
50
+ name = "times over memory"
51
+ query = "deriv(ts(\"tenant.memory_cap.nover\", env=${env}))"
52
+ }]
53
+ }]
54
+ },
55
+ { chart = [
56
+ {
57
+ units = "B"
58
+ name = "Sinatra application memory"
59
+ source = [
60
+ {
61
+ scatter_plot_source = "Y"
62
+ query_builder_enabled = false
63
+ source_description = ""
64
+ name = "New Query"
65
+ query = "sum(ts(\"process.memory.pr_rssize.*\", svc=\"svc:/application/sinatra/*\" and env=${env}), svc)"
66
+ }]
67
+ },
68
+ {
69
+ units = ""
70
+ name = "top memory consumers"
71
+ source = [
72
+ {
73
+ scatter_plot_source = "Y"
74
+ query_builder_enabled = false
75
+ source_description = ""
76
+ name = "by process name"
77
+ query = "sum(ts(\"process.memory.pr_rssize.*\", env=${env}), metrics)"
78
+ }]
79
+ }]
80
+ }]
81
+ },
82
+ { name = "nginx"
83
+ row = [
84
+ { chart = [
85
+ {
86
+ units = "req/s"
87
+ name = "\"200\" HTTP requests"
88
+ source = [
89
+ {
90
+ scatter_plot_source = "Y"
91
+ query_builder_enabled = false
92
+ source_description = ""
93
+ name = "Query"
94
+ query = "rate(ts(\"nginx.code.200\"))"
95
+ }]
96
+ },
97
+ {
98
+ units = "ms"
99
+ name = "request latency"
100
+ source = [
101
+ {
102
+ scatter_plot_source = "Y"
103
+ query_builder_enabled = false
104
+ source_description = ""
105
+ name = "total response time"
106
+ query = "ts(\"nginx.time.response.*\")"
107
+ },
108
+ {
109
+ scatter_plot_source = "Y"
110
+ query_builder_enabled = false
111
+ source_description = ""
112
+ name = "upstream response time"
113
+ query = "ts(\"nginx.time.upstream_response.*\")"
114
+ }]
115
+ },
116
+ {
117
+ units = "req/s"
118
+ name = "HTTP Errors"
119
+ source = [
120
+ {
121
+ scatter_plot_source = "Y"
122
+ query_builder_enabled = false
123
+ source_description = ""
124
+ name = "40x"
125
+ query = "ceil(rate(ts(\"nginx.code.4*\")))"
126
+ },
127
+ {
128
+ scatter_plot_source = "Y"
129
+ query_builder_enabled = false
130
+ source_description = ""
131
+ name = "50x"
132
+ query = "ceil(rate(ts(\"nginx.code.5*\")))"
133
+ }]
134
+ }]
135
+ }]
136
+ },
137
+ { name = "Processes and Services"
138
+ row = [
139
+ { chart = [
140
+ {
141
+ units = "processes"
142
+ name = "processes"
143
+ description = "number active processes in zone"
144
+ source = [
145
+ {
146
+ scatter_plot_source = "Y"
147
+ query_builder_enabled = true
148
+ source_description = ""
149
+ name = "running processes"
150
+ query = "ts(\"tenant.nprocs.usage\", env=${env})"
151
+ }]
152
+ },
153
+ {
154
+ units = "services"
155
+ name = "Service States"
156
+ description = "count of services in each possible state. Disabled service are not shown,"
157
+ source = [
158
+ {
159
+ scatter_plot_source = "Y"
160
+ query_builder_enabled = false
161
+ source_description = ""
162
+ name = "New Query"
163
+ query = "ts(\"smf.svcs.*\", env=${env})"
164
+ }]
165
+ }]
166
+ }]
167
+ },
168
+ { name = "Network"
169
+ row = [
170
+ { chart = [
171
+ {
172
+ units = "bytes"
173
+ name = "Network In"
174
+ source = [
175
+ {
176
+ scatter_plot_source = "Y"
177
+ query_builder_enabled = false
178
+ source_description = ""
179
+ name = "New Query"
180
+ query = "deriv(ts(\"network.*.net0.rbytes64\", env=${env}))"
181
+ }]
182
+ },
183
+ {
184
+ units = "bytes"
185
+ name = "Network Out"
186
+ source = [
187
+ {
188
+ scatter_plot_source = "Y"
189
+ query_builder_enabled = false
190
+ source_description = ""
191
+ name = "network out"
192
+ query = "deriv(ts(\"network.*.net0.obytes64\", env=${env}))"
193
+ }]
194
+ }]
195
+ },
196
+ { chart = [
197
+ {
198
+ units = "s"
199
+ name = "Puppet Run Time"
200
+ source = [
201
+ {
202
+ scatter_plot_source = "Y"
203
+ query_builder_enabled = false
204
+ source_description = ""
205
+ name = "time"
206
+ query = "ts(\"puppet.time.*\", env=${env})"
207
+ }]
208
+ },
209
+ {
210
+ units = "Units"
211
+ name = "Puppet Changes"
212
+ description = ""
213
+ source = [
214
+ {
215
+ scatter_plot_source = "Y"
216
+ query_builder_enabled = false
217
+ source_description = ""
218
+ name = "New Query"
219
+ query = "ts(\"puppet.changes.total\")"
220
+ }]
221
+ }]
222
+ }]
223
+ },
224
+ { name = "Page Impressions"
225
+ row = [
226
+ { chart = [
227
+ {
228
+ units = ""
229
+ name = "Most read posts"
230
+ source = [
231
+ {
232
+ scatter_plot_source = "Y"
233
+ query_builder_enabled = false
234
+ source_description = ""
235
+ name = "Query"
236
+ query = "sum(ts(\"nginx.code.200\", vhost=sysdef.xyz and path=\"/post/*\"), pointTags)"
237
+ }]
238
+ }]
239
+ },
240
+ { chart = [
241
+ {
242
+ units = ""
243
+ name = "most viewed pieces"
244
+ description = ""
245
+ source = [
246
+ {
247
+ scatter_plot_source = "Y"
248
+ query_builder_enabled = false
249
+ source_description = ""
250
+ name = "Query"
251
+ query = "sum(ts(\"nginx.code.200\", vhost=\"rdfisher.co.uk\" and path=\"/piece/*\"), pointTags)"
252
+ }]
253
+ }]
254
+ }]
255
+ }]
256
+ tags = []
257
+ }