Class: PuppetGhostbuster

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet-ghostbuster.rb,
lib/puppet-ghostbuster/version.rb,
lib/puppet-ghostbuster/configuration.rb

Defined Under Namespace

Classes: Bin, Configuration, OptParser

Constant Summary collapse

VERSION =
'0.4.2'
@@issues =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path = '.') ⇒ PuppetGhostbuster

Returns a new instance of PuppetGhostbuster.



167
168
169
170
171
172
173
# File 'lib/puppet-ghostbuster.rb', line 167

def initialize(path = '.')
  self.path = path
  @@logger = Logger.new(STDERR).tap do |log|
    log.progname = 'PuppetGhostbuster'
    log.level=PuppetGhostbuster.configuration.loglevel
  end
end

Instance Attribute Details

#pathObject

Returns the value of attribute path.



12
13
14
# File 'lib/puppet-ghostbuster.rb', line 12

def path
  @path
end

Class Method Details

.cacheObject



50
51
52
# File 'lib/puppet-ghostbuster.rb', line 50

def self.cache
  "/var/tmp/puppet-ghostbuster.#{puppetdbserverfilename}.cache"
end

.clientObject



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/puppet-ghostbuster.rb', line 69

def self.client
  @@logger.debug "Connecting to puppet DB #{configuration.puppetdbserverurl}"
  PuppetDB::Client.new({
    :server => "#{configuration.puppetdbserverurl}/pdb/query",
    :pem    => {
      'key'     => configuration.hostprivkey,
      'cert'    => configuration.hostcert,
      'ca_file' => configuration.localcacert,
    }
  }, 4)
end

.configurationObject



38
39
40
# File 'lib/puppet-ghostbuster.rb', line 38

def self.configuration
  @configuration ||= PuppetGhostbuster::Configuration.new
end

.get_cacheObject



61
62
63
64
65
66
67
# File 'lib/puppet-ghostbuster.rb', line 61

def self.get_cache
  if File.exists?(cache)
    JSON.parse(File.read(cache))
  else
    false
  end
end

.puppetdbserverfilenameObject



46
47
48
# File 'lib/puppet-ghostbuster.rb', line 46

def self.puppetdbserverfilename
  return configuration.puppetdbserverurl.gsub(/[:\/]/,'_')
end

.update_cache(value) ⇒ Object



54
55
56
57
58
59
# File 'lib/puppet-ghostbuster.rb', line 54

def self.update_cache(value)
  File.open(cache, 'w') do |f|
    f.write(value)
  end
  value
end

.used_classesObject



81
82
83
84
85
86
87
88
89
90
# File 'lib/puppet-ghostbuster.rb', line 81

def self.used_classes
  return get_cache || update_cache(
    client.request(
      'resources',
      [:'=', 'type', 'Class'],
    ).data.map { |resource|
      resource['title']
    }
  )
end

Instance Method Details

#configurationObject



42
43
44
# File 'lib/puppet-ghostbuster.rb', line 42

def configuration
  self.class.configuration
end

#exclude(filelist) ⇒ Object



15
16
17
18
19
20
21
22
23
24
# File 'lib/puppet-ghostbuster.rb', line 15

def exclude(filelist)
  ignorefile = "#{path}/.ghostbusterignore"
  if File.exist?(ignorefile) then
    ignorelist = File.readlines(ignorefile).each {|l| l.chomp!}
    ignorelist.each do |ignorerule|
      filelist.reject! { |item| item =~ /^#{path}\/#{ignorerule}/ }
    end
  end
  filelist
end

#filesObject



34
35
36
# File 'lib/puppet-ghostbuster.rb', line 34

def files
  exclude Dir["#{path}/**/files/**/*"]
end

#find_unused_classesObject



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/puppet-ghostbuster.rb', line 92

def find_unused_classes
  @@logger.info 'Now trying to find unused classes'
  manifests.each do |file|
    @@logger.debug "  file #{file}."
    if File.symlink?(file)
      @@logger.warn "  Skipping symlink #{file}"
      next
    end
    if c = File.readlines(file).grep(/^class\s+([^\s\(\{]+)/){$1}[0]
      class_name = c.split('::').map(&:capitalize).join('::')
      count = self.class.used_classes.select { |klass| klass == class_name }.size
      @@issues << { :title => "[GhostBuster] Class #{class_name} seems unused", :body => file } if count == 0
    end
  end
end

#find_unused_definesObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/puppet-ghostbuster.rb', line 108

def find_unused_defines
  @@logger.info 'Now trying to find unused defines'
  manifests.each do |file|
    if File.symlink?(file)
      @@logger.warn "  Skipping symlink #{file}"
      next
    end
    if d = File.readlines(file).grep(/^define\s+([^\s\(\{]+)/){$1}[0]
      define_name = d.split('::').map(&:capitalize).join('::')
      count = self.class.client.request('resources', [:'=', 'type', define_name]).data.size
      @@issues << { :title => "[GhostBuster] Define #{define_name} seems unused", :body => file } if count == 0
    end
  end
end

#find_unused_filesObject



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/puppet-ghostbuster.rb', line 144

def find_unused_files
  @@logger.info 'Now trying to find unused files'
  files.each do |file|
    next unless File.file?(file)
    module_name, file_name = file.match(/.*\/([^\/]+)\/files\/(.+)$/).captures
    count = 0
    manifests.each do |manifest|
      if File.symlink?(manifest)
        @@logger.warn "  Skipping symlink #{manifest}"
        next
      end
      if match = manifest.match(/.*\/([^\/]+)\/manifests\/.+$/)
        manifest_module_name = match.captures[0]
        if manifest_module_name == module_name
          count += File.readlines(manifest).grep(/["']\$\{module_name\}\/#{file_name}["']/).size
        end
      end
      count += File.readlines(manifest).grep(/#{module_name}\/#{file_name}/).size
    end
    @@issues << { :title => "[GhostBuster] File #{module_name}/#{file_name} seems unused", :body => file } if count == 0
  end
end

#find_unused_templatesObject



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/puppet-ghostbuster.rb', line 123

def find_unused_templates
  @@logger.info 'Now trying to find unused templates'
  templates.each do |template|
    next unless File.file?(template)
    module_name, template_name = template.match(/.*\/([^\/]+)\/templates\/(.+)$/).captures
    count = 0
    manifests.each do |manifest|
      if File.symlink?(manifest)
        @@logger.warn "  Skipping symlink #{manifest}"
        next
      end
      if match = manifest.match(/.*\/([^\/]+)\/manifests\/.+$/)
        manifest_module_name = match.captures[0]
        count += File.readlines(manifest).grep(/["']\$\{module_name\}\/#{template_name}["']/).size if manifest_module_name == module_name
      end
      count += File.readlines(manifest).grep(/["']#{module_name}\/#{template_name}["']/).size
    end
    @@issues << { :title => "[GhostBuster] Template #{module_name}/#{template_name} seems unused", :body => template } if count == 0
  end
end

#manifestsObject



26
27
28
# File 'lib/puppet-ghostbuster.rb', line 26

def manifests
  exclude Dir["#{path}/**/manifests/**/*.pp"]
end

#runObject



175
176
177
178
179
180
181
# File 'lib/puppet-ghostbuster.rb', line 175

def run
  find_unused_classes
  find_unused_defines
  find_unused_templates
  find_unused_files
  puts @@issues.to_json
end

#templatesObject



30
31
32
# File 'lib/puppet-ghostbuster.rb', line 30

def templates
  exclude Dir["#{path}/**/templates/**/*"]
end