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.
@@ -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( :path => 'dropsonde/metrics', :module => Dropsonde::Metrics)
8
+ extend LittlePlugger(path: 'dropsonde/metrics', module: Dropsonde::Metrics)
5
9
 
6
10
  def initialize
7
- Dropsonde::Metrics.disregard_plugins(*Dropsonde.settings[:blacklist])
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
- sha2 = Digest::SHA512.new
15
- sha2.update Puppet.settings[:certname]
16
- sha2.update Puppet.settings[:cacert]
17
- sha2.update Dropsonde.settings[:seed] if Dropsonde.settings[:seed]
18
- @siteid = sha2.hexdigest
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 = " Loaded telemetry plugins\n"
24
- str << " ===============================\n\n"
38
+ str = " Loaded telemetry plugins\n"
39
+ str += " ===============================\n\n"
25
40
  Dropsonde::Metrics.plugins.each do |name, plugin|
26
- str << name.to_s
27
- str << "\n--------\n"
28
- str << plugin.description.strip
29
- str << "\n\n"
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[:blacklist]
32
- str << "Disabled plugins:\n"
33
- str << " #{Dropsonde.settings[:blacklist].join(', ')}"
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 |name, plugin|
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 = " Puppet Telemetry Report Preview\n"
49
- str << " ===============================\n\n"
50
- Dropsonde::Metrics.plugins.each do |name, plugin|
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 << plugin.name+"\n"
58
- str << "-------------------------------\n"
59
- str << plugin.description
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.first
77
+ values = row.values.flatten
63
78
 
64
- desc = schema.find {|item| item[:name].to_sym == key.to_sym}[:description]
65
- str << "- #{key}: #{desc}\n"
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 << " #{item}\n"
82
+ str += " #{item}\n"
68
83
  end
69
84
  end
70
- str << "\n\n"
85
+ str += "\n\n"
71
86
  end
72
- str << "Site ID:\n"
73
- str << siteid
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 |name, plugin|
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' => row.values.first,
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 sanity_check_data(plugin)
96
- data = plugin.run
97
- keys_data = data.map {|item| item.keys }.flatten.map(&:to_s)
98
- keys_schema = plugin.schema.map {|item| item[:name] }
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 or schema.find {|item| item.class != Hash}
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 == 0
152
+ count = schema.reject { |item| item[field] }.count
153
+ next if count.zero?
118
154
 
119
- error << "The #{plugin.name} plugin schema has #{count} missing #{field}s\n"
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": "NULLABLE",
138
- "name": "message_id",
139
- "type": "STRING"
173
+ "mode": 'NULLABLE',
174
+ "name": 'message_id',
175
+ "type": 'STRING',
140
176
  },
141
177
  {
142
- "description": "A unique identifier for a site, derived as a hash of the CA certificate and optional seed.",
143
- "mode": "NULLABLE",
144
- "name": "site_id",
145
- "type": "BYTES"
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": "The name of the product.",
149
- "mode": "NULLABLE",
150
- "name": "product",
151
- "type": "STRING"
184
+ "description": 'The name of the product.',
185
+ "mode": 'NULLABLE',
186
+ "name": 'product',
187
+ "type": 'STRING',
152
188
  },
153
189
  {
154
- "description": "Version of the project.",
155
- "mode": "NULLABLE",
156
- "name": "version",
157
- "type": "STRING"
190
+ "description": 'Version of the project.',
191
+ "mode": 'NULLABLE',
192
+ "name": 'version',
193
+ "type": 'STRING',
158
194
  },
159
195
  {
160
- "description": "Time the checkin to Dujour occurred.",
161
- "mode": "NULLABLE",
162
- "name": "timestamp",
163
- "type": "TIMESTAMP"
196
+ "description": 'Time the checkin to Dujour occurred.',
197
+ "mode": 'NULLABLE',
198
+ "name": 'timestamp',
199
+ "type": 'TIMESTAMP',
164
200
  },
165
201
  {
166
- "description": "IP Address of node checking in to Dujour.",
167
- "mode": "NULLABLE",
168
- "name": "ip",
169
- "type": "STRING"
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": "popularity-module",
177
- "version": "1.0.0",
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
- module Puppet
2
- class Module
1
+ # frozen_string_literal: true
3
2
 
4
- unless Module.method_defined? :"forge_module?"
5
- def forge_module?
6
- Dropsonde::Cache.forgeModule? self
7
- end
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
- unless Module.method_defined? :forge_slug
11
- def forge_slug
12
- self.forge_name.tr('/','-') rescue nil
13
- end
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Dropsonde
2
- VERSION = '0.0.2'
4
+ VERSION = '0.0.6'
3
5
  end
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
- @@pdbclient = nil
13
- @@settings = {}
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
- @@settings = arg
49
+
50
+ @settings = arg
17
51
  end
18
52
 
19
- def self.settings
20
- @@settings
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 "unknown format"
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
- :header => {'Content-Type' => 'application/json'},
48
- :body => Dropsonde::Metrics.new.report.to_json
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.puppetDB
67
- return @@pdbclient if @@pdbclient
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
- @@pdbclient = PuppetDB::Client.new({
76
- :server => server,
77
- :pem => {
78
- 'key' => Puppet.settings[:hostprivkey],
79
- 'cert' => Puppet.settings[:hostcert],
80
- 'ca_file' => Puppet.settings[:localcacert],
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.2
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: 2020-05-07 00:00:00.000000000 Z
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 2
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.0.6
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.