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
@@ -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
|
-
<<~
|
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
|
-
|
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":
|
23
|
-
"mode":
|
24
|
-
"name":
|
25
|
-
"type":
|
25
|
+
"description": 'The class name name',
|
26
|
+
"mode": 'NULLABLE',
|
27
|
+
"name": 'name',
|
28
|
+
"type": 'STRING',
|
26
29
|
},
|
27
30
|
{
|
28
|
-
"description":
|
29
|
-
"mode":
|
30
|
-
"name":
|
31
|
-
"type":
|
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":
|
35
|
-
"mode":
|
36
|
-
"name":
|
37
|
-
"type":
|
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":
|
42
|
-
"name":
|
43
|
-
"type":
|
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
|
57
|
+
return unless puppetdb_session
|
55
58
|
|
56
|
-
classes =
|
57
|
-
facts =
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
78
|
-
|
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
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
:
|
91
|
+
class_platforms: data,
|
90
92
|
]
|
91
93
|
end
|
92
94
|
|
@@ -95,25 +97,26 @@ 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 = [
|
100
|
+
platforms = %w[RedHat Debian Windows Suse FreeBSD Darwin Archlinux AIX]
|
99
101
|
classes = ['', '::Config', '::Service', '::Server', '::Client', '::Packages']
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
103
|
+
dropsonde_cache = Dropsonde::Cache.new('foo', 7, true)
|
104
|
+
data = dropsonde_cache.modules
|
105
|
+
.sample(rand(35))
|
106
|
+
.map { |item|
|
107
|
+
name = item.split('-').last.capitalize + classes.sample
|
105
108
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
109
|
+
rand(5).times.map do
|
110
|
+
{
|
111
|
+
name: name,
|
112
|
+
platform: platforms.sample,
|
113
|
+
count: rand(1000),
|
114
|
+
}
|
115
|
+
end
|
116
|
+
}.flatten
|
114
117
|
|
115
118
|
[
|
116
|
-
:
|
119
|
+
class_platforms: data.uniq,
|
117
120
|
]
|
118
121
|
end
|
119
122
|
|
@@ -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
|
-
<<~
|
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
|
-
|
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":
|
23
|
-
"mode":
|
24
|
-
"name":
|
25
|
-
"type":
|
25
|
+
"description": 'The method name',
|
26
|
+
"mode": 'NULLABLE',
|
27
|
+
"name": 'name',
|
28
|
+
"type": 'STRING',
|
26
29
|
},
|
27
30
|
{
|
28
|
-
"description":
|
29
|
-
"mode":
|
30
|
-
"name":
|
31
|
-
"type":
|
32
|
-
}
|
31
|
+
"description": 'How many times is it used',
|
32
|
+
"mode": 'NULLABLE',
|
33
|
+
"name": 'count',
|
34
|
+
"type": 'INTEGER',
|
35
|
+
},
|
33
36
|
],
|
34
|
-
"description":
|
35
|
-
"mode":
|
36
|
-
"name":
|
37
|
-
"type":
|
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
|
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
|
-
|
59
|
+
indices.map { |i| tokens[i + 2] }
|
60
|
+
}.flatten.compact
|
58
61
|
|
59
|
-
methods.reject! {|name| [
|
62
|
+
methods.reject! { |name| %w[mod forge moduledir].include? name }
|
60
63
|
|
61
64
|
methods = methods.uniq.map do |name|
|
62
65
|
{
|
63
|
-
:
|
64
|
-
:
|
66
|
+
name: name,
|
67
|
+
count: methods.count(name),
|
65
68
|
}
|
66
69
|
end
|
67
70
|
|
68
71
|
[
|
69
|
-
{ :
|
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
|
-
:
|
79
|
-
{:
|
80
|
-
{:
|
81
|
-
{:
|
82
|
-
{:
|
83
|
-
{:
|
84
|
-
{:
|
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
|
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