Example #1
0
def main():
    """Declare command line options"""
    parser = ArgumentParser(description='ouroboros', formatter_class=RawTextHelpFormatter,
                            epilog='EXAMPLE: ouroboros -d tcp://1.2.3.4:5678 -i 20 -m container1 container2 -l warn')

    core_group = parser.add_argument_group("Core", "Configuration of core functionality")
    core_group.add_argument('-v', '--version', action='version', version=VERSION)

    core_group.add_argument('-d', '--docker-sockets', nargs='+', default=Config.docker_sockets, dest='DOCKER_SOCKETS',
                            help='Sockets for docker management\n'
                                 'DEFAULT: "unix://var/run/docker.sock"\n'
                                 'EXAMPLE: -d unix://var/run/docker.sock tcp://192.168.1.100:2376')

    core_group.add_argument('-t', '--docker-tls', default=Config.docker_tls, dest='DOCKER_TLS',
                            action='store_true', help='Enable docker TLS\n'
                                                      'REQUIRES: docker cert mount')

    core_group.add_argument('-T', '--docker-tls-verify', default=Config.docker_tls_verify, dest='DOCKER_TLS_VERIFY',
                            action='store_false', help='Verify the CA Certificate mounted for TLS\n'
                                                       'DEFAULT: True')

    core_group.add_argument('-i', '--interval', type=int, default=Config.interval, dest='INTERVAL',
                            help='Interval in seconds between checking for updates\n'
                                 'DEFAULT: 300')

    core_group.add_argument('-C', '--cron', default=Config.cron, dest='CRON',
                            help='Cron formatted string for scheduling\n'
                                 'EXAMPLE: "*/5 * * * *"')

    core_group.add_argument('-l', '--log-level', choices=['debug', 'info', 'warn', 'error', 'critical'],
                            dest='LOG_LEVEL', default=Config.log_level, help='Set logging level\n'
                                                                             'DEFAULT: info')

    core_group.add_argument('-u', '--self-update', default=Config.self_update, dest='SELF_UPDATE', action='store_true',
                            help='Let ouroboros update itself')

    core_group.add_argument('-S', '--swarm', default=Config.swarm, dest='SWARM', action='store_true',
                            help='Put ouroboros in swarm mode')

    core_group.add_argument('-o', '--run-once', default=Config.run_once, action='store_true', dest='RUN_ONCE',
                            help='Single run')

    core_group.add_argument('-A', '--dry-run', default=Config.dry_run, action='store_true', dest='DRY_RUN',
                            help='Run without making changes. Best used with run-once')

    core_group.add_argument('-N', '--notifiers', nargs='+', default=Config.notifiers, dest='NOTIFIERS',
                            help='Apprise formatted notifiers\n'
                                 'EXAMPLE: -N discord://1234123412341234/jasdfasdfasdfasddfasdf '
                                 'mailto://*****:*****@gmail.com')

    docker_group = parser.add_argument_group("Docker", "Configuration of docker functionality")
    docker_group.add_argument('-m', '--monitor', nargs='+', default=Config.monitor, dest='MONITOR',
                              help='Which container(s) to monitor\n'
                                   'DEFAULT: All')

    docker_group.add_argument('-n', '--ignore', nargs='+', default=Config.ignore, dest='IGNORE',
                              help='Container(s) to ignore\n'
                                   'EXAMPLE: -n container1 container2')

    docker_group.add_argument('-k', '--label-enable', default=Config.label_enable, dest='LABEL_ENABLE',
                              action='store_true', help='Enable label monitoring for ouroboros label options\n'
                                                        'Note: labels take precedence'
                                                        'DEFAULT: False')

    docker_group.add_argument('-M', '--labels-only', default=Config.labels_only, dest='LABELS_ONLY',
                              action='store_true', help='Only watch containers that utilize labels\n'
                                                        'This allows a more strict compliance for environments'
                                                        'DEFAULT: False')

    docker_group.add_argument('-c', '--cleanup', default=Config.cleanup, dest='CLEANUP', action='store_true',
                              help='Remove old images after updating')

    docker_group.add_argument('-r', '--repo-user', default=Config.repo_user, dest='REPO_USER',
                              help='Private docker registry username\n'
                                   'EXAMPLE: [email protected]')

    docker_group.add_argument('-R', '--repo-pass', default=Config.repo_pass, dest='REPO_PASS',
                              help='Private docker registry password\n'
                                   'EXAMPLE: MyPa$$w0rd')

    data_group = parser.add_argument_group('Data Export', 'Configuration of data export functionality')
    data_group.add_argument('-D', '--data-export', choices=['prometheus', 'influxdb'], default=Config.data_export,
                            dest='DATA_EXPORT', help='Enable exporting of data for chosen option')

    data_group.add_argument('-a', '--prometheus-addr', default=Config.prometheus_addr,
                            dest='PROMETHEUS_ADDR', help='Bind address to run Prometheus exporter on\n'
                                                         'DEFAULT: 127.0.0.1')

    data_group.add_argument('-p', '--prometheus-port', type=int, default=Config.prometheus_port,
                            dest='PROMETHEUS_PORT', help='Port to run Prometheus exporter on\n'
                                                         'DEFAULT: 8000')

    data_group.add_argument('-I', '--influx-url', default=Config.influx_url, dest='INFLUX_URL',
                            help='URL for influxdb\n'
                                  'DEFAULT: 127.0.0.1')

    data_group.add_argument('-P', '--influx-port', type=int, default=Config.influx_port, dest='INFLUX_PORT',
                            help='PORT for influxdb\n'
                                  'DEFAULT: 8086')

    data_group.add_argument('-U', '--influx-username', default=Config.influx_username, dest='INFLUX_USERNAME',
                            help='Username for influxdb\n'
                                  'DEFAULT: root')

    data_group.add_argument('-x', '--influx-password', default=Config.influx_password, dest='INFLUX_PASSWORD',
                            help='Password for influxdb\n'
                                  'DEFAULT: root')

    data_group.add_argument('-X', '--influx-database', default=Config.influx_database, dest='INFLUX_DATABASE',
                            help='Influx database name. Required if using influxdb')

    data_group.add_argument('-s', '--influx-ssl', default=Config.influx_ssl, dest='INFLUX_SSL', action='store_true',
                            help='Use SSL when connecting to influxdb')

    data_group.add_argument('-V', '--influx-verify-ssl', default=Config.influx_verify_ssl, dest='INFLUX_VERIFY_SSL',
                            action='store_true', help='Verify SSL certificate when connecting to influxdb')

    docker_group.add_argument('--skip-startup-notifications', default=Config.skip_startup_notifications,
                              dest='SKIP_STARTUP_NOTIFICATIONS', action='store_true',
                              help='Do not send ouroboros notifications when starting')

    args = parser.parse_args()

    if environ.get('LOG_LEVEL'):
        log_level = environ.get('LOG_LEVEL')
    else:
        log_level = args.LOG_LEVEL
    ol = OuroborosLogger(level=log_level)
    ol.logger.info('Version: %s-%s', VERSION, BRANCH)
    config = Config(environment_vars=environ, cli_args=args)
    config_dict = {key: value for key, value in vars(config).items() if key.upper() in config.options}
    ol.logger.debug("Ouroboros configuration: %s", config_dict)

    data_manager = DataManager(config)
    notification_manager = NotificationManager(config, data_manager)
    scheduler = BackgroundScheduler()
    scheduler.start()

    for socket in config.docker_sockets:
        try:
            docker = Docker(socket, config, data_manager, notification_manager)
            if config.swarm:
                mode = Service(docker)
            else:
                mode = Container(docker)

            if config.run_once:
                scheduler.add_job(mode.update, name=f'Run Once container update for {socket}')
            else:
                if mode.mode == 'container':
                    scheduler.add_job(mode.self_check, name=f'Self Check for {socket}')
                if config.cron:
                    scheduler.add_job(
                        mode.update,
                        name=f'Cron container update for {socket}',
                        trigger='cron',
                        minute=config.cron[0],
                        hour=config.cron[1],
                        day=config.cron[2],
                        month=config.cron[3],
                        day_of_week=config.cron[4],
                        misfire_grace_time=15
                    )
                else:
                    scheduler.add_job(
                        mode.update,
                        name=f'Initial run interval container update for {socket}'
                    )
                    scheduler.add_job(
                        mode.update,
                        name=f'Interval container update for {socket}',
                        trigger='interval', seconds=config.interval
                    )
        except ConnectionError:
            ol.logger.error("Could not connect to socket %s. Check your config", socket)

    if config.run_once:
        next_run = None
    elif config.cron:
        next_run = scheduler.get_jobs()[0].next_run_time
    else:
        now = datetime.now(timezone.utc).astimezone()
        next_run = (now + timedelta(0, config.interval)).strftime("%Y-%m-%d %H:%M:%S")

    if not config.skip_startup_notifications:
        notification_manager.send(kind='startup', next_run=next_run)

    while scheduler.get_jobs():
        sleep(1)

    scheduler.shutdown()
Example #2
0
def main():
    """Declare command line options"""
    parser = ArgumentParser(
        description='ouroboros',
        formatter_class=RawTextHelpFormatter,
        epilog=
        'EXAMPLE: ouroboros -d tcp://1.2.3.4:5678 -i 20 -m container1 container2 -l warn'
    )

    core_group = parser.add_argument_group(
        "Core", "Configuration of core functionality")
    core_group.add_argument('-v',
                            '--version',
                            action='version',
                            version=VERSION)

    core_group.add_argument(
        '-d',
        '--docker-sockets',
        nargs='+',
        default=Config.docker_sockets,
        dest='DOCKER_SOCKETS',
        help='Sockets for docker management\n'
        'DEFAULT: "unix://var/run/docker.sock"\n'
        'EXAMPLE: -d unix://var/run/docker.sock tcp://192.168.1.100:2376')

    core_group.add_argument('-t',
                            '--docker-tls-verify',
                            default=False,
                            dest='DOCKER_TLS_VERIFY',
                            action='store_true',
                            help='Enable docker TLS\n'
                            'REQUIRES: docker cert mount')

    core_group.add_argument(
        '-i',
        '--interval',
        type=int,
        default=Config.interval,
        dest='INTERVAL',
        help='Interval in seconds between checking for updates\n'
        'DEFAULT: 300')

    core_group.add_argument(
        '-l',
        '--log-level',
        choices=['debug', 'info', 'warn', 'error', 'critical'],
        dest='LOG_LEVEL',
        default=Config.log_level,
        help='Set logging level\n'
        'DEFAULT: info')

    core_group.add_argument('-u',
                            '--self-update',
                            default=False,
                            dest='SELF_UPDATE',
                            action='store_true',
                            help='Let ouroboros update itself')

    core_group.add_argument('-o',
                            '--run-once',
                            default=False,
                            action='store_true',
                            dest='RUN_ONCE',
                            help='Single run')

    docker_group = parser.add_argument_group(
        "Docker", "Configuration of docker functionality")
    docker_group.add_argument('-m',
                              '--monitor',
                              nargs='+',
                              default=Config.monitor,
                              dest='MONITOR',
                              help='Which container(s) to monitor\n'
                              'DEFAULT: All')

    docker_group.add_argument('-n',
                              '--ignore',
                              nargs='+',
                              default=Config.ignore,
                              dest='IGNORE',
                              help='Container(s) to ignore\n'
                              'EXAMPLE: -n container1 container2')

    docker_group.add_argument(
        '-k',
        '--label-enable',
        default=False,
        dest='LABEL_ENABLE',
        action='store_true',
        help='Only watch ouroboros enable labeled containers\n'
        'Note: labels take precedence over monitor/ignore'
        'DEFAULT: False')

    docker_group.add_argument('-c',
                              '--cleanup',
                              default=False,
                              dest='CLEANUP',
                              action='store_true',
                              help='Remove old images after updating')

    docker_group.add_argument(
        '-L',
        '--latest',
        default=False,
        dest='LATEST',
        action='store_true',
        help='Check for latest image instead of pulling current tag')

    docker_group.add_argument('-r',
                              '--repo-user',
                              default=None,
                              dest='REPO_USER',
                              help='Private docker registry username\n'
                              'EXAMPLE: [email protected]')

    docker_group.add_argument('-R',
                              '--repo-pass',
                              default=None,
                              dest='REPO_PASS',
                              help='Private docker registry password\n'
                              'EXAMPLE: MyPa$$w0rd')

    data_group = parser.add_argument_group(
        'Data Export', 'Configuration of data export functionality')
    data_group.add_argument('-D',
                            '--data-export',
                            choices=['prometheus', 'influxdb'],
                            default=None,
                            dest='DATA_EXPORT',
                            help='Enable exporting of data for chosen option')

    data_group.add_argument('-a',
                            '--prometheus-addr',
                            default=Config.prometheus_addr,
                            dest='PROMETHEUS_ADDR',
                            help='Bind address to run Prometheus exporter on\n'
                            'DEFAULT: 127.0.0.1')

    data_group.add_argument('-p',
                            '--prometheus-port',
                            type=int,
                            default=Config.prometheus_port,
                            dest='PROMETHEUS_PORT',
                            help='Port to run Prometheus exporter on\n'
                            'DEFAULT: 8000')

    data_group.add_argument('-I',
                            '--influx-url',
                            default=Config.influx_url,
                            dest='INFLUX_URL',
                            help='URL for influxdb\n'
                            'DEFAULT: 127.0.0.1')

    data_group.add_argument('-P',
                            '--influx-port',
                            type=int,
                            default=Config.influx_port,
                            dest='INFLUX_PORT',
                            help='PORT for influxdb\n'
                            'DEFAULT: 8086')

    data_group.add_argument('-U',
                            '--influx-username',
                            default=Config.influx_username,
                            dest='INFLUX_USERNAME',
                            help='Username for influxdb\n'
                            'DEFAULT: root')

    data_group.add_argument('-x',
                            '--influx-password',
                            default=Config.influx_password,
                            dest='INFLUX_PASSWORD',
                            help='Password for influxdb\n'
                            'DEFAULT: root')

    data_group.add_argument(
        '-X',
        '--influx-database',
        default=Config.influx_password,
        dest='INFLUX_DATABASE',
        help='Influx database name. Required if using influxdb')

    data_group.add_argument('-s',
                            '--influx-ssl',
                            default=False,
                            dest='INFLUX_SSL',
                            action='store_true',
                            help='Use SSL when connecting to influxdb')

    data_group.add_argument(
        '-V',
        '--influx-verify-ssl',
        default=False,
        dest='INFLUX_VERIFY_SSL',
        action='store_true',
        help='Verify SSL certificate when connecting to influxdb')

    notification_group = parser.add_argument_group(
        'Notifications', 'Configuration of notification functionality')
    notification_group.add_argument(
        '-w',
        '--webhook-urls',
        nargs='+',
        default=Config.webhook_urls,
        dest='WEBHOOK_URLS',
        help='Webhook POST urls\n'
        'EXAMPLE: -w https://domain.tld/1234/asdf http://123.123.123.123:4040/re235'
    )

    notification_group.add_argument(
        '-y',
        '--pushover-token',
        default=Config.pushover_token,
        dest='PUSHOVER_TOKEN',
        help='Pushover token to authenticate against application\n'
        'EXAMPLE: -y af2r52352asd')

    notification_group.add_argument(
        '-Y',
        '--pushover-device',
        default=Config.pushover_device,
        dest='PUSHOVER_DEVICE',
        help='Device to receive pushover notification\n'
        'EXAMPLE: -Y SamsungGalaxyS8')

    notification_group.add_argument('-z',
                                    '--pushover-user',
                                    default=Config.pushover_user,
                                    dest='PUSHOVER_USER',
                                    help='Pushover user bound to application\n'
                                    'EXAMPLE: -z asdfweawefasdfawef')

    notification_group.add_argument('-e',
                                    '--smtp-host',
                                    default=Config.smtp_host,
                                    dest='SMTP_HOST',
                                    help='SMTP relay hostname\n'
                                    'EXAMPLE: -e smtp.gmail.com')

    notification_group.add_argument('-E',
                                    '--smtp-port',
                                    default=Config.smtp_port,
                                    type=int,
                                    dest='SMTP_PORT',
                                    help='SMTP relay port\n'
                                    'EXAMPLE: -E 587')

    notification_group.add_argument('-f',
                                    '--smtp-starttls',
                                    default=False,
                                    dest='SMTP_STARTTLS',
                                    action='store_true',
                                    help='SMTP relay uses STARTTLS')

    notification_group.add_argument('-F',
                                    '--smtp-username',
                                    default=Config.smtp_username,
                                    dest='SMTP_USERNAME',
                                    help='SMTP relay username\n'
                                    'EXAMPLE: -F [email protected]')

    notification_group.add_argument('-g',
                                    '--smtp-password',
                                    default=Config.smtp_password,
                                    dest='SMTP_PASSWORD',
                                    help='SMTP relay password\n'
                                    'EXAMPLE: -g MyPa$$w0rd')

    notification_group.add_argument(
        '-G',
        '--smtp-recipients',
        default=Config.smtp_recipients,
        dest='SMTP_RECIPIENTS',
        nargs='+',
        help='SMTP notification recipients\n'
        'EXAMPLE: -G [email protected] [email protected]')

    notification_group.add_argument('-j',
                                    '--smtp-from-email',
                                    default=Config.smtp_from_email,
                                    dest='SMTP_FROM_EMAIL',
                                    help='SMTP from email\n'
                                    'EXAMPLE: -g [email protected]')

    notification_group.add_argument('-J',
                                    '--smtp-from-name',
                                    default=Config.smtp_from_name,
                                    dest='SMTP_FROM_NAME',
                                    help='SMTP from name\n'
                                    'DEFAULT: Ouroboros')

    args = parser.parse_args()

    if environ.get('LOG_LEVEL'):
        log_level = environ.get('LOG_LEVEL')
    else:
        log_level = args.LOG_LEVEL
    ol = OuroborosLogger(level=log_level)
    ol.logger.info('Version: %s-%s', VERSION, BRANCH)
    config = Config(environment_vars=environ, cli_args=args)
    config_dict = {
        key: value
        for key, value in vars(config).items() if key.upper() in config.options
    }
    ol.logger.debug("Ouroboros configuration: %s", config_dict)

    data_manager = DataManager(config)
    notification_manager = NotificationManager(config, data_manager)

    for socket in config.docker_sockets:
        docker = Docker(socket, config, data_manager, notification_manager)
        schedule.every(config.interval).seconds.do(
            docker.update_containers).tag(f'update-containers-{socket}')

    schedule.run_all()

    if args.RUN_ONCE:
        for socket in config.docker_sockets:
            schedule.clear(f'update-containers-{socket}')

    while schedule.jobs:
        schedule.run_pending()
        sleep(1)