Exemple #1
0
    def load(self, current_dir: str, source: str, source_version: Optional[str]) -> ModuleContent:
        # Local path references start with "./" or "../"
        if not source.startswith("./") and not source.startswith("../"):
            return ModuleContent(None)

        module_path = os.path.normpath(os.path.join(current_dir, source))
        if not os.path.exists(module_path):
            raise FileNotFoundError(module_path)

        return ModuleContent(module_path)
Exemple #2
0
    def _load_module(self) -> ModuleContent:
        if os.path.exists(self.dest_dir):
            return ModuleContent(dir=None)

        best_version = self._find_best_version()

        request_download_url = os.path.join(self.REGISTRY_URL_PREFIX, self.module_source, best_version, 'download')
        response = requests.get(url=request_download_url)
        if response.status_code != HTTPStatus.OK and response.status_code != HTTPStatus.NO_CONTENT:
            return ModuleContent(dir=None)
        else:
            return ModuleContent(dir=None, next_url=response.headers.get('X-Terraform-Get', ''))
Exemple #3
0
 def _load_module(self) -> ModuleContent:
     try:
         module_source = self.module_source.lstrip('git::')
         if module_source.startswith('ssh:'):
             return ModuleContent(dir=None)
         git_getter = GitGetter(module_source, create_clone_and_result_dirs=False)
         git_getter.temp_dir = self.dest_dir
         git_getter.do_get()
         return_dir = self.dest_dir
         if self.inner_module:
             return_dir = os.path.join(self.dest_dir, self.inner_module)
         return ModuleContent(dir=return_dir)
     except Exception as e:
         self.logger.error(f'failed to get {self.module_source} because of {e}')
         return ModuleContent(dir=None)
Exemple #4
0
    def load(self, current_dir: str, source: str,
             source_version: Optional[str]) -> ModuleContent:
        """
Search all registered loaders for the first one which is able to load the module source type. For more
information, see `loader.ModuleLoader.load`.
        """
        last_exception = None
        for loader in self.loaders:
            try:
                content = loader.load(current_dir, source, source_version)
            except Exception as e:
                last_exception = e
                continue

            if content is None:
                continue
            elif not content.loaded():
                content.cleanup()
                continue
            else:
                return content

        if last_exception is not None:
            raise last_exception
        return ModuleContent(None)
Exemple #5
0
    def load(self, current_dir: str, source: str,
             source_version: Optional[str]) -> ModuleContent:
        """
Search all registered loaders for the first one which is able to load the module source type. For more
information, see `loader.ModuleLoader.load`.
        """
        if os.name == 'nt':
            # For windows, due to limitations in the allowed characters for path names, the hash of the source is used.
            # https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
            source_hash = hashlib.md5(source.encode())  # nosec
            local_dir = os.path.join(self.root_dir,
                                     self.external_modules_folder_name,
                                     source_hash.hexdigest())
        else:
            local_dir = os.path.join(self.root_dir,
                                     self.external_modules_folder_name, source)
        inner_module = ""
        next_url = source
        last_exception = None
        while next_url:
            source = next_url
            next_url = ""
            if source in self.failed_urls_cache:
                break
            for loader in self.loaders:
                if not self.download_external_modules and loader.is_external:
                    continue
                try:
                    content = loader.load(
                        root_dir=self.root_dir,
                        current_dir=current_dir,
                        source=source,
                        source_version=source_version,
                        dest_dir=local_dir,
                        external_modules_folder_name=self.
                        external_modules_folder_name,
                        inner_module=inner_module,
                    )
                except Exception as e:
                    last_exception = e
                    continue
                if content.next_url:
                    next_url = content.next_url
                    if loader.inner_module:
                        local_dir = loader.dest_dir
                        inner_module = loader.inner_module
                    break
                if content is None:
                    continue
                elif not content.loaded():
                    if content.failed_url:
                        self.failed_urls_cache.add(content.failed_url)
                    content.cleanup()
                    continue
                else:
                    return content

        if last_exception is not None:
            raise last_exception
        return ModuleContent(None)
Exemple #6
0
    def load(
        self,
        root_dir: str,
        current_dir: str,
        source: str,
        source_version: Optional[str],
        dest_dir: str,
        external_modules_folder_name: str,
        inner_module: Optional[str] = None,
    ) -> ModuleContent:
        """
This function provides an opportunity for the loader to load a module's content if it chooses to do so.
There are three resulting states that can occur when calling this function:
 1) the loader can't handle the source type, in which case a ModuleContent is returned for which
    the `loaded()` method will return False.
 2) the loader can handle the source type and loading is successful, in which case a ModuleContent
    object is returned for which `loaded()` returns True and which provides the directory containing
    the module files
 3) the loader tried to load the module content but and error occurred, in which case an exception
    is raised.
        :param current_dir: Directory containing the reference to the module.
        :param source: the raw source string from the module's `source` attribute (e.g.,
                       "hashicorp/consul/aws" or "git::https://example.com/vpc.git?ref=v1.2.0")
        :param source_version: contains content from the module's `version` attribute, if provided
        :param dest_dir: where to save the downloaded module
        :return: A ModuleContent object which may or may not being loaded.
        """
        self.root_dir = root_dir

        self.module_source = source
        self.current_dir = current_dir
        self.version = str(source_version)

        self.dest_dir = dest_dir
        self.external_modules_folder_name = external_modules_folder_name
        self.inner_module = inner_module

        if not self._is_matching_loader():
            return ModuleContent(dir=None)

        module_path = self._find_module_path()
        if os.path.exists(module_path):
            return ModuleContent(dir=module_path)

        self.logger.debug(
            f"getting module {self.module_source} version: {self.version}")
        return self._load_module()
    def _load_module(self) -> ModuleContent:
        module_path = os.path.normpath(os.path.join(self.current_dir, self.module_source))
        if self.module_source.startswith(self.current_dir):
            module_path = self.module_source
        if not os.path.exists(module_path):
            raise FileNotFoundError(module_path)

        return ModuleContent(module_path)
Exemple #8
0
    def _load_module(self) -> ModuleContent:
        try:
            self._process_generic_git_repo()

            module_source = self.module_source.replace("git::", "")
            git_getter = GitGetter(module_source,
                                   create_clone_and_result_dirs=False)
            git_getter.temp_dir = self.dest_dir
            git_getter.do_get()

            return_dir = self.dest_dir
            if self.inner_module:
                return_dir = os.path.join(self.dest_dir, self.inner_module)
            return ModuleContent(dir=return_dir)
        except Exception as e:
            self.logger.error(
                f"failed to get {self.module_source} because of {e}")
            return ModuleContent(dir=None, failed_url=self.module_source)
Exemple #9
0
    def load(self, current_dir: str, source: str,
             source_version: Optional[str]) -> ModuleContent:
        # Reference: https://www.terraform.io/docs/modules/sources.html#terraform-registry

        # Format: [<HOSTNAME>/]<NAMESPACE>/<NAME>/<PROVIDER>
        # Example: hashicorp/consul/aws
        slash_count = source.count("/") != 2
        if source.startswith("/") or source.endswith(
                "/") or slash_count < 2 or slash_count > 3:
            return ModuleContent(None)

        tokens = source.split("/")

        if len(tokens) == 3:
            host = "registry.terraform.io"
            namespace = tokens[0]
            name = tokens[1]
            provider = tokens[2]
        else:
            host = tokens[0]
            namespace = tokens[1]
            name = tokens[2]
            provider = tokens[3]

        # Info: https://www.terraform.io/docs/internals/module-registry-protocol.html#sample-request-1
        base_url = f"https://{host}/{namespace}/{name}/{provider}"

        with requests.session() as session:
            if not source_version:
                source_version = self._determine_latest_version(
                    base_url, session)

            temp_dir = tempfile.TemporaryDirectory()
            try:
                self._download_source(base_url, source_version, session)
                return ModuleContent(temp_dir)
            except:
                temp_dir.cleanup()
                raise
Exemple #10
0
    def load(self, current_dir: str, source: str,
             source_version: Optional[str]) -> ModuleContent:
        """
Search all registered loaders for the first one which is able to load the module source type. For more
information, see `loader.ModuleLoader.load`.
        """
        local_dir = os.path.join(current_dir,
                                 self.external_modules_folder_name, source)
        inner_module = ''
        next_url = source
        last_exception = None
        while next_url:
            source = next_url
            next_url = ''
            if source in self.failed_urls_cache:
                break
            for loader in self.loaders:
                if not self.download_external_modules and loader.is_external:
                    continue
                try:
                    content = loader.load(current_dir, source, source_version,
                                          local_dir, inner_module)
                except Exception as e:
                    last_exception = e
                    continue
                if content.next_url:
                    next_url = content.next_url
                    if loader.inner_module:
                        local_dir = loader.dest_dir
                        inner_module = loader.inner_module
                    break
                if content is None:
                    continue
                elif not content.loaded():
                    if content.failed_url:
                        self.failed_urls_cache.add(content.failed_url)
                    content.cleanup()
                    continue
                else:
                    return content

        if last_exception is not None:
            raise last_exception
        return ModuleContent(None)