Пример #1
0
 def test_skip_locks_before_reading(self, data_path, cfg_file):
     """
     Here we test that the object constructor waits for a second and
     raises a Runtime error because it tries to lock the file for reading by default
     """
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=True)
     yacman.YacAttMap(filepath=cfg_file, skip_read_lock=True)
     yacmap.make_readonly()
Пример #2
0
 def test_locks_before_reading_by_default(self, data_path, cfg_file):
     """
     Here we test that the object constructor waits for a second and
     raises a Runtime error because it tries to lock the file for reading by default
     """
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=True)
     with pytest.raises(RuntimeError):
         yacman.YacAttMap(filepath=cfg_file, wait_max=1)
     yacmap.make_readonly()
Пример #3
0
 def test_entries_update(self, name, data_path, entry):
     filepath = make_cfg_file_path(name, data_path)
     yacmap = yacman.YacAttMap(entries={})
     yacmap.test = entry
     yacmap.write(filepath=filepath)
     yacmap.make_readonly(
     )  # need to remove the lock; the next line locks for read
     yacmapin = yacman.YacAttMap(filepath=filepath, writable=False)
     assert yacmapin.test == entry
     os.remove(filepath)
Пример #4
0
 def test_context_manager_saves_updates(self, cfg_file, state):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=state)
     with yacmap as y:
         y.testattr = "testval"
     if not getattr(yacmap[IK], RO_KEY, True):
         yacmap.make_readonly()
     yacmap1 = yacman.YacAttMap(filepath=cfg_file, writable=True)
     assert yacmap1.testattr == "testval"
     del yacmap1["testattr"]
     yacmap1.make_readonly()
Пример #5
0
def load_remote_registry_path(bulker_config, registry_path, filepath=None):
    cratevars = parse_registry_path(registry_path)
    if cratevars:
        # assemble the query string
        if 'registry_url' in bulker_config.bulker:
            base_url = bulker_config.bulker.registry_url
        else:
            # base_url = "http://big.databio.org/bulker/"
            base_url = DEFAULT_BASE_URL
        query = cratevars["crate"]
        if cratevars["tag"] != "default":
            query = query + "_" + cratevars["tag"]
        if not cratevars["namespace"]:
            cratevars["namespace"] = "bulker"  # default namespace
        query = cratevars["namespace"] + "/" + query
        # Until we have an API:
        query = query + ".yaml"

        if not filepath:
            filepath = os.path.join(base_url, query)
    else:
        _LOGGER.error(
            "Unable to parse registry path: {}".format(registry_path))
        sys.exit(1)

    if is_url(filepath):
        _LOGGER.debug("Got URL: {}".format(filepath))
        try:  #python3
            from urllib.request import urlopen
            from urllib.error import HTTPError
        except:  #python2
            from urllib2 import urlopen
            from urllib2 import URLError as HTTPError
        try:
            response = urlopen(filepath)
        except HTTPError as e:
            if cratevars:
                _LOGGER.error(
                    "The requested remote manifest '{}' is not found.".format(
                        filepath))
                sys.exit(1)
            else:
                raise e
        data = response.read()  # a `bytes` object
        text = data.decode('utf-8')
        manifest_lines = yacman.YacAttMap(yamldata=text)
    else:
        manifest_lines = yacman.YacAttMap(filepath=filepath)

    return manifest_lines, cratevars
Пример #6
0
 def test_context_manager_does_not_change_state(self, cfg_file, state):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=state)
     with yacmap as _:
         pass
     is_ro = getattr(yacmap[IK], RO_KEY, None)
     is_writable = None if is_ro is None else not is_ro
     assert is_writable == state
Пример #7
0
 def test_init_with_empty_file(self, data_path):
     a, v = "testattr", "testval"
     empty_file_path = os.path.join(data_path, "empty_file.yaml")
     open(empty_file_path, "a").close()
     y = yacman.YacAttMap(entries={a: v}, filepath=empty_file_path)
     assert a in y
     os.remove(empty_file_path)
Пример #8
0
 def test_write_creates_file(self, data_path, list_locks):
     with pytest.warns(UserWarning):
         yacmap = yacman.YacAttMap(entries={}, writable=True)
     yacmap.write(filepath=make_cfg_file_path("writeout.yaml", data_path))
     assert os.path.exists(make_lock_path("writeout.yaml", data_path))
     assert os.path.exists(make_cfg_file_path("writeout.yaml", data_path))
     os.remove(make_cfg_file_path("writeout.yaml", data_path))
Пример #9
0
 def test_validation_fails_in_constructor(self, schema, value):
     """
     test object that does not adhere to the schema
     guidelines does not pass validation
     """
     with pytest.raises(ValidationError):
         yacman.YacAttMap(entries={"testattr": value}, schema_source=schema)
Пример #10
0
    def activate_package(self, package_name):
        """
        Activates a compute package.

        This copies the computing attributes from the configuration file into
        the `compute` attribute, where the class stores current compute
        settings.

        :param str package_name: name for non-resource compute bundle,
            the name of a subsection in an environment configuration file
        :return bool: success flag for attempt to establish compute settings
        """

        # Hope that environment & environment compute are present.
        act_msg = "Activating compute package '{}'".format(package_name)
        if package_name == "default":
            _LOGGER.debug(act_msg)
        else:
            _LOGGER.info(act_msg)

        if (package_name and self.compute_packages
                and package_name in self.compute_packages):
            # Augment compute, creating it if needed.
            if self.compute is None:
                _LOGGER.debug("Creating Project compute")
                self.compute = yacman.YacAttMap()
                _LOGGER.debug("Adding entries for package_name '{}'".format(
                    package_name))

            self.compute.add_entries(self.compute_packages[package_name])

            # Ensure submission template is absolute. This *used to be* handled
            # at update (so the paths were stored as absolutes in the packages),
            # but now, it makes more sense to do it here so we can piggyback on
            # the default update() method and not even have to do that.
            if not os.path.isabs(self.compute.submission_template):
                try:
                    self.compute.submission_template = os.path.join(
                        os.path.dirname(self["__internal"].file_path),
                        self.compute.submission_template,
                    )
                except AttributeError as e:
                    # Environment and environment compute should at least have been
                    # set as null-valued attributes, so execution here is an error.
                    _LOGGER.error(str(e))

            _LOGGER.debug("Submit template set to: {}".format(
                self.compute.submission_template))

            return True

        else:
            # Scenario in which environment and environment compute are
            # both present--but don't evaluate to True--is fairly harmless.
            _LOGGER.debug(
                "Can't activate package. compute_packages = {}".format(
                    self.compute_packages))

        return False
Пример #11
0
 def test_locking_is_opt_in(self, cfg_file, locked_cfg_file):
     """
     this tests backwards compatibility, in the past the locking system did not exist.
     Consequently, to make yacman backwards compatible, multiple processes should be able to read and write to
     the file when no arguments but the intput are specified
     """
     yacman.YacAttMap(filepath=cfg_file)
     assert not os.path.exists(locked_cfg_file)
Пример #12
0
 def test_make_writable_rereads_source_file(self, cfg_file):
     """
     Test that the the changes made to the cfg by other processes
     are re-read after the original process is made writable
     """
     yacmap1 = yacman.YacAttMap(filepath=cfg_file, writable=False)
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=True)
     yacmap.test = "test"
     yacmap.write()
     yacmap.make_readonly()
     yacmap1.make_writable(cfg_file)
     assert yacmap1.test == "test"
     # remove added entry after the test
     if "test" in yacmap1:
         del yacmap1["test"]
         yacmap1.write()
     yacmap1.make_readonly()
Пример #13
0
    def reset_active_settings(self):
        """
        Clear out current compute settings.

        :return bool: success flag
        """
        self.compute = yacman.YacAttMap()
        return True
Пример #14
0
def test_float_idx():

    data = yacman.YacAttMap(yamldata=yaml_str)
    # We should be able to access this by string, not by int index.
    assert (data['2'] == "two")
    with pytest.raises(KeyError):
        data[2]

    del data
Пример #15
0
 def test_validation_in_write(self, cfg_file, schema):
     """
     test object that adheres to the schema guidelines passes
     validation on write
     """
     y = yacman.YacAttMap(filepath=cfg_file,
                          schema_source=schema,
                          write_validate=True,
                          writable=True)
     y.write()
Пример #16
0
 def test_warn_on_write_when_not_locked(self, name, data_path, cfg_file,
                                        locked_cfg_file):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=True)
     filename = make_cfg_file_path(name, data_path)
     f = os.open(filename, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
     os.close(f)
     with pytest.warns(UserWarning):
         yacmap.write(filename)
     os.remove(filename)
     assert os.path.exists(make_lock_path(name, data_path))
     assert not os.path.exists(locked_cfg_file)
Пример #17
0
 def test_validation_fails_in_write(self, cfg_file, schema, value):
     """
     test object that does not adhere to the schema guidelines does not pass
      validation on write
     """
     y = yacman.YacAttMap(filepath=cfg_file,
                          schema_source=schema,
                          write_validate=True,
                          writable=True)
     y["testattr"] = value
     with pytest.raises(ValidationError):
         y.write()
Пример #18
0
    def get_adapters(self):
        """
        Get current adapters, if defined.

        Adapters are sourced from the 'adapters' section in the root of the
        divvy configuration file and updated with an active compute
        package-specific set of adapters, if any defined in 'adapters' section
        under currently active compute package.

        :return yacman.YacAttMap: current adapters mapping
        """
        adapters = yacman.YacAttMap()
        if "adapters" in self and self.adapters is not None:
            adapters.update(self.adapters)
        if "compute" in self and "adapters" in self.compute:
            adapters.update(self.compute.adapters)
        if not adapters:
            _LOGGER.debug(
                "No adapters determined in divvy configuration file.")
        return adapters
Пример #19
0
def test_bulker_init():

    try:
        shutil.rmtree(DUMMY_CFG_FOLDER)
        os.mkdir(DUMMY_CFG_FOLDER)
        os.mkdir(DUMMY_CFG_TEMPLATES)
        # TODO: Clean up these folders
        # Why do I have to pre-create these anyway? I guess to test init?
        os.mkdir(os.path.join(DUMMY_CFG_TEMPLATES, "zsh_start"))
        os.mkdir(os.path.join(DUMMY_CFG_TEMPLATES, "zsh_start_strict"))
    except:
        pass

    bulker_init(DUMMY_CFG_FILEPATH, DEFAULT_CONFIG_FILEPATH, "docker")
    bulker_config = yacman.YacAttMap(filepath=DEFAULT_CONFIG_FILEPATH)

    manifest, cratevars = load_remote_registry_path(bulker_config, "demo",
                                                    None)
    # del bulker_config

    try:
        shutil.rmtree(DUMMY_CFG_FOLDER)
    except:
        pass
Пример #20
0
def main():
    """ Primary workflow """

    parser = logmuse.add_logging_options(build_argparser())
    args, remaining_args = parser.parse_known_args()
    logger_kwargs = {"level": args.verbosity, "devmode": args.logdev}
    logmuse.init_logger(name="yacman", **logger_kwargs)
    global _LOGGER
    _LOGGER = logmuse.logger_via_cli(args)

    _LOGGER.debug("Command given: {}".format(args.command))

    if not args.command:
        parser.print_help()
        _LOGGER.error("No command given")
        sys.exit(1)

    if args.command == "init":
        bulkercfg = args.config
        _LOGGER.debug("Initializing bulker configuration")
        _is_writable(os.path.dirname(bulkercfg), check_exist=False)
        bulker_init(bulkercfg, DEFAULT_CONFIG_FILEPATH, args.engine)
        sys.exit(0)

    bulkercfg = select_bulker_config(args.config)
    bulker_config = yacman.YacAttMap(filepath=bulkercfg, writable=False)

    if args.command == "list":
        # Output header via logger and content via print so the user can
        # redirect the list from stdout if desired without the header as clutter

        if args.simple:
            fmt = "{namespace}/{crate}:{tag}"
        else:
            _LOGGER.info("Available crates:")
            fmt = "{namespace}/{crate}:{tag} -- {path}"

        if bulker_config.bulker.crates:
            for namespace, crates in bulker_config.bulker.crates.items():
                for crate, tags in crates.items():
                    for tag, path in tags.items():
                        print(
                            fmt.format(namespace=namespace,
                                       crate=crate,
                                       tag=tag,
                                       path=path))
        else:
            _LOGGER.info(
                "No crates available. Use 'bulker load' to load a crate.")
        sys.exit(1)

    # For all remaining commands we need a crate identifier

    _LOGGER.info("Bulker config: {}".format(bulkercfg))
    if args.command == "activate":
        try:
            cratelist = parse_registry_paths(
                args.crate_registry_paths,
                bulker_config.bulker.default_namespace)
            _LOGGER.debug(cratelist)
            _LOGGER.info("Activating bulker crate: {}{}".format(
                args.crate_registry_paths, " (Strict)" if args.strict else ""))
            bulker_activate(bulker_config,
                            cratelist,
                            echo=args.echo,
                            strict=args.strict,
                            prompt=args.no_prompt)
        except KeyError as e:
            parser.print_help(sys.stderr)
            _LOGGER.error("{} is not an available crate".format(e))
            sys.exit(1)
        except MissingCrateError as e:
            _LOGGER.error("Missing crate: {}".format(e))
            sys.exit(1)
        except AttributeError as e:
            _LOGGER.error(
                "Your bulker config file is outdated, you need to re-initialize it: {}"
                .format(e))
            sys.exit(1)

    if args.command == "run":
        try:
            cratelist = parse_registry_paths(args.crate_registry_paths)
            _LOGGER.info("Activating crate: {}\n".format(
                args.crate_registry_paths))
            bulker_run(bulker_config, cratelist, args.cmd, strict=args.strict)
        except KeyError as e:
            parser.print_help(sys.stderr)
            _LOGGER.error("{} is not an available crate".format(e))
            sys.exit(1)
        except MissingCrateError as e:
            _LOGGER.error("Missing crate: {}".format(e))
            sys.exit(1)

    if args.command == "load":
        bulker_config.make_writable()
        manifest, cratevars = load_remote_registry_path(
            bulker_config, args.crate_registry_paths, args.manifest)
        exe_template_jinja = None
        build_template_jinja = None
        shell_template_jinja = None

        exe_template = mkabs(bulker_config.bulker.executable_template,
                             os.path.dirname(bulker_config._file_path))
        build_template = mkabs(bulker_config.bulker.build_template,
                               os.path.dirname(bulker_config._file_path))
        try:
            shell_template = mkabs(bulker_config.bulker.shell_template,
                                   os.path.dirname(bulker_config._file_path))
        except AttributeError:
            _LOGGER.error(
                "You need to re-initialize your bulker config or add a 'shell_template' attribute."
            )
            sys.exit(1)

        try:
            assert (os.path.exists(exe_template))
        except AssertionError:
            _LOGGER.error(
                "Bulker config points to a missing executable template: {}".
                format(exe_template))
            sys.exit(1)

        with open(exe_template, 'r') as f:
            # with open(DOCKER_TEMPLATE, 'r') as f:
            contents = f.read()
            exe_template_jinja = jinja2.Template(contents)

        try:
            assert (os.path.exists(shell_template))
        except AssertionError:
            _LOGGER.error(
                "Bulker config points to a missing shell template: {}".format(
                    shell_template))
            sys.exit(1)

        with open(shell_template, 'r') as f:
            # with open(DOCKER_TEMPLATE, 'r') as f:
            contents = f.read()
            shell_template_jinja = jinja2.Template(contents)

        if args.build:
            try:
                assert (os.path.exists(build_template))
            except AssertionError:
                _LOGGER.error(
                    "Bulker config points to a missing build template: {}".
                    format(build_template))
                sys.exit(1)

            _LOGGER.info(
                "Building images with template: {}".format(build_template))
            with open(build_template, 'r') as f:
                contents = f.read()
                build_template_jinja = jinja2.Template(contents)

        bulker_load(manifest,
                    cratevars,
                    bulker_config,
                    exe_jinja2_template=exe_template_jinja,
                    shell_jinja2_template=shell_template_jinja,
                    crate_path=args.path,
                    build=build_template_jinja,
                    force=args.force)

    if args.command == "inspect":
        if args.crate_registry_paths == "":
            _LOGGER.error(
                "No active create. Inspect requires a provided crate, or a currently active create."
            )
            sys.exit(1)
        manifest, cratevars = load_remote_registry_path(
            bulker_config, args.crate_registry_paths, None)
        manifest_name = cratevars['crate']

        print("Bulker manifest: {}".format(args.crate_registry_paths))
        crate_path = os.path.join(bulker_config.bulker.default_crate_folder,
                                  cratevars['namespace'], manifest_name,
                                  cratevars['tag'])
        if not os.path.isabs(crate_path):
            crate_path = os.path.join(os.path.dirname(bcfg._file_path),
                                      crate_path)
        print("Crate path: {}".format(crate_path))
        import glob
        filenames = glob.glob(os.path.join(crate_path, "*"))
        available_commands = [
            x for x in [os.path.basename(x) for x in filenames] if x[0] != "_"
        ]
        print("Available commands: {}".format(available_commands))
Пример #21
0
def bulker_load(manifest,
                cratevars,
                bcfg,
                exe_jinja2_template,
                shell_jinja2_template,
                crate_path=None,
                build=False,
                force=False):
    manifest_name = cratevars['crate']
    # We store them in folder: namespace/crate/version
    if not crate_path:
        crate_path = os.path.join(bcfg.bulker.default_crate_folder,
                                  cratevars['namespace'], manifest_name,
                                  cratevars['tag'])
    if not os.path.isabs(crate_path):
        crate_path = os.path.join(os.path.dirname(bcfg._file_path), crate_path)

    _LOGGER.debug("Crate path: {}".format(crate_path))
    _LOGGER.debug("cratevars: {}".format(cratevars))
    # Update the config file
    if not bcfg.bulker.crates:
        bcfg.bulker.crates = {}
    if not hasattr(bcfg.bulker.crates, cratevars['namespace']):
        bcfg.bulker.crates[cratevars['namespace']] = yacman.YacAttMap({})
    if not hasattr(bcfg.bulker.crates[cratevars['namespace']],
                   cratevars['crate']):
        bcfg.bulker.crates[cratevars['namespace']][
            cratevars['crate']] = yacman.YacAttMap({})
    if hasattr(bcfg.bulker.crates[cratevars['namespace']][cratevars['crate']],
               cratevars['tag']):
        _LOGGER.debug(bcfg.bulker.crates[cratevars['namespace']][
            cratevars['crate']].to_dict())
        if not (force or query_yes_no(
                "That manifest has already been loaded. Overwrite?")):
            return
        else:
            bcfg.bulker.crates[cratevars['namespace']][cratevars['crate']][str(
                cratevars['tag'])] = crate_path
            _LOGGER.warning(
                "Removing all executables in: {}".format(crate_path))
            try:
                shutil.rmtree(crate_path)
            except:
                _LOGGER.error(
                    "Error removing crate at {}. Did your crate path change? Remove it manually."
                    .format(crate_path))
    else:
        bcfg.bulker.crates[cratevars['namespace']][cratevars['crate']][str(
            cratevars['tag'])] = crate_path

    # Now make the crate

    # First add any imports

    mkdir(crate_path, exist_ok=True)
    if hasattr(manifest.manifest, "imports") and manifest.manifest.imports:
        for imp in manifest.manifest.imports:
            imp_cratevars = parse_registry_path(imp)
            imp_crate_path = os.path.join(bcfg.bulker.default_crate_folder,
                                          imp_cratevars['namespace'],
                                          imp_cratevars['crate'],
                                          imp_cratevars['tag'])
            if not os.path.isabs(imp_crate_path):
                imp_crate_path = os.path.join(os.path.dirname(bcfg._file_path),
                                              imp_crate_path)
            if not os.path.exists(imp_crate_path):
                _LOGGER.error("Can't import crate '{}' from '{}'".format(
                    imp, imp_crate_path))
                # Recursively load any non-existant imported crates.
                imp_manifest, imp_cratevars = load_remote_registry_path(
                    bcfg, imp, None)
                _LOGGER.debug(imp_manifest)
                _LOGGER.debug(imp_cratevars)
                bulker_load(imp_manifest,
                            imp_cratevars,
                            bcfg,
                            exe_jinja2_template,
                            shell_jinja2_template,
                            crate_path=None,
                            build=build,
                            force=force)
            _LOGGER.info("Importing crate '{}' from '{}'.".format(
                imp, imp_crate_path))
            copy_tree(imp_crate_path, crate_path)

    # should put this in a function
    def host_tool_specific_args(bcfg, pkg, hosttool_arg_key):
        _LOGGER.debug("Arg key: '{}'".format(hosttool_arg_key))
        # Here we're parsing the *image*, not the crate registry path.
        imvars = parse_registry_path_image(pkg['docker_image'])
        _LOGGER.debug(imvars)
        try:
            amap = bcfg.bulker.tool_args[imvars['namespace']][imvars['image']]
            if imvars['tag'] != 'default' and hasattr(amap, imvars['tag']):
                string = amap[imvars['tag']][hosttool_arg_key]
            else:
                string = amap.default[hosttool_arg_key]
            _LOGGER.debug(string)
            return string
        except:
            _LOGGER.debug("No host/tool args found.")
            return ""

    cmdlist = []
    cmd_count = 0
    if hasattr(manifest.manifest, "commands") and manifest.manifest.commands:
        for pkg in manifest.manifest.commands:
            _LOGGER.debug(pkg)
            pkg.update(bcfg.bulker)  # Add terms from the bulker config
            pkg = copy.deepcopy(
                yacman.YacAttMap(pkg))  # (otherwise it's just a dict)
            # We have to deepcopy it so that changes we make to pkg aren't reflected in bcfg.

            if pkg.container_engine == "singularity" and "singularity_image_folder" in pkg:
                pkg["singularity_image"] = os.path.basename(
                    pkg["docker_image"])
                pkg["namespace"] = os.path.dirname(pkg["docker_image"])

                if os.path.isabs(pkg["singularity_image_folder"]):
                    sif = pkg["singularity_image_folder"]
                else:
                    sif = os.path.join(os.path.dirname(bcfg._file_path),
                                       pkg["singularity_image_folder"])

                pkg["singularity_fullpath"] = os.path.join(
                    sif, pkg["namespace"], pkg["singularity_image"])

                mkdir(os.path.dirname(pkg["singularity_fullpath"]),
                      exist_ok=True)
            command = pkg["command"]
            path = os.path.join(crate_path, command)
            _LOGGER.debug("Writing {cmd}".format(cmd=path))
            cmdlist.append(command)

            # Add any host-specific tool-specific args
            hosttool_arg_key = "{engine}_args".format(
                engine=bcfg.bulker.container_engine)
            hts = host_tool_specific_args(bcfg, pkg, hosttool_arg_key)
            _LOGGER.debug("Adding host-tool args: {}".format(hts))
            if hasattr(pkg, hosttool_arg_key):
                pkg[hosttool_arg_key] += " " + hts
            else:
                pkg[hosttool_arg_key] = hts

            # Remove any excluded volumes from the package
            exclude_vols = host_tool_specific_args(bcfg, pkg,
                                                   "exclude_volumes")
            _LOGGER.debug("Volume list: {}".format(pkg["volumes"]))
            _LOGGER.debug("pkg: {}".format(pkg))
            if len(exclude_vols) > 0:
                for item in exclude_vols:
                    _LOGGER.debug("Excluding volume: '{}'".format(item))
                    try:
                        pkg["volumes"].remove(item)
                    except:
                        pass
                _LOGGER.debug("Volume list: {}".format(pkg["volumes"]))
            else:
                _LOGGER.debug("No excluded volumes")

            with open(path, "w") as fh:
                fh.write(exe_jinja2_template.render(pkg=pkg))
                os.chmod(path, 0o755)

            # shell commands
            path_shell = os.path.join(crate_path, "_" + command)
            _LOGGER.debug(
                "Writing shell command: '{cmd}'".format(cmd=path_shell))
            with open(path_shell, "w") as fh:
                fh.write(shell_jinja2_template.render(pkg=pkg))
                os.chmod(path_shell, 0o755)

            if build:
                buildscript = build.render(pkg=pkg)
                x = os.system(buildscript)
                if x != 0:
                    _LOGGER.error(
                        "------ Error building. Build script used: ------")
                    _LOGGER.error(buildscript)
                    _LOGGER.error(
                        "------------------------------------------------")
                _LOGGER.info("Container available at: {cmd}".format(
                    cmd=pkg["singularity_fullpath"]))

    # host commands
    host_cmdlist = []
    if hasattr(manifest.manifest,
               "host_commands") and manifest.manifest.host_commands:
        _LOGGER.info("Populating host commands")
        for cmd in manifest.manifest.host_commands:
            _LOGGER.debug(cmd)
            if not is_command_callable(cmd):
                _LOGGER.warning("Requested host command is not callable and "
                                "therefore not created: '{}'".format(cmd))
                continue
            local_exe = find_executable(cmd)
            path = os.path.join(crate_path, cmd)
            host_cmdlist.append(cmd)
            os.symlink(local_exe, path)

            # The old way: TODO: REMOVE THIS
            if False:
                populated_template = LOCAL_EXE_TEMPLATE.format(cmd=local_exe)
                with open(path, "w") as fh:
                    fh.write(populated_template)
                    os.chmod(path, 0o755)

    cmd_count = len(cmdlist)
    host_cmd_count = len(host_cmdlist)
    if cmd_count < 1 and host_cmd_count < 1:
        _LOGGER.error("No commands provided. Crate not created.")
        os.rmdir(crate_path)
        crate_path_parent = os.path.dirname(crate_path)
        if not os.listdir(crate_path_parent):
            os.rmdir(crate_path_parent)
        sys.exit(1)

    rp = "{namespace}/{crate}:{tag}".format(namespace=cratevars['namespace'],
                                            crate=cratevars['crate'],
                                            tag=cratevars['tag'])

    _LOGGER.info("Loading manifest: '{rp}'."
                 " Activate with 'bulker activate {rp}'.".format(rp=rp))
    if cmd_count > 0:
        _LOGGER.info("Commands available: {}".format(", ".join(cmdlist)))
    if host_cmd_count > 0:
        _LOGGER.info("Host commands available: {}".format(
            ", ".join(host_cmdlist)))

    bcfg.write()
Пример #22
0
def bulker_init(config_path, template_config_path, container_engine=None):
    """
    Initialize a config file.
    
    :param str config_path: path to bulker configuration file to 
        create/initialize
    :param str template_config_path: path to bulker configuration file to 
        copy FROM
    """
    if not config_path:
        _LOGGER.error("You must specify a file path to initialize.")
        return

    if not template_config_path:
        _LOGGER.error("You must specify a template config file path.")
        return

    if not container_engine:
        check_engines = ["docker", "singularity"]
        for engine in check_engines:
            if is_command_callable(engine):
                _LOGGER.info("Guessing container engine is {}.".format(engine))
                container_engine = engine
                break  # it's a priority list, stop at the first found engine

    if config_path and not (os.path.exists(config_path)
                            and not query_yes_no("Exists. Overwrite?")):
        # dcc.write(config_path)
        # Init should *also* write the templates.
        dest_folder = os.path.dirname(config_path)
        dest_templates_dir = os.path.join(dest_folder, TEMPLATE_SUBDIR)
        # templates_subdir =  TEMPLATE_SUBDIR
        copy_tree(os.path.dirname(template_config_path), dest_templates_dir)
        new_template = os.path.join(dest_folder,
                                    os.path.basename(template_config_path))
        bulker_config = yacman.YacAttMap(filepath=template_config_path,
                                         writable=True)
        _LOGGER.debug("Engine used: {}".format(container_engine))
        bulker_config.bulker.container_engine = container_engine
        if bulker_config.bulker.container_engine == "docker":
            bulker_config.bulker.executable_template = os.path.join(
                TEMPLATE_SUBDIR, DOCKER_EXE_TEMPLATE)
            bulker_config.bulker.shell_template = os.path.join(
                TEMPLATE_SUBDIR, DOCKER_SHELL_TEMPLATE)
            bulker_config.bulker.build_template = os.path.join(
                TEMPLATE_SUBDIR, DOCKER_BUILD_TEMPLATE)
        elif bulker_config.bulker.container_engine == "singularity":
            bulker_config.bulker.executable_template = os.path.join(
                TEMPLATE_SUBDIR, SINGULARITY_EXE_TEMPLATE)
            bulker_config.bulker.shell_template = os.path.join(
                TEMPLATE_SUBDIR, SINGULARITY_SHELL_TEMPLATE)
            bulker_config.bulker.build_template = os.path.join(
                TEMPLATE_SUBDIR, SINGULARITY_BUILD_TEMPLATE)
        bulker_config.bulker.rcfile = os.path.join(TEMPLATE_SUBDIR,
                                                   RCFILE_TEMPLATE)
        bulker_config.bulker.rcfile_strict = os.path.join(
            TEMPLATE_SUBDIR, RCFILE_STRICT_TEMPLATE)
        bulker_config.write(config_path)
        # copyfile(template_config_path, new_template)
        # os.rename(new_template, config_path)
        _LOGGER.info("Wrote new configuration file: {}".format(config_path))
    else:
        _LOGGER.warning(
            "Can't initialize, file exists: {} ".format(config_path))
Пример #23
0
 def test_make_writable_changes_filepath(self, cfg_file, name, data_path):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=False)
     yacmap.make_writable(make_cfg_file_path(name, data_path))
     assert getattr(yacmap[IK], FILEPATH_KEY) != cfg_file
Пример #24
0
 def test_make_writable_makes_object_writable(self, cfg_file):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=False)
     yacmap.make_writable()
     assert not getattr(yacmap[IK], RO_KEY, True)
Пример #25
0
 def test_make_writable_doesnt_change_already_writable_objects(
         self, cfg_file):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=True)
     assert yacmap == yacmap.make_writable()
Пример #26
0
 def test_make_readonly_returns_false_if_nothing_unlocked(self, cfg_file):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=False)
     assert not yacmap.make_readonly()
Пример #27
0
 def test_make_readonly_removes_lock_and_returns_true(
         self, cfg_file, list_locks):
     yacmap = yacman.YacAttMap(filepath=cfg_file, writable=True)
     assert yacmap.make_readonly()
     assert len(list_locks) == 0
Пример #28
0
 def test_warnings(self, cfg_file):
     with pytest.warns(None):
         yacman.YacAttMap({}, writable=True)
Пример #29
0
 def test_unlock_errors_when_no_filepath_provided(self, cfg_file):
     yacmap = yacman.YacAttMap({})
     with pytest.raises(TypeError):
         yacmap.make_readonly()
Пример #30
0
 def test_filename_required_when_object_created_from_mapping(self):
     yacmap = yacman.YacAttMap(entries={})
     with pytest.raises(TypeError):
         yacmap.write()