dropsonde 0.0.5 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,19 @@
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
4
7
  # All plugins are initialized before any metrics are generated.
8
+ require 'puppet/info_service'
9
+ require 'puppet/info_service/class_information_service'
5
10
  end
6
11
 
7
12
  def self.description
8
- <<~EOF
13
+ <<~DESCRIPTION
9
14
  This group of metrics exports name & version information about the public
10
15
  modules installed in all environments, ignoring private modules.
11
- EOF
16
+ DESCRIPTION
12
17
  end
13
18
 
14
19
  def self.schema
@@ -18,49 +23,89 @@ class Dropsonde::Metrics::Modules
18
23
  {
19
24
  "fields": [
20
25
  {
21
- "description": "The module name",
22
- "mode": "NULLABLE",
23
- "name": "name",
24
- "type": "STRING"
26
+ "description": 'The module name',
27
+ "mode": 'NULLABLE',
28
+ "name": 'name',
29
+ "type": 'STRING',
25
30
  },
26
31
  {
27
- "description": "The module slug (author-name)",
28
- "mode": "NULLABLE",
29
- "name": "slug",
30
- "type": "STRING"
32
+ "description": 'The module slug (author-name)',
33
+ "mode": 'NULLABLE',
34
+ "name": 'slug',
35
+ "type": 'STRING',
31
36
  },
32
37
  {
33
- "description": "The module version",
34
- "mode": "NULLABLE",
35
- "name": "version",
36
- "type": "STRING"
37
- }
38
+ "description": 'The module version',
39
+ "mode": 'NULLABLE',
40
+ "name": 'version',
41
+ "type": 'STRING',
42
+ },
38
43
  ],
39
- "description": "List of modules in all environments.",
40
- "mode": "REPEATED",
41
- "name": "modules",
42
- "type": "RECORD"
44
+ "description": 'List of modules in all environments.',
45
+ "mode": 'REPEATED',
46
+ "name": 'modules',
47
+ "type": 'RECORD',
43
48
  },
44
49
  {
45
50
  "fields": [
46
51
  {
47
- "description": "The class name",
48
- "mode": "NULLABLE",
49
- "name": "name",
50
- "type": "STRING"
52
+ "description": 'The class name',
53
+ "mode": 'NULLABLE',
54
+ "name": 'name',
55
+ "type": 'STRING',
51
56
  },
52
57
  {
53
- "description": "How many nodes it is declared on",
54
- "mode": "NULLABLE",
55
- "name": "count",
56
- "type": "INTEGER"
57
- }
58
+ "description": 'How many nodes it is declared on',
59
+ "mode": 'NULLABLE',
60
+ "name": 'count',
61
+ "type": 'INTEGER',
62
+ },
58
63
  ],
59
- "description": "List of classes and counts in all environments.",
60
- "mode": "REPEATED",
61
- "name": "classes",
62
- "type": "RECORD"
63
- }
64
+ "description": 'List of classes and counts in all environments.',
65
+ "mode": 'REPEATED',
66
+ "name": 'classes',
67
+ "type": 'RECORD',
68
+ },
69
+ {
70
+ "fields": [
71
+ {
72
+ "description": 'The module name',
73
+ "mode": 'NULLABLE',
74
+ "name": 'name',
75
+ "type": 'STRING',
76
+ },
77
+ {
78
+ "description": 'The module slug (author-name)',
79
+ "mode": 'NULLABLE',
80
+ "name": 'slug',
81
+ "type": 'STRING',
82
+ },
83
+ {
84
+ "description": 'The module version',
85
+ "mode": 'NULLABLE',
86
+ "name": 'version',
87
+ "type": 'STRING',
88
+ },
89
+ ],
90
+ "description": 'List of modules whose classes are not declared in any environments.',
91
+ "mode": 'REPEATED',
92
+ "name": 'unused_modules',
93
+ "type": 'RECORD',
94
+ },
95
+ {
96
+ "fields": [
97
+ {
98
+ "description": 'The class name',
99
+ "mode": 'NULLABLE',
100
+ "name": 'name',
101
+ "type": 'STRING',
102
+ },
103
+ ],
104
+ "description": 'List of unused classes in all environments.',
105
+ "mode": 'REPEATED',
106
+ "name": 'unused_classes',
107
+ "type": 'RECORD',
108
+ },
64
109
  ]
65
110
  end
66
111
 
@@ -68,46 +113,76 @@ class Dropsonde::Metrics::Modules
68
113
  # run just before generating this metric
69
114
  end
70
115
 
71
- def self.run
116
+ def self.run(puppetdb_session = nil)
72
117
  # 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 do |env|
75
- Puppet.lookup(:environments).get(env).modules.map do|mod|
118
+ environments = Puppet.lookup(:environments).list.map { |e| e.name }
119
+ modules = environments.map { |env|
120
+ Puppet.lookup(:environments).get(env).modules.map do |mod|
76
121
  next unless mod.forge_module?
77
122
 
78
123
  {
79
- :name => mod.name,
80
- :slug => mod.forge_slug,
81
- :version => mod.version,
124
+ name: mod.name,
125
+ slug: mod.forge_slug,
126
+ version: mod.version,
82
127
  }
83
128
  end
84
- end.flatten.compact.uniq
129
+ }.flatten.compact.uniq
85
130
 
86
- if Dropsonde.puppetDB
131
+ if puppetdb_session
87
132
  # classes and how many nodes they're enforced on
88
- results = Dropsonde.puppetDB.request( '',
89
- 'resources[type, title] { type = "Class" }'
90
- ).data
133
+ results = puppetdb_session.puppet_db.request('', 'resources[type, title] { type = "Class" }').data
91
134
 
92
135
  # select only classes from public modules.
93
136
  # Use uniq to reduce the iteration over very large datasets
94
- classes = results.uniq.map do |klass|
137
+ classes = results.uniq.map { |klass|
95
138
  title = klass['title']
96
139
  modname = title.split('::').first.downcase
97
- next unless modules.find {|mod| mod[:name] == modname }
140
+ next unless modules.find { |mod| mod[:name] == modname }
98
141
 
99
142
  {
100
- :name => title,
101
- :count => results.count {|row| row['title'] == title},
143
+ name: title,
144
+ count: results.count { |row| row['title'] == title },
102
145
  }
103
- end.compact
146
+ }.compact
147
+
148
+ # now lets get a list of all classes so we can identify which are unused
149
+ infoservice = Puppet::InfoService::ClassInformationService.new
150
+ env_hash = {}
151
+ environments.each do |env|
152
+ manifests = Puppet.lookup(:environments).get(env).modules.reduce([]) do |acc, mod|
153
+ next acc unless mod.forge_module?
154
+
155
+ acc.concat mod.all_manifests
156
+ end
157
+ env_hash[env] = manifests
158
+ end
159
+
160
+ klasses_per_env = infoservice.classes_per_environment(env_hash)
161
+
162
+ installed_classes = klasses_per_env.reduce([]) do |klasses, (_key, env)|
163
+ names = env.reduce([]) do |acc, (_file, contents)|
164
+ acc.concat(contents[:classes].map { |c| c[:name] })
165
+ end
166
+
167
+ klasses.concat names
168
+ end
169
+
170
+ unused_modules = installed_classes.map { |c| c.split('::').first }.sort.uniq
171
+ classes.each { |c| unused_modules.delete(c[:name].split('::').first.downcase) }
172
+
173
+ unused_classes = installed_classes.dup
174
+ classes.each { |c| unused_classes.delete(c[:name].downcase) }
104
175
  else
105
176
  classes = []
177
+ unused_modules = []
178
+ unused_classes = []
106
179
  end
107
180
 
108
181
  [
109
- { :modules => modules },
110
- { :classes => classes },
182
+ { modules: modules },
183
+ { classes: classes },
184
+ { unused_modules: unused_modules },
185
+ { unused_classes: unused_classes },
111
186
  ]
112
187
  end
113
188
 
@@ -119,19 +194,29 @@ class Dropsonde::Metrics::Modules
119
194
  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
195
  classes = ['', '::Config', '::Service', '::Server', '::Client', '::Packages']
121
196
  [
122
- :modules => Dropsonde::Cache.modules
123
- .sample(rand(100))
124
- .map {|item| {
125
- :name => item.split('-').last,
126
- :slug => item,
127
- :version => versions.sample,
128
- }},
129
- :classes => Dropsonde::Cache.modules
130
- .sample(rand(500))
131
- .map {|item| {
132
- :name => item.split('-').last.capitalize + classes.sample,
133
- :count => rand(750),
134
- }},
197
+ modules: Dropsonde::Cache.modules
198
+ .sample(rand(100))
199
+ .map do |item|
200
+ {
201
+ name: item.split('-').last,
202
+ slug: item,
203
+ version: versions.sample,
204
+ }
205
+ end,
206
+ classes: Dropsonde::Cache.modules
207
+ .sample(rand(500))
208
+ .map do |item|
209
+ {
210
+ name: item.split('-').last.capitalize + classes.sample,
211
+ count: rand(750),
212
+ }
213
+ end,
214
+ unused_modules: Dropsonde::Cache.modules
215
+ .sample(rand(500))
216
+ .map { |item| item.split('-').last },
217
+ unused_classes: Dropsonde::Cache.modules
218
+ .sample(rand(500))
219
+ .map { |item| item.split('-').last.capitalize + classes.sample },
135
220
  ]
136
221
  end
137
222
 
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # platforms plugin
1
4
  class Dropsonde::Metrics::Platforms
2
5
  def self.initialize_platforms
3
6
  # require any libraries needed here -- no need to load puppet; it's already initialized
@@ -5,11 +8,11 @@ class Dropsonde::Metrics::Platforms
5
8
  end
6
9
 
7
10
  def self.description
8
- <<~EOF
11
+ <<~DESCRIPTION
9
12
  This group of metrics generates usage patterns by platform.
10
13
  Currently implemented is a list of classes, the platforms
11
14
  they are declared on, and a count of each combination.
12
- EOF
15
+ DESCRIPTION
13
16
  end
14
17
 
15
18
  def self.schema
@@ -19,29 +22,29 @@ class Dropsonde::Metrics::Platforms
19
22
  {
20
23
  "fields": [
21
24
  {
22
- "description": "The class name name",
23
- "mode": "NULLABLE",
24
- "name": "name",
25
- "type": "STRING"
25
+ "description": 'The class name name',
26
+ "mode": 'NULLABLE',
27
+ "name": 'name',
28
+ "type": 'STRING',
26
29
  },
27
30
  {
28
- "description": "The osfamily of the node the class is declared on",
29
- "mode": "NULLABLE",
30
- "name": "platform",
31
- "type": "STRING"
31
+ "description": 'The osfamily of the node the class is declared on',
32
+ "mode": 'NULLABLE',
33
+ "name": 'platform',
34
+ "type": 'STRING',
32
35
  },
33
36
  {
34
- "description": "The number of time this combination is declared",
35
- "mode": "NULLABLE",
36
- "name": "count",
37
- "type": "INTEGER"
37
+ "description": 'The number of time this combination is declared',
38
+ "mode": 'NULLABLE',
39
+ "name": 'count',
40
+ "type": 'INTEGER',
38
41
  },
39
42
  ],
40
43
  "description": "List of all classes in the infrastructure and platforms they're declared on.",
41
- "mode": "REPEATED",
42
- "name": "class_platforms",
43
- "type": "RECORD"
44
- }
44
+ "mode": 'REPEATED',
45
+ "name": 'class_platforms',
46
+ "type": 'RECORD',
47
+ },
45
48
  ]
46
49
  end
47
50
 
@@ -49,44 +52,43 @@ class Dropsonde::Metrics::Platforms
49
52
  # run just before generating this metric
50
53
  end
51
54
 
52
- def self.run
55
+ def self.run(puppetdb_session = nil)
53
56
  # skip this metric if we don't have an active PuppetDB connection
54
- return unless Dropsonde.puppetDB
57
+ return unless puppetdb_session
55
58
 
56
- classes = Dropsonde.puppetDB.request( '', 'resources[certname, title] { type = "Class" }').data
57
- facts = Dropsonde.puppetDB.request( '', 'facts[certname, value] { name = "osfamily" }').data
59
+ classes = puppetdb_session.puppet_db.request('', 'resources[certname, title] { type = "Class" }').data
60
+ facts = puppetdb_session.puppet_db.request('', 'facts[certname, value] { name = "osfamily" }').data
58
61
 
59
62
  # All public Forge modules that are installed.
60
- modules = Puppet.lookup(:environments).list.map {|env|
61
- env.modules.select {|mod|
62
- mod.forge_module?
63
- }.map {|fmod|
64
- fmod.name
65
- }}.flatten.uniq
66
-
67
- data = classes.map {|item|
68
- # filter out any that don't come from public Forge modules
69
- mod = item['title'].split('::').first.downcase
70
- next unless modules.include? mod
71
-
72
- item['platform'] = facts.find {|fact|
73
- fact['certname'] == item['certname']
74
- }['value']
63
+ modules = Puppet.lookup(:environments).list.map { |env|
64
+ env.modules.select { |mod| mod.forge_module? }.map do |fmod|
65
+ fmod.name
66
+ end
67
+ }.flatten.uniq
75
68
 
76
- {
77
- :name => item['title'],
78
- :platform => item['platform'],
79
- }
69
+ data = classes.map { |item|
70
+ # filter out any that don't come from public Forge modules
71
+ mod = item['title'].split('::').first.downcase
72
+ next unless modules.include? mod
73
+
74
+ item['platform'] = facts.find { |fact|
75
+ fact['certname'] == item['certname']
76
+ }['value']
77
+
78
+ {
79
+ name: item['title'],
80
+ platform: item['platform'],
81
+ }
80
82
  }.compact
81
83
 
82
- data.each {|item|
83
- item['count'] = data.select {|i|
84
- i[:name] == item[:name] and i[:platform] == item[:platform]
85
- }.count
86
- }
84
+ data.each do |item|
85
+ item[:count] = data.select { |i|
86
+ i[:name] == item[:name] and i[:platform] == item[:platform]
87
+ }.count
88
+ end
87
89
 
88
90
  [
89
- :class_platforms => data,
91
+ class_platforms: data,
90
92
  ]
91
93
  end
92
94
 
@@ -95,25 +97,25 @@ class Dropsonde::Metrics::Platforms
95
97
  # make it easier to write data aggregation queries without access to the
96
98
  # actual private data that users have submitted.
97
99
 
98
- platforms = ['RedHat', 'Debian', 'Windows', 'Suse', 'FreeBSD', 'Darwin', 'Archlinux', 'AIX']
100
+ platforms = %w[RedHat Debian Windows Suse FreeBSD Darwin Archlinux AIX]
99
101
  classes = ['', '::Config', '::Service', '::Server', '::Client', '::Packages']
100
102
 
101
103
  data = Dropsonde::Cache.modules
102
- .sample(rand(35))
103
- .map do |item|
104
- name = item.split('-').last.capitalize + classes.sample
105
-
106
- rand(5).times.map do
107
- {
108
- :name => name,
109
- :platform => platforms.sample,
110
- :count => rand(1000),
111
- }
112
- end
113
- end.flatten
104
+ .sample(rand(35))
105
+ .map { |item|
106
+ name = item.split('-').last.capitalize + classes.sample
107
+
108
+ rand(5).times.map do
109
+ {
110
+ name: name,
111
+ platform: platforms.sample,
112
+ count: rand(1000),
113
+ }
114
+ end
115
+ }.flatten
114
116
 
115
117
  [
116
- :class_platforms => data.uniq,
118
+ class_platforms: data.uniq,
117
119
  ]
118
120
  end
119
121
 
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # puppetfiles plugin
1
4
  class Dropsonde::Metrics::Puppetfiles
2
5
  def self.initialize_puppetfiles
3
6
  # require any libraries needed here -- no need to load puppet; it's already initialized
@@ -6,10 +9,10 @@ class Dropsonde::Metrics::Puppetfiles
6
9
  end
7
10
 
8
11
  def self.description
9
- <<~EOF
12
+ <<~DESCRIPTION
10
13
  This generates interesting stats about Puppetfiles used in your environments,
11
14
  including whether your Puppetfiles have Ruby code in them.
12
- EOF
15
+ DESCRIPTION
13
16
  end
14
17
 
15
18
  def self.schema
@@ -19,23 +22,23 @@ class Dropsonde::Metrics::Puppetfiles
19
22
  {
20
23
  "fields": [
21
24
  {
22
- "description": "The method name",
23
- "mode": "NULLABLE",
24
- "name": "name",
25
- "type": "STRING"
25
+ "description": 'The method name',
26
+ "mode": 'NULLABLE',
27
+ "name": 'name',
28
+ "type": 'STRING',
26
29
  },
27
30
  {
28
- "description": "How many times is it used",
29
- "mode": "NULLABLE",
30
- "name": "count",
31
- "type": "INTEGER"
32
- }
31
+ "description": 'How many times is it used',
32
+ "mode": 'NULLABLE',
33
+ "name": 'count',
34
+ "type": 'INTEGER',
35
+ },
33
36
  ],
34
- "description": "Ruby methods used in Puppetfiles.",
35
- "mode": "REPEATED",
36
- "name": "puppetfile_ruby_methods",
37
- "type": "RECORD"
38
- }
37
+ "description": 'Ruby methods used in Puppetfiles.',
38
+ "mode": 'REPEATED',
39
+ "name": 'puppetfile_ruby_methods',
40
+ "type": 'RECORD',
41
+ },
39
42
  ]
40
43
  end
41
44
 
@@ -43,30 +46,30 @@ class Dropsonde::Metrics::Puppetfiles
43
46
  # run just before generating this metric
44
47
  end
45
48
 
46
- def self.run
47
- methods = Dir.entries(Puppet.settings[:environmentpath]).map do |entry|
49
+ def self.run(_puppetdb_session = nil)
50
+ methods = Dir.entries(Puppet.settings[:environmentpath]).map { |entry|
48
51
  puppetfile = File.join(Puppet.settings[:environmentpath], entry, 'Puppetfile')
49
52
 
50
53
  next if entry.start_with? '.'
51
54
  next unless File.file? puppetfile
52
55
 
53
56
  tokens = Ripper.sexp(File.read(puppetfile)).flatten
54
- indices = tokens.map.with_index {|a, i| a == :command ? i : nil}.compact
57
+ indices = tokens.map.with_index { |a, i| (a == :command) ? i : nil }.compact
55
58
 
56
- indices.map {|i| tokens[i+2] }
57
- end.flatten.compact
59
+ indices.map { |i| tokens[i + 2] }
60
+ }.flatten.compact
58
61
 
59
- methods.reject! {|name| ['mod', 'forge', 'moduledir'].include? name }
62
+ methods.reject! { |name| %w[mod forge moduledir].include? name }
60
63
 
61
64
  methods = methods.uniq.map do |name|
62
65
  {
63
- :name => name,
64
- :count => methods.count(name),
66
+ name: name,
67
+ count: methods.count(name),
65
68
  }
66
69
  end
67
70
 
68
71
  [
69
- { :puppetfile_ruby_methods => methods },
72
+ { puppetfile_ruby_methods: methods },
70
73
  ]
71
74
  end
72
75
 
@@ -75,13 +78,13 @@ class Dropsonde::Metrics::Puppetfiles
75
78
  # make it easier to write data aggregation queries without access to the
76
79
  # actual private data that users have submitted.
77
80
  [
78
- :puppetfile_ruby_methods => [
79
- {:name => 'require', :count => rand(200)},
80
- {:name => 'each', :count => rand(200)},
81
- {:name => 'puts', :count => rand(200)},
82
- {:name => 'select', :count => rand(200)},
83
- {:name => 'reject', :count => rand(200)},
84
- {:name => 'read', :count => rand(200)},
81
+ puppetfile_ruby_methods: [
82
+ { name: 'require', count: rand(200) },
83
+ { name: 'each', count: rand(200) },
84
+ { name: 'puts', count: rand(200) },
85
+ { name: 'select', count: rand(200) },
86
+ { name: 'reject', count: rand(200) },
87
+ { name: 'read', count: rand(200) },
85
88
  ].shuffle,
86
89
  ]
87
90
  end