Verified Commit 7fd64a6b authored by anarcat's avatar anarcat
Browse files

blacken

parent dc8ff717
Loading
Loading
Loading
Loading
+101 −55
Original line number Diff line number Diff line
#!/usr/bin/python3
# coding: utf-8

''''''
""""""

# Copyright (C) 2016 Antoine Beaupré <anarcat@debian.org>
#
@@ -48,21 +48,40 @@ from fabric_tpa.reboot import (
# "sleep between hosts" policy. This probably requires overriding the
# Executor class? See also https://github.com/fabric/fabric/issues/2069
def parse_args(args=sys.argv[1:]):
    parser = argparse.ArgumentParser(description=__doc__,
                                     epilog='''''')
    parser.add_argument('--quiet', '-q', dest='log_level',
                        action='store_const', const='warning', default='info')
    parser.add_argument('--debug', '-d', dest='log_level',
                        action='store_const', const='debug', default='info')
    parser.add_argument('--force', '-f', action='store_true',
                        help='force reboot even if not needed')
    parser.add_argument('--skip-ganeti-checks', action='store_true',
                        help='forcibly reboot Ganeti hosts without checking')
    parser.add_argument('--skip-ganeti-empty', action='store_true',
                        help='reboot instances on the node as well, avoiding migrations')
    parser = argparse.ArgumentParser(description=__doc__, epilog="""""")
    parser.add_argument(
        '--ganeti-migrate-back', action='store_true',
        help='migrate the instances back after reboot',
        "--quiet",
        "-q",
        dest="log_level",
        action="store_const",
        const="warning",
        default="info",
    )
    parser.add_argument(
        "--debug",
        "-d",
        dest="log_level",
        action="store_const",
        const="debug",
        default="info",
    )
    parser.add_argument(
        "--force", "-f", action="store_true", help="force reboot even if not needed"
    )
    parser.add_argument(
        "--skip-ganeti-checks",
        action="store_true",
        help="forcibly reboot Ganeti hosts without checking",
    )
    parser.add_argument(
        "--skip-ganeti-empty",
        action="store_true",
        help="reboot instances on the node as well, avoiding migrations",
    )
    parser.add_argument(
        "--ganeti-migrate-back",
        action="store_false",
        help="migrate the instances back after reboot",
    )
    # TODO: autodetect from LDAP. current documented behavior is
    # according to rebootPolicy:
@@ -73,51 +92,77 @@ def parse_args(args=sys.argv[1:]):
    # (e.g. with hosts listed by hand here)
    #
    # "manual" seems to be the default policy
    parser.add_argument('--hosts', '-H', nargs='+',
                        help="host(s) to reboot, can be comma-separated")
    parser.add_argument('--delay-down', default=DEFAULT_DELAY_DOWN, type=int,
                        help='how long to wait for host to shutdown (default: %(default)s seconds)')  # noqa: E501
    parser.add_argument('--delay-up', default=DEFAULT_DELAY_UP, type=int,
                        help='how long to wait for host to come back up (default: %(default)s seconds)')  # noqa: E501
    parser.add_argument('--delay-hosts', default=DEFAULT_DELAY_HOSTS, type=int,
                        help='how long to wait between hosts (default: %(default)s seconds)')  # noqa: E501
    parser.add_argument('--delay-shutdown', default=DEFAULT_DELAY_SHUTDOWN,
                        type=int, help='delay, in minutes, passed to the shutdown command (default: %(default)s minutes)')  # noqa: E501
    parser.add_argument('--reason', default='rebooting for security upgrades',
                        help='reason to give users (default: %(default)s)')
    parser.add_argument('--kind', default=ShutdownType.reboot, type=ShutdownType.validator,
                        help='kind of reboot to do (default: %(default)s)')
    parser.add_argument(
        "--hosts", "-H", nargs="+", help="host(s) to reboot, can be comma-separated"
    )
    parser.add_argument(
        "--delay-down",
        default=DEFAULT_DELAY_DOWN,
        type=int,
        help="how long to wait for host to shutdown (default: %(default)s seconds)",
    )  # noqa: E501
    parser.add_argument(
        "--delay-up",
        default=DEFAULT_DELAY_UP,
        type=int,
        help="how long to wait for host to come back up (default: %(default)s seconds)",
    )  # noqa: E501
    parser.add_argument(
        "--delay-hosts",
        default=DEFAULT_DELAY_HOSTS,
        type=int,
        help="how long to wait between hosts (default: %(default)s seconds)",
    )  # noqa: E501
    parser.add_argument(
        "--delay-shutdown",
        default=DEFAULT_DELAY_SHUTDOWN,
        type=int,
        help="delay, in minutes, passed to the shutdown command (default: %(default)s minutes)",
    )  # noqa: E501
    parser.add_argument(
        "--reason",
        default="rebooting for security upgrades",
        help="reason to give users (default: %(default)s)",
    )
    parser.add_argument(
        "--kind",
        default=ShutdownType.reboot,
        type=ShutdownType.validator,
        help="kind of reboot to do (default: %(default)s)",
    )
    return parser.parse_args(args=args)


def main(args):
    first = True
    # split each hostname on comma, like `fab -H` does
    for hostname in [x for h in args.hosts for x in h.split(',')]:
    for hostname in [x for h in args.hosts for x in h.split(",")]:
        con = host.find_context(hostname)
        logging.info("checking if host %s needs a reboot", hostname)
        if not needs_reboot(con):
            if args.force:
                logging.warning('rebooting anyways because of --force')
                logging.warning("rebooting anyways because of --force")
            else:
                logging.info('host %s does not need a reboot, skipping', hostname)
                logging.info("host %s does not need a reboot, skipping", hostname)
                continue
        if first:
            first = False
        else:
            logging.info('sleeping %d seconds before rebooting %s',
                         args.delay_hosts, hostname)
            logging.info(
                "sleeping %d seconds before rebooting %s", args.delay_hosts, hostname
            )
            now = datetime.now(timezone.utc)
            logging.info(
                'now is %s, it is safe to interrupt this program until %s',
                "now is %s, it is safe to interrupt this program until %s",
                now,
                now + timedelta(seconds=args.delay_hosts),
            )
            time.sleep(args.delay_hosts)
        delay_shutdown = args.delay_shutdown

        logging.info('rebooting host %s', hostname)
        if not shutdown_and_wait(con,
        logging.info("rebooting host %s", hostname)
        if not shutdown_and_wait(
            con,
            reason=args.reason,
            kind=args.kind,
            delay_down=args.delay_down,
@@ -127,31 +172,32 @@ def main(args):
            ganeti_empty=not args.skip_ganeti_empty,
            ganeti_migrate_back=args.ganeti_migrate_back,
        ):
            logging.error('rebooting host %s failed, aborting', hostname)
            logging.error("rebooting host %s failed, aborting", hostname)
            break

        logging.info('done with host %s', hostname)
        logging.info("done with host %s", hostname)
        # raise the bell so we bring attention to this window
        print('\a')
        print("\a")
    # TODO: rebalance ganeti cluster if nodes were migrated


if __name__ == '__main__':
if __name__ == "__main__":
    args = parse_args()
    logging.basicConfig(format='%(message)s', level=args.log_level.upper())
    logging.basicConfig(format="%(message)s", level=args.log_level.upper())
    # override default logging policies in submodules
    #
    # without this, we get debugging info from paramiko with --verbose
    for mod in 'fabric', 'paramiko', 'invoke':
        logging.getLogger(mod).setLevel('WARNING')
    for mod in "fabric", "paramiko", "invoke":
        logging.getLogger(mod).setLevel("WARNING")
    try:
        main(args)
    except Exception as e:
        logging.error('unexpected exception during reboot: [%r] %s', e, e)
        if args.log_level.upper() == 'DEBUG':
        logging.error("unexpected exception during reboot: [%r] %s", e, e)
        if args.log_level.upper() == "DEBUG":
            import traceback
            import pdb
            import sys

            traceback.print_exc()
            pdb.post_mortem()
        sys.exit(1)