Пример #1
0
 def get_acl(cls, obj=None):
     # pylint: disable=bad-staticmethod-argument
     handler_class_name = settings.ACL['MODEL_HANDLERS'].get(
         cls.__name__, settings.ACL['MODEL_HANDLERS'].get("Default"))
     return import_class(handler_class_name)(cls, obj)
Пример #2
0
class _Base:
    __slots__ = 'options', 'proj', 'path'

    regex = r"(^[\w\d\.\-_]{1,})\.yml"
    handler_class = import_class(settings.PROJECT_CI_HANDLER_CLASS)

    def __init__(self, project: Project, **options):
        self.options = options
        self.proj = project
        self.path = self.proj.path

    def _set_status(self, status) -> NoReturn:
        self.proj.set_status(status)

    @raise_context()
    def _load_yaml(self) -> Dict[Text, Any]:
        '''
        Loading `.polemarch.yaml` data.

        :return: Data from `.polemarch.yaml` file.
        :type ret: dict
        '''
        self.proj.get_yaml_subcache().clear()
        return self.proj.get_yaml()

    def _path_exists(self, path: Text) -> bool:
        return os.path.exists(path)

    def _dir_exists(self, path_dir: Text) -> bool:
        return self._path_exists(path_dir) and os.path.isdir(path_dir)

    def message(self, message: Any, level: Text = 'debug') -> NoReturn:
        getattr(logger, level.lower(),
                logger.debug)('Syncing project [{}] - {}'.format(
                    self.proj.id, message))

    def pm_handle_sync_on_run(self, feature: Text, data: bool) -> NoReturn:
        '''
        Set sync_on_run if it is setted in `.polemarch.yaml`.

        :param feature: feature name
        :param data: all data from file
        '''
        value = str(data[feature])
        _, created = self.proj.variables.update_or_create(
            key='repo_sync_on_run', defaults=dict(value=value))
        self.message('{} repo_sync_on_run to {}'.format(
            'Set' if created else 'Update', value))

    @raise_context()
    def __create_template(self, template_name: Text,
                          template_data: Dict) -> Template:
        '''
        Creates one template from `.polemarch.yaml`.

        :param template_name: Template name
        :param template_data: Template data
        :return: created Template object
        '''
        self.message(
            'Loading template[{}] into the project.'.format(template_name))
        return self.proj.template.create(name=template_name, **template_data)

    def pm_handle_templates(self, feature: Text, data: Dict) -> NoReturn:
        '''
        Get and create (if is not existed) templates from `.polemarch.yaml`.

        :param feature: feature name
        :param data: all data from file
        '''
        rewrite = data.get('templates_rewrite', False)
        data = data[feature]
        qs_existed = self.proj.template.filter(name__in=data.keys())
        existed = qs_existed.values_list('name', flat=True)
        for template_name, template_data in data.items():
            if not rewrite and template_name in existed:
                self.message(
                    'Template[{}] already in project.'.format(template_name))
                continue
            self.__create_template(template_name, template_data)

    def pm_handle_view(self, feature: Text, data: Dict) -> NoReturn:
        '''
        Clear view data from cache

        :param feature: feature name
        :param data: all data from file
        '''
        # pylint: disable=unused-argument
        self.proj.get_yaml_subcache('view').clear()
        self.message(self.proj.execute_view_data, 'debug')

    def pm_handle_unknown(self, feature: Text, data: Any) -> NoReturn:  # nocv
        '''
        Logging unknowing data from `.polemarch.yaml`.
        '''
        self.message('{} - this feature is not realised yet.'.format(feature),
                     'info')
        logger.debug(str(data))

    def _handle_yaml(self, data: Union[Dict, None]) -> NoReturn:
        """
        Loads and returns data from `.polemarch.yaml` file
        """
        for feature in data.keys():
            if feature in [
                    'templates_rewrite',
            ]:
                continue
            self.message(
                'Set settings from ".polemarch.yaml" - {}.'.format(feature))
            feature_name = 'pm_handle_{}'.format(feature)
            getattr(self, feature_name, self.pm_handle_unknown)(feature, data)

    def _set_tasks_list(self,
                        playbooks_names: Iterable[pathlib.Path]) -> NoReturn:
        """
        Updates playbooks in project.
        """
        # pylint: disable=invalid-name
        project = self.proj
        project.playbook.all().delete()
        PlaybookModel = self.proj.playbook.model
        hidden = project.hidden
        split = str.split
        playbook_objects = (PlaybookModel(name=split(str(p), ".yml")[0],
                                          playbook=p,
                                          hidden=hidden,
                                          project=project)
                            for p in playbooks_names)
        PlaybookModel.objects.bulk_create(
            playbook_objects) if playbook_objects else None

    def __get_project_modules(
            self, module_path: Iterable[Text]) -> List[Union[Text, Dict]]:
        valid_paths = tuple(filter(self._dir_exists, module_path))
        if not valid_paths:
            return []
        modules = AnsibleModules(detailed=False, paths=valid_paths)
        modules.clear_cache()
        modules_list = modules.all()
        modules_list.sort()
        return modules_list

    @raise_context()
    def _set_project_modules(self) -> None:
        '''
        Update project modules
        '''
        # pylint: disable=invalid-name
        project = self.proj
        project.get_ansible_config_parser().clear_cache()
        project.modules.all().delete()
        ModuleClass = self.proj.modules.model
        paths = project.config.get('DEFAULT_MODULE_PATH', [])
        paths = filter(lambda mp: project.path in mp, paths)
        modules = self.__get_project_modules(paths)
        ModuleClass.objects.bulk_create(
            [ModuleClass(path=path, project=project) for path in modules])

    def _update_tasks(self, files: Iterable[pathlib.Path]) -> NoReturn:
        '''
        Find and update playbooks in project.
        :param files: list of filenames.
        '''
        # reg = re.compile(self.regex)
        # playbooks = filter(reg.match, files)
        self._set_tasks_list(files)

    def _get_files(self, repo: Any = None) -> pathlib.Path:
        '''
        Get all files, where playbooks should be.
        :param repo: Repo object
        :type repo: object, None
        :return: list of files in dir
        :rtype: list
        '''
        # pylint: disable=unused-argument
        return pathlib.Path(self.path)

    def search_files(self,
                     repo: Any = None,
                     pattern: Text = '**/*') -> Iterable[pathlib.Path]:
        return self._get_files(repo).glob(pattern)

    def _operate(self, operation: Callable, **kwargs) -> Any:
        return operation(kwargs)

    def _make_operations(self, operation: Callable) -> Any:
        '''
        Handle VCS operations and sync data from project.

        :param operation: function that should be hdandled.
        :return: tuple with repo-object and fetch-results
        '''
        self._set_status("SYNC")
        try:
            with transaction.atomic():
                result = self._operate(operation)
                self._set_status("OK")
                self._update_tasks(self.search_files(result[0], '*.yml'))
                self._set_project_modules()
                self._handle_yaml(self._load_yaml() or dict())
        except Exception as err:
            logger.debug(traceback.format_exc())
            self.message('Sync error: {}'.format(err), 'error')
            self._set_status("ERROR")
            raise
        else:
            with raise_context(verbose=True):
                self.handler_class(self, result).trigger_execution()
            return result

    def make_clone(self, options):  # pragma: no cover
        '''
        Make operations for clone repo
        :param options: any options, like env variables or any thing
        :return: tuple object with 2 args: repo obj and fetch results
        '''
        raise NotImplementedError

    def make_update(self, options):  # pragma: no cover
        '''
        Make operation for fetch repo tree
        :param options: any options, like env variables or any thing
        :return: tuple object with 2 args: repo obj and fetch results
        '''
        raise NotImplementedError

    def get_revision(self, *args, **kwargs) -> Text:
        # pylint: disable=unused-argument
        return "NO VCS"

    def get_branch_name(self) -> Text:
        return "NO VCS"

    def delete(self) -> Text:
        '''
        Handler, which removes project data directory.

        :return: user message
        '''
        if os.path.exists(self.path):
            if os.path.isfile(self.path):
                os.remove(self.path)  # nocv
            else:
                shutil.rmtree(self.path)
            return "Repository removed!"
        return "Repository does not exists."  # nocv

    def clone(self) -> Text:
        # pylint: disable=broad-except
        attempt = 2
        for __ in range(attempt):
            try:
                repo = self._make_operations(self.make_clone)[0]
                return "Received {} files.".format(
                    len(list(self.search_files(repo))))
            except:
                self.delete()
        raise Exception("Clone didn't perform by {} attempts.".format(attempt))

    def get(self) -> Any:
        # pylint: disable=broad-except
        attempt = 2
        for __ in range(attempt):
            try:
                return self._make_operations(self.make_update)
            except:
                self.delete()
        raise Exception("Upd didn't perform by {} attempts.".format(attempt))

    def check(self):
        pass  # nocv

    def revision(self) -> Text:
        return self._operate(self.get_revision)
Пример #3
0
 def _get_mod_info(self, key, sub):
     try:
         path = "{}.{}.{}".format(self.mod.__name__, key, sub)
         return import_class(path)
     except BaseException as exception_object:
         return exception_object