diff --git a/server/.env.sample b/server/.env.sample index da35a24..7afb614 100644 --- a/server/.env.sample +++ b/server/.env.sample @@ -6,4 +6,5 @@ ENV=local # this should be your wildcard domain name DOMAIN_NAME=localhost # example: sarthi.yourdomain.io -VAULT_TOKEN="random_token" \ No newline at end of file +VAULT_TOKEN="random_token" +VAULT_BASE_URL="http://vault:8200" \ No newline at end of file diff --git a/server/app.py b/server/app.py index 110a72a..6f53049 100644 --- a/server/app.py +++ b/server/app.py @@ -36,8 +36,9 @@ def deploy(): # Create DeploymentConfig object project_url_split = data.get("project_git_url").split('/') + project_name = f'{project_url_split[-2]}_{project_url_split[-1]}'.split('.git')[0] config = DeploymentConfig( - project_name=f'{project_url_split[-2]}_{project_url_split[-1]}', + project_name=project_name, branch_name=data.get("branch_name"), project_git_url=data.get("project_git_url"), compose_file_location=data.get("compose_file_location") or "docker-compose.yml", diff --git a/server/docker-compose.yml b/server/docker-compose.yml index 86c19dc..fd9bb64 100644 --- a/server/docker-compose.yml +++ b/server/docker-compose.yml @@ -33,6 +33,7 @@ services: ENV: ${ENV:-local} DOMAIN_NAME: ${DOMAIN_NAME:-localhost} VAULT_TOKEN: ${VAULT_TOKEN} + VAULT_BASE_URL: ${VAULT_BASE_URL:-http://vault:8200} depends_on: - nginx - vault diff --git a/server/requirements.txt b/server/requirements.txt index 6c4e1a2..7ceaae8 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -2,4 +2,5 @@ pyyaml flask pyjwt Flask-HTTPAuth -python-dotenv \ No newline at end of file +python-dotenv +requests \ No newline at end of file diff --git a/server/sarthi/deployer.py b/server/sarthi/deployer.py index 0c31543..8dc2e64 100644 --- a/server/sarthi/deployer.py +++ b/server/sarthi/deployer.py @@ -4,7 +4,7 @@ import subprocess import typing -from .utils import ComposeHelper, DeploymentConfig, NginxHelper +from .utils import ComposeHelper, DeploymentConfig, NginxHelper, SecretsHelper logger = logging.getLogger(__name__) @@ -13,8 +13,9 @@ class Deployer: def __init__(self, config: DeploymentConfig): self._config = config self._DEPLOYMENTS_MOUNT_DIR: typing.Final[str] = os.environ.get("DEPLOYMENTS_MOUNT_DIR") + self._deployment_namespace = f"{self._config.project_name}_{self._config.branch_name}_{config.get_project_hash()}" self._project_path: typing.Final[str] = os.path.join( - self._DEPLOYMENTS_MOUNT_DIR, config.get_project_hash() + self._DEPLOYMENTS_MOUNT_DIR, self._deployment_namespace ) self._setup_project() @@ -22,7 +23,7 @@ def __init__(self, config: DeploymentConfig): os.path.join(self._project_path, config.compose_file_location) ) self._nginx_helper = NginxHelper(config) - self._deployment_namespace = config.get_project_hash() + self._secrets_helper = SecretsHelper(self._config.project_name, self._config.branch_name) self._outer_proxy_conf_location = ( os.environ.get("NGINX_PROXY_CONF_LOCATION") or "/etc/nginx/conf.d" ) @@ -75,6 +76,7 @@ def _deploy_project(self): ) # TODO: Keep retrying finding a new port for race conditions self._project_nginx_port = self._nginx_helper.find_free_port() + self._secrets_helper.inject_env_variables(self._project_path) self._compose_helper.start_services( self._project_nginx_port, conf_file_path, self._deployment_namespace ) diff --git a/server/sarthi/utils.py b/server/sarthi/utils.py index ec030fb..6fd78ec 100644 --- a/server/sarthi/utils.py +++ b/server/sarthi/utils.py @@ -6,6 +6,7 @@ import subprocess import typing from dataclasses import dataclass, fields +import requests import yaml @@ -258,6 +259,25 @@ def reload_nginx(self): ) logger.info("Nginx reloaded successfully.") +class SecretsHelper: + def __init__(self, project_name, branch_name): + self._secrets_namespace = f"{project_name}/{branch_name}" + self._secret_url = f"{os.environ.get('VAULT_BASE_URL')}/v1/kv/data/{self._secrets_namespace}" + self._headers = { + "X-Vault-Token": os.environ.get('VAULT_TOKEN') + } + + def inject_env_variables(self, project_path): + response = requests.get(url=self._secret_url, headers=self._headers) + if response.status_code != 200: + logger.debug(f"No secrets found in vault for {self._secrets_namespace}") + return + logger.debug(f"Found secrets for {self._secrets_namespace}") + secret_data = response.json() + with open(os.path.join(project_path, ".env"), 'w') as file: + for key, value in secret_data['data']['data'].items(): + file.write(f"{key}={value}\n") + def get_random_stub(project_name: str) -> str: return hashlib.md5(project_name.encode()).hexdigest()[:16]