Exemple #1
0
def rc_load_ini(fpath, emheading=None):
    """Load INI-formatted data from a (resource) file.

    :param fpath:     pathlib.Path, path to a source file
    :param emheading: str, heading to be added to the exception's description
    :return:          dict, configparser.ConfigParser.read_dict() compatible
                      data.
    """
    assert isinstance(fpath, Path) and fpath.is_absolute(), (
        f'Argument: fpath: Absolute pathlib.Path is required: {fpath}')

    cfg_parser = cfp.ConfigParser()

    try:
        with fpath.open() as fp:
            cfg_parser.read_file(fp)
    except FileNotFoundError:
        err_msg = f'Load: {fpath}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCNotFoundError(err_msg)
    except (OSError, RuntimeError) as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCError(err_msg)
    except cfp.Error as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCInvalidError(err_msg)
    else:
        return {k: dict(v) for k, v in cfg_parser.items()}
Exemple #2
0
def rc_load_json(fpath, emheading=None):
    """Load JSON-formatted data from a (resource) file.

    :param fpath:     pathlib.Path, path to a source file.
    :param emheading: str, heading to be added to the exception's description
    :return:          json obj, JSON-formatted data
    """
    assert isinstance(fpath, Path) and fpath.is_absolute(), (
        f'Argument: fpath: Absolute pathlib.Path is required: {fpath}')

    try:
        with fpath.open() as fp:
            j_body = json.load(fp, strict=False)
    except FileNotFoundError:
        err_msg = f'Load: {fpath}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCNotFoundError(err_msg)
    except (OSError, RuntimeError) as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCError(err_msg)
    except cr_exc.JSON_ERRORS as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCInvalidError(err_msg)
    else:
        return j_body
Exemple #3
0
def load_dcos_conf_template(fpath: Path):
    """Load the DC/OS aggregated configuration template from disk.

    :param fpath: Path, path to template
    """
    try:
        with fpath.open() as f:
            return template.parse_str(f.read())
    except (OSError, RuntimeError) as e:
        raise cr_exc.RCError(f'DC/OS aggregated config: Template: Load:'
                             f' {fpath}: {type(e).__name__}: {e}') from e
Exemple #4
0
    def save(self):
        """Save package manifest to a file within the active packages index."""
        fpath = self.pkgactive_dpath.joinpath(f'{self.pkg_id}.json')

        try:
            with fpath.open(mode='w') as fp:
                json.dump(self.body, fp)
        except (OSError, RuntimeError) as e:
            err_msg = f'Package manifest: Save: {type(e).__name__}: {e}'
            raise cr_exc.RCError(err_msg)

        LOG.debug(f'Package manifest: Save: {fpath}')
Exemple #5
0
def rc_load_ini(fpath, emheading=None, render=False, context=None):
    """Load INI-formatted data from a resource file. Content of a resource
    file can be pre-processed by Jinja2 rendering engine before being passed to
    INI-parser.

    :param fpath:     pathlib.Path, path to a source file
    :param emheading: str, heading to be added to the exception's description
    :param render:    bool, perform template rendering
    :param context:   ResourceContext, rendering context data object
    :return:          dict, configparser.ConfigParser.read_dict() compatible
                      data.
    """
    assert isinstance(fpath, Path) and fpath.is_absolute(), (
        f'Argument: fpath: Absolute pathlib.Path is required: {fpath}'
    )

    if context is None:
        context_items = {}
    else:
        assert isinstance(context, ResourceContext), (
            f'Argument: context:'
            f' Got {type(context).__name__} instead of ResourceContext'
        )
        context_items = context.get_items()

    cfg_parser = cfp.ConfigParser()

    try:
        if render is True:
            jj2_env = jj2.Environment(
                loader=jj2.FileSystemLoader(str(fpath.parent))
            )
            jj2_tmpl = jj2_env.get_template(str(fpath.name))
            ini_str = jj2_tmpl.render(**context_items)
            LOG.debug(f'rc_load_ini(): ini_str: {ini_str}')
            cfg_parser.read_string(ini_str, source=str(fpath))
        else:
            with fpath.open() as fp:
                cfg_parser.read_file(fp)
    except (FileNotFoundError, jj2.TemplateNotFound) as e:
        err_msg = f'Load: {fpath}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCNotFoundError(err_msg) from e
    except (OSError, RuntimeError) as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCError(err_msg) from e
    except (jj2.TemplateError, cfp.Error) as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCInvalidError(err_msg) from e
    else:
        return {k: dict(v) for k, v in cfg_parser.items()}
Exemple #6
0
    def _get_inst_state(self):
        """"""
        istate_fpath = self.inst_storage.state_dpath.joinpath(
            cm_const.DCOS_INST_STATE_FNAME_DFT)
        try:
            inst_state = InstallationState.load(istate_fpath)
            LOG.debug(f'{self.msg_src}: DC/OS installation state descriptor:'
                      f' Load: {inst_state}')
        except cr_exc.RCNotFoundError:
            inst_state = None

        if inst_state is None:
            msg_base = (f'{self.msg_src}:'
                        f' DC/OS installation state descriptor: Create')
            try:
                inst_state = InstallationState(self.inst_storage.istor_nodes)
                LOG.debug(f'{msg_base}: {inst_state}')
            except AssertionError as e:
                raise cr_exc.RCError(f'{msg_base}: {type(e).__name__}: {e}')
            except cr_exc.RCError as e:
                raise cr_exc.RCError(f'{msg_base}: {e}')

        return inst_state
Exemple #7
0
    def save(self):
        """Save package manifest to a file within the active packages index."""
        fpath = getattr(
            self._istor_nodes,
            ISTOR_NODE.PKGACTIVE).joinpath(f'{self._pkg_id.pkg_id}.json')

        try:
            with fpath.open(mode='w') as fp:
                json.dump(self.body, fp)
        except (OSError, RuntimeError) as e:
            err_msg = f'Package manifest: Save: {type(e).__name__}: {e}'
            raise cr_exc.RCError(err_msg) from e

        LOG.debug(f'Package manifest: Save: {fpath}')
Exemple #8
0
def rc_load_json(fpath, emheading=None, render=False, context=None):
    """Load JSON-formatted data from a resource file. Content of a resource
    file can be pre-processed by Jinja2 rendering engine before being passed to
    JSON-parser.

    :param fpath:     pathlib.Path, path to a source file.
    :param emheading: str, heading to be added to the exception's description
    :param render:    bool, perform template rendering
    :param context:   ResourceContext, rendering context data object
    :return:          json obj, JSON-formatted data
    """
    assert isinstance(fpath, Path) and fpath.is_absolute(), (
        f'Argument: fpath: Absolute pathlib.Path is required: {fpath}'
    )

    if context is None:
        context_items = {}
    else:
        assert isinstance(context, ResourceContext), (
            f'Argument: context:'
            f' Got {type(context).__name__} instead of ResourceContext'
        )
        context_items = context.get_items(json_ready=True)

    try:
        if render is True:
            jj2_env = jj2.Environment(
                loader=jj2.FileSystemLoader(str(fpath.parent))
            )
            jj2_tmpl = jj2_env.get_template(str(fpath.name))
            json_str = jj2_tmpl.render(**context_items)
            LOG.debug(f'rc_load_json(): json_str: {json_str}')
            j_body = json.loads(json_str, strict=False)
        else:
            with fpath.open() as fp:
                j_body = json.load(fp, strict=False)
    except (FileNotFoundError, jj2.TemplateNotFound) as e:
        err_msg = f'Load: {fpath}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCNotFoundError(err_msg) from e
    except (OSError, RuntimeError) as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCError(err_msg) from e
    except (jj2.TemplateError,) + cr_exc.JSON_ERRORS as e:
        err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
        err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
        raise cr_exc.RCInvalidError(err_msg) from e
    else:
        return j_body
Exemple #9
0
    def delete_manifest(self, mheading: str=None, dpath: Path=None):
        """Delete package's manifest from filesystem.

        :param mheading: str, descriptive heading to be added to error/log
                         messages
        :param dpath:    Path, absolute path to the host directory
                         where to delete from
        """
        mhd_base = f'{self.msg_src}: {self.id.pkg_name}'
        mheading = f'{mheading}: {mhd_base}' if mheading else mhd_base

        try:
            self.manifest.delete(dpath)
        except (OSError, RuntimeError, cr_exc.RCError) as e:
            err_msg = f'{mheading}: Deregister package: {self.id}: {e}'
            raise cr_exc.RCError(err_msg) from e
Exemple #10
0
    def load_dcos_conf_template(fpath):
        """Load the DC/OS aggregated configuration template from disk.

        :param fpath: pathlib.Path, path to template
        """
        p_key = re.compile(r' *- path: (?P<g1>.*)')
        c_key = re.compile(r' *content: [|].*')
        h_key = re.compile(r' *#.*$')

        try:
            with fpath.open() as fp:

                aggregator = {'package': []}
                path = ''
                content = []

                for line in fp:
                    pk_match = p_key.match(line)
                    ck_match = c_key.match(line)
                    hk_match = h_key.match(line)

                    if pk_match:

                        if path:
                            item = {'path': path, 'content': ''.join(content)}
                            aggregator['package'].append(item)
                            path = pk_match.group('g1')
                            content = []
                        else:
                            path = pk_match.group('g1')
                    elif ck_match:
                        continue
                    elif hk_match:
                        continue
                    else:
                        if not path:
                            continue
                        else:
                            content.append(line.strip(' '))

                item = {'path': path, 'content': ''.join(content)}
                aggregator['package'].append(item)
        except (OSError, RuntimeError) as e:
            raise cr_exc.RCError(f'DC/OS aggregated config: Template: Load:'
                                 f' {fpath}: {type(e).__name__}: {e}') from e

        return aggregator
Exemple #11
0
    def save_manifest(self, mheading: str=None, dpath: Path=None):
        """Save package's manifest to filesystem.

        :param mheading: str, descriptive heading to be added to error/log
                         messages
        :param dpath:    Path, absolute path to the host directory
                         where to save to
        """
        mhd_base = f'{self.msg_src}: {self.id.pkg_name}'
        mheading = f'{mheading}: {mhd_base}' if mheading else mhd_base

        try:
            dpath.mkdir(parents=True, exist_ok=True)
            self.manifest.save(dpath)
        except (OSError, RuntimeError, cr_exc.RCError) as e:
            err_msg = f'{mheading}: Register package: {self.id}: {e}'
            raise cr_exc.RCError(err_msg) from e
Exemple #12
0
    def load_dcos_conf_template(fpath: Path):
        """Load the DC/OS aggregated configuration template from disk.

        :param fpath: Path, path to template
        """
        # TODO: Functionality implemented in this method needs to be reused
        #       in other application parts (e.g. CmdConfigUpgrade) and so, it
        #       has been arranged as a standalone function
        #       load_dcos_conf_template().
        #       Thus the CmdConfigSetup is to be moved to use that standalone
        #       function instead of this method to avoid massive code
        #       duplication.
        try:
            with fpath.open() as f:
                return template.parse_str(f.read())
        except (OSError, RuntimeError) as e:
            raise cr_exc.RCError(f'DC/OS aggregated config: Template: Load:'
                                 f' {fpath}: {type(e).__name__}: {e}') from e
Exemple #13
0
    def delete(self, dpath: Path = None):
        """Delete package manifest file.

        :param dpath: Path, absolute path to the host directory where
                      to delete from
        """
        if dpath is None:
            dpath = getattr(self._istor_nodes, ISTOR_NODE.PKGACTIVE)

        fpath = dpath.joinpath(f'{self._pkg_id.pkg_id}.json')

        try:
            fpath.unlink()
        except (OSError, RuntimeError) as e:
            err_msg = f'{self.msg_src}: Delete: {type(e).__name__}: {e}'
            raise cr_exc.RCError(err_msg) from e

        LOG.debug(f'{self.msg_src}: Delete: {fpath}')
Exemple #14
0
    def wrapper(fpath: Path, emheading: str = None, render: bool = False,
                context: ResourceContext = None) -> Any:
        try:
            content = func(fpath, emheading, render, context)

        except (FileNotFoundError, jj2.TemplateNotFound) as e:
            err_msg = f'Load: {fpath}'
            err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
            raise cr_exc.RCNotFoundError(err_msg) from e
        except (OSError, RuntimeError) as e:
            err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
            err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
            raise cr_exc.RCError(err_msg) from e
        except (jj2.TemplateError, yaml.YAMLError) + cr_exc.JSON_ERRORS as e:
            err_msg = f'Load: {fpath}: {type(e).__name__}: {e}'
            err_msg = f'{emheading}: {err_msg}' if emheading else err_msg
            raise cr_exc.RCInvalidError(err_msg) from e
        else:
            return content
Exemple #15
0
    def save(self, dpath: Path = None):
        """Save package manifest to a file.

        :param dpath: Path, absolute path to the host directory where
                      to save to
        """
        if dpath is None:
            # Manifest host directory defaults to the active packages index
            dpath = getattr(self._istor_nodes, ISTOR_NODE.PKGACTIVE)

        fpath = dpath.joinpath(f'{self._pkg_id.pkg_id}.json')

        try:
            with fpath.open(mode='w') as fp:
                json.dump(self.body, fp)
        except (OSError, RuntimeError) as e:
            err_msg = f'{self.msg_src}: Save: {type(e).__name__}: {e}'
            raise cr_exc.RCError(err_msg) from e

        LOG.debug(f'{self.msg_src}: Save: {fpath}')
Exemple #16
0
    def _handle_teardown(self):
        """Teardown the currently installed DC/OS."""
        mheading = f'{self.msg_src}: Execute'
        pkg_manifests = (
            self.config.inst_storage.get_pkgactive(PackageManifest.load)
        )
        packages_bulk = {
            m.pkg_id.pkg_name: Package(manifest=m) for m in pkg_manifests
        }

        iroot_dpath = self.config.inst_storage.root_dpath
        itmp_dpath = self.config.inst_storage.tmp_dpath
        pkgactive_old_dpath = itmp_dpath.joinpath(
            f'{storage.DCOS_PKGACTIVE_DPATH_DFT}.old'
        )
        sh_conf_dname = storage.DCOS_INST_CFG_DPATH_DFT
        sh_exec_dname = storage.DCOS_INST_BIN_DPATH_DFT
        sh_lib__dname = storage.DCOS_INST_LIB_DPATH_DFT

        # Teardown installed packages
        for package in cr_utl.pkg_sort_by_deps(packages_bulk):
            package.handle_svc_wipe(mheading)
            package.handle_uninst_extras(mheading)
            package.save_manifest(mheading, pkgactive_old_dpath)
            package.delete_manifest(mheading)

        # Remove/preserve shared directories
        for dname in sh_conf_dname, sh_exec_dname, sh_lib__dname:
            active_dpath = iroot_dpath.joinpath(dname)
            preserve_dpath = itmp_dpath.joinpath(f'{dname}.old')
            try:
                cm_utl.rmdir(str(preserve_dpath), recursive=True)
                active_dpath.rename(preserve_dpath)
            except (OSError, RuntimeError) as e:
                err_msg = (f'{mheading}: Preserve shared directory:'
                           f' {active_dpath}: {type(e).__name__}: {e}')
                raise cr_exc.RCError(err_msg) from e

            LOG.debug(f'{mheading}: Preserve shared directory: {active_dpath}:'
                      f' {preserve_dpath}')
Exemple #17
0
    def handle_vardata_wipe(self, mheading: str=None):
        """Execute steps on wiping of package's variable data.

        :param mheading: str, descriptive heading to be added to error/log
                         messages
        """
        mhd_base = f'{self.msg_src}: {self.id.pkg_name}'
        mheading = f'{mheading}: {mhd_base}' if mheading else mhd_base

        work_dpath = getattr(self.manifest.istor_nodes, ISTOR_NODE.WORK)
        run_dpath = getattr(self.manifest.istor_nodes, ISTOR_NODE.RUN)

        for host_dpath in work_dpath, run_dpath:
            dpath = host_dpath.joinpath(self.id.pkg_name)
            try:
                cm_utl.rmdir(str(dpath), recursive=True)
                dpath.mkdir(parents=True, exist_ok=True)
                LOG.debug(f'{mheading}: Wipe variable data: {dpath}: OK')
            except (OSError, RuntimeError) as e:
                err_msg = (f'{mheading}: Wipe variable data: {dpath}:'
                           f' {type(e).__name__}: {e}')
                raise cr_exc.RCError(err_msg) from e