diff --git a/Tests/iaas/flavor-naming/README.md b/Tests/iaas/flavor-naming/README.md new file mode 100644 index 000000000..6c15cfc20 --- /dev/null +++ b/Tests/iaas/flavor-naming/README.md @@ -0,0 +1,174 @@ +# SCS flavor name tooling + +This directory contains three basic tools: + +- `cli.py`, a command-line interface for syntax-checking flavor names, turning them into prose descriptions + or yaml documents, and interactively constructing flavor names; +- `flavor-form.py`, a CGI script for a web form that offers roughly the same features, +- `flavor-names-openstack.py`, a script that connects to an OpenStack environment and checks the syntax + of all publicly available flavors. + +## cli.py + +The command-line syntax of this script is best shown via the built-in help function: + +``` +$ ./cli.py --help +Usage: cli.py [OPTIONS] COMMAND [ARGS]... + +Options: + -d, --debug + -v, --verbose + --help Show this message and exit. + +Commands: + input Interactively constructs a flavor name. + parse Validates flavor names, optionally turns into prose/yaml. +``` + +### Parse + +``` + ./cli.py parse --help +Usage: cli.py parse [OPTIONS] {v1|v1/v2|v2/v1|v2|v3|latest} [NAME]... + + Validates flavor names, optionally turns into prose/yaml. + + The first argument selects the version of the flavor naming standard upon + which to base the syntax validation. With 'v1/v2', flavor names of both + kinds are accepted, but warnings are emitted for v2, and similarly with + 'v2/v1', where warnings are emitted for v1. + +Options: + -o, --output [none|prose|yaml] select output format (default: none) + --help Show this message and exit. +``` + +Here is an example invokation: + +``` +$ ./cli.py parse --output prose v1/v2 SCS-16T-64-3x10s_bms_hwv_i3h_GNa-64_ib +WARNING: Name is merely tolerated v2: SCS-16T-64-3x10s_bms_hwv_i3h_GNa-64_ib +SCS flavor with 16 High Perf Intel Ice Lake SMT Threads with 64.0 GiB RAM on Bare Metal System with HW virt and SSD 3x10GB root volume and Pass-Through GPU nVidia Ampere (w/ 64 CU/EU/SM) and Infiniband +``` + +And one example with a wrong name: + +``` +$ ./cli.py parse --output prose v3 SCS-2T-4_ic +Extra characters: _ic: SCS-2T-4_ic +``` + +Noteworthy: if `--verbose` is used, the output format `none` will produce an output for every name (even +those that are valid): + +``` +$ ./cli.py --verbose parse v3 SCS-16T-64 SC-2T-4 SCS-2-4 +OK: SCS-16T-64 +NOT an SCS flavor: SC-2T-4 +Failed to parse main part: SCS-2-4 +``` + +### Input + +``` +$ ./cli.py input --help +Usage: cli.py input [OPTIONS] + + Interactively constructs a flavor name. + +Options: + --help Show this message and exit. +``` + +Example invokation: + +``` +$ ./cli.py input +CPU-RAM + #vCPUs: 16 + CPU type Options: + L: LowPerf vCPUs + V: vCPUs + T: SMT Threads + C: Dedicated Cores + CPU type: T + ?Insec SMT: + ##GiB RAM: 64 + ?no ECC: + ?RAM Over: +Disk + #.NrDisks: 3 + #.GB Disk: 10 + Disk type Options: + : (unspecified) + n: Networked + h: Local HDD + s: SSD + p: HiPerf NVMe + Disk type: s +Hypervisor + Hypervisor Options: + kvm: KVM + xen: Xen + hyv: Hyper-V + vmw: VMware + bms: Bare Metal System + Hypervisor: bms +Hardware/NestedVirtualization + ?HardwareVirt: y +CPUBrand + CPU Vendor Options: + i: Intel + z: AMD + a: ARM + r: RISC-V + CPU Vendor: i + #.CPU Gen Options: + : (unspecified) + 0: Unspec/Pre-Skylake + 1: Skylake + 2: Cascade Lake + 3: Ice Lake + 4: Sapphire Rapids + #.CPU Gen: 3 + Performance Options: + : Std Perf + h: High Perf + hh: Very High Perf + hhh: Very Very High Perf + Performance: h +GPU + Type Options: + g: vGPU + G: Pass-Through GPU + Type: G + Brand Options: + N: nVidia + A: AMD + I: Intel + Brand: N + Gen Options: + : (unspecified) + f: Fermi + k: Kepler + m: Maxwell + p: Pascal + v: Volta + t: Turing + a: Ampere + l: AdaLovelace + Gen: a + #.CU/EU/SM: 64 + Performance Options: + : Std Perf + h: High Perf + hh: Very High Perf + hhh: Very Very High Perf + Performance: +Infiniband + ?IB: y +SCS-16T-64-3x10s_bms_i3h_GNa-64_ib +``` + +Where the final line is the constructed flavor name, and everything above is the interactive session. diff --git a/Tests/iaas/flavor-naming/cli.py b/Tests/iaas/flavor-naming/cli.py index f3f5b12cc..8688a7663 100755 --- a/Tests/iaas/flavor-naming/cli.py +++ b/Tests/iaas/flavor-naming/cli.py @@ -85,38 +85,44 @@ def process_pipeline(rc, *args, **kwargs): @cli.command() @click.argument('version', type=click.Choice(list(VERSIONS), case_sensitive=False)) -@click.argument('namestr', nargs=-1) -@click.option('-o', '--output', 'output', type=click.Choice(['name', 'description', 'yaml'])) +@click.argument('name', nargs=-1) +@click.option('-o', '--output', 'output', type=click.Choice(['none', 'prose', 'yaml']), + help='select output format (default: none)') @click.pass_obj -def parse(cfg, version, namestr, output='name'): +def parse(cfg, version, name, output='none'): + """Validates flavor names, optionally turns into prose/yaml. + + The first argument selects the version of the flavor naming standard upon which to base the syntax + validation. With 'v1/v2', flavor names of both kinds are accepted, but warnings are emitted for v2, + and similarly with 'v2/v1', where warnings are emitted for v1. + """ version = VERSIONS.get(version) printv = cfg.printv errors = 0 - for name in namestr: + for namestr in name: try: - flavorname = version.parse(name) + flavorname = version.parse(namestr) except ValueError as exc: - print(f"{exc}: {name}") + print(f"{exc}: {namestr}") errors += 1 else: if flavorname is None: - print(f"NOT an SCS flavor: {name}") - elif output == 'description': + print(f"NOT an SCS flavor: {namestr}") + elif output == 'prose': printv(name, end=': ') print(f"{prettyname(flavorname)}") elif output == 'yaml': print(yaml.dump(flavorname_to_dict(flavorname), explicit_start=True)) else: - printv(f"OK: {name}") + printv(f"OK: {namestr}") return errors @cli.command() -@click.option('-p', '--pretty', 'pretty', is_flag=True) -def input(pretty=False): +def input(): + """Interactively constructs a flavor name.""" flavorname = inputflavor() - outfn = prettyname if pretty else outputter - print(outfn(flavorname)) + print(outputter(flavorname)) if __name__ == '__main__':