| #!/usr/bin/python |
| from subprocess import check_output, STDOUT, CalledProcessError |
| import os |
| import time |
| import argparse |
| import logging |
| import stat |
| |
| # Root location of git repos |
| GITROOT = "/srv/repositories" |
| # Export filename |
| EXPORT_FILE = "git-daemon-export-ok" |
| |
| logging.basicConfig() |
| log = logging.getLogger('check-git-repos') |
| |
| |
| def run_command(cmd, dir): |
| log.debug("executing %s in %s", cmd, dir) |
| try: |
| out = check_output(cmd, stderr=STDOUT, |
| cwd=dir) |
| except CalledProcessError as e: |
| return e.returncode, e.output |
| return 0, out |
| |
| |
| def update_server_info(path): |
| return run_command(["git", "update-server-info"], path) |
| |
| |
| def get_file_refs(path): |
| filerefs = {} |
| with open(os.path.join(path, "info/refs")) as f: |
| for line in f: |
| if line: |
| data = line.split() |
| filerefs[data[1]] = data[0] |
| return filerefs |
| |
| |
| def get_git_refs(path): |
| ret, out = run_command(["git", "show-ref", "-d"], path) |
| lines = out.split("\n") |
| gitrefs = {} |
| for line in lines: |
| if line: |
| data = line.split() |
| gitrefs[data[1]] = data[0] |
| return gitrefs |
| |
| |
| def perms_check(file): |
| st_mode = os.stat(file).st_mode |
| mode = stat.S_IFREG | stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | \ |
| stat.S_IROTH |
| if st_mode != mode: |
| log.warn("Permissions wrong for file %s, changing %s=>%s", file, |
| oct(st_mode), oct(mode)) |
| os.chmod(file, mode) |
| |
| |
| def get_repos(): |
| paths = [] |
| for root, dirs, files in os.walk(GITROOT, followlinks=True): |
| if root.endswith(".git/info"): |
| if "refs" in files: |
| log.debug("found refs file %s", root+"/refs") |
| repo_path = os.path.dirname(root) |
| repo_name = os.path.basename(os.path.normpath(repo_path)) |
| if repo_name != "gitolite-admin.git": |
| paths.append(repo_path) |
| return paths |
| |
| |
| def check_ref_status(path): |
| filerefs = get_file_refs(path) |
| gitrefs = get_git_refs(path) |
| diff = set(filerefs.items()) ^ set(gitrefs.items()) |
| if len(diff) > 0: |
| log.warn("%s refs file out of date, diff: %s", path, diff) |
| ret, out = update_server_info(path) |
| if ret != 0 or out != "": |
| log.error("error processing %s, exited %i", path, ret) |
| log.error(out) |
| |
| |
| def check_file_exists(filepath, islink=False, linkpath=None): |
| if not os.path.exists(filepath): |
| log.warn("%s not found", filepath) |
| else: |
| if islink: |
| if not os.path.islink(filepath): |
| log.warn("%s is not a link as expected", filepath) |
| if linkpath: |
| if os.path.realpath(filepath) != linkpath: |
| log.warn("%s does not link to %s", filepath, linkpath) |
| |
| |
| def process(paths): |
| for path in paths: |
| refsfile = os.path.join(path, "info/refs") |
| perms_check(refsfile) |
| perms_check(path+"/objects/info/packs") |
| # check_file_exists(os.path.join(path, EXPORT_FILE)) |
| check_file_exists(path+"/hooks/post-update", True) |
| check_ref_status(path) |
| |
| |
| if __name__ == '__main__': |
| oldumask = os.umask(0022) |
| parser = argparse.ArgumentParser( |
| description='Check git repositories') |
| parser.add_argument('--log', default='WARN', |
| choices=('WARN', 'INFO', 'DEBUG'), |
| help='Logging level to use. Default=%(default)s') |
| args = parser.parse_args() |
| log.setLevel(getattr(logging, args.log)) |
| pathlist = get_repos() |
| process(pathlist) |
| os.umask(oldumask) |