Source code for aup.setup

"""
..
  Copyright (c) 2018 LG Electronics Inc.
  SPDX-License-Identifier: GPL-3.0-or-later

Setup scripts for Auptimizer
============================

:mod:`aup.setup` is the entry point to set up the `.aup` environment.

See :doc:`environment` for more details.

Run it as:

  python -m aup.setup [env_template] ...

The templates are at ``Examples/2dfunc_diff_res/*.ini``.

Additional arguments
--------------------

.. program-output:: python3 -m aup.setup -h

APIs
----
"""
import json
import logging
import os
from shutil import rmtree
import sys

import click
import coloredlogs
from six.moves import input
from six.moves.configparser import ConfigParser

from .utils import get_default_username, LOG_LEVEL

# Name of resources in .aup database
GPU_RESOURCE_NAME = "gpu_mapping"
NODE_RESOURCE_NAME = "node_mapping"
AWS_RESOURCE_NAME = "aws_mapping"
logger = logging.getLogger("aup.setup")

PYTHON_EXEC = sys.executable

def _create_folder(folder, overwrite=False):
    """Create a folder"""
    if folder[0] == "~":
        folder = os.path.expanduser(folder)
    if os.path.exists(folder):
        if not overwrite:
            logger.fatal("Folder %s exists, please remove folder or use --overwrite", folder)
            raise Exception("Folder {} exists, please remove folder or use --overwrite".format(folder))
        else:
            rmtree(folder)
    try:
        os.mkdir(folder)
    except Exception as e:   # pragma: no cover
        logger.fatal("Failed to create folder, check the error message below")
        raise e
    return folder


def _set_resource(resource, config, target, start_rid):
    """Update resource allocation in Auptimizer and track resource ID"""
    if resource == "none":
        if config.has_option("Auptimizer", target):
            logger.warning("Remove conflict resource %s in Auptimizer.", target)
            config.remove_option("Auptimizer", target)
    else:
        if os.path.isfile(resource):
            with open(resource, 'r') as f:
                d = f.readlines()
        else:
            d = resource.split(",")
        if len(d) == 0 or d[0] == "":
            logger.critical("No resources for %s", target)
        resources = {}
        for i in d:
            resources[start_rid] = i.strip()
            start_rid += 1
        logger.info("Assign resource %s as %s", target, json.dumps(resources))
        config.set("Auptimizer", target, json.dumps(resources))
    return start_rid


[docs]def interactive_env(config): # pragma: no cover config.add_section("Auptimizer") aup_path = input("Auptimizer Environment path - Auptimizer_PATH (Default is `.aup`):") or ".aup" config.set("Auptimizer", "Auptimizer_PATH", aup_path) aup_tmp = input("Auptimizer Temp folder - TMP_FOLDER (/tmp/auptmp):") or "/tmp/auptmp" config.set("Auptimizer", "TMP_FOLDER", aup_tmp) config.set("Auptimizer", "SQL_ENGINE", "sqlite") return config
[docs]def interactive_setup(env, config, cpu, gpu, node, aws, user, overwrite): # pragma: no cover """ Interactive user interface to get parameters for setup """ print("Hit ENTER to use default values in brackets.") if env == ".": env = input("Load existing Auptimizer environment (env.ini file path), hit ENTER to initialize a new one:") if env.strip() == "": config = interactive_env(config) else: if not os.path.isfile(env): logger.fatal("Environment file %s does not exist, exit!", env) exit(1) try: config.read(env) except Exception as e: logger.fatal("Failed to load environment template %s using ConfigParser", env) raise e cpu = int(input("Number of CPUs for parallel jobs (%d):" % cpu) or cpu) gpu = input("GPU template file or comma-separated IDs (%s):" % gpu) or gpu node = input("Node template file (%s) or comma-separated nodes (user@ip:[port] [keyfile]):" % node) or node aws = input("AWS template file (%s) or comma-separated nodes (user@ip):[port] [keyfile]):" % aws) or aws user = input("Username (%s):" % user) or user if not overwrite: overwrite = input("Overwrite (y/N)").lower() == "y" return config, cpu, gpu, node, aws, user, overwrite
[docs]def setup(config, cpu, gpu, node, aws, user, overwrite, log): """ Set up .aup environment :param config: env config :param cpu: number of cpu jobs :param gpu: gpu configuration file, 'none' if not exist :param node: node file, 'none' if not exist :param aws: aws file :param user: username, user specified > OS USER variable > 'default' :param overwrite: overwrite existing .aup environment :param log: log level for setupdb """ folder_path = _create_folder(config.get("Auptimizer", "Auptimizer_PATH"), overwrite=overwrite) config.set("Auptimizer", "Auptimizer_PATH", folder_path) folder_path = _create_folder(config.get("Auptimizer", "TMP_FOLDER"), overwrite=True) config.set("Auptimizer", "TMP_FOLDER", folder_path) pending_commands = [] rid = 1 rid = _set_resource(gpu, config, GPU_RESOURCE_NAME, rid) rid = _set_resource(node, config, NODE_RESOURCE_NAME, rid) rid = _set_resource(aws, config, AWS_RESOURCE_NAME, rid) logger.debug("Create %d resources", rid) if config.get("Auptimizer", "SQL_ENGINE") == "sqlite": tmp_path = os.path.join(config.get("Auptimizer", "Auptimizer_PATH"), "sqlite3.db") config.set("Auptimizer", "SQLITE_FILE", tmp_path) pending_commands.append(PYTHON_EXEC + " -m aup.setupdb.sqlite %s --user %s --cpu %d --log %s" % ( os.path.join(config.get("Auptimizer", "Auptimizer_PATH"), "env.ini"), user, cpu, log)) else: logger.fatal("SQL engine %s is not implemented", config.get("Auptimizer", "SQL_ENGINE")) exit(1) env_path = os.path.join(config.get("Auptimizer", "Auptimizer_PATH"), "env.ini") with open(env_path, "w") as f: logger.info("Write env.ini to %s", env_path) config.write(f) logger.info("Following commands are being executed:") for i, command in enumerate(pending_commands): logger.info("Executing command: " + command) rflag = os.system(command) if rflag != 0: logger.fatal("Failed in setup commands\nFollowing commands need finish manually (and debug):\n %s", "\n".join(pending_commands[i:])) exit(1)
@click.command(name="Continuous Training Engine Setup", context_settings=dict(help_option_names=['-h', '--help'])) @click.argument("env", default=".", type=click.Path(exists=True)) @click.option("--cpu", default=4, help="Number of cores") @click.option("--gpu", default='none', help="GPU file path") @click.option("--node", default='none', help="Node file path") @click.option("--aws", default='none', help="AWS file path") @click.option("--user", default=None, help="User account for Auptimizer") @click.option('--overwrite', is_flag=True, help="overwrite existing folder (and records!)") @click.option("--log", default="info", type=click.Choice(LOG_LEVEL.keys()), help="Log level") def main(env, cpu, gpu, node, aws, user, overwrite, log): # pragma: no cover """ Create environment based on env file for Auptimizer \b\n Copyright (C) 2018 LG Electronics Inc. \b\n GPL-3.0 License. This program comes with ABSOLUTELY NO WARRANTY; \b\n Arguments: env {str}: Auptimizer config folder path. Default to create at `./.aup/`. Leave empty to create a new one. Or use the path of the filename (env.ini) to load predefined values (also use --overwrite). \b Raises: Exception: If failed to load the existing Auptimizer configuration file. """ coloredlogs.install(level=LOG_LEVEL[log], fmt="%(levelname)s - %(message)s") user = get_default_username(user) config = ConfigParser() config.optionxform = str if env == ".": # interactive config, cpu, gpu, node, aws, user, overwrite = \ interactive_setup(env, config, cpu, gpu, node, aws, user, overwrite) else: try: if not os.path.isfile(env): logger.info("Load default env.ini file.") env = os.path.join(env, "env.ini") config.read(env) except Exception as e: logger.fatal("failed to read %s", env) raise e setup(config, cpu, gpu, node, aws, user, overwrite, log) if __name__ == "__main__": main()