120 lines
3.0 KiB
Python
120 lines
3.0 KiB
Python
# -*- encoding: utf-8 -*-
|
|
import importlib.resources
|
|
from fnmatch import fnmatch
|
|
import re
|
|
|
|
import click
|
|
|
|
from phi.cli.utils import generate_from_templates
|
|
from phi.security import hash_pass
|
|
|
|
|
|
SERVICE_RE = re.compile(r"^(.+?):(.+)$")
|
|
|
|
templates = [
|
|
f.name.strip(".j2")
|
|
for f in importlib.resources.files("phi.cli.templates").iterdir()
|
|
if not f.name.endswith(".py")
|
|
]
|
|
|
|
|
|
def debug(ctx, out):
|
|
if ctx.obj["debug"]:
|
|
click.echo(f"DEBUG: {out}", err=True)
|
|
|
|
|
|
def validate_services(ctx, _, value):
|
|
for service in value:
|
|
if not SERVICE_RE.match(service):
|
|
click.echo(f"Unparsable service '{service}' - must match /^(.+?):(.+)$/")
|
|
ctx.exit()
|
|
|
|
return value
|
|
|
|
|
|
@click.group(
|
|
name="phiadm", help="This cli may be used to interact with a local phid instance"
|
|
)
|
|
@click.option("-d", "--debug", is_flag=True, help="Enable debugging information")
|
|
@click.pass_context
|
|
def cli(ctx, debug):
|
|
ctx.ensure_object(dict)
|
|
ctx.obj["debug"] = debug
|
|
|
|
|
|
@cli.command(
|
|
"generate",
|
|
help="The base name of this LDAP directory (e.g. 'dc=example,dc=com')",
|
|
)
|
|
@click.option(
|
|
"-t",
|
|
"--template",
|
|
type=click.STRING,
|
|
multiple=True,
|
|
help=f"Name of the template (allowed: {', '.join(templates)};"
|
|
+ " accepts also glob-like patterns)",
|
|
)
|
|
@click.option(
|
|
"-s",
|
|
"--default-service",
|
|
type=click.STRING,
|
|
multiple=True,
|
|
callback=validate_services,
|
|
help="A pair <name>:<password> representing a service (and the associated password)"
|
|
)
|
|
@click.option(
|
|
"--root-password",
|
|
type=click.STRING,
|
|
required=True,
|
|
help="The cleartext password for the root user",
|
|
)
|
|
@click.option(
|
|
"--phi-password",
|
|
type=click.STRING,
|
|
required=True,
|
|
help="The cleartext password for the phi service",
|
|
)
|
|
@click.argument(
|
|
"base_dn",
|
|
type=click.STRING,
|
|
)
|
|
@click.pass_context
|
|
def generate(ctx, template, default_service, root_password, phi_password, base_dn):
|
|
config = get_config(base_dn, phi_password, root_password)
|
|
debug(ctx, f"default_service: {default_service}")
|
|
if default_service:
|
|
add_default_services(config, default_service)
|
|
debug(ctx, f"config: {config}")
|
|
debug(ctx, f"templates: {templates}")
|
|
|
|
if not template:
|
|
template = templates
|
|
|
|
for name, content in generate_from_templates(config):
|
|
debug(ctx, f"current template: {name}")
|
|
if any(fnmatch(name, t) for t in template):
|
|
click.echo(content)
|
|
|
|
|
|
def get_config(base_dn, phi_password, root_password):
|
|
config = {"default_services": []}
|
|
config["base_dn"] = base_dn
|
|
config["phi_password"] = hash_pass(phi_password)
|
|
config["root_password"] = hash_pass(root_password)
|
|
|
|
return config
|
|
|
|
|
|
def add_default_services(config, services):
|
|
for service in services:
|
|
user, password = parse_service(service)
|
|
config["default_services"].append(
|
|
{"name": user, "password": hash_pass(password)})
|
|
|
|
|
|
def parse_service(service):
|
|
res = SERVICE_RE.search(service).groups()
|
|
if len(res) != 2:
|
|
raise ValueError(res)
|
|
return res[0], res[1]
|