Exemple #1
0
 def rollback() -> None:
     """"""
     for path in rollback_path_list:  # type: Path
         # Remove an existing DC/OS installation storage element
         try:
             cm_utl.rmdir(path=str(path), recursive=True)
         except (OSError, RuntimeError) as e:
             LOG.error(f'{self.__class__.__name__}: Construction:'
                       f' Rollback: {path}: {type(e).__name__}: {e}')
Exemple #2
0
    def remove_package(self, pkg_id: PackageId) -> None:
        """Remove a package from the local package repository.

        :param pkg_id: PackageId, package ID
        """
        try:
            pkg_dpath = self.pkgrepo_dpath.joinpath(pkg_id.pkg_id)
            cm_utl.rmdir(str(pkg_dpath), recursive=True)
        except (OSError, RuntimeError) as e:
            raise cr_exc.RCRemoveError(
                f'Package {pkg_id.pkg_id}: {type(e).__name__}: {e}')
Exemple #3
0
 def destruct(self) -> None:
     """Remove entire existing DC/OS installation storage."""
     for path in self.istor_nodes[1:]:  # type: Path
         if path.is_absolute() and path.is_dir():
             try:
                 cm_utl.rmdir(path=str(path), recursive=True)
                 LOG.debug(f'{self.__class__.__name__}: Destruction:'
                           f' Remove directory: {path}')
             except (OSError, RuntimeError) as e:
                 raise cr_exc.InstallationStorageError(
                     f'Destruction: Remove directory: {path}:'
                     f' {type(e).__name__}: {e}')
Exemple #4
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:
            cm_utl.rmdir(str(dpath), recursive=True)
            dpath.mkdir(parents=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 #5
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 #6
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
Exemple #7
0
    def _handle_teardown_post(self):
        """Perform extra steps on cleaning up unplanned (diverging from initial
        winpanda design and so, not removed by normal teardown procedure) DC/OS
        installation leftovers (see the CmdSetup._handle_pkg_dir_setup() and
        workaround for dcos-diagnostics part in the
        InstallationStorage.add_package()).
        """
        mheading = f'{self.msg_src}: Execute'
        LOG.debug(f'{mheading}: After steps: ...')

        iroot_dpath = self.config.inst_storage.root_dpath
        ivar_dpath = self.config.inst_storage.var_dpath
        itmp_dpath = self.config.inst_storage.tmp_dpath

        wipe_dirs = [
            iroot_dpath.joinpath('include'),
            iroot_dpath.joinpath('mesos-logs'),
            ivar_dpath.joinpath('lib'),
        ]

        for dpath in wipe_dirs:
            try:
                cm_utl.rmdir(str(dpath), recursive=True)
                LOG.debug(f'{mheading}: After steps: Remove dir: {dpath}: OK')
            except (OSError, RuntimeError) as e:
                LOG.warning(f'{mheading}: After steps: Remove dir: {dpath}:'
                            f' {type(e).__name__}: {e}')

        wipe_files = [
            iroot_dpath.joinpath('dcos-diagnostics.exe'),
            iroot_dpath.joinpath('servicelist.txt'),
        ]

        for fpath in wipe_files:
            try:
                fpath.unlink()
                LOG.debug(f'{mheading}: After steps: Remove file: {fpath}: OK')
            except (OSError, RuntimeError) as e:
                LOG.warning(f'{mheading}: After steps: Remove file: {fpath}:'
                            f' {type(e).__name__}: {e}')

        # Restore objects created/populated by entities/processes outside
        # of winpanda routines, but required for winpanda to do it's stuff.

        restore_dirs = [
            iroot_dpath / 'etc',
            iroot_dpath / 'etc' / 'roles',
        ]

        for dpath in restore_dirs:
            try:
                dpath.mkdir(parents=True, exist_ok=True)
                LOG.debug(f'{mheading}: After steps: Restore dir: {dpath}: OK')
            except (OSError, RuntimeError) as e:
                LOG.warning(f'{mheading}: After steps: Restore dir: {dpath}:'
                            f' {type(e).__name__}: {e}')

        restore_files = [
            (itmp_dpath / 'etc.old' / 'cluster.conf', iroot_dpath / 'etc'),
            (itmp_dpath / 'etc.old' / 'paths.json', iroot_dpath / 'etc'),
            (itmp_dpath / 'etc.old' / 'roles' / 'slave',
             iroot_dpath / 'etc' / 'roles'),
        ]

        for fspec in restore_files:
            try:
                shutil.copy(str(fspec[0]),
                            str(fspec[1]),
                            follow_symlinks=False)
                LOG.debug(
                    f'{mheading}: After steps: Restore file: {fspec}: OK')
            except (OSError, RuntimeError) as e:
                LOG.warning(f'{mheading}: After steps: Restore file: {fspec}:'
                            f' {type(e).__name__}: {e}')

        LOG.debug(f'{mheading}: After steps: OK')
Exemple #8
0
    def construct(self, clean: bool = False) -> None:
        """Construct DC/OS installation storage.

        :param clean: boolean, create a clean FS folder structure, wiping
                      out any possible leftovers, if True. Otherwise repair FS
                      directory structure, creating any missed pieces, as
                      required.
        """
        clean_ready = self._inst_stor_is_clean_ready(clean=clean)
        LOG.debug(f'{self.__class__.__name__}:'
                  f' Construction: Clean ready: {clean_ready}')
        rollback_path_list = []  # type: List

        def rollback() -> None:
            """"""
            for path in rollback_path_list:  # type: Path
                # Remove an existing DC/OS installation storage element
                try:
                    cm_utl.rmdir(path=str(path), recursive=True)
                except (OSError, RuntimeError) as e:
                    LOG.error(f'{self.__class__.__name__}: Construction:'
                              f' Rollback: {path}: {type(e).__name__}: {e}')

        for path in self.istor_nodes:  # type: Path
            if path.exists():
                if path.is_symlink():
                    rollback()
                    raise cr_exc.InstallationStorageError(
                        f'Construction: Symlink conflict: {path}'
                    )
                elif path.is_reserved():
                    rollback()
                    raise cr_exc.InstallationStorageError(
                        f'Construction: Reserved name conflict: {path}'
                    )
                elif not path.is_dir():
                    # Remove a file
                    try:
                        path.unlink()
                        LOG.debug(f'{self.__class__.__name__}:'
                                  f' Construction: Auto-cleanup: File: {path}')
                    except (OSError, RuntimeError) as e:
                        rollback()
                        raise cr_exc.InstallationStorageError(
                            f'Construction: Auto-cleanup: File: {path}:'
                            f' {type(e).__name__}: {e}'
                        ) from e
                    # Create a fresh DC/OS installation storage element
                    try:
                        path.mkdir(parents=True, exist_ok=True)
                        LOG.debug(f'{self.__class__.__name__}: Construction:'
                                  f' Create directory: {path}')
                    except (OSError, RuntimeError) as e:
                        rollback()
                        raise cr_exc.InstallationStorageError(
                            f'Construction: Create directory: {path}:'
                            f' {type(e).__name__}: {e}'
                        ) from e
                elif clean is True:
                    if clean_ready is True:
                        # Remove an existing DC/OS installation storage element
                        try:
                            cm_utl.rmdir(path=str(path), recursive=True)
                            LOG.debug(f'{self.__class__.__name__}:'
                                      f' Construction: Cleanup: {path}')
                        except (OSError, RuntimeError) as e:
                            rollback()
                            raise cr_exc.InstallationStorageError(
                                f'Construction: Cleanup: {path}:'
                                f' {type(e).__name__}: {e}'
                            ) from e
                        # Create a fresh DC/OS installation storage element
                        try:
                            path.mkdir(parents=True, exist_ok=True)
                            LOG.debug(f'{self.__class__.__name__}:'
                                      f' Construction: Create directory:'
                                      f' {path}')
                        except (OSError, RuntimeError) as e:
                            rollback()
                            raise cr_exc.InstallationStorageError(
                                f'Construction: Create directory: {path}:'
                                f' {type(e).__name__}: {e}'
                            ) from e
                    else:
                        rollback()
                        raise cr_exc.InstallationStorageError(
                            f'Construction:  Not ready for cleanup : {path}'
                        )
            else:
                # Create a fresh DC/OS installation storage element
                try:
                    path.mkdir(parents=True, exist_ok=True)
                    rollback_path_list.append(path)
                    LOG.debug(f'{self.__class__.__name__}: Construction:'
                              f' Create directory: {path}')
                except (OSError, RuntimeError) as e:
                    rollback()
                    raise cr_exc.InstallationStorageError(
                        f'Construction: Create directory: {path}:'
                        f' {type(e).__name__}: {e}'
                    ) from e
def test_rm_not_dir_should_fail(*args):
    """Try remove file and raise exception."""
    with pytest.raises(OSError):
        utils.rmdir('/tmp/.000')
Exemple #10
0
def test_rm_reserved_should_fail(*args):
    """Try remove reserved path and raise exception."""
    with pytest.raises(OSError):
        utils.rmdir('/tmp/.000')
Exemple #11
0
def test_rm_symlink_should_fail(*args):
    """Try remove symlink and raise exception."""
    with pytest.raises(OSError):
        utils.rmdir('/tmp/.000')
Exemple #12
0
def test_rm_nonexistent_dir_should_fail(*args):
    """Remove empty path without exceptions and None result."""
    assert utils.rmdir('path') is None