def __init__( self, track: str, secret_name: str = "", file_secret_name: str = "", basic_auth_secret_name: str = "", image: str = "", urls: str = "", is_dependent_project: bool = False, deploy_name: str = "", **kwargs: str, ) -> None: # Set variables from arguments and if they do not exist, # then default to settings variables. for env_var, attr in PROJECT_ARG_SETTINGS_MAPPING.items(): if attr in kwargs: setattr(self, attr, kwargs[attr]) else: setattr(self, attr, getattr(settings, env_var, "")) postfix = self.name self.track = track self.image = image self.secret_name = secret_name self.file_secret_name = file_secret_name self.basic_auth_secret_name = basic_auth_secret_name self.urls = urls self.is_dependent_project = is_dependent_project if not image: docker = Docker() self.image = docker.image_tag # TODO: Only set secret names if there are actual secrets if not self.secret_name: self.secret_name = get_secret_name(track=track, postfix=postfix) if not self.file_secret_name: file_secret_postfix = f"{postfix}-file" self.file_secret_name = get_secret_name( track=track, postfix=file_secret_postfix) self.deploy_name = deploy_name if not deploy_name: self.deploy_name = get_deploy_name(track=track, postfix=postfix) self.dependency_projects = ([] if is_dependent_project else self.get_dependency_projects(self.track)) secret_prefixes = ([ f"{env_var_safe_key(self.name)}_{settings.K8S_SECRET_PREFIX}" ] if self.is_dependent_project else [ settings.K8S_SECRET_PREFIX, f"{env_var_safe_key(self.name)}_{settings.K8S_SECRET_PREFIX}", ]) self.secret_data = get_environment_vars_by_prefixes( prefixes=secret_prefixes) for dep_project in self.dependency_projects: self.secret_data[ f"{env_var_safe_key(dep_project.name)}_URL"] = dep_project.url
def get_base_server_url(self) -> URL: deploy_name = get_deploy_name(self.track) port = DATABASE_DEFAULT_PORT_MAPPING[AMQP] host = f"{deploy_name}-rabbitmq" return URL( drivername=AMQP, host=host, port=port, username=self.username, password=self.password, )
def deploy_service(self, service: "Service", namespace: str, track: str) -> None: deploy_name = get_deploy_name(track=track, postfix=service.name) self.helm.upgrade_chart( chart=service.chart, chart_path=service.chart_path, name=deploy_name, namespace=namespace, values=service.values, values_files=service.values_files, version=service.chart_version, )
def get_database_url(self) -> URL: deploy_name = get_deploy_name(self.track) port = DATABASE_DEFAULT_PORT_MAPPING[POSTGRES] host = f"{deploy_name}-{POSTGRES}" return URL( drivername=POSTGRES, host=host, port=port, username=self.username, password=self.password, database=self.database, )
def deploy_service(self, service: "Service", namespace: str, track: str) -> None: deploy_name = get_deploy_name(track=track, postfix=service.name) with settings.plugin_manager.lifecycle.service_deployment( namespace=namespace, service=service, track=track): self.helm.upgrade_chart( chart=service.chart, chart_path=service.chart_path, name=deploy_name, namespace=namespace, values=service.values, values_files=service.values_files, version=service.chart_version, )
def test_get_deploy_name( slug: str, track: str, postfix: Optional[str], expected: str, ) -> None: with mock.patch.object(settings, "ENVIRONMENT_SLUG", slug): deploy_name = get_deploy_name(track=track, postfix=postfix) assert len(deploy_name) <= DEPLOY_NAME_MAX_HELM_NAME_LENGTH if expected.startswith("/") and expected.endswith("/"): # Treat as a regular expression assert re.match(f"^{expected[1:-1]}$", deploy_name) else: assert deploy_name == expected
def test_delete_all(kubernetes: Kubernetes, test_namespace: str) -> None: track = DEFAULT_TRACK deploy_name = get_deploy_name(track=track) project = Project(track=track) kubernetes.create_secret( data={"test": "test"}, namespace=test_namespace, track=track, project=project, secret_name=project.secret_name, ) kubernetes.delete_all(namespace=test_namespace, labels={"release": deploy_name}) with pytest.raises(Exception): kubernetes.get(resource="secret", name=test_namespace)
def __init__( self, chart: str = "bitnami/postgresql", chart_version: str = "7.7.2", username: str = settings.DATABASE_USER, password: str = settings.DATABASE_PASSWORD, database: str = settings.DATABASE_DB, artifact_name: str = "DATABASE_URL", **kwargs: Any, ) -> None: kwargs["name"] = POSTGRES kwargs["chart"] = chart kwargs["chart_version"] = chart_version kwargs["artifact_name"] = artifact_name super().__init__(**kwargs) self.username = username self.password = password self.database = database image = DockerImageRef.parse_string(settings.POSTGRES_IMAGE) self.memory_request = self.service_specific_values.get("MEMORY_REQUEST", "50Mi") self.cpu_request = self.service_specific_values.get("CPU_REQUEST", "50m") self.values: _Values = { "image": {"repository": image.repository}, "fullnameOverride": get_deploy_name(track=self.track, postfix=self.name), "postgresqlUsername": self.username, "postgresqlPassword": self.password, "postgresqlDatabase": self.database, "resources": { "requests": {"memory": self.memory_request, "cpu": self.cpu_request}, }, } if image.registry is not None: self.values["image"]["registry"] = image.registry if image.tag is not None: self.values["image"]["tag"] = image.tag
def create_secret( self, data: Dict[str, str], namespace: str, track: str, project: Project, secret_name: str, encode: bool = True, ) -> None: deploy_name = get_deploy_name(track=track, postfix=project.name) v1 = k8s_client.CoreV1Api(self.client) v1_metadata = k8s_client.V1ObjectMeta(name=secret_name, namespace=namespace, labels={"release": deploy_name}) if encode: encoded_data = self._encode_secret(data) else: encoded_data = data body = k8s_client.V1Secret(data=encoded_data, metadata=v1_metadata, type="generic") logger.info( icon=f"{self.ICON} 🔨", title= f"Creating secret '{secret_name}' for namespace '{namespace}': ", end="", ) try: v1.create_namespaced_secret(namespace=namespace, body=body) except ApiException: try: v1.replace_namespaced_secret(name=secret_name, namespace=namespace, body=body) except ApiException as e: self._handle_api_error(e, raise_client_exception=True) logger.success()
def get_base_database_url(self) -> URL: deploy_name = get_deploy_name(self.track) port = DATABASE_DEFAULT_PORT_MAPPING[MYSQL] host = f"{deploy_name}-{MYSQL}" return URL(drivername=MYSQL, host=host, port=port)