dropsonde 0.0.2 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.