def _span_end( self, span_name: str, status: Optional["status.StatusCode"] = None, ) -> bool: # Check that the current context matches the lifecycle if context.get_value(self.lifecycle_key) != span_name: logger.warning(f"Requested span not active: {span_name}") return False span = trace.get_current_span() # Set span status if status is not None: span.set_status(status) # End current span span.end() # Pop context stack context_detach_token: Optional[str] = None try: context_detach_token = self.context_detach_tokens[-1] except IndexError: pass if context_detach_token: context.detach(context_detach_token) self.context_detach_tokens.pop() else: logger.warning(f"Context detach token missing: {span_name}") return True
def _map_ci_variables(self) -> None: """ Map CI variables to settings Strategy: 1. If a value is set in the env, use it 2. If a value is not set in the env and a CI value is set, use the CI value 3. If a value is not set in the env and not in the CI, use the default value """ if not self.active_ci: return None for name_from, name_to in self.active_ci.MAPPING.items(): if name_to not in _VARIABLE_DEFINITIONS: logger.warning( message= f"CI variable mapping failed, no setting called {name_to}") has_set_value = name_to if name_to in os.environ else None if not has_set_value: has_set_value = (f"{self.PROJECT_NAME_SAFE}_{name_to}" if f"{self.PROJECT_NAME_SAFE}_{name_to}" in os.environ else None) if has_set_value: continue parser, default_value = _VARIABLE_DEFINITIONS[name_to] ci_value = parser(name_from, None) if not ci_value: continue setattr(self, name_to, ci_value)
def _parse_file_secrets( self, filesecrets: Dict[str, str]) -> Tuple[Dict[str, str], Dict[str, str]]: if settings.active_ci: valid_prefixes = settings.active_ci.VALID_FILE_SECRET_PATH_PREFIXES else: raise ImproperlyConfigured("An active CI is needed") filecontents = {} mapping = {} for name, filename in filesecrets.items(): path = Path(filename) if not validate_file_secret_path(path, valid_prefixes): # TODO: This needs refactoring. Variable names do not match the contents. # If path-variable doesn't contain a valid path, we expect it to contain # the value for the secret file and we can use it directly. logger.warning( f'Not a valid file path for a file "{name}". Using contents as a secret value.' ) # Here we expect that filename-variable contains the secret filecontents[name] = b64encode( filename.encode("UTF-8")).decode("UTF-8") mapping[name] = f"{settings.K8S_FILE_SECRET_MOUNTPATH}/{name}" continue try: filecontents[name] = self._b64_encode_file(path) mapping[name] = f"{settings.K8S_FILE_SECRET_MOUNTPATH}/{name}" except OSError as e: logger.error(f'Error while reading a file: "{path}"', error=e) return filecontents, mapping
def delete_image(self, image: DockerImage) -> None: logger.warning(icon=f"{self.ICON}", message="Removing Docker image") for tag in image.tags: logger.info(message=f"\t {image.repository}:{tag}: ", end="") delete_command = ["docker", "rmi", f"{image.repository}:{tag}"] result = run_os_command(delete_command, shell=False) if result.return_code: logger.std(result, raise_exception=False) else: logger.success()
def _import_plugins( directory: Optional[Path] = None, ) -> Generator[Type[PluginBase], None, None]: if not directory: directory = Path(__file__).parent for init_file in directory.glob("*/__init__.py"): module_name = init_file.parent.name module = import_module(f".{module_name}", package=__package__) try: yield getattr(module, "Plugin") except AttributeError: logger.warning(f"Unable to load plugin: {module_name}")
def map_variables(self, fields: Dict[str, "ModelField"], suppress_warnings: bool = False) -> Dict[str, Any]: """ Map CI variables to settings If the source name starts with '=', get the value from mapper's attribute. Otwerwise read the value from environment. """ values = {} for name_to, name_from in self.MAPPING.items(): if name_to not in fields: if not suppress_warnings: logger.warning( message= f"CI variable mapping failed, no setting called {name_to}" ) continue if name_from.startswith("="): name_from = name_from[1:] try: value = getattr(self, name_from) except AttributeError: if not suppress_warnings: logger.warning( message= f"CI variable mapping failed, no mapper attribute called {name_from}" ) continue elif name_from in os.environ: raw_value = os.environ.get(name_from) value, error = fields[name_to].validate(raw_value, {}, loc=name_from) if error: raise ImproperlyConfigured( f"Invalid valid value: {name_from}={raw_value}") else: value = None if value is not None: values[name_to] = value return values
def _parse_file_secrets( self, filesecrets: Dict[str, str]) -> Tuple[Dict[str, str], Dict[str, str]]: if settings.active_ci: valid_prefixes = settings.active_ci.VALID_FILE_SECRET_PATH_PREFIXES else: raise ImproperlyConfigured("An active CI is needed") filecontents = {} mapping = {} for name, filename in filesecrets.items(): path = Path(filename) if not validate_file_secret_path(path, valid_prefixes): logger.warning(f'Not a valid file path: "{path}". Skipping.') continue try: filecontents[name] = self._b64_encode_file(path) mapping[name] = f"{settings.K8S_FILE_SECRET_MOUNTPATH}/{name}" except OSError as e: logger.error(f'Error while reading a file: "{path}"', error=e) return filecontents, mapping