def delete( self, resource: str, name: Optional[str] = None, labels: Optional[Dict[str, str]] = None, namespace: str = settings.K8S_NAMESPACE, ) -> None: os_command = [ "kubectl", "delete", resource, "--ignore-not-found", "--wait=true", f"--namespace={namespace}", ] logger.info(icon=f"{self.ICON} 🗑️ ", title=f"Removing {resource}", end="") if labels: labels_str = self.labels_to_string(labels) os_command += ["-l", labels_str] logger.info(title=f" with labels {labels_str}", end="") if name: os_command += [name] logger.info(title=f" with name '{name}'", end="") logger.info(": ", end="") result = run_os_command(os_command, shell=True) if not result.return_code: logger.success() else: logger.std(result, raise_exception=True)
def get_certification_issuer(self, track: str) -> Optional[str]: logger.info(icon=f"{self.ICON} 🏵️️", title="Checking certification issuer", end="") raise_exception = False if settings.K8S_CLUSTER_ISSUER: cert_issuer: str = settings.K8S_CLUSTER_ISSUER logger.info(message=" (settings): ", end="") raise_exception = True else: cert_issuer = f"certificate-letsencrypt-{track}" logger.info(message=" (track): ", end="") os_command = ["kubectl", "get", "clusterissuer", cert_issuer] result = run_os_command(os_command, shell=True) if not result.return_code: logger.success(message=cert_issuer) return cert_issuer else: error_message = f'No issuer "{cert_issuer}" found, using cluster defaults' if raise_exception: logger.error(message=error_message, raise_exception=True) else: logger.info(message=error_message) return None
def update_repos(self) -> None: logger.info(icon=f"{self.ICON} 🔄", title="Updating Helm repos: ", end="") result = run_os_command(["helm", "repo", "update"]) if not result.return_code: logger.success() else: logger.std(result, raise_exception=True)
def update_submodules(self, depth: int = 0, jobs: int = 0) -> None: """ Update all submodules Returns: None """ os_command = [ "git", "submodule", "update", "--init", "--recursive", ] if depth: os_command += ["--depth", f"{depth}"] if jobs: os_command += ["--jobs", f"{jobs}"] logger.info(icon=f"{self.ICON} 🌱", title="Updating submodules: ", end="") result = run_os_command(os_command) if result.return_code: logger.std(result, raise_exception=True) logger.success()
def remove_repo(self, repo_name: str) -> None: logger.info( icon=f"{self.ICON} âž–", title=f"Removing Helm repo {repo_name}: ", end="", ) result = run_os_command(["helm", "repo", "remove", repo_name]) if not result.return_code: logger.success() else: logger.std(result, raise_exception=True)
def add_repo(self, repo_name: str, repo_url: str, update: bool = True) -> None: logger.info( icon=f"{self.ICON} âž•", title=f"Adding Helm repo {repo_url} with name {repo_name}: ", end="", ) result = run_os_command(["helm", "repo", "add", repo_name, repo_url]) if not result.return_code: logger.success() else: logger.std(result, raise_exception=True) if update: self.update_repos()
def _create_basic_auth_data( self, basic_auth_users: List[BasicAuthUser] = settings.K8S_INGRESS_BASIC_AUTH ) -> Dict[str, str]: """ Create secret data from list of `BasicAuthUser` The user credentials from the list of users will be encrypted and added to a temporary file using the `htpasswd` tool from Apache. The file is then read and base64 encoded (as required by Kubernetes secrets). Args: basic_auth_users: List of `BasicAuthUser`s Returns: A dict with the key `auth` and base64 content of a htpasswd file as value """ logger.info(icon=f"{self.ICON} 🔨", title="Generating basic auth data: ", end="") if not basic_auth_users: return {} with tempfile.NamedTemporaryFile() as f: passwd_path = Path(f.name) for i, user in enumerate(basic_auth_users): os_command = ["htpasswd", "-b"] if i == 0: os_command.append("-c") os_command += [str(passwd_path), user.username, user.password] result = run_os_command(os_command) if result.return_code: logger.error( message= "The 'htpasswd' command failed to create an entry", raise_exception=True, ) encoded_file = self._b64_encode_file(passwd_path) logger.success() logger.info( message= f"\t {len(settings.K8S_INGRESS_BASIC_AUTH)} users will be added to basic auth" ) return {"auth": encoded_file}
def get( self, resource: str, name: Optional[str] = None, labels: Optional[Dict[str, str]] = None, namespace: str = settings.K8S_NAMESPACE, raise_exception: bool = True, ) -> SubprocessResult: os_command = ["kubectl", "get"] logger.info(icon=f"{self.ICON} ℹ️ ", title=f"Getting {resource}", end="") os_command += self._resource_command( resource=resource, name=name, labels=labels, namespace=namespace ) logger.info(": ", end="") result = run_os_command(os_command, shell=True) # nosec if not result.return_code: logger.success() else: logger.std(result, raise_exception=raise_exception) return result
def logs( self, labels: Optional[Dict[str, str]] = None, since_time: Optional[str] = None, namespace: str = settings.K8S_NAMESPACE, print_result: bool = True, raise_exception: bool = True, ) -> SubprocessResult: os_command = [ "kubectl", "logs", f"--namespace={namespace}", "--prefix=true", "--timestamps=true", "--tail=100", ] logger.info(icon=f"{self.ICON} 📋️️ ", title="Getting logs for resource: ", end="") if labels: labels_str = self.labels_to_string(labels) os_command += ["-l", labels_str] logger.info(title=f" with labels {labels_str}", end="") if since_time: os_command += [f"--since-time={since_time}"] logger.info(title=f" since {since_time}", end="") result = run_os_command(os_command, shell=True) if not result.return_code: logger.success() if print_result: logger.std(result) else: logger.std(result, raise_exception=raise_exception) return result
def upgrade_chart( self, name: str, values: HelmValues, namespace: str, chart: str = "", chart_path: Optional[Path] = None, values_files: Optional[List[Path]] = None, install: bool = True, version: Optional[str] = None, raise_exception: bool = True, ) -> SubprocessResult: if chart_path: if not chart_path.is_absolute(): chart_path = settings.devops_root_path / chart_path if not chart_path.exists(): logger.error( message=f"Path '{str(chart_path)}' does not exist", error=OSError(), raise_exception=True, ) chart = str(chart_path) logger.info( icon=f"{self.ICON} 📄", title=f"Upgrading chart from '{chart}': ", end="", ) replica_timeout_multiplier = 2 if settings.K8S_REPLICACOUNT > 1 else 1 timeout = ( (settings.K8S_PROBE_INITIAL_DELAY * replica_timeout_multiplier) + (settings.K8S_PROBE_FAILURE_THRESHOLD * settings.K8S_PROBE_PERIOD) + 120 # Buffer time ) # Construct initial helm upgrade command install_arg = "--install" if install else "" helm_command = [ "helm", "upgrade", "--atomic", "--timeout", f"{timeout}s", "--history-max", "30", install_arg, "--namespace", f"{namespace}", ] if version: helm_command += ["--version", version] # Add values files if values_files: helm_command += self.get_chart_params(flag="--values", values=values_files) safe_name = kubernetes_safe_name(name=name) values_yaml = yaml.dump(values) with NamedTemporaryFile(buffering=0) as fobj: fobj.write(values_yaml.encode()) result = run_os_command( [*helm_command, "--values", fobj.name, f"{safe_name}", f"{chart}"], ) if result.return_code: logger.std(result, raise_exception=raise_exception) return result logger.success() logger.info(f"\tName: {safe_name} (orig: {name})") logger.info(f"\tNamespace: {namespace}") return result