Last active
August 29, 2015 14:10
-
-
Save spraints/483a4c3eb51afce7a247 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/ Usage: sudo ruby docker-aufs-fsck.rb | |
#/ Your docker aufs storage will be checked for orphaned or missing layers. | |
def main | |
aufs_root = find_aufs_root | |
die "Could not find aufs root!" if aufs_root.nil? | |
fsck = Fsck.new({ | |
:images => `docker images -a -q --no-trunc`.split(/\s+/), | |
:containers => `docker ps -a -q --no-trunc`.split(/\s+/), | |
}) | |
Dir.chdir(aufs_root) do | |
Subdirs.each do |dir| | |
Dir.new(dir).each do |id| | |
next if id == "." || id == ".." | |
fsck.scan(id) | |
end | |
end | |
end | |
fsck.each_error do |error| | |
puts error | |
end | |
end | |
Subdirs = %w(layers diff mnt) | |
class Fsck | |
def initialize(options) | |
@tracked = options | |
@processed = {} | |
@graph = {} | |
@graph_errors = [] | |
end | |
def scan(id) | |
load_graph(id) | |
@processed[id] ||= { | |
:missing_files => Subdirs.select { |subdir| ! File.exist?(File.join(subdir, id)) }, | |
} | |
end | |
def each_error | |
@graph_errors.each do |error| | |
yield error | |
end | |
@processed.each do |id, info| | |
if info[:missing_files].any? | |
yield "#{id}: Missing #{info[:missing_files].join(", ")}" | |
end | |
end | |
@tracked.each do |type, ids| | |
# type should be :images or :containers | |
ids.each do |id| | |
if !@processed[id] | |
yield "#{type} #{id}: not in storage!" | |
end | |
if !@graph[id] | |
yield "#{type} #{id}: not in the graph!" | |
else | |
@graph[id][:is] = type | |
end | |
end | |
end | |
@graph.each do |id, node| | |
if node[:tip] && !node[:is] | |
yield "#{id}: Not reachable from any image or container!" | |
end | |
end | |
end | |
private | |
def load_graph(id) | |
layers = File.read(File.join("layers", id)).lines.map(&:strip) | |
# inject is designed for neckbeards | |
layers.inject(@graph[id] ||= {:id => id, :tip => true}) do |cur_node, next_id| | |
cur_node[:next] ||= next_id | |
if cur_node[:next] != next_id | |
@graph_errors << "layers/#{id}: #{cur_node[:id]} -> #{cur_node[:next]} AND #{next_id}" | |
end | |
(@graph[next_id] ||= {:id => next_id}).tap { |node| node[:tip] = false } | |
end | |
end | |
end | |
def find_aufs_root | |
docker_info = `docker info` | |
docker_info =~ /Storage Driver: aufs/ and | |
docker_info =~ /^ Root Dir: (.*)/ and | |
$1 | |
end | |
def die(message) | |
puts message | |
exit 1 | |
end | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment