dropsonde 0.0.5 → 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/bin/dropsonde +12 -6
- data/lib/dropsonde/cache.rb +37 -33
- data/lib/dropsonde/metrics/dependencies.rb +37 -32
- data/lib/dropsonde/metrics/environments.rb +13 -10
- data/lib/dropsonde/metrics/modules.rb +71 -65
- data/lib/dropsonde/metrics/platforms.rb +64 -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 +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4a87b2c8abe75d07a73a52a48041c2734bb7914a54df3471d696458f3f0cb05
|
4
|
+
data.tar.gz: cd2b7d3a36aa9aa386997ab21f7ffee57387819b08a79407b98c5bfdbbcd619d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a033ee5a796d3dab8c46d7562848255ca66552671f31f58ffde8a5a00f98dbcf1e9485a8279529b7c78094f96add8e932fa401e634ccfc067f5c9b72eed93c3
|
7
|
+
data.tar.gz: b86bc1f854fe414a388534ced35132d0744ac21001298d3eefce326afa97a63bd56ce9b250458889690831e7b0343963666377eaf10c25c38861b50e1160225d
|
data/bin/dropsonde
CHANGED
@@ -5,6 +5,9 @@ require 'dropsonde'
|
|
5
5
|
class Dropsonde
|
6
6
|
extend GLI::App
|
7
7
|
|
8
|
+
@cache = nil
|
9
|
+
@puppetdb_session = Dropsonde.new
|
10
|
+
|
8
11
|
program_desc 'A simple telemetry tool for Puppet infrastructures'
|
9
12
|
config_file "#{File.dirname(Puppet.settings[:confdir])}/telemetry.yaml"
|
10
13
|
version Dropsonde::VERSION
|
@@ -30,15 +33,18 @@ class Dropsonde
|
|
30
33
|
desc 'Any number or string used to generate the randomized site ID.'
|
31
34
|
flag [:seed]
|
32
35
|
|
36
|
+
desc 'Static site ID'
|
37
|
+
flag [:siteid]
|
38
|
+
|
33
39
|
pre do |global, command, options, args|
|
34
40
|
Dropsonde.settings = global
|
35
|
-
Dropsonde::Cache.
|
41
|
+
@cache = Dropsonde::Cache.new(global[:cachepath], global[:ttl], global[:update])
|
36
42
|
end
|
37
43
|
|
38
44
|
desc 'Manually update the Forge module name cache'
|
39
45
|
command :update do |c|
|
40
46
|
c.action do |global, options, args|
|
41
|
-
|
47
|
+
@cache.update
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
@@ -55,8 +61,8 @@ class Dropsonde
|
|
55
61
|
c.flag [:format], :default_value => 'human'
|
56
62
|
|
57
63
|
c.action do |global, options, args|
|
58
|
-
|
59
|
-
Dropsonde.generate_report(options[:format])
|
64
|
+
@cache.autoupdate
|
65
|
+
Dropsonde.generate_report(options[:format], @puppetdb_session)
|
60
66
|
end
|
61
67
|
end
|
62
68
|
|
@@ -69,7 +75,7 @@ class Dropsonde
|
|
69
75
|
c.flag [:port], :default_value => 443, :type => Integer
|
70
76
|
|
71
77
|
c.action do |global, options, args|
|
72
|
-
|
78
|
+
@cache.autoupdate
|
73
79
|
Dropsonde.submit_report(options[:endpoint], options[:port])
|
74
80
|
end
|
75
81
|
end
|
@@ -111,7 +117,7 @@ class Dropsonde
|
|
111
117
|
c.flag [:filename], :default_value => 'example.jsonl'
|
112
118
|
|
113
119
|
c.action do |global, options, args|
|
114
|
-
|
120
|
+
@cache.autoupdate
|
115
121
|
Dropsonde.generate_example(options[:size], options[:filename])
|
116
122
|
end
|
117
123
|
end
|
data/lib/dropsonde/cache.rb
CHANGED
@@ -1,34 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
require 'json'
|
3
5
|
require 'fileutils'
|
4
6
|
require 'puppet_forge'
|
5
7
|
|
8
|
+
# cache class
|
6
9
|
class Dropsonde::Cache
|
7
|
-
|
10
|
+
@autoupdate = false
|
8
11
|
|
9
|
-
def
|
12
|
+
def initialize(path, ttl, autoupdate)
|
10
13
|
FileUtils.mkdir_p(path)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
if File.file?
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
PuppetForge.user_agent =
|
14
|
+
@path = "#{File.expand_path(path)}/forge.json"
|
15
|
+
@ttl = ttl
|
16
|
+
@autoupdate = autoupdate
|
17
|
+
|
18
|
+
@@cache = if File.file? @path # rubocop:disable Style/ClassVars
|
19
|
+
JSON.parse(File.read(@path))
|
20
|
+
else
|
21
|
+
{
|
22
|
+
'timestamp' => '2000-1-1', # long before any puppet modules were released!
|
23
|
+
'modules' => [],
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
PuppetForge.user_agent = 'Dropsonde Telemetry Client/0.0.1'
|
25
28
|
end
|
26
29
|
|
27
|
-
def
|
30
|
+
def modules
|
28
31
|
@@cache['modules']
|
29
32
|
end
|
30
33
|
|
31
|
-
def
|
34
|
+
def cache
|
35
|
+
@@cache
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.forge_module?(mod)
|
32
39
|
case mod
|
33
40
|
when Puppet::Module
|
34
41
|
modname = mod.forge_slug
|
@@ -39,12 +46,12 @@ class Dropsonde::Cache
|
|
39
46
|
end
|
40
47
|
return unless modname
|
41
48
|
|
42
|
-
modules.include? modname.tr('/','-')
|
49
|
+
@@cache['modules'].include? modname.tr('/', '-')
|
43
50
|
end
|
44
51
|
|
45
|
-
def
|
46
|
-
puts
|
47
|
-
iter = PuppetForge::Module.all(:
|
52
|
+
def update
|
53
|
+
puts 'Updating module cache...'
|
54
|
+
iter = PuppetForge::Module.all(sort_by: 'latest_release')
|
48
55
|
newest = DateTime.parse(@@cache['timestamp'])
|
49
56
|
|
50
57
|
@@cache['timestamp'] = iter.first.updated_at
|
@@ -53,7 +60,7 @@ class Dropsonde::Cache
|
|
53
60
|
# stop once we reach modules we've already cached
|
54
61
|
break if DateTime.parse(iter.first.updated_at) <= newest
|
55
62
|
|
56
|
-
@@cache['modules'].concat
|
63
|
+
@@cache['modules'].concat(iter.map { |mod| mod.slug })
|
57
64
|
|
58
65
|
iter = iter.next
|
59
66
|
print '.'
|
@@ -62,22 +69,19 @@ class Dropsonde::Cache
|
|
62
69
|
@@cache['modules'].sort!
|
63
70
|
@@cache['modules'].uniq!
|
64
71
|
|
65
|
-
File.write(
|
72
|
+
File.write(@path, JSON.pretty_generate(@@cache))
|
66
73
|
end
|
67
74
|
|
68
|
-
def
|
69
|
-
return unless
|
75
|
+
def autoupdate
|
76
|
+
return unless @autoupdate
|
70
77
|
|
71
|
-
unless File.file?
|
72
|
-
puts
|
73
|
-
puts
|
78
|
+
unless File.file? @path
|
79
|
+
puts 'Dropsonde caches a list of all Forge modules to ensure that it only reports'
|
80
|
+
puts 'usage data on public modules. Generating this cache may take some time on'
|
74
81
|
puts "the first run and you'll see your screen fill up with dots."
|
75
82
|
update
|
76
83
|
end
|
77
84
|
|
78
|
-
if (Date.today - File.mtime(
|
79
|
-
update
|
80
|
-
end
|
85
|
+
return update if (Date.today - File.mtime(@path).to_date).to_i > @ttl
|
81
86
|
end
|
82
|
-
|
83
87
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# dependencies plugin
|
1
4
|
class Dropsonde::Metrics::Dependencies
|
2
5
|
def self.initialize_dependencies
|
3
6
|
# require any libraries needed here -- no need to load puppet; it's already initialized
|
@@ -5,10 +8,10 @@ class Dropsonde::Metrics::Dependencies
|
|
5
8
|
end
|
6
9
|
|
7
10
|
def self.description
|
8
|
-
<<~
|
11
|
+
<<~DESCRIPTION
|
9
12
|
This group of metrics discovers dependencies between modules in all
|
10
13
|
environments. It will omit dependencies on private modules.
|
11
|
-
|
14
|
+
DESCRIPTION
|
12
15
|
end
|
13
16
|
|
14
17
|
def self.schema
|
@@ -18,23 +21,23 @@ class Dropsonde::Metrics::Dependencies
|
|
18
21
|
{
|
19
22
|
"fields": [
|
20
23
|
{
|
21
|
-
"description":
|
22
|
-
"mode":
|
23
|
-
"name":
|
24
|
-
"type":
|
24
|
+
"description": 'The depended on module name',
|
25
|
+
"mode": 'NULLABLE',
|
26
|
+
"name": 'name',
|
27
|
+
"type": 'STRING',
|
25
28
|
},
|
26
29
|
{
|
27
|
-
"description":
|
28
|
-
"mode":
|
29
|
-
"name":
|
30
|
-
"type":
|
31
|
-
}
|
30
|
+
"description": 'The depended on module version requirement',
|
31
|
+
"mode": 'NULLABLE',
|
32
|
+
"name": 'version_requirement',
|
33
|
+
"type": 'STRING',
|
34
|
+
},
|
32
35
|
],
|
33
|
-
"description":
|
34
|
-
"mode":
|
35
|
-
"name":
|
36
|
-
"type":
|
37
|
-
}
|
36
|
+
"description": 'List of modules that private modules in all environments depend on.',
|
37
|
+
"mode": 'REPEATED',
|
38
|
+
"name": 'dependencies',
|
39
|
+
"type": 'RECORD',
|
40
|
+
},
|
38
41
|
]
|
39
42
|
end
|
40
43
|
|
@@ -42,26 +45,25 @@ class Dropsonde::Metrics::Dependencies
|
|
42
45
|
# run just before generating this metric
|
43
46
|
end
|
44
47
|
|
45
|
-
def self.run
|
48
|
+
def self.run(_puppetdb_session = nil)
|
46
49
|
# return an array of hashes representing the data to be merged into the combined checkin
|
47
|
-
environments = Puppet.lookup(:environments).list.map{|e|e.name}
|
48
|
-
modules = environments.map
|
50
|
+
environments = Puppet.lookup(:environments).list.map { |e| e.name }
|
51
|
+
modules = environments.map { |env|
|
49
52
|
Puppet.lookup(:environments).get(env).modules
|
50
|
-
|
53
|
+
}.flatten
|
51
54
|
|
52
55
|
# we want only PUBLIC modules that PRIVATE modules depend on
|
53
|
-
dependencies = modules.map
|
56
|
+
dependencies = modules.map { |mod|
|
54
57
|
next unless mod.dependencies
|
55
|
-
next if Dropsonde::Cache.
|
58
|
+
next if Dropsonde::Cache.forge_module? mod # skip unless this is a private module
|
56
59
|
|
57
60
|
# and return a list of all public modules it depends on
|
58
|
-
mod.dependencies.select {|
|
59
|
-
|
61
|
+
mod.dependencies.select { |dep| Dropsonde::Cache.forge_module? dep }
|
62
|
+
}.flatten.compact
|
60
63
|
|
61
64
|
[
|
62
|
-
{ :
|
65
|
+
{ dependencies: dependencies },
|
63
66
|
]
|
64
|
-
|
65
67
|
end
|
66
68
|
|
67
69
|
def self.example
|
@@ -69,14 +71,17 @@ class Dropsonde::Metrics::Dependencies
|
|
69
71
|
# make it easier to write data aggregation queries without access to the
|
70
72
|
# actual private data that users have submitted.
|
71
73
|
|
74
|
+
dropsonde_cache = Dropsonde::Cache.new('foo', 7, true)
|
72
75
|
versions = ['>= 1.5.2', '>= 4.3.2', '>= 3.0.0 < 4.0.0', '>= 2.2.1 < 5.0.0', '>= 5.0.0 < 7.0.0', '>= 4.11.0']
|
73
76
|
[
|
74
|
-
:
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
dependencies: dropsonde_cache.modules
|
78
|
+
.sample(rand(250))
|
79
|
+
.map do |item|
|
80
|
+
{
|
81
|
+
name: item,
|
82
|
+
version_requirement: versions.sample,
|
83
|
+
}
|
84
|
+
end,
|
80
85
|
]
|
81
86
|
end
|
82
87
|
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# environments plugin
|
1
4
|
class Dropsonde::Metrics::Environments
|
2
5
|
def self.initialize_environments
|
3
6
|
# Require any libraries needed here -- no need to load puppet or puppetdb;
|
@@ -7,20 +10,20 @@ class Dropsonde::Metrics::Environments
|
|
7
10
|
|
8
11
|
def self.description
|
9
12
|
# This is a Ruby squiggle heredoc; just a multi-line string with indentation removed
|
10
|
-
<<~
|
13
|
+
<<~DESCRIPTION
|
11
14
|
This group of metrics gathers information about environments.
|
12
|
-
|
15
|
+
DESCRIPTION
|
13
16
|
end
|
14
17
|
|
15
18
|
def self.schema
|
16
19
|
# return an array of hashes of a partial schema to be merged into the complete schema
|
17
20
|
[
|
18
21
|
{
|
19
|
-
"description":
|
20
|
-
"mode":
|
21
|
-
"name":
|
22
|
-
"type":
|
23
|
-
}
|
22
|
+
"description": 'The number of environments',
|
23
|
+
"mode": 'NULLABLE',
|
24
|
+
"name": 'environment_count',
|
25
|
+
"type": 'INTEGER',
|
26
|
+
},
|
24
27
|
]
|
25
28
|
end
|
26
29
|
|
@@ -28,10 +31,10 @@ class Dropsonde::Metrics::Environments
|
|
28
31
|
# run just before generating this metric
|
29
32
|
end
|
30
33
|
|
31
|
-
def self.run
|
34
|
+
def self.run(_puppetdb_session = nil)
|
32
35
|
# return an array of hashes representing the data to be merged into the combined checkin
|
33
36
|
[
|
34
|
-
:
|
37
|
+
environment_count: Puppet.lookup(:environments).list.count,
|
35
38
|
]
|
36
39
|
end
|
37
40
|
|
@@ -40,7 +43,7 @@ class Dropsonde::Metrics::Environments
|
|
40
43
|
# make it easier to write data aggregation queries without access to the
|
41
44
|
# actual private data that users have submitted.
|
42
45
|
[
|
43
|
-
:
|
46
|
+
environment_count: rand(1..100),
|
44
47
|
]
|
45
48
|
end
|
46
49
|
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# modules plugin
|
1
4
|
class Dropsonde::Metrics::Modules
|
2
5
|
def self.initialize_modules
|
3
6
|
# require any libraries needed here -- no need to load puppet; it's already initialized
|
@@ -5,10 +8,10 @@ class Dropsonde::Metrics::Modules
|
|
5
8
|
end
|
6
9
|
|
7
10
|
def self.description
|
8
|
-
<<~
|
11
|
+
<<~DESCRIPTION
|
9
12
|
This group of metrics exports name & version information about the public
|
10
13
|
modules installed in all environments, ignoring private modules.
|
11
|
-
|
14
|
+
DESCRIPTION
|
12
15
|
end
|
13
16
|
|
14
17
|
def self.schema
|
@@ -18,49 +21,49 @@ class Dropsonde::Metrics::Modules
|
|
18
21
|
{
|
19
22
|
"fields": [
|
20
23
|
{
|
21
|
-
"description":
|
22
|
-
"mode":
|
23
|
-
"name":
|
24
|
-
"type":
|
24
|
+
"description": 'The module name',
|
25
|
+
"mode": 'NULLABLE',
|
26
|
+
"name": 'name',
|
27
|
+
"type": 'STRING',
|
25
28
|
},
|
26
29
|
{
|
27
|
-
"description":
|
28
|
-
"mode":
|
29
|
-
"name":
|
30
|
-
"type":
|
30
|
+
"description": 'The module slug (author-name)',
|
31
|
+
"mode": 'NULLABLE',
|
32
|
+
"name": 'slug',
|
33
|
+
"type": 'STRING',
|
31
34
|
},
|
32
35
|
{
|
33
|
-
"description":
|
34
|
-
"mode":
|
35
|
-
"name":
|
36
|
-
"type":
|
37
|
-
}
|
36
|
+
"description": 'The module version',
|
37
|
+
"mode": 'NULLABLE',
|
38
|
+
"name": 'version',
|
39
|
+
"type": 'STRING',
|
40
|
+
},
|
38
41
|
],
|
39
|
-
"description":
|
40
|
-
"mode":
|
41
|
-
"name":
|
42
|
-
"type":
|
42
|
+
"description": 'List of modules in all environments.',
|
43
|
+
"mode": 'REPEATED',
|
44
|
+
"name": 'modules',
|
45
|
+
"type": 'RECORD',
|
43
46
|
},
|
44
47
|
{
|
45
48
|
"fields": [
|
46
49
|
{
|
47
|
-
"description":
|
48
|
-
"mode":
|
49
|
-
"name":
|
50
|
-
"type":
|
50
|
+
"description": 'The class name',
|
51
|
+
"mode": 'NULLABLE',
|
52
|
+
"name": 'name',
|
53
|
+
"type": 'STRING',
|
51
54
|
},
|
52
55
|
{
|
53
|
-
"description":
|
54
|
-
"mode":
|
55
|
-
"name":
|
56
|
-
"type":
|
57
|
-
}
|
56
|
+
"description": 'How many nodes it is declared on',
|
57
|
+
"mode": 'NULLABLE',
|
58
|
+
"name": 'count',
|
59
|
+
"type": 'INTEGER',
|
60
|
+
},
|
58
61
|
],
|
59
|
-
"description":
|
60
|
-
"mode":
|
61
|
-
"name":
|
62
|
-
"type":
|
63
|
-
}
|
62
|
+
"description": 'List of classes and counts in all environments.',
|
63
|
+
"mode": 'REPEATED',
|
64
|
+
"name": 'classes',
|
65
|
+
"type": 'RECORD',
|
66
|
+
},
|
64
67
|
]
|
65
68
|
end
|
66
69
|
|
@@ -68,46 +71,44 @@ class Dropsonde::Metrics::Modules
|
|
68
71
|
# run just before generating this metric
|
69
72
|
end
|
70
73
|
|
71
|
-
def self.run
|
74
|
+
def self.run(puppetdb_session = nil)
|
72
75
|
# return an array of hashes representing the data to be merged into the combined checkin
|
73
|
-
environments = Puppet.lookup(:environments).list.map{|e|e.name}
|
74
|
-
modules = environments.map
|
75
|
-
Puppet.lookup(:environments).get(env).modules.map do|mod|
|
76
|
+
environments = Puppet.lookup(:environments).list.map { |e| e.name }
|
77
|
+
modules = environments.map { |env|
|
78
|
+
Puppet.lookup(:environments).get(env).modules.map do |mod|
|
76
79
|
next unless mod.forge_module?
|
77
80
|
|
78
81
|
{
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:
|
82
|
+
name: mod.name,
|
83
|
+
slug: mod.forge_slug,
|
84
|
+
version: mod.version,
|
82
85
|
}
|
83
86
|
end
|
84
|
-
|
87
|
+
}.flatten.compact.uniq
|
85
88
|
|
86
|
-
if
|
89
|
+
if puppetdb_session
|
87
90
|
# classes and how many nodes they're enforced on
|
88
|
-
results =
|
89
|
-
'resources[type, title] { type = "Class" }'
|
90
|
-
).data
|
91
|
+
results = puppetdb_session.puppet_db.request('', 'resources[type, title] { type = "Class" }').data
|
91
92
|
|
92
93
|
# select only classes from public modules.
|
93
94
|
# Use uniq to reduce the iteration over very large datasets
|
94
|
-
classes = results.uniq.map
|
95
|
+
classes = results.uniq.map { |klass|
|
95
96
|
title = klass['title']
|
96
97
|
modname = title.split('::').first.downcase
|
97
|
-
next unless modules.find {|mod| mod[:name] == modname }
|
98
|
+
next unless modules.find { |mod| mod[:name] == modname }
|
98
99
|
|
99
100
|
{
|
100
|
-
:
|
101
|
-
:
|
101
|
+
name: title,
|
102
|
+
count: results.count { |row| row['title'] == title },
|
102
103
|
}
|
103
|
-
|
104
|
+
}.compact
|
104
105
|
else
|
105
106
|
classes = []
|
106
107
|
end
|
107
108
|
|
108
109
|
[
|
109
|
-
{ :
|
110
|
-
{ :
|
110
|
+
{ modules: modules },
|
111
|
+
{ classes: classes },
|
111
112
|
]
|
112
113
|
end
|
113
114
|
|
@@ -118,20 +119,25 @@ class Dropsonde::Metrics::Modules
|
|
118
119
|
|
119
120
|
versions = ['1.3.2', '0.0.1', '0.1.2', '1.0.0', '3.0.2', '7.10', '6.1.0', '2.1.0', '1.4.0']
|
120
121
|
classes = ['', '::Config', '::Service', '::Server', '::Client', '::Packages']
|
122
|
+
dropsonde_cache = Dropsonde::Cache.new('foo', 7, true)
|
121
123
|
[
|
122
|
-
:
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
124
|
+
modules: dropsonde_cache.modules
|
125
|
+
.sample(rand(100))
|
126
|
+
.map do |item|
|
127
|
+
{
|
128
|
+
name: item.split('-').last,
|
129
|
+
slug: item,
|
130
|
+
version: versions.sample,
|
131
|
+
}
|
132
|
+
end,
|
133
|
+
classes: dropsonde_cache.modules
|
134
|
+
.sample(rand(500))
|
135
|
+
.map do |item|
|
136
|
+
{
|
137
|
+
name: item.split('-').last.capitalize + classes.sample,
|
138
|
+
count: rand(750),
|
139
|
+
}
|
140
|
+
end,
|
135
141
|
]
|
136
142
|
end
|
137
143
|
|