dropsonde 0.0.5 → 0.0.8
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/CHANGELOG.md +72 -0
- data/README.md +42 -13
- data/bin/dropsonde +13 -7
- data/lib/dropsonde/cache.rb +42 -32
- data/lib/dropsonde/metrics/dependencies.rb +36 -32
- data/lib/dropsonde/metrics/environments.rb +13 -10
- data/lib/dropsonde/metrics/modules.rb +150 -65
- data/lib/dropsonde/metrics/platforms.rb +63 -61
- data/lib/dropsonde/metrics/puppetfiles.rb +35 -32
- data/lib/dropsonde/metrics.rb +80 -77
- data/lib/dropsonde/monkeypatches.rb +12 -11
- data/lib/dropsonde/version.rb +3 -1
- data/lib/dropsonde.rb +64 -26
- metadata +5 -4
data/lib/dropsonde/metrics.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
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
11
|
if Dropsonde.settings[:enable]
|
@@ -17,76 +21,81 @@ class Dropsonde::Metrics
|
|
17
21
|
def siteid
|
18
22
|
return @siteid if @siteid
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
+
|
25
34
|
@siteid
|
26
35
|
end
|
27
36
|
|
28
37
|
def list
|
29
|
-
str
|
30
|
-
str
|
38
|
+
str = " Loaded telemetry plugins\n"
|
39
|
+
str += " ===============================\n\n"
|
31
40
|
Dropsonde::Metrics.plugins.each do |name, plugin|
|
32
|
-
str
|
33
|
-
str
|
34
|
-
str
|
35
|
-
str
|
41
|
+
str += name.to_s
|
42
|
+
str += "\n--------\n"
|
43
|
+
str += plugin.description.strip
|
44
|
+
str += "\n\n"
|
36
45
|
end
|
37
46
|
if Dropsonde.settings[:disable]
|
38
|
-
str
|
39
|
-
str
|
47
|
+
str += "Disabled plugins:\n"
|
48
|
+
str += " #{Dropsonde.settings[:disable].join(', ')}"
|
40
49
|
end
|
41
50
|
str
|
42
51
|
end
|
43
52
|
|
44
53
|
def schema
|
45
54
|
schema = skeleton_schema
|
46
|
-
Dropsonde::Metrics.plugins.each do |
|
55
|
+
Dropsonde::Metrics.plugins.each do |_name, plugin|
|
47
56
|
schema.concat(sanity_check_schema(plugin))
|
48
57
|
end
|
49
58
|
check_for_duplicates(schema)
|
50
59
|
schema
|
51
60
|
end
|
52
61
|
|
53
|
-
def preview
|
54
|
-
str
|
55
|
-
str
|
56
|
-
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|
|
57
66
|
schema = plugin.schema
|
58
67
|
|
59
68
|
plugin.setup if plugin.respond_to? :setup
|
60
|
-
data = sanity_check_data(plugin, plugin.run)
|
69
|
+
data = sanity_check_data(plugin, plugin.run(puppetdb_session))
|
61
70
|
plugin.cleanup if plugin.respond_to? :cleanup
|
62
71
|
|
63
|
-
str
|
64
|
-
str
|
65
|
-
str
|
72
|
+
str += "#{plugin.name}\n"
|
73
|
+
str += "-------------------------------\n"
|
74
|
+
str += plugin.description
|
66
75
|
data.each do |row|
|
67
76
|
key = row.keys.first
|
68
77
|
values = row.values.flatten
|
69
78
|
|
70
|
-
desc = schema.find {|item| item[:name].to_sym == key.to_sym}[:description]
|
71
|
-
str
|
79
|
+
desc = schema.find { |item| item[:name].to_sym == key.to_sym }[:description]
|
80
|
+
str += "- #{key}: #{desc}\n"
|
72
81
|
values.each do |item|
|
73
|
-
str
|
82
|
+
str += " #{item}\n"
|
74
83
|
end
|
75
84
|
end
|
76
|
-
str
|
85
|
+
str += "\n\n"
|
77
86
|
end
|
78
|
-
str
|
79
|
-
str
|
87
|
+
str += "Site ID:\n"
|
88
|
+
str += siteid
|
80
89
|
str
|
81
90
|
end
|
82
91
|
|
83
|
-
def report
|
92
|
+
def report(puppetdb_session = nil)
|
84
93
|
snapshots = {}
|
85
|
-
Dropsonde::Metrics.plugins.each do |
|
94
|
+
Dropsonde::Metrics.plugins.each do |_name, plugin|
|
86
95
|
plugin.setup
|
87
|
-
sanity_check_data(plugin, plugin.run).each do |row|
|
96
|
+
sanity_check_data(plugin, plugin.run(puppetdb_session)).each do |row|
|
88
97
|
snapshots[row.keys.first] = {
|
89
|
-
'value'
|
98
|
+
'value' => row.values.first,
|
90
99
|
'timestamp' => Time.now.iso8601,
|
91
100
|
}
|
92
101
|
end
|
@@ -106,7 +115,7 @@ class Dropsonde::Metrics
|
|
106
115
|
results[:ip] = IPAddr.new(rand(2**32), Socket::AF_INET)
|
107
116
|
results.delete(:'self-service-analytics')
|
108
117
|
|
109
|
-
Dropsonde::Metrics.plugins.each do |
|
118
|
+
Dropsonde::Metrics.plugins.each do |_name, plugin|
|
110
119
|
sanity_check_data(plugin, plugin.example).each do |row|
|
111
120
|
results.merge!(row)
|
112
121
|
end
|
@@ -121,8 +130,8 @@ class Dropsonde::Metrics
|
|
121
130
|
# This allows plugin authors to easily skip metrics with no results
|
122
131
|
return [] if data.nil?
|
123
132
|
|
124
|
-
keys_data = data.map {|item| item.keys }.flatten.map(&:to_s)
|
125
|
-
keys_schema = plugin.schema.map {|item| item[:name] }
|
133
|
+
keys_data = data.map { |item| item.keys }.flatten.map(&:to_s)
|
134
|
+
keys_schema = plugin.schema.map { |item| item[:name] }
|
126
135
|
|
127
136
|
disallowed = (keys_data - keys_schema)
|
128
137
|
|
@@ -134,16 +143,16 @@ class Dropsonde::Metrics
|
|
134
143
|
def sanity_check_schema(plugin)
|
135
144
|
schema = plugin.schema
|
136
145
|
|
137
|
-
if schema.class != Array
|
146
|
+
if (schema.class != Array) || schema.find { |item| item.class != Hash }
|
138
147
|
raise "The #{plugin.name} plugin schema is not an array of hashes"
|
139
148
|
end
|
140
149
|
|
141
150
|
error = ''
|
142
151
|
[:name, :type, :description].each do |field|
|
143
|
-
count = schema.reject {|item| item[field] }.count
|
144
|
-
next if count
|
152
|
+
count = schema.reject { |item| item[field] }.count
|
153
|
+
next if count.zero?
|
145
154
|
|
146
|
-
error
|
155
|
+
error += "The #{plugin.name} plugin schema has #{count} missing #{field}s\n"
|
147
156
|
end
|
148
157
|
raise error unless error.empty?
|
149
158
|
|
@@ -151,8 +160,8 @@ class Dropsonde::Metrics
|
|
151
160
|
end
|
152
161
|
|
153
162
|
def check_for_duplicates(schema)
|
154
|
-
keys = schema.map {|col| col[:name] }
|
155
|
-
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
|
156
165
|
|
157
166
|
raise "The schema defines duplicate keys: #{dupes}" unless dupes.empty?
|
158
167
|
end
|
@@ -161,61 +170,55 @@ class Dropsonde::Metrics
|
|
161
170
|
[
|
162
171
|
{
|
163
172
|
"description": "An ID that's unique for each checkin to Dujour.",
|
164
|
-
"mode":
|
165
|
-
"name":
|
166
|
-
"type":
|
173
|
+
"mode": 'NULLABLE',
|
174
|
+
"name": 'message_id',
|
175
|
+
"type": 'STRING',
|
167
176
|
},
|
168
177
|
{
|
169
|
-
"description":
|
170
|
-
"mode":
|
171
|
-
"name":
|
172
|
-
"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',
|
173
182
|
},
|
174
183
|
{
|
175
|
-
"description":
|
176
|
-
"mode":
|
177
|
-
"name":
|
178
|
-
"type":
|
184
|
+
"description": 'The name of the product.',
|
185
|
+
"mode": 'NULLABLE',
|
186
|
+
"name": 'product',
|
187
|
+
"type": 'STRING',
|
179
188
|
},
|
180
189
|
{
|
181
|
-
"description":
|
182
|
-
"mode":
|
183
|
-
"name":
|
184
|
-
"type":
|
190
|
+
"description": 'Version of the project.',
|
191
|
+
"mode": 'NULLABLE',
|
192
|
+
"name": 'version',
|
193
|
+
"type": 'STRING',
|
185
194
|
},
|
186
195
|
{
|
187
|
-
"description":
|
188
|
-
"mode":
|
189
|
-
"name":
|
190
|
-
"type":
|
196
|
+
"description": 'Time the checkin to Dujour occurred.',
|
197
|
+
"mode": 'NULLABLE',
|
198
|
+
"name": 'timestamp',
|
199
|
+
"type": 'TIMESTAMP',
|
191
200
|
},
|
192
201
|
{
|
193
|
-
"description":
|
194
|
-
"mode":
|
195
|
-
"name":
|
196
|
-
"type":
|
197
|
-
}
|
202
|
+
"description": 'IP Address of node checking in to Dujour.',
|
203
|
+
"mode": 'NULLABLE',
|
204
|
+
"name": 'ip',
|
205
|
+
"type": 'STRING',
|
206
|
+
},
|
198
207
|
]
|
199
208
|
end
|
200
209
|
|
201
210
|
def skeleton_report
|
202
211
|
{
|
203
|
-
"product":
|
204
|
-
"version":
|
212
|
+
"product": 'popularity-module',
|
213
|
+
"version": '1.0.0',
|
205
214
|
"site_id": siteid,
|
206
215
|
"self-service-analytics": {
|
207
|
-
"snapshots": {
|
208
|
-
}
|
216
|
+
"snapshots": {},
|
217
|
+
},
|
209
218
|
}
|
210
219
|
end
|
211
220
|
|
212
221
|
def generate_guid
|
213
|
-
|
214
|
-
(0..8).to_a.map{|a| rand(16).to_s(16)}.join,
|
215
|
-
(0..4).to_a.map{|a| rand(16).to_s(16)}.join,
|
216
|
-
(0..4).to_a.map{|a| rand(16).to_s(16)}.join,
|
217
|
-
(0..4).to_a.map{|a| rand(16).to_s(16)}.join,
|
218
|
-
(0..12).to_a.map{|a| rand(16).to_s(16)}.join
|
219
|
-
]
|
222
|
+
SecureRandom.uuid
|
220
223
|
end
|
221
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,26 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'httpclient'
|
3
5
|
require 'puppetdb'
|
4
6
|
require 'inifile'
|
5
7
|
require 'puppet'
|
6
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.
|
7
12
|
class Dropsonde
|
8
13
|
require 'dropsonde/cache'
|
9
14
|
require 'dropsonde/metrics'
|
10
15
|
require 'dropsonde/monkeypatches'
|
11
16
|
require 'dropsonde/version'
|
12
17
|
|
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
|
14
39
|
|
15
|
-
|
16
|
-
|
40
|
+
overrides
|
41
|
+
end
|
42
|
+
|
43
|
+
Puppet.initialize_settings(puppet_settings_overrides)
|
44
|
+
|
45
|
+
@pdbclient = nil
|
46
|
+
@settings = {}
|
17
47
|
def self.settings=(arg)
|
18
48
|
raise "Requires a Hash to set all settings at once, not a #{arg.class}" unless arg.is_a? Hash
|
19
|
-
|
49
|
+
|
50
|
+
@settings = arg
|
20
51
|
end
|
21
52
|
|
22
|
-
|
23
|
-
|
53
|
+
class << self
|
54
|
+
attr_reader :settings
|
24
55
|
end
|
25
56
|
|
26
57
|
def self.generate_schema
|
@@ -32,24 +63,32 @@ class Dropsonde
|
|
32
63
|
puts Dropsonde::Metrics.new.list
|
33
64
|
end
|
34
65
|
|
35
|
-
def self.generate_report(format)
|
66
|
+
def self.generate_report(format, puppetdb_session = nil)
|
36
67
|
case format
|
37
68
|
when 'json'
|
38
|
-
puts JSON.pretty_generate(Dropsonde::Metrics.new.report)
|
69
|
+
puts JSON.pretty_generate(Dropsonde::Metrics.new.report(puppetdb_session))
|
39
70
|
when 'human'
|
40
71
|
puts
|
41
|
-
puts Dropsonde::Metrics.new.preview
|
72
|
+
puts Dropsonde::Metrics.new.preview(puppetdb_session)
|
42
73
|
else
|
43
|
-
raise
|
74
|
+
raise 'unknown format'
|
44
75
|
end
|
45
76
|
end
|
46
77
|
|
47
78
|
def self.submit_report(endpoint, port)
|
48
|
-
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
|
+
|
49
89
|
result = client.post("#{endpoint}:#{port}",
|
50
|
-
|
51
|
-
|
52
|
-
)
|
90
|
+
header: { 'Content-Type' => 'application/json' },
|
91
|
+
body: Dropsonde::Metrics.new.report.to_json)
|
53
92
|
|
54
93
|
if result.status == 200
|
55
94
|
data = JSON.parse(result.body)
|
@@ -69,15 +108,15 @@ class Dropsonde
|
|
69
108
|
def self.generate_example(size, filename)
|
70
109
|
metrics = Dropsonde::Metrics.new
|
71
110
|
File.open(filename, 'w') do |file|
|
72
|
-
|
111
|
+
(0...size).each do |_i|
|
73
112
|
file.write(metrics.example.to_json)
|
74
113
|
file.write("\n")
|
75
114
|
end
|
76
115
|
end
|
77
116
|
end
|
78
117
|
|
79
|
-
def
|
80
|
-
return
|
118
|
+
def puppet_db
|
119
|
+
return @pdbclient if @pdbclient
|
81
120
|
|
82
121
|
config = File.join(Puppet.settings[:confdir], 'puppetdb.conf')
|
83
122
|
|
@@ -85,14 +124,13 @@ class Dropsonde
|
|
85
124
|
|
86
125
|
server = IniFile.load(config)['main']['server_urls'].split(',').first
|
87
126
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
+
})
|
96
135
|
end
|
97
|
-
|
98
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.8
|
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: 2022-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -146,6 +146,7 @@ executables:
|
|
146
146
|
extensions: []
|
147
147
|
extra_rdoc_files: []
|
148
148
|
files:
|
149
|
+
- CHANGELOG.md
|
149
150
|
- LICENSE
|
150
151
|
- README.md
|
151
152
|
- bin/dropsonde
|
@@ -161,7 +162,7 @@ files:
|
|
161
162
|
- lib/dropsonde/version.rb
|
162
163
|
homepage: https://github.com/puppetlabs/dropsonde
|
163
164
|
licenses:
|
164
|
-
- Apache
|
165
|
+
- Apache-2.0
|
165
166
|
metadata: {}
|
166
167
|
post_install_message:
|
167
168
|
rdoc_options: []
|
@@ -178,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
179
|
- !ruby/object:Gem::Version
|
179
180
|
version: '0'
|
180
181
|
requirements: []
|
181
|
-
rubygems_version: 3.
|
182
|
+
rubygems_version: 3.1.6
|
182
183
|
signing_key:
|
183
184
|
specification_version: 4
|
184
185
|
summary: A simple telemetry probe for gathering usage information about Puppet infrastructures.
|