Skip to content

Instantly share code, notes, and snippets.

@spraints
Last active August 29, 2015 14:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spraints/483a4c3eb51afce7a247 to your computer and use it in GitHub Desktop.
Save spraints/483a4c3eb51afce7a247 to your computer and use it in GitHub Desktop.
#/ 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