dropsonde 0.0.2 → 0.0.6
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 +4 -4
- data/README.md +20 -7
- data/bin/dropsonde +60 -17
- data/lib/dropsonde/cache.rb +42 -31
- data/lib/dropsonde/metrics/dependencies.rb +46 -25
- data/lib/dropsonde/metrics/environments.rb +53 -0
- data/lib/dropsonde/metrics/modules.rb +86 -53
- data/lib/dropsonde/metrics/platforms.rb +126 -0
- data/lib/dropsonde/metrics/puppetfiles.rb +44 -25
- data/lib/dropsonde/metrics.rb +116 -76
- data/lib/dropsonde/monkeypatches.rb +12 -11
- data/lib/dropsonde/version.rb +3 -1
- data/lib/dropsonde.rb +75 -24
- metadata +6 -4
data/lib/dropsonde/metrics.rb
CHANGED
@@ -1,86 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'little-plugger'
|
4
|
+
require 'securerandom'
|
2
5
|
|
6
|
+
# metrics class
|
3
7
|
class Dropsonde::Metrics
|
4
|
-
extend LittlePlugger(
|
8
|
+
extend LittlePlugger(path: 'dropsonde/metrics', module: Dropsonde::Metrics)
|
5
9
|
|
6
10
|
def initialize
|
7
|
-
Dropsonde
|
11
|
+
if Dropsonde.settings[:enable]
|
12
|
+
Dropsonde.settings[:disable] ||= []
|
13
|
+
disable = Dropsonde::Metrics.plugins.keys - Dropsonde.settings[:enable].map(&:to_sym)
|
14
|
+
Dropsonde.settings[:disable].concat disable
|
15
|
+
end
|
16
|
+
|
17
|
+
Dropsonde::Metrics.disregard_plugins(*Dropsonde.settings[:disable])
|
8
18
|
Dropsonde::Metrics.initialize_plugins
|
9
19
|
end
|
10
20
|
|
11
21
|
def siteid
|
12
22
|
return @siteid if @siteid
|
13
23
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
24
|
+
@siteid = Dropsonde.settings[:siteid]
|
25
|
+
|
26
|
+
unless @siteid
|
27
|
+
sha2 = Digest::SHA512.new
|
28
|
+
sha2.update Puppet.settings[:certname]
|
29
|
+
sha2.update Puppet.settings[:cacert]
|
30
|
+
sha2.update Dropsonde.settings[:seed] if Dropsonde.settings[:seed]
|
31
|
+
@siteid = sha2.hexdigest
|
32
|
+
end
|
33
|
+
|
19
34
|
@siteid
|
20
35
|
end
|
21
36
|
|
22
37
|
def list
|
23
|
-
str
|
24
|
-
str
|
38
|
+
str = " Loaded telemetry plugins\n"
|
39
|
+
str += " ===============================\n\n"
|
25
40
|
Dropsonde::Metrics.plugins.each do |name, plugin|
|
26
|
-
str
|
27
|
-
str
|
28
|
-
str
|
29
|
-
str
|
41
|
+
str += name.to_s
|
42
|
+
str += "\n--------\n"
|
43
|
+
str += plugin.description.strip
|
44
|
+
str += "\n\n"
|
30
45
|
end
|
31
|
-
if Dropsonde.settings[:
|
32
|
-
str
|
33
|
-
str
|
46
|
+
if Dropsonde.settings[:disable]
|
47
|
+
str += "Disabled plugins:\n"
|
48
|
+
str += " #{Dropsonde.settings[:disable].join(', ')}"
|
34
49
|
end
|
35
50
|
str
|
36
51
|
end
|
37
52
|
|
38
53
|
def schema
|
39
54
|
schema = skeleton_schema
|
40
|
-
Dropsonde::Metrics.plugins.each do |
|
55
|
+
Dropsonde::Metrics.plugins.each do |_name, plugin|
|
41
56
|
schema.concat(sanity_check_schema(plugin))
|
42
57
|
end
|
43
58
|
check_for_duplicates(schema)
|
44
59
|
schema
|
45
60
|
end
|
46
61
|
|
47
|
-
def preview
|
48
|
-
str
|
49
|
-
str
|
50
|
-
Dropsonde::Metrics.plugins.each do |
|
62
|
+
def preview(puppetdb_session = nil)
|
63
|
+
str = " Puppet Telemetry Report Preview\n"
|
64
|
+
str += " ===============================\n\n"
|
65
|
+
Dropsonde::Metrics.plugins.each do |_name, plugin|
|
51
66
|
schema = plugin.schema
|
52
67
|
|
53
|
-
plugin.setup
|
54
|
-
data = sanity_check_data(plugin)
|
55
|
-
plugin.cleanup
|
68
|
+
plugin.setup if plugin.respond_to? :setup
|
69
|
+
data = sanity_check_data(plugin, plugin.run(puppetdb_session))
|
70
|
+
plugin.cleanup if plugin.respond_to? :cleanup
|
56
71
|
|
57
|
-
str
|
58
|
-
str
|
59
|
-
str
|
72
|
+
str += "#{plugin.name}\n"
|
73
|
+
str += "-------------------------------\n"
|
74
|
+
str += plugin.description
|
60
75
|
data.each do |row|
|
61
76
|
key = row.keys.first
|
62
|
-
values = row.values.
|
77
|
+
values = row.values.flatten
|
63
78
|
|
64
|
-
desc = schema.find {|item| item[:name].to_sym == key.to_sym}[:description]
|
65
|
-
str
|
79
|
+
desc = schema.find { |item| item[:name].to_sym == key.to_sym }[:description]
|
80
|
+
str += "- #{key}: #{desc}\n"
|
66
81
|
values.each do |item|
|
67
|
-
str
|
82
|
+
str += " #{item}\n"
|
68
83
|
end
|
69
84
|
end
|
70
|
-
str
|
85
|
+
str += "\n\n"
|
71
86
|
end
|
72
|
-
str
|
73
|
-
str
|
87
|
+
str += "Site ID:\n"
|
88
|
+
str += siteid
|
74
89
|
str
|
75
90
|
end
|
76
91
|
|
77
|
-
def report
|
92
|
+
def report(puppetdb_session = nil)
|
78
93
|
snapshots = {}
|
79
|
-
Dropsonde::Metrics.plugins.each do |
|
94
|
+
Dropsonde::Metrics.plugins.each do |_name, plugin|
|
80
95
|
plugin.setup
|
81
|
-
sanity_check_data(plugin).each do |row|
|
96
|
+
sanity_check_data(plugin, plugin.run(puppetdb_session)).each do |row|
|
82
97
|
snapshots[row.keys.first] = {
|
83
|
-
'value'
|
98
|
+
'value' => row.values.first,
|
84
99
|
'timestamp' => Time.now.iso8601,
|
85
100
|
}
|
86
101
|
end
|
@@ -92,10 +107,31 @@ class Dropsonde::Metrics
|
|
92
107
|
results
|
93
108
|
end
|
94
109
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
110
|
+
def example
|
111
|
+
require 'ipaddr'
|
112
|
+
results = skeleton_report
|
113
|
+
results[:message_id] = generate_guid
|
114
|
+
results[:timestamp] = rand((Time.now - 60 * 60 * 24 * 365)..Time.now).utc
|
115
|
+
results[:ip] = IPAddr.new(rand(2**32), Socket::AF_INET)
|
116
|
+
results.delete(:'self-service-analytics')
|
117
|
+
|
118
|
+
Dropsonde::Metrics.plugins.each do |_name, plugin|
|
119
|
+
sanity_check_data(plugin, plugin.example).each do |row|
|
120
|
+
results.merge!(row)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
results
|
125
|
+
end
|
126
|
+
|
127
|
+
# We accept both the plugin and data gathered from the plugin so that
|
128
|
+
# we can sanitize both data and example data
|
129
|
+
def sanity_check_data(plugin, data)
|
130
|
+
# This allows plugin authors to easily skip metrics with no results
|
131
|
+
return [] if data.nil?
|
132
|
+
|
133
|
+
keys_data = data.map { |item| item.keys }.flatten.map(&:to_s)
|
134
|
+
keys_schema = plugin.schema.map { |item| item[:name] }
|
99
135
|
|
100
136
|
disallowed = (keys_data - keys_schema)
|
101
137
|
|
@@ -107,16 +143,16 @@ class Dropsonde::Metrics
|
|
107
143
|
def sanity_check_schema(plugin)
|
108
144
|
schema = plugin.schema
|
109
145
|
|
110
|
-
if schema.class != Array
|
146
|
+
if (schema.class != Array) || schema.find { |item| item.class != Hash }
|
111
147
|
raise "The #{plugin.name} plugin schema is not an array of hashes"
|
112
148
|
end
|
113
149
|
|
114
150
|
error = ''
|
115
151
|
[:name, :type, :description].each do |field|
|
116
|
-
count = schema.reject {|item| item[field] }.count
|
117
|
-
next if count
|
152
|
+
count = schema.reject { |item| item[field] }.count
|
153
|
+
next if count.zero?
|
118
154
|
|
119
|
-
error
|
155
|
+
error += "The #{plugin.name} plugin schema has #{count} missing #{field}s\n"
|
120
156
|
end
|
121
157
|
raise error unless error.empty?
|
122
158
|
|
@@ -124,8 +160,8 @@ class Dropsonde::Metrics
|
|
124
160
|
end
|
125
161
|
|
126
162
|
def check_for_duplicates(schema)
|
127
|
-
keys = schema.map {|col| col[:name] }
|
128
|
-
dupes = keys.select{ |e| keys.count(e) > 1 }.uniq
|
163
|
+
keys = schema.map { |col| col[:name] }
|
164
|
+
dupes = keys.select { |e| keys.count(e) > 1 }.uniq
|
129
165
|
|
130
166
|
raise "The schema defines duplicate keys: #{dupes}" unless dupes.empty?
|
131
167
|
end
|
@@ -134,51 +170,55 @@ class Dropsonde::Metrics
|
|
134
170
|
[
|
135
171
|
{
|
136
172
|
"description": "An ID that's unique for each checkin to Dujour.",
|
137
|
-
"mode":
|
138
|
-
"name":
|
139
|
-
"type":
|
173
|
+
"mode": 'NULLABLE',
|
174
|
+
"name": 'message_id',
|
175
|
+
"type": 'STRING',
|
140
176
|
},
|
141
177
|
{
|
142
|
-
"description":
|
143
|
-
"mode":
|
144
|
-
"name":
|
145
|
-
"type":
|
178
|
+
"description": 'A unique identifier for a site, derived as a hash of the CA certificate and optional seed.',
|
179
|
+
"mode": 'NULLABLE',
|
180
|
+
"name": 'site_id',
|
181
|
+
"type": 'BYTES',
|
146
182
|
},
|
147
183
|
{
|
148
|
-
"description":
|
149
|
-
"mode":
|
150
|
-
"name":
|
151
|
-
"type":
|
184
|
+
"description": 'The name of the product.',
|
185
|
+
"mode": 'NULLABLE',
|
186
|
+
"name": 'product',
|
187
|
+
"type": 'STRING',
|
152
188
|
},
|
153
189
|
{
|
154
|
-
"description":
|
155
|
-
"mode":
|
156
|
-
"name":
|
157
|
-
"type":
|
190
|
+
"description": 'Version of the project.',
|
191
|
+
"mode": 'NULLABLE',
|
192
|
+
"name": 'version',
|
193
|
+
"type": 'STRING',
|
158
194
|
},
|
159
195
|
{
|
160
|
-
"description":
|
161
|
-
"mode":
|
162
|
-
"name":
|
163
|
-
"type":
|
196
|
+
"description": 'Time the checkin to Dujour occurred.',
|
197
|
+
"mode": 'NULLABLE',
|
198
|
+
"name": 'timestamp',
|
199
|
+
"type": 'TIMESTAMP',
|
164
200
|
},
|
165
201
|
{
|
166
|
-
"description":
|
167
|
-
"mode":
|
168
|
-
"name":
|
169
|
-
"type":
|
170
|
-
}
|
202
|
+
"description": 'IP Address of node checking in to Dujour.',
|
203
|
+
"mode": 'NULLABLE',
|
204
|
+
"name": 'ip',
|
205
|
+
"type": 'STRING',
|
206
|
+
},
|
171
207
|
]
|
172
208
|
end
|
173
209
|
|
174
210
|
def skeleton_report
|
175
211
|
{
|
176
|
-
"product":
|
177
|
-
"version":
|
212
|
+
"product": 'popularity-module',
|
213
|
+
"version": '1.0.0',
|
178
214
|
"site_id": siteid,
|
179
215
|
"self-service-analytics": {
|
180
|
-
"snapshots": {
|
181
|
-
}
|
216
|
+
"snapshots": {},
|
217
|
+
},
|
182
218
|
}
|
183
219
|
end
|
220
|
+
|
221
|
+
def generate_guid
|
222
|
+
SecureRandom.uuid
|
223
|
+
end
|
184
224
|
end
|
@@ -1,17 +1,18 @@
|
|
1
|
-
|
2
|
-
class Module
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
# puppet module class
|
4
|
+
class Puppet::Module
|
5
|
+
unless Module.method_defined? :"forge_module?"
|
6
|
+
def forge_module?
|
7
|
+
Dropsonde::Cache.forge_module? self
|
8
8
|
end
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
unless Module.method_defined? :forge_slug
|
12
|
+
def forge_slug
|
13
|
+
forge_name.tr('/', '-')
|
14
|
+
rescue StandardError
|
15
|
+
nil
|
14
16
|
end
|
15
|
-
|
16
17
|
end
|
17
18
|
end
|
data/lib/dropsonde/version.rb
CHANGED
data/lib/dropsonde.rb
CHANGED
@@ -1,23 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'httpclient'
|
3
5
|
require 'puppetdb'
|
4
6
|
require 'inifile'
|
7
|
+
require 'puppet'
|
5
8
|
|
9
|
+
# This class handles caching module process, generate reports,
|
10
|
+
# fetchs all plugins defined in lib/dropsonde/metrics and also
|
11
|
+
# handle connection and request to PuppetDB.
|
6
12
|
class Dropsonde
|
7
13
|
require 'dropsonde/cache'
|
8
14
|
require 'dropsonde/metrics'
|
9
15
|
require 'dropsonde/monkeypatches'
|
10
16
|
require 'dropsonde/version'
|
11
17
|
|
12
|
-
|
13
|
-
|
18
|
+
def self.puppet_settings_overrides
|
19
|
+
overrides = []
|
20
|
+
if (confdir = ENV['PUPPET_CONFDIR'])
|
21
|
+
overrides << '--confdir'
|
22
|
+
overrides << confdir
|
23
|
+
end
|
24
|
+
|
25
|
+
if (codedir = ENV['PUPPET_CODEDIR'])
|
26
|
+
overrides << '--codedir'
|
27
|
+
overrides << codedir
|
28
|
+
end
|
29
|
+
|
30
|
+
if (vardir = ENV['PUPPET_VARDIR'])
|
31
|
+
overrides << '--vardir'
|
32
|
+
overrides << vardir
|
33
|
+
end
|
34
|
+
|
35
|
+
if (logdir = ENV['PUPPET_LOGDIR'])
|
36
|
+
overrides << '--logdir'
|
37
|
+
overrides << logdir
|
38
|
+
end
|
39
|
+
|
40
|
+
overrides
|
41
|
+
end
|
42
|
+
|
43
|
+
Puppet.initialize_settings(puppet_settings_overrides)
|
44
|
+
|
45
|
+
@pdbclient = nil
|
46
|
+
@settings = {}
|
14
47
|
def self.settings=(arg)
|
15
48
|
raise "Requires a Hash to set all settings at once, not a #{arg.class}" unless arg.is_a? Hash
|
16
|
-
|
49
|
+
|
50
|
+
@settings = arg
|
17
51
|
end
|
18
52
|
|
19
|
-
|
20
|
-
|
53
|
+
class << self
|
54
|
+
attr_reader :settings
|
21
55
|
end
|
22
56
|
|
23
57
|
def self.generate_schema
|
@@ -29,24 +63,32 @@ class Dropsonde
|
|
29
63
|
puts Dropsonde::Metrics.new.list
|
30
64
|
end
|
31
65
|
|
32
|
-
def self.generate_report(format)
|
66
|
+
def self.generate_report(format, puppetdb_session = nil)
|
33
67
|
case format
|
34
68
|
when 'json'
|
35
|
-
puts JSON.pretty_generate(Dropsonde::Metrics.new.report)
|
69
|
+
puts JSON.pretty_generate(Dropsonde::Metrics.new.report(puppetdb_session))
|
36
70
|
when 'human'
|
37
71
|
puts
|
38
|
-
puts Dropsonde::Metrics.new.preview
|
72
|
+
puts Dropsonde::Metrics.new.preview(puppetdb_session)
|
39
73
|
else
|
40
|
-
raise
|
74
|
+
raise 'unknown format'
|
41
75
|
end
|
42
76
|
end
|
43
77
|
|
44
78
|
def self.submit_report(endpoint, port)
|
45
|
-
client = HTTPClient.new
|
79
|
+
client = HTTPClient.new
|
80
|
+
|
81
|
+
# The httpclient gem ships with some expired CA certificates.
|
82
|
+
# This causes us to load the certs shipped with whatever
|
83
|
+
# Ruby is used to execute this gem's commands, which are generally
|
84
|
+
# more up-to-date, especially if using puppet-agent's Ruby.
|
85
|
+
#
|
86
|
+
# Note that this is no-op with Windows system Ruby.
|
87
|
+
client.ssl_config.set_default_paths
|
88
|
+
|
46
89
|
result = client.post("#{endpoint}:#{port}",
|
47
|
-
|
48
|
-
|
49
|
-
)
|
90
|
+
header: { 'Content-Type' => 'application/json' },
|
91
|
+
body: Dropsonde::Metrics.new.report.to_json)
|
50
92
|
|
51
93
|
if result.status == 200
|
52
94
|
data = JSON.parse(result.body)
|
@@ -63,8 +105,18 @@ class Dropsonde
|
|
63
105
|
end
|
64
106
|
end
|
65
107
|
|
66
|
-
def self.
|
67
|
-
|
108
|
+
def self.generate_example(size, filename)
|
109
|
+
metrics = Dropsonde::Metrics.new
|
110
|
+
File.open(filename, 'w') do |file|
|
111
|
+
(0...size).each do |_i|
|
112
|
+
file.write(metrics.example.to_json)
|
113
|
+
file.write("\n")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def puppet_db
|
119
|
+
return @pdbclient if @pdbclient
|
68
120
|
|
69
121
|
config = File.join(Puppet.settings[:confdir], 'puppetdb.conf')
|
70
122
|
|
@@ -72,14 +124,13 @@ class Dropsonde
|
|
72
124
|
|
73
125
|
server = IniFile.load(config)['main']['server_urls'].split(',').first
|
74
126
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
127
|
+
@pdbclient = PuppetDB::Client.new({
|
128
|
+
server: server,
|
129
|
+
pem: {
|
130
|
+
'key' => Puppet.settings[:hostprivkey],
|
131
|
+
'cert' => Puppet.settings[:hostcert],
|
132
|
+
'ca_file' => Puppet.settings[:localcacert],
|
133
|
+
},
|
134
|
+
})
|
83
135
|
end
|
84
|
-
|
85
136
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dropsonde
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Ford
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -153,13 +153,15 @@ files:
|
|
153
153
|
- lib/dropsonde/cache.rb
|
154
154
|
- lib/dropsonde/metrics.rb
|
155
155
|
- lib/dropsonde/metrics/dependencies.rb
|
156
|
+
- lib/dropsonde/metrics/environments.rb
|
156
157
|
- lib/dropsonde/metrics/modules.rb
|
158
|
+
- lib/dropsonde/metrics/platforms.rb
|
157
159
|
- lib/dropsonde/metrics/puppetfiles.rb
|
158
160
|
- lib/dropsonde/monkeypatches.rb
|
159
161
|
- lib/dropsonde/version.rb
|
160
162
|
homepage: https://github.com/puppetlabs/dropsonde
|
161
163
|
licenses:
|
162
|
-
- Apache
|
164
|
+
- Apache-2.0
|
163
165
|
metadata: {}
|
164
166
|
post_install_message:
|
165
167
|
rdoc_options: []
|
@@ -176,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
176
178
|
- !ruby/object:Gem::Version
|
177
179
|
version: '0'
|
178
180
|
requirements: []
|
179
|
-
rubygems_version: 3.
|
181
|
+
rubygems_version: 3.1.2
|
180
182
|
signing_key:
|
181
183
|
specification_version: 4
|
182
184
|
summary: A simple telemetry probe for gathering usage information about Puppet infrastructures.
|