#!/usr/bin/env python3 # Module Imports import os import grp import pwd import sys import glob import click import random import shutil import string from passlib.hash import pbkdf2_sha256 # Project Imports from hyperglass import hyperglass from hyperglass import render as render # Initialize shutil copy function cp = shutil.copyfile @click.group() def hg(): pass @hg.command() def clearcache(): """Clears the Flask-Caching cache""" try: hyperglass.clearCache() click.secho("✓ Successfully cleared cache.", fg="green", bold=True) except: click.secho("✗ Failed to clear cache.", fg="red", bold=True) raise @hg.command() def generatekey(string_length=16): """Generates 16 character API Key for hyperglass-frr API, and a corresponding PBKDF2 SHA256 Hash""" ld = string.ascii_letters + string.digits api_key = "".join(random.choice(ld) for i in range(string_length)) key_hash = pbkdf2_sha256.hash(api_key) click.secho( f""" Your API Key is: {api_key} Place your API Key in the `configuration.py` of your API module. For example, in: `hyperglass-frr/configuration.py` Your Key Hash is: {key_hash} Use this hash as the password for the device using the API module. For example, in: `hyperglass/hyperglass/configuration/devices.toml` """ ) @hg.command() def testserver(): """Starts Flask development server for testing without WSGI/Reverse Proxy""" try: hyperglass.render.css.renderTemplate() hyperglass.app.run(host="0.0.0.0", debug=True, port=5000) click.secho("✓ Started test server.", fg="green", bold=True) except: click.secho("✗ Failed to start test server.", fg="red", bold=True) raise @hg.command() def render(): """Renders Jinja2 and Sass templates to HTML & CSS files""" try: hyperglass.render.css.renderTemplate() click.secho("✓ Successfully rendered CSS templates.", fg="green", bold=True) except: click.secho("✗ Failed to render CSS templates.", fg="red", bold=True) raise try: hyperglass.render.html.renderTemplate("index") click.secho("✓ Successfully rendered HTML templates.", fg="green", bold=True) except: click.secho("✗ Failed to render HTML templates.", fg="red", bold=True) raise @hg.command() def migrateconfig(): """Copies example configuration files to usable config files""" try: click.secho("Migrating example config files...", fg="cyan") hyperglass_root = os.path.dirname(hyperglass.__file__) config_dir = os.path.join(hyperglass_root, "configuration/") examples = glob.iglob(os.path.join(config_dir, "*.example")) for f in examples: basefile, extension = os.path.splitext(f) newfile = basefile if os.path.exists(newfile): click.secho(f"{newfile} already exists", fg="blue") else: try: cp(f, newfile) click.secho(f"✓ Migrated {newfile}", fg="green") except: click.secho(f"✗ Failed to migrate {newfile}", fg="red") raise click.secho( "✓ Successfully migrated example config files", fg="green", bold=True ) except: click.secho("✗ Error migrating example config files", fg="red", bold=True) raise @hg.command() def migrategunicorn(): """Copies example Gunicorn config file to a usable config""" try: click.secho("Migrating example Gunicorn configuration...", fg="cyan") hyperglass_root = os.path.dirname(hyperglass.__file__) ex_file = os.path.join(hyperglass_root, "gunicorn_config.py.example") basefile, extension = os.path.splitext(ex_file) newfile = basefile if os.path.exists(newfile): click.secho(f"{newfile} already exists", fg="blue") else: try: cp(ex_file, newfile) click.secho(f"✓ Migrated {newfile}", fg="green") except: click.secho(f"✗ Failed to migrate {newfile}", fg="red") raise click.secho( "✓ Successfully migrated example Gunicorn configuration", fg="green", bold=True, ) except: click.secho( "✗ Error migrating example Gunicorn configuration", fg="red", bold=True ) raise @hg.command() @click.option("--dir", default="/etc/systemd/system") def migratesystemd(dir): """Copies example systemd service file to /etc/systemd/system/""" try: click.secho("Migrating example systemd service...", fg="cyan") hyperglass_root = os.path.dirname(hyperglass.__file__) ex_file_base = "hyperglass.service.example" ex_file = os.path.join(hyperglass_root, ex_file_base) basefile, extension = os.path.splitext(ex_file_base) newfile = os.path.join(dir, basefile) if os.path.exists(newfile): click.secho(f"{newfile} already exists", fg="blue") else: try: cp(ex_file, newfile) click.secho(f"✓ Migrated {newfile}", fg="green") except: click.secho(f"✗ Failed to migrate {newfile}", fg="red") raise click.secho( f"✓ Successfully migrated example systemd service to: {newfile}", fg="green", bold=True, ) except: click.secho("✗ Error migrating example systemd service", fg="red", bold=True) raise @hg.command() @click.option("--user", default="www-data") @click.option("--group", default="www-data") def fixpermissions(user, group): """Effectively runs `chmod` and `chown` on the hyperglass/hyperglass directory""" hyperglass_root = os.path.dirname(hyperglass.__file__) uid = pwd.getpwnam(user).pw_uid gid = grp.getgrnam(group).gr_gid try: os.chown(hyperglass_root, uid, gid) click.secho( "✓ Successfully changed hyperglass/ ownership", fg="green", bold=True ) except: click.secho("✗ Failed to change hyperglass/ ownership", fg="red", bold=True) raise try: os.chmod(hyperglass_root, 0o744) click.secho( "✓ Successfully changed hyperglass/ permissions", fg="green", bold=True ) except: click.secho("✗ Failed to change hyperglass/ permissions", fg="red", bold=True) raise if __name__ == "__main__": hg()