From 27682765e7e4a36ff9a691b23a75f4fb066ee299 Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Wed, 27 Dec 2023 21:48:11 +0100 Subject: [PATCH 01/11] =?UTF-8?q?=F0=9F=94=A7refactor:=20aws=20account=20a?= =?UTF-8?q?dd=20filter=20and=20extra=20vairables=20params?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/aws/api/container/create.py | 9 +- sld-api-backend/src/aws/api/container/get.py | 14 +- sld-api-backend/src/aws/api/v1/aws.py | 2 +- .../src/aws/domain/entities/aws.py | 43 +++-- .../src/aws/infrastructure/models.py | 5 +- .../src/aws/infrastructure/repositories.py | 150 +++++++++--------- .../src/azure/infrastructure/models.py | 3 +- .../src/deploy/api/container/deploy/get.py | 1 - .../src/deploy/infrastructure/repositories.py | 4 +- .../src/gcp/infrastructure/models.py | 3 +- .../worker/security/providers_credentials.py | 93 +++-------- 11 files changed, 144 insertions(+), 183 deletions(-) diff --git a/sld-api-backend/src/aws/api/container/create.py b/sld-api-backend/src/aws/api/container/create.py index d33358ec..5a2f2e00 100644 --- a/sld-api-backend/src/aws/api/container/create.py +++ b/sld-api-backend/src/aws/api/container/create.py @@ -22,13 +22,16 @@ async def create_new_aws_profile( status_code=409, detail="The squad or environment field must have a value that is not a string.", ) - db_aws_account = crud_aws.get_squad_aws_profile( - db=db, squad=aws.squad, environment=aws.environment + filters = schemas_aws.AwsAccountFilter() + filters.squad = aws.squad + filters.environment = aws.environment + db_aws_account = crud_aws.get_all_aws_profile( + db=db, filters=filters ) if db_aws_account: raise HTTPException(status_code=409, detail="Account already exists") try: - result = crud_aws.create_aws_profile(db=db, aws=aws) + crud_aws.create_aws_profile(db=db, aws=aws) crud_activity.create_activity_log( db=db, username=current_user.username, diff --git a/sld-api-backend/src/aws/api/container/get.py b/sld-api-backend/src/aws/api/container/get.py index 10bf4462..0986bf58 100644 --- a/sld-api-backend/src/aws/api/container/get.py +++ b/sld-api-backend/src/aws/api/container/get.py @@ -2,18 +2,20 @@ from sqlalchemy.orm import Session from src.aws.infrastructure import repositories as crud_aws +from src.aws.domain.entities import aws as schemas_aws from src.shared.security import deps from src.users.domain.entities import users as schemas_users from src.users.infrastructure import repositories as crud_users async def get_all_aws_accounts( - current_user: schemas_users.User = Depends(deps.get_current_active_user), + skip: int = 0, + limit: int = 100, db: Session = Depends(deps.get_db), + current_user: schemas_users.User = Depends(deps.get_current_active_user), + filters: schemas_aws.AwsAccountFilter = Depends(schemas_aws.AwsAccountFilter), + ): - # Check if the user has privileges if not crud_users.is_master(db, current_user): - return crud_aws.get_squad_aws_profile( - db=db, squad=current_user.squad, environment=None - ) - return crud_aws.get_all_aws_profile(db=db) + filters.squad = current_user.squad + return crud_aws.get_all_aws_profile(db=db, filters=filters, skip=skip, limit=limit) diff --git a/sld-api-backend/src/aws/api/v1/aws.py b/sld-api-backend/src/aws/api/v1/aws.py index 649c03f4..0c15f0f1 100644 --- a/sld-api-backend/src/aws/api/v1/aws.py +++ b/sld-api-backend/src/aws/api/v1/aws.py @@ -17,7 +17,7 @@ async def create_new_aws_profile( @router.get("/", status_code=200, response_model=list[schemas_aws.AwsAccountResponse]) async def get_all_aws_accounts( - get_aws_profile: schemas_aws.AwsAsumeProfile = Depends(get.get_all_aws_accounts), + get_aws_profile: schemas_aws.AwsAccountResponse = Depends(get.get_all_aws_accounts), ): return get_aws_profile diff --git a/sld-api-backend/src/aws/domain/entities/aws.py b/sld-api-backend/src/aws/domain/entities/aws.py index 6cbfe477..6b486ba0 100644 --- a/sld-api-backend/src/aws/domain/entities/aws.py +++ b/sld-api-backend/src/aws/domain/entities/aws.py @@ -1,23 +1,19 @@ -from typing import Optional +from typing import Optional, Dict, Any -from pydantic import BaseModel, Field, constr +from pydantic import BaseModel, constr class AwsBase(BaseModel): squad: constr(strip_whitespace=True) environment: constr(strip_whitespace=True) access_key_id: constr(strip_whitespace=True) - secret_access_key: Optional[constr(strip_whitespace=True)] = Field( - None, example="string" - ) + secret_access_key: constr(strip_whitespace=True) default_region: constr(strip_whitespace=True) + extra_variables: Optional[Dict[str, Any]] = None - default_region: constr(strip_whitespace=True) class AwsAsumeProfile(AwsBase): - profile_name: Optional[constr(strip_whitespace=True)] = None role_arn: Optional[constr(strip_whitespace=True)] = None - source_profile: Optional[constr(strip_whitespace=True)] = None class Aws(AwsBase): @@ -26,10 +22,31 @@ class Aws(AwsBase): class Config: from_attributes = True + class AwsAccountResponse(BaseModel): id: int - squad: constr(strip_whitespace=True) - environment: constr(strip_whitespace=True) - profile_name: Optional[constr(strip_whitespace=True)] = None - role_arn: Optional[constr(strip_whitespace=True)] = None - source_profile: Optional[constr(strip_whitespace=True)] = None \ No newline at end of file + squad: str + environment: str + default_region: Optional[str] + role_arn: Optional[str] + extra_variables: Optional[Dict[str, Any]] + + class Config: + from_attributes = True + + +class AwsAccountResponseRepo(AwsAccountResponse): + access_key_id: str + secret_access_key: str + + class Config: + from_attributes = True + + +class AwsAccountFilter(BaseModel): + id: Optional[int] = None + squad: Optional[str] = None + access_key_id: Optional[str] = None + environment: Optional[str] = None + default_region: Optional[str] = None + role_arn: Optional[str] = None diff --git a/sld-api-backend/src/aws/infrastructure/models.py b/sld-api-backend/src/aws/infrastructure/models.py index a84abb38..6c34e3d5 100644 --- a/sld-api-backend/src/aws/infrastructure/models.py +++ b/sld-api-backend/src/aws/infrastructure/models.py @@ -1,7 +1,7 @@ import datetime from config.database import Base -from sqlalchemy import Column, DateTime, Integer, String, UniqueConstraint +from sqlalchemy import Column, DateTime, Integer, String, UniqueConstraint, JSON class Aws_provider(Base): @@ -12,8 +12,9 @@ class Aws_provider(Base): access_key_id = Column(String(200), nullable=False) secret_access_key = Column(String(200), nullable=False) default_region = Column(String(200)) - profile_name = Column(String(200), nullable=False) + profile_name = Column(String(200), nullable=True) role_arn = Column(String(200), nullable=True) source_profile = Column(String(200), nullable=True) + extra_variables = Column(JSON, nullable=True) created_at = Column(DateTime, default=datetime.datetime.now()) __table_args__ = (UniqueConstraint("squad", "environment"),) diff --git a/sld-api-backend/src/aws/infrastructure/repositories.py b/sld-api-backend/src/aws/infrastructure/repositories.py index 22497605..ea83e6e7 100644 --- a/sld-api-backend/src/aws/infrastructure/repositories.py +++ b/sld-api-backend/src/aws/infrastructure/repositories.py @@ -1,10 +1,13 @@ import datetime +from typing import List from sqlalchemy.orm import Session +from sqlalchemy import desc, or_ + import src.aws.infrastructure.models as models from src.aws.domain.entities import aws as schemas_aws -from src.shared.security.vault import vault_decrypt, vault_encrypt +from src.shared.security.vault import vault_encrypt @vault_encrypt @@ -15,35 +18,21 @@ def encrypt(secreto): raise err -@vault_decrypt -def decrypt(secreto): - try: - return secreto - except Exception as err: - raise err - - def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile): encrypt_access_key_id = encrypt(aws.access_key_id) encrypt_secret_access_key = encrypt(aws.secret_access_key) + encrypted_extra_variables = {key: encrypt(val) for key, val in aws.extra_variables.items()} if aws.extra_variables else None + db_aws = models.Aws_provider( access_key_id=encrypt_access_key_id, secret_access_key=encrypt_secret_access_key, environment=aws.environment, default_region=aws.default_region, - profile_name=aws.profile_name, role_arn=aws.role_arn, - source_profile=aws.source_profile, + extra_variables=encrypted_extra_variables, created_at=datetime.datetime.now(), squad=aws.squad, ) - check_None = [None, "string"] - if db_aws.role_arn in check_None: - db_aws.role_arn = "" - if db_aws.profile_name in check_None: - db_aws.profile_name = "" - if db_aws.source_profile in check_None: - db_aws.source_profile = "" try: db.add(db_aws) db.commit() @@ -53,84 +42,89 @@ def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile): raise err -def get_credentials_aws_profile(db: Session, environment: str, squad: str): - get_access_key = ( - db.query(models.Aws_provider.access_key_id) - .filter(models.Aws_provider.environment == environment) - .filter(models.Aws_provider.squad == squad) - .first() - ) - get_secret_access_key = ( - db.query(models.Aws_provider.secret_access_key) - .filter(models.Aws_provider.environment == environment) - .filter(models.Aws_provider.squad == squad) - .first() - ) - default_region = ( - db.query(models.Aws_provider.default_region) - .filter(models.Aws_provider.environment == environment) - .filter(models.Aws_provider.squad == squad) - .first() - ) - profile_name = ( - db.query(models.Aws_provider.profile_name) +def get_credentials_aws_profile(db: Session, environment: str, squad: str) -> schemas_aws.AwsAccountResponseRepo: + aws_provider_data = ( + db.query(models.Aws_provider) .filter(models.Aws_provider.environment == environment) .filter(models.Aws_provider.squad == squad) .first() ) - role_arn = ( - db.query(models.Aws_provider.role_arn) - .filter(models.Aws_provider.environment == environment) - .filter(models.Aws_provider.squad == squad) - .first() - ) - source_profile = ( - db.query(models.Aws_provider.source_profile) - .filter(models.Aws_provider.environment == environment) - .filter(models.Aws_provider.squad == squad) - .first() + return schemas_aws.AwsAccountResponseRepo( + id=aws_provider_data.id, + squad=aws_provider_data.squad, + environment=aws_provider_data.environment, + access_key_id=aws_provider_data.access_key_id, + secret_access_key=aws_provider_data.secret_access_key, + role_arn=aws_provider_data.role_arn, + default_region=aws_provider_data.default_region, + extra_variables=aws_provider_data.extra_variables, ) - try: - return { - "access_key": decrypt(get_access_key[0]), - "secret_access_key": decrypt(get_secret_access_key[0]), - "default_region": default_region[0], - "profile_name": profile_name[0], - "role_arn": role_arn[0], - "source_profile": source_profile[0], - } - except Exception as err: - raise err -def get_squad_aws_profile(db: Session, squad: str, environment: str): +def get_squad_aws_profile( + db: Session, squad: str, filters: schemas_aws.AwsAccountFilter, skip: int = 0, limit: int = 100 +) -> List[schemas_aws.AwsAccountResponse]: try: - if environment != None: - return ( - db.query(models.Aws_provider) - .filter(models.Aws_provider.squad == squad) - .filter(models.Aws_provider.environment == environment) - .first() - ) - result = [] - for i in squad: - result.extend( - db.query(models.Aws_provider) - .filter(models.Aws_provider.squad == i) - .all() + query = ( + db.query(models.Aws_provider) + .filter(models.Aws_provider.squad == squad) + ) + + for field, value in filters.model_dump().items(): + if value is not None: + query = query.filter(getattr(models.Aws_provider, field) == value) + + results = query.order_by(desc(models.Aws_provider.id)).offset(skip).limit(limit).all() + + aws_profiles = [] + for result in results: + aws_profile = schemas_aws.AwsAccountResponse( + id=result.id, + squad=result.squad, + environment=result.environment, + default_region=result.default_region, + role_arn=result.role_arn, + extra_variables=result.extra_variables, ) - return set(result) + aws_profiles.append(aws_profile) + return aws_profiles except Exception as err: raise err -def get_all_aws_profile(db: Session): +def get_all_aws_profile( + db: Session, filters: schemas_aws.AwsAccountFilter, skip: int = 0, limit: int = 100 +) -> List[schemas_aws.AwsAccountResponse]: try: - return db.query(models.Aws_provider).all() + query = db.query(models.Aws_provider) + + for field, value in filters.model_dump().items(): + if value is not None: + if field == 'squad' and isinstance(value, list): + or_conditions = [getattr(models.Aws_provider, field).like(f"%{v}%") for v in value] + query = query.filter(or_(*or_conditions)) + else: + query = query.filter(getattr(models.Aws_provider, field) == value) + + results = query.order_by(desc(models.Aws_provider.id)).offset(skip).limit(limit).all() + + aws_profiles = [] + for result in results: + aws_profile = schemas_aws.AwsAccountResponse( + id=result.id, + squad=result.squad, + environment=result.environment, + default_region=result.default_region, + role_arn=result.role_arn, + extra_variables=result.extra_variables, + ) + aws_profiles.append(aws_profile) + return aws_profiles except Exception as err: raise err + def delete_aws_profile_by_id(db: Session, aws_profile_id: int): try: db.query(models.Aws_provider).filter( diff --git a/sld-api-backend/src/azure/infrastructure/models.py b/sld-api-backend/src/azure/infrastructure/models.py index 4dfde48a..87ed2e50 100644 --- a/sld-api-backend/src/azure/infrastructure/models.py +++ b/sld-api-backend/src/azure/infrastructure/models.py @@ -1,7 +1,7 @@ import datetime from config.database import Base -from sqlalchemy import Column, DateTime, Integer, String, UniqueConstraint +from sqlalchemy import Column, DateTime, Integer, String, UniqueConstraint, JSON class Azure_provider(Base): @@ -13,5 +13,6 @@ class Azure_provider(Base): client_secret = Column(String(200), nullable=False) subscription_id = Column(String(200), nullable=False) tenant_id = Column(String(200), nullable=False) + extra_variables = Column(JSON, nullable=True) created_at = Column(DateTime, default=datetime.datetime.now()) __table_args__ = (UniqueConstraint("squad", "environment"),) diff --git a/sld-api-backend/src/deploy/api/container/deploy/get.py b/sld-api-backend/src/deploy/api/container/deploy/get.py index c6393921..ced0f3b0 100644 --- a/sld-api-backend/src/deploy/api/container/deploy/get.py +++ b/sld-api-backend/src/deploy/api/container/deploy/get.py @@ -22,7 +22,6 @@ async def get_all_deploys( filters: DeployFilter = Depends(DeployFilter), ) -> List[DeployFilterResponse]: try: - # Si el usuario no es un maestro, aplicar el filtro de escuadrón if not crud_users.is_master(db, current_user): filters.squad = current_user.squad diff --git a/sld-api-backend/src/deploy/infrastructure/repositories.py b/sld-api-backend/src/deploy/infrastructure/repositories.py index ee991fd9..7f803f70 100644 --- a/sld-api-backend/src/deploy/infrastructure/repositories.py +++ b/sld-api-backend/src/deploy/infrastructure/repositories.py @@ -210,17 +210,15 @@ def get_deploys(db: Session, filters: DeployFilter, skip: int = 0, limit: int = results = query.order_by(desc(models.Deploy.id)).offset(skip).limit(limit).all() - # Crear una lista de DeployFilterResponse a partir de los resultados deploy_responses = [] for deploy, icon_path in results: deploy_dict = deploy.__dict__ - deploy_dict['icon_path'] = icon_path # Agregar el icon_path al diccionario + deploy_dict['icon_path'] = icon_path deploy_responses.append(DeployFilterResponse(**deploy_dict)) return deploy_responses - class MetricsFetcher: def __init__(self, db: Session): self.db = db diff --git a/sld-api-backend/src/gcp/infrastructure/models.py b/sld-api-backend/src/gcp/infrastructure/models.py index 2dbbaca0..138c9939 100644 --- a/sld-api-backend/src/gcp/infrastructure/models.py +++ b/sld-api-backend/src/gcp/infrastructure/models.py @@ -1,7 +1,7 @@ import datetime from config.database import Base -from sqlalchemy import Column, DateTime, Integer, String, UniqueConstraint +from sqlalchemy import Column, DateTime, Integer, String, UniqueConstraint, JSON class Gcloud_provider(Base): @@ -10,5 +10,6 @@ class Gcloud_provider(Base): environment = Column(String(200), nullable=False) squad = Column(String(200), nullable=False) gcloud_keyfile_json = Column(String(5000), nullable=False) + extra_variables = Column(JSON, nullable=True) created_at = Column(DateTime, default=datetime.datetime.now()) __table_args__ = (UniqueConstraint("squad", "environment"),) diff --git a/sld-api-backend/src/worker/security/providers_credentials.py b/sld-api-backend/src/worker/security/providers_credentials.py index a9ee9bff..f3536eeb 100644 --- a/sld-api-backend/src/worker/security/providers_credentials.py +++ b/sld-api-backend/src/worker/security/providers_credentials.py @@ -5,8 +5,17 @@ import os from config.api import settings +from src.shared.security.vault import vault_decrypt +@vault_decrypt +def decrypt(secreto): + try: + return secreto + except Exception as err: + raise err + + class SecretsProviders: def __init__(self, secret_provider: dict) -> None: self.secret_provider = secret_provider @@ -25,74 +34,6 @@ def createLocalFolder(dir_path: str): raise -def aws_config(secreto): - try: - config = configparser.ConfigParser(strict=False) - # Check if pass me profile - if secreto.get("profile_name"): - # Create folder in home user - createLocalFolder(settings.AWS_CONGIG_DEFAULT_FOLDER) - # Read config - config.read(settings.AWS_SHARED_CONFIG_FILE) - profile_name = secreto.get("profile_name") - if not config.has_section(f"profile {profile_name}"): - config.add_section(f"profile {profile_name}") - config.set(f"profile {profile_name}", "role_arn", secreto.get("role_arn")) - config.set( - f"profile {profile_name}", - "region", - secreto.get("default_region"), - ) - config.set( - f"profile {profile_name}", - "source_profile", - secreto.get("source_profile"), - ) - with open(settings.AWS_SHARED_CONFIG_FILE, "w") as configfile: - config.write(configfile) - logging.info( - "created config done" - ) - del secreto - del profile_name - del configfile - del config - return True - except Exception as err: - return False - logging.warning(err) - - -def aws_credentials(secreto): - try: - config = configparser.ConfigParser(strict=False) - if secreto.get("source_profile"): - config.read(settings.AWS_SHARED_CREDENTIALS_FILE) - source_profile = secreto.get("source_profile") - if not config.has_section(source_profile): - config.add_section(source_profile) - config.set(source_profile, "region", secreto.get("default_region")) - config.set(source_profile, "aws_access_key_id", secreto.get("access_key")) - config.set( - source_profile, - "aws_secret_access_key", - secreto.get("secret_access_key"), - ) - with open(settings.AWS_SHARED_CREDENTIALS_FILE, "w") as credentialsfile: - config.write(credentialsfile) - logging.info( - "created credentials done" - ) - del secreto - del source_profile - del credentialsfile - del config - return True - except Exception as err: - return False - logging.warning(err) - - def secret( stack_name, environment, @@ -102,12 +43,16 @@ def secret( ): if any(i in stack_name.lower() for i in settings.AWS_PREFIX): try: - if not aws_config(secreto) or not aws_credentials(secreto): - os.environ["AWS_ACCESS_KEY_ID"] = secreto.get("access_key") - os.environ["AWS_SECRET_ACCESS_KEY"] = secreto.get("secret_access_key") - logging.info( - f"Set aws account without asume role {squad}, {environment}, {stack_name}, {name}" - ) + os.environ["AWS_ACCESS_KEY_ID"] = decrypt(secreto.get("access_key_id")) + os.environ["AWS_SECRET_ACCESS_KEY"] = decrypt(secreto.get("secret_access_key")) + os.environ["AWS_DEFAULT_REGION"] = secreto.get("default_region") + if secreto.get("role_arn"): + logging.info("Set role_arn for assume role") + os.environ["TF_VAR_role_arn"] = secreto.get("role_arn") + logging.info(f"TF_VAR_role_arn = {secreto.get('role_arn')}") + logging.info( + f'Set aws account {squad}, {environment}, {stack_name}, {secreto.get("default_region")}, {name}' + ) except Exception as err: logging.warning(err) From cf35ff5d6af91be2ce9e8bae8e0635b4dd78d335 Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Thu, 28 Dec 2023 01:34:24 +0100 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=94=A7refactor:=20aws=20add=20updat?= =?UTF-8?q?e=20account?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/aws/api/container/create.py | 3 +- sld-api-backend/src/aws/api/container/get.py | 2 +- .../src/aws/api/container/update.py | 38 +++++++++ sld-api-backend/src/aws/api/v1/aws.py | 13 ++- .../src/aws/domain/entities/aws.py | 15 +++- .../src/aws/infrastructure/repositories.py | 80 +++++++++++-------- .../src/deploy/api/container/deploy/create.py | 2 +- .../src/worker/domain/entities/actions.py | 2 +- .../worker/security/providers_credentials.py | 12 ++- 9 files changed, 118 insertions(+), 49 deletions(-) create mode 100644 sld-api-backend/src/aws/api/container/update.py diff --git a/sld-api-backend/src/aws/api/container/create.py b/sld-api-backend/src/aws/api/container/create.py index 5a2f2e00..7efbefc8 100644 --- a/sld-api-backend/src/aws/api/container/create.py +++ b/sld-api-backend/src/aws/api/container/create.py @@ -31,13 +31,12 @@ async def create_new_aws_profile( if db_aws_account: raise HTTPException(status_code=409, detail="Account already exists") try: - crud_aws.create_aws_profile(db=db, aws=aws) crud_activity.create_activity_log( db=db, username=current_user.username, squad=current_user.squad, action=f"Create AWS account {aws.squad} {aws.environment}", ) - return {"result": f"Create AWS account {aws.squad} {aws.environment}"} + return crud_aws.create_aws_profile(db=db, aws=aws) except Exception as err: raise HTTPException(status_code=400, detail=str(err)) diff --git a/sld-api-backend/src/aws/api/container/get.py b/sld-api-backend/src/aws/api/container/get.py index 0986bf58..0235faa9 100644 --- a/sld-api-backend/src/aws/api/container/get.py +++ b/sld-api-backend/src/aws/api/container/get.py @@ -15,7 +15,7 @@ async def get_all_aws_accounts( current_user: schemas_users.User = Depends(deps.get_current_active_user), filters: schemas_aws.AwsAccountFilter = Depends(schemas_aws.AwsAccountFilter), -): +) -> list[schemas_aws.AwsAccountResponse]: if not crud_users.is_master(db, current_user): filters.squad = current_user.squad return crud_aws.get_all_aws_profile(db=db, filters=filters, skip=skip, limit=limit) diff --git a/sld-api-backend/src/aws/api/container/update.py b/sld-api-backend/src/aws/api/container/update.py new file mode 100644 index 00000000..8e17cdcc --- /dev/null +++ b/sld-api-backend/src/aws/api/container/update.py @@ -0,0 +1,38 @@ +from fastapi import Depends, HTTPException +from sqlalchemy.orm import Session + +from src.activityLogs.infrastructure import repositories as crud_activity +from src.aws.domain.entities import aws as schemas_aws +from src.aws.infrastructure import repositories as crud_aws +from src.shared.security import deps +from src.users.domain.entities import users as schemas_users +from src.users.infrastructure import repositories as crud_users + + +async def update_aws_account( + deploy_id: int, + aws: schemas_aws.AwsAsumeProfile, + current_user: schemas_users.User = Depends(deps.get_current_active_user), + db: Session = Depends(deps.get_db), +): + # Check if the user has privileges + if not crud_users.is_master(db, current_user): + raise HTTPException(status_code=403, detail="Not enough permissions") + if "string" in [aws.squad, aws.environment]: + raise HTTPException( + status_code=409, + detail="The squad or environment field must have a value that is not a string.", + ) + + try: + filters = schemas_aws.AwsAccountFilter() + filters.id = deploy_id + db_aws_account = crud_aws.get_all_aws_profile(db=db, filters=filters) + + if db_aws_account: + # If the AWS profile already exists, perform an update + aws_id_to_update = db_aws_account[0].id # Assuming you want to update the first matching profile + return await crud_aws.update_aws_profile(db=db, aws_id=aws_id_to_update, updated_aws=aws) + + except Exception as err: + raise HTTPException(status_code=400, detail=str(err)) diff --git a/sld-api-backend/src/aws/api/v1/aws.py b/sld-api-backend/src/aws/api/v1/aws.py index 0c15f0f1..373ff096 100644 --- a/sld-api-backend/src/aws/api/v1/aws.py +++ b/sld-api-backend/src/aws/api/v1/aws.py @@ -1,13 +1,13 @@ from fastapi import APIRouter, Depends -from src.aws.api.container import create, delete, get +from src.aws.api.container import create, delete, get, update from src.aws.domain.entities import aws as schemas_aws router = APIRouter() @router.post("/", status_code=200) -async def create_new_aws_profile( +async def create_new_aws_account( create_aws_profile: schemas_aws.AwsAsumeProfile = Depends( create.create_new_aws_profile ), @@ -15,6 +15,15 @@ async def create_new_aws_profile( return create_aws_profile +@router.patch("/{aws_account_id}", status_code=200) +async def update_aws_account( + update_account: schemas_aws.AwsAsumeProfile = Depends( + update.update_aws_account + ), +): + return update_account + + @router.get("/", status_code=200, response_model=list[schemas_aws.AwsAccountResponse]) async def get_all_aws_accounts( get_aws_profile: schemas_aws.AwsAccountResponse = Depends(get.get_all_aws_accounts), diff --git a/sld-api-backend/src/aws/domain/entities/aws.py b/sld-api-backend/src/aws/domain/entities/aws.py index 6b486ba0..14c52432 100644 --- a/sld-api-backend/src/aws/domain/entities/aws.py +++ b/sld-api-backend/src/aws/domain/entities/aws.py @@ -1,6 +1,6 @@ from typing import Optional, Dict, Any -from pydantic import BaseModel, constr +from pydantic import BaseModel, constr, SecretStr class AwsBase(BaseModel): @@ -23,21 +23,28 @@ class Config: from_attributes = True -class AwsAccountResponse(BaseModel): +class AwsAccountResponseBase(BaseModel): id: int squad: str environment: str default_region: Optional[str] role_arn: Optional[str] - extra_variables: Optional[Dict[str, Any]] class Config: from_attributes = True -class AwsAccountResponseRepo(AwsAccountResponse): +class AwsAccountResponse(AwsAccountResponseBase): + extra_variables: Optional[Dict[str, SecretStr]] + + class Config: + from_attributes = True + + +class AwsAccountResponseRepo(AwsAccountResponseBase): access_key_id: str secret_access_key: str + extra_variables: Optional[Dict[str, Any]] = None class Config: from_attributes = True diff --git a/sld-api-backend/src/aws/infrastructure/repositories.py b/sld-api-backend/src/aws/infrastructure/repositories.py index ea83e6e7..e204c827 100644 --- a/sld-api-backend/src/aws/infrastructure/repositories.py +++ b/sld-api-backend/src/aws/infrastructure/repositories.py @@ -18,7 +18,7 @@ def encrypt(secreto): raise err -def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile): +def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> schemas_aws.AwsAccountResponse: encrypt_access_key_id = encrypt(aws.access_key_id) encrypt_secret_access_key = encrypt(aws.secret_access_key) encrypted_extra_variables = {key: encrypt(val) for key, val in aws.extra_variables.items()} if aws.extra_variables else None @@ -37,11 +37,55 @@ def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile): db.add(db_aws) db.commit() db.refresh(db_aws) - return db_aws + return schemas_aws.AwsAccountResponse( + id=db_aws.id, + squad=db_aws.squad, + environment=db_aws.environment, + default_region=db_aws.default_region, + role_arn=db_aws.role_arn, + extra_variables=db_aws.extra_variables, + ) except Exception as err: raise err +async def update_aws_profile(db: Session, aws_id: int, updated_aws: schemas_aws.AwsAsumeProfile) -> schemas_aws.AwsAccountResponse: + db_aws = db.query(models.Aws_provider).filter(models.Aws_provider.id == aws_id).first() + + if db_aws: + # Update only the fields that are present in the updated_aws object + if updated_aws.access_key_id: + db_aws.access_key_id = encrypt(updated_aws.access_key_id) + if updated_aws.secret_access_key: + db_aws.secret_access_key = encrypt(updated_aws.secret_access_key) + if updated_aws.extra_variables: + db_aws.extra_variables = {key: encrypt(val) for key, val in updated_aws.extra_variables.items()} + + # Update the remaining fields + db_aws.environment = updated_aws.environment + db_aws.default_region = updated_aws.default_region + db_aws.role_arn = updated_aws.role_arn + db_aws.squad = updated_aws.squad + + try: + db.commit() + db.refresh(db_aws) + return schemas_aws.AwsAccountResponse( + id=db_aws.id, + squad=db_aws.squad, + environment=db_aws.environment, + default_region=db_aws.default_region, + role_arn=db_aws.role_arn, + extra_variables=db_aws.extra_variables, + ) + except Exception as err: + raise err + else: + # Handle the case where the specified AWS profile ID doesn't exist + raise ValueError(f"AWS profile with id {aws_id} not found") + + + def get_credentials_aws_profile(db: Session, environment: str, squad: str) -> schemas_aws.AwsAccountResponseRepo: aws_provider_data = ( db.query(models.Aws_provider) @@ -61,37 +105,6 @@ def get_credentials_aws_profile(db: Session, environment: str, squad: str) -> sc ) -def get_squad_aws_profile( - db: Session, squad: str, filters: schemas_aws.AwsAccountFilter, skip: int = 0, limit: int = 100 -) -> List[schemas_aws.AwsAccountResponse]: - try: - query = ( - db.query(models.Aws_provider) - .filter(models.Aws_provider.squad == squad) - ) - - for field, value in filters.model_dump().items(): - if value is not None: - query = query.filter(getattr(models.Aws_provider, field) == value) - - results = query.order_by(desc(models.Aws_provider.id)).offset(skip).limit(limit).all() - - aws_profiles = [] - for result in results: - aws_profile = schemas_aws.AwsAccountResponse( - id=result.id, - squad=result.squad, - environment=result.environment, - default_region=result.default_region, - role_arn=result.role_arn, - extra_variables=result.extra_variables, - ) - aws_profiles.append(aws_profile) - return aws_profiles - except Exception as err: - raise err - - def get_all_aws_profile( db: Session, filters: schemas_aws.AwsAccountFilter, skip: int = 0, limit: int = 100 ) -> List[schemas_aws.AwsAccountResponse]: @@ -124,7 +137,6 @@ def get_all_aws_profile( raise err - def delete_aws_profile_by_id(db: Session, aws_profile_id: int): try: db.query(models.Aws_provider).filter( diff --git a/sld-api-backend/src/deploy/api/container/deploy/create.py b/sld-api-backend/src/deploy/api/container/deploy/create.py index dc69a1f2..123916a8 100644 --- a/sld-api-backend/src/deploy/api/container/deploy/create.py +++ b/sld-api-backend/src/deploy/api/container/deploy/create.py @@ -20,7 +20,7 @@ from src.tasks.infrastructure import repositories as crud_tasks from src.users.domain.entities import users as schemas_users from src.users.infrastructure import repositories as crud_users -from src.worker.domain.entities.worker import DeployParams, DownloadGitRepoParams +from src.worker.domain.entities.worker import DeployParams async def deploy_infra_by_stack_name( diff --git a/sld-api-backend/src/worker/domain/entities/actions.py b/sld-api-backend/src/worker/domain/entities/actions.py index 1752c70b..053b4b27 100644 --- a/sld-api-backend/src/worker/domain/entities/actions.py +++ b/sld-api-backend/src/worker/domain/entities/actions.py @@ -13,4 +13,4 @@ class StructActionsBase(BaseModel): secreto: Dict variables_file: Optional[str] project_path: Optional[str] - task_id: str \ No newline at end of file + task_id: str diff --git a/sld-api-backend/src/worker/security/providers_credentials.py b/sld-api-backend/src/worker/security/providers_credentials.py index f3536eeb..6147001f 100644 --- a/sld-api-backend/src/worker/security/providers_credentials.py +++ b/sld-api-backend/src/worker/security/providers_credentials.py @@ -14,7 +14,13 @@ def decrypt(secreto): return secreto except Exception as err: raise err - + + +def export_environment_variables(dictionary): + if 'extra_variables' in dictionary and isinstance(dictionary['extra_variables'], dict): + for key, value in dictionary['extra_variables'].items(): + os.environ[key] = decrypt(value) + class SecretsProviders: def __init__(self, secret_provider: dict) -> None: @@ -43,6 +49,7 @@ def secret( ): if any(i in stack_name.lower() for i in settings.AWS_PREFIX): try: + export_environment_variables(secreto) os.environ["AWS_ACCESS_KEY_ID"] = decrypt(secreto.get("access_key_id")) os.environ["AWS_SECRET_ACCESS_KEY"] = decrypt(secreto.get("secret_access_key")) os.environ["AWS_DEFAULT_REGION"] = secreto.get("default_region") @@ -76,9 +83,6 @@ def secret( R.export() -# os.environ["GOOGLE_CLOUD_KEYFILE_JSON"] = gcloud_keyfile - - def unsecret(stack_name, environment, squad, name, secreto): if any(i in stack_name.lower() for i in settings.AWS_PREFIX): try: From 2c605b175a64d5af70acbc9cbbe5ce0421095bc6 Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Thu, 28 Dec 2023 01:55:00 +0100 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=90=9Bfix:=20disbale=20pagination?= =?UTF-8?q?=20cloud=20accounts=20and=20add=20edit=20schedule=20when=20dest?= =?UTF-8?q?roy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sld-dashboard/app/base/static/assets/js/pagination.js | 4 ---- sld-dashboard/app/home/routes.py | 4 +--- sld-dashboard/app/home/templates/aws-list.html | 8 ++++---- sld-dashboard/app/home/templates/azure-list.html | 6 +++--- .../app/home/templates/custom-provider-list.html | 6 +++--- sld-dashboard/app/home/templates/deploys-list.html | 6 +++++- sld-dashboard/app/home/templates/gcp-list.html | 6 +++--- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/sld-dashboard/app/base/static/assets/js/pagination.js b/sld-dashboard/app/base/static/assets/js/pagination.js index e81c2bc7..edf1049e 100644 --- a/sld-dashboard/app/base/static/assets/js/pagination.js +++ b/sld-dashboard/app/base/static/assets/js/pagination.js @@ -29,10 +29,6 @@ $(document).ready(function(){ displayPage(1); } - // Event Delegation for edit buttons and other interactive elements - $(document).on('click', '.edit-button', function() { - // Aquí iría el código para manejar la edición - }); // Existing search functionality $("#myInput").on("keyup", function() { diff --git a/sld-dashboard/app/home/routes.py b/sld-dashboard/app/home/routes.py index 7ed0e5ab..a750e7d9 100644 --- a/sld-dashboard/app/home/routes.py +++ b/sld-dashboard/app/home/routes.py @@ -1325,8 +1325,6 @@ def list_activity(limit): # Users - - @blueprint.route("/users-new", methods=["GET", "POST"]) @login_required def new_user(): @@ -1580,7 +1578,7 @@ def delete_aws_account(aws_account_id): if response.get("status_code") == 200: flash( - f"Account Deleted" + "Account Deleted" ) elif response.get("status_code") == 409: flash(response["json"].get("detail"), "error") diff --git a/sld-dashboard/app/home/templates/aws-list.html b/sld-dashboard/app/home/templates/aws-list.html index ec68ea70..e0bb93fa 100644 --- a/sld-dashboard/app/home/templates/aws-list.html +++ b/sld-dashboard/app/home/templates/aws-list.html @@ -134,14 +134,14 @@

All aws accounts

- +
  • Next
  • - + +--> {% include 'includes/footer.html' %} @@ -150,6 +150,6 @@

    All aws accounts

    {% block javascripts %} - + {% endblock javascripts %} diff --git a/sld-dashboard/app/home/templates/azure-list.html b/sld-dashboard/app/home/templates/azure-list.html index da16a91a..bb959cb5 100644 --- a/sld-dashboard/app/home/templates/azure-list.html +++ b/sld-dashboard/app/home/templates/azure-list.html @@ -130,14 +130,14 @@

    All azure accounts

    - +
  • Next
  • +--> {% include 'includes/footer.html' %} @@ -146,5 +146,5 @@

    All azure accounts

    {% block javascripts %} - + {% endblock javascripts %} \ No newline at end of file diff --git a/sld-dashboard/app/home/templates/custom-provider-list.html b/sld-dashboard/app/home/templates/custom-provider-list.html index d5885c35..a8511dd9 100644 --- a/sld-dashboard/app/home/templates/custom-provider-list.html +++ b/sld-dashboard/app/home/templates/custom-provider-list.html @@ -126,14 +126,14 @@

    All custom providers accounts

    - +
  • Next
  • +--> {% include 'includes/footer.html' %} @@ -143,5 +143,5 @@

    All custom providers accounts

    {% block javascripts %} - + {% endblock javascripts %} \ No newline at end of file diff --git a/sld-dashboard/app/home/templates/deploys-list.html b/sld-dashboard/app/home/templates/deploys-list.html index 5ba77b90..eb5a0e41 100644 --- a/sld-dashboard/app/home/templates/deploys-list.html +++ b/sld-dashboard/app/home/templates/deploys-list.html @@ -216,7 +216,7 @@

    All Deploys

    - Start: + Apply: {{ deploy.start_time }}
    @@ -260,6 +260,10 @@

    All Deploys

    Clone + + + Schedule + Destroy diff --git a/sld-dashboard/app/home/templates/gcp-list.html b/sld-dashboard/app/home/templates/gcp-list.html index bda398a7..11a5345c 100644 --- a/sld-dashboard/app/home/templates/gcp-list.html +++ b/sld-dashboard/app/home/templates/gcp-list.html @@ -126,14 +126,14 @@

    All gcp accounts

    - +
  • Next
  • +--> {% include 'includes/footer.html' %} @@ -142,5 +142,5 @@

    All gcp accounts

    {% block javascripts %} - + {% endblock javascripts %} \ No newline at end of file From d9e60bec077e28fddc357b637573adb67401e349 Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Thu, 28 Dec 2023 01:56:20 +0100 Subject: [PATCH 04/11] =?UTF-8?q?=E2=AC=86=20Bump:=20apply=20hotfix=20clou?= =?UTF-8?q?d=20account=20v3.4.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- play-with-sld/kubernetes/k8s/sld-dashboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/play-with-sld/kubernetes/k8s/sld-dashboard.yml b/play-with-sld/kubernetes/k8s/sld-dashboard.yml index c0820bb6..b8064192 100644 --- a/play-with-sld/kubernetes/k8s/sld-dashboard.yml +++ b/play-with-sld/kubernetes/k8s/sld-dashboard.yml @@ -17,7 +17,7 @@ spec: subdomain: primary containers: - name: sld-dashboard - image: d10s0vsky/sld-dashboard:v3.4.0 + image: d10s0vsky/sld-dashboard:v3.4.1 env: - name: PATH value: "/home/sld/.asdf/shims:/home/sld/.asdf/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" From ac4dacdeeb74793b32af15502aa7f713da6d3d70 Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Fri, 29 Dec 2023 00:44:45 +0100 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=94=A7refactor:=20aws=20backend?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/aws/api/container/create.py | 5 +- .../src/aws/api/container/delete.py | 10 ++- sld-api-backend/src/aws/api/container/get.py | 2 +- .../src/aws/api/container/update.py | 34 ++++---- .../src/aws/domain/entities/aws.py | 8 ++ .../src/aws/infrastructure/models.py | 1 + .../src/aws/infrastructure/repositories.py | 81 +++++++------------ .../src/azure/infrastructure/models.py | 1 + .../custom_providers/infrastructure/models.py | 1 + .../src/deploy/api/container/deploy/create.py | 2 +- .../src/deploy/api/container/deploy/delete.py | 2 +- .../deploy/api/container/deploy/destroy.py | 2 +- .../src/deploy/api/container/deploy/update.py | 2 +- .../src/deploy/api/container/plan/create.py | 2 +- .../src/deploy/api/container/plan/get.py | 2 +- .../src/gcp/infrastructure/models.py | 1 + .../src/shared/helpers/get_data.py | 4 +- 17 files changed, 73 insertions(+), 87 deletions(-) diff --git a/sld-api-backend/src/aws/api/container/create.py b/sld-api-backend/src/aws/api/container/create.py index 7efbefc8..c753e34a 100644 --- a/sld-api-backend/src/aws/api/container/create.py +++ b/sld-api-backend/src/aws/api/container/create.py @@ -14,7 +14,6 @@ async def create_new_aws_profile( current_user: schemas_users.User = Depends(deps.get_current_active_user), db: Session = Depends(deps.get_db), ): - # Check if the user has privileges if not crud_users.is_master(db, current_user): raise HTTPException(status_code=403, detail="Not enough permissions") if "string" in [aws.squad, aws.environment]: @@ -25,7 +24,7 @@ async def create_new_aws_profile( filters = schemas_aws.AwsAccountFilter() filters.squad = aws.squad filters.environment = aws.environment - db_aws_account = crud_aws.get_all_aws_profile( + db_aws_account = await crud_aws.get_all_aws_profile( db=db, filters=filters ) if db_aws_account: @@ -37,6 +36,6 @@ async def create_new_aws_profile( squad=current_user.squad, action=f"Create AWS account {aws.squad} {aws.environment}", ) - return crud_aws.create_aws_profile(db=db, aws=aws) + return await crud_aws.create_aws_profile(db=db, aws=aws) except Exception as err: raise HTTPException(status_code=400, detail=str(err)) diff --git a/sld-api-backend/src/aws/api/container/delete.py b/sld-api-backend/src/aws/api/container/delete.py index 7fb5f7cc..022f1d2b 100644 --- a/sld-api-backend/src/aws/api/container/delete.py +++ b/sld-api-backend/src/aws/api/container/delete.py @@ -3,6 +3,7 @@ from src.activityLogs.infrastructure import repositories as crud_activity from src.aws.infrastructure import repositories as crud_aws +from src.aws.domain.entities import aws as schemas_aws from src.shared.security import deps from src.users.domain.entities import users as schemas_users from src.users.infrastructure import repositories as crud_users @@ -12,12 +13,17 @@ async def aws_account_by_id( aws_account_id: int, current_user: schemas_users.User = Depends(deps.get_current_active_user), db: Session = Depends(deps.get_db), -): +) -> schemas_aws.AwsAsumeProfile: if not crud_users.is_master(db, current_user): raise HTTPException(status_code=403, detail="Not enough permissions") + filters = schemas_aws.AwsAccountFilter() + filters.id = aws_account_id + db_aws_account = await crud_aws.get_all_aws_profile(db=db, filters=filters) + if not db_aws_account: + raise HTTPException(status_code=404, detail="Account not found") - result = crud_aws.delete_aws_profile_by_id(db=db, aws_profile_id=aws_account_id) + result = await crud_aws.delete_aws_profile_by_id(db=db, aws_account_id=aws_account_id) crud_activity.create_activity_log( db=db, username=current_user.username, diff --git a/sld-api-backend/src/aws/api/container/get.py b/sld-api-backend/src/aws/api/container/get.py index 0235faa9..7e78c920 100644 --- a/sld-api-backend/src/aws/api/container/get.py +++ b/sld-api-backend/src/aws/api/container/get.py @@ -18,4 +18,4 @@ async def get_all_aws_accounts( ) -> list[schemas_aws.AwsAccountResponse]: if not crud_users.is_master(db, current_user): filters.squad = current_user.squad - return crud_aws.get_all_aws_profile(db=db, filters=filters, skip=skip, limit=limit) + return await crud_aws.get_all_aws_profile(db=db, filters=filters, skip=skip, limit=limit) diff --git a/sld-api-backend/src/aws/api/container/update.py b/sld-api-backend/src/aws/api/container/update.py index 8e17cdcc..12929b27 100644 --- a/sld-api-backend/src/aws/api/container/update.py +++ b/sld-api-backend/src/aws/api/container/update.py @@ -10,29 +10,25 @@ async def update_aws_account( - deploy_id: int, - aws: schemas_aws.AwsAsumeProfile, + aws_account_id: int, + aws: schemas_aws.AwsAccountUpdate, current_user: schemas_users.User = Depends(deps.get_current_active_user), db: Session = Depends(deps.get_db), -): - # Check if the user has privileges +) -> schemas_aws.AwsAsumeProfile: if not crud_users.is_master(db, current_user): raise HTTPException(status_code=403, detail="Not enough permissions") - if "string" in [aws.squad, aws.environment]: - raise HTTPException( - status_code=409, - detail="The squad or environment field must have a value that is not a string.", - ) - try: filters = schemas_aws.AwsAccountFilter() - filters.id = deploy_id - db_aws_account = crud_aws.get_all_aws_profile(db=db, filters=filters) - - if db_aws_account: - # If the AWS profile already exists, perform an update - aws_id_to_update = db_aws_account[0].id # Assuming you want to update the first matching profile - return await crud_aws.update_aws_profile(db=db, aws_id=aws_id_to_update, updated_aws=aws) - + filters.id = aws_account_id + db_aws_account = await crud_aws.get_all_aws_profile(db=db, filters=filters) + if not db_aws_account: + raise HTTPException(status_code=404, detail="Account not found") + crud_activity.create_activity_log( + db=db, + username=current_user.username, + squad=current_user.squad, + action=f"Update AWS account {aws.squad} {aws.environment}", + ) + return await crud_aws.update_aws_profile(db=db, aws_account_id=aws_account_id, updated_aws=aws) except Exception as err: - raise HTTPException(status_code=400, detail=str(err)) + raise err diff --git a/sld-api-backend/src/aws/domain/entities/aws.py b/sld-api-backend/src/aws/domain/entities/aws.py index 14c52432..d4424746 100644 --- a/sld-api-backend/src/aws/domain/entities/aws.py +++ b/sld-api-backend/src/aws/domain/entities/aws.py @@ -1,3 +1,4 @@ +import datetime from typing import Optional, Dict, Any from pydantic import BaseModel, constr, SecretStr @@ -29,6 +30,8 @@ class AwsAccountResponseBase(BaseModel): environment: str default_region: Optional[str] role_arn: Optional[str] + created_at: Optional[datetime.datetime] = None + updated_at: Optional[datetime.datetime] = None class Config: from_attributes = True @@ -57,3 +60,8 @@ class AwsAccountFilter(BaseModel): environment: Optional[str] = None default_region: Optional[str] = None role_arn: Optional[str] = None + + +class AwsAccountUpdate(AwsAccountFilter): + secret_access_key: Optional[str] = None + extra_variables: Optional[Dict[str, Any]] = None diff --git a/sld-api-backend/src/aws/infrastructure/models.py b/sld-api-backend/src/aws/infrastructure/models.py index 6c34e3d5..ab9c4a5c 100644 --- a/sld-api-backend/src/aws/infrastructure/models.py +++ b/sld-api-backend/src/aws/infrastructure/models.py @@ -17,4 +17,5 @@ class Aws_provider(Base): source_profile = Column(String(200), nullable=True) extra_variables = Column(JSON, nullable=True) created_at = Column(DateTime, default=datetime.datetime.now()) + updated_at = Column(DateTime, nullable=True) __table_args__ = (UniqueConstraint("squad", "environment"),) diff --git a/sld-api-backend/src/aws/infrastructure/repositories.py b/sld-api-backend/src/aws/infrastructure/repositories.py index e204c827..83b34ae8 100644 --- a/sld-api-backend/src/aws/infrastructure/repositories.py +++ b/sld-api-backend/src/aws/infrastructure/repositories.py @@ -18,7 +18,7 @@ def encrypt(secreto): raise err -def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> schemas_aws.AwsAccountResponse: +async def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> schemas_aws.AwsAccountResponse: encrypt_access_key_id = encrypt(aws.access_key_id) encrypt_secret_access_key = encrypt(aws.secret_access_key) encrypted_extra_variables = {key: encrypt(val) for key, val in aws.extra_variables.items()} if aws.extra_variables else None @@ -37,23 +37,16 @@ def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> schemas db.add(db_aws) db.commit() db.refresh(db_aws) - return schemas_aws.AwsAccountResponse( - id=db_aws.id, - squad=db_aws.squad, - environment=db_aws.environment, - default_region=db_aws.default_region, - role_arn=db_aws.role_arn, - extra_variables=db_aws.extra_variables, - ) + return schemas_aws.AwsAccountResponse.model_validate(obj=db_aws) except Exception as err: + db.rollback() raise err -async def update_aws_profile(db: Session, aws_id: int, updated_aws: schemas_aws.AwsAsumeProfile) -> schemas_aws.AwsAccountResponse: - db_aws = db.query(models.Aws_provider).filter(models.Aws_provider.id == aws_id).first() - +async def update_aws_profile(db: Session, aws_account_id: int, updated_aws: schemas_aws.AwsAccountUpdate) -> schemas_aws.AwsAccountResponse: + + db_aws = db.query(models.Aws_provider).filter(models.Aws_provider.id == aws_account_id).first() if db_aws: - # Update only the fields that are present in the updated_aws object if updated_aws.access_key_id: db_aws.access_key_id = encrypt(updated_aws.access_key_id) if updated_aws.secret_access_key: @@ -61,51 +54,34 @@ async def update_aws_profile(db: Session, aws_id: int, updated_aws: schemas_aws. if updated_aws.extra_variables: db_aws.extra_variables = {key: encrypt(val) for key, val in updated_aws.extra_variables.items()} - # Update the remaining fields db_aws.environment = updated_aws.environment db_aws.default_region = updated_aws.default_region db_aws.role_arn = updated_aws.role_arn db_aws.squad = updated_aws.squad + db_aws.updated_at = datetime.datetime.now() try: db.commit() db.refresh(db_aws) - return schemas_aws.AwsAccountResponse( - id=db_aws.id, - squad=db_aws.squad, - environment=db_aws.environment, - default_region=db_aws.default_region, - role_arn=db_aws.role_arn, - extra_variables=db_aws.extra_variables, - ) + return schemas_aws.AwsAccountResponse.model_validate(db_aws) except Exception as err: + db.rollback() raise err else: - # Handle the case where the specified AWS profile ID doesn't exist - raise ValueError(f"AWS profile with id {aws_id} not found") - + raise ValueError(f"AWS profile with id {aws_account_id} not found") -def get_credentials_aws_profile(db: Session, environment: str, squad: str) -> schemas_aws.AwsAccountResponseRepo: +async def get_credentials_aws_profile(db: Session, environment: str, squad: str) -> schemas_aws.AwsAccountResponseRepo: aws_provider_data = ( db.query(models.Aws_provider) .filter(models.Aws_provider.environment == environment) .filter(models.Aws_provider.squad == squad) .first() ) - return schemas_aws.AwsAccountResponseRepo( - id=aws_provider_data.id, - squad=aws_provider_data.squad, - environment=aws_provider_data.environment, - access_key_id=aws_provider_data.access_key_id, - secret_access_key=aws_provider_data.secret_access_key, - role_arn=aws_provider_data.role_arn, - default_region=aws_provider_data.default_region, - extra_variables=aws_provider_data.extra_variables, - ) + return schemas_aws.AwsAccountResponseRepo.model_validate(obj=aws_provider_data) -def get_all_aws_profile( +async def get_all_aws_profile( db: Session, filters: schemas_aws.AwsAccountFilter, skip: int = 0, limit: int = 100 ) -> List[schemas_aws.AwsAccountResponse]: try: @@ -130,6 +106,8 @@ def get_all_aws_profile( default_region=result.default_region, role_arn=result.role_arn, extra_variables=result.extra_variables, + created_at=result.created_at, + updated_at=result.updated_at, ) aws_profiles.append(aws_profile) return aws_profiles @@ -137,23 +115,18 @@ def get_all_aws_profile( raise err -def delete_aws_profile_by_id(db: Session, aws_profile_id: int): +async def delete_aws_profile_by_id(db: Session, aws_account_id: int) -> schemas_aws.AwsAccountResponse: try: - db.query(models.Aws_provider).filter( - models.Aws_provider.id == aws_profile_id - ).delete() - db.commit() - return {aws_profile_id: "deleted", "aws_profile_id": aws_profile_id} - except Exception as err: - raise err - - -def get_cloud_account_by_id(db: Session, provider_id: int): - try: - return ( - db.query(models.Aws_provider) - .filter(models.Aws_provider.id == provider_id) - .first() - ) + aws_profile = db.query(models.Aws_provider).filter( + models.Aws_provider.id == aws_account_id + ).first() + if aws_profile: + db.delete(aws_profile) + db.commit() + response_data = schemas_aws.AwsAccountResponse.model_validate(aws_profile) + return response_data + else: + raise f"AWS profile with id {aws_account_id} not found" except Exception as err: + db.rollback() raise err diff --git a/sld-api-backend/src/azure/infrastructure/models.py b/sld-api-backend/src/azure/infrastructure/models.py index 87ed2e50..95a88ec2 100644 --- a/sld-api-backend/src/azure/infrastructure/models.py +++ b/sld-api-backend/src/azure/infrastructure/models.py @@ -15,4 +15,5 @@ class Azure_provider(Base): tenant_id = Column(String(200), nullable=False) extra_variables = Column(JSON, nullable=True) created_at = Column(DateTime, default=datetime.datetime.now()) + updated_at = Column(DateTime, nullable=True) __table_args__ = (UniqueConstraint("squad", "environment"),) diff --git a/sld-api-backend/src/custom_providers/infrastructure/models.py b/sld-api-backend/src/custom_providers/infrastructure/models.py index ce4e2f1c..649febdd 100644 --- a/sld-api-backend/src/custom_providers/infrastructure/models.py +++ b/sld-api-backend/src/custom_providers/infrastructure/models.py @@ -11,4 +11,5 @@ class Custom_provider(Base): squad = Column(String(200), nullable=False) configuration = Column(JSON, nullable=False) created_at = Column(DateTime, default=datetime.datetime.now()) + updated_at = Column(DateTime, nullable=True) __table_args__ = (UniqueConstraint("squad", "environment"),) diff --git a/sld-api-backend/src/deploy/api/container/deploy/create.py b/sld-api-backend/src/deploy/api/container/deploy/create.py index 123916a8..c5ae9b73 100644 --- a/sld-api-backend/src/deploy/api/container/deploy/create.py +++ b/sld-api-backend/src/deploy/api/container/deploy/create.py @@ -41,7 +41,7 @@ async def deploy_infra_by_stack_name( status_code=403, detail=f"Not enough permissions in {squad}" ) # Get credentials by providers supported - secreto = check_prefix( + secreto = await check_prefix( db, stack_name=deploy.stack_name, environment=deploy.environment, squad=squad ) # Get info from stack data diff --git a/sld-api-backend/src/deploy/api/container/deploy/delete.py b/sld-api-backend/src/deploy/api/container/deploy/delete.py index ab78fe89..eb3811da 100644 --- a/sld-api-backend/src/deploy/api/container/deploy/delete.py +++ b/sld-api-backend/src/deploy/api/container/deploy/delete.py @@ -38,7 +38,7 @@ async def delete_infra_by_id( project_path = deploy_data.project_path variables = deploy_data.variables # Get credentials by providers supported - secreto = check_prefix( + secreto = await check_prefix( db, stack_name=stack_name, environment=environment, squad=squad ) # Get info from stack data diff --git a/sld-api-backend/src/deploy/api/container/deploy/destroy.py b/sld-api-backend/src/deploy/api/container/deploy/destroy.py index 2f42c217..fec8a8dc 100644 --- a/sld-api-backend/src/deploy/api/container/deploy/destroy.py +++ b/sld-api-backend/src/deploy/api/container/deploy/destroy.py @@ -43,7 +43,7 @@ async def destroy_infra( project_path = deploy_data.project_path name = deploy_data.name # Get credentials by providers supported - secreto = check_prefix( + secreto = await check_prefix( db, stack_name=stack_name, environment=environment, squad=squad ) # Get info from stack data diff --git a/sld-api-backend/src/deploy/api/container/deploy/update.py b/sld-api-backend/src/deploy/api/container/deploy/update.py index 2fa022db..ca07bf89 100644 --- a/sld-api-backend/src/deploy/api/container/deploy/update.py +++ b/sld-api-backend/src/deploy/api/container/deploy/update.py @@ -45,7 +45,7 @@ async def deploy_by_id( environment = deploy_data.environment name = deploy_data.name # Get credentials by providers supported - secreto = check_prefix( + secreto = await check_prefix( db, stack_name=stack_name, environment=environment, squad=squad ) # Get info from stack data diff --git a/sld-api-backend/src/deploy/api/container/plan/create.py b/sld-api-backend/src/deploy/api/container/plan/create.py index ac91453f..39eefb3b 100644 --- a/sld-api-backend/src/deploy/api/container/plan/create.py +++ b/sld-api-backend/src/deploy/api/container/plan/create.py @@ -34,7 +34,7 @@ async def plan_infra_by_stack_name( status_code=403, detail=f"Not enough permissions in {squad}" ) # Get credentials by providers supported - secreto = check_prefix( + secreto = await check_prefix( db, stack_name=deploy.stack_name, environment=deploy.environment, squad=squad ) # Get info from stack data diff --git a/sld-api-backend/src/deploy/api/container/plan/get.py b/sld-api-backend/src/deploy/api/container/plan/get.py index 0efb5aa3..ce9ac6d7 100644 --- a/sld-api-backend/src/deploy/api/container/plan/get.py +++ b/sld-api-backend/src/deploy/api/container/plan/get.py @@ -29,7 +29,7 @@ async def get_plan_by_id_deploy( status_code=403, detail=f"Not enough permissions in {deploy_data.squad}" ) # Get credentials by providers supported - secreto = check_prefix( + secreto = await check_prefix( db, stack_name=deploy_data.stack_name, environment=deploy_data.environment, diff --git a/sld-api-backend/src/gcp/infrastructure/models.py b/sld-api-backend/src/gcp/infrastructure/models.py index 138c9939..b1bb3c99 100644 --- a/sld-api-backend/src/gcp/infrastructure/models.py +++ b/sld-api-backend/src/gcp/infrastructure/models.py @@ -12,4 +12,5 @@ class Gcloud_provider(Base): gcloud_keyfile_json = Column(String(5000), nullable=False) extra_variables = Column(JSON, nullable=True) created_at = Column(DateTime, default=datetime.datetime.now()) + updated_at = Column(DateTime, nullable=True) __table_args__ = (UniqueConstraint("squad", "environment"),) diff --git a/sld-api-backend/src/shared/helpers/get_data.py b/sld-api-backend/src/shared/helpers/get_data.py index 643f8362..c434bf79 100644 --- a/sld-api-backend/src/shared/helpers/get_data.py +++ b/sld-api-backend/src/shared/helpers/get_data.py @@ -181,10 +181,10 @@ def check_cron_schedule(cron_time: str): return True -def check_prefix(db, stack_name: str, environment: str, squad: str): +async def check_prefix(db, stack_name: str, environment: str, squad: str): try: if any(i in stack_name.lower() for i in settings.AWS_PREFIX): - secreto = crud_aws.get_credentials_aws_profile( + secreto = await crud_aws.get_credentials_aws_profile( db=db, environment=environment, squad=squad ) return secreto From 722272ff653f59ca098c140a9ec16675c9dd0684 Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Fri, 29 Dec 2023 00:49:28 +0100 Subject: [PATCH 06/11] =?UTF-8?q?=F0=9F=94=A7refactor:=20aws=20backend=20a?= =?UTF-8?q?ctivity=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sld-api-backend/src/aws/api/container/create.py | 3 ++- sld-api-backend/src/aws/api/container/update.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sld-api-backend/src/aws/api/container/create.py b/sld-api-backend/src/aws/api/container/create.py index c753e34a..b948eaa3 100644 --- a/sld-api-backend/src/aws/api/container/create.py +++ b/sld-api-backend/src/aws/api/container/create.py @@ -30,12 +30,13 @@ async def create_new_aws_profile( if db_aws_account: raise HTTPException(status_code=409, detail="Account already exists") try: + result = await crud_aws.create_aws_profile(db=db, aws=aws) crud_activity.create_activity_log( db=db, username=current_user.username, squad=current_user.squad, action=f"Create AWS account {aws.squad} {aws.environment}", ) - return await crud_aws.create_aws_profile(db=db, aws=aws) + return result except Exception as err: raise HTTPException(status_code=400, detail=str(err)) diff --git a/sld-api-backend/src/aws/api/container/update.py b/sld-api-backend/src/aws/api/container/update.py index 12929b27..e379483b 100644 --- a/sld-api-backend/src/aws/api/container/update.py +++ b/sld-api-backend/src/aws/api/container/update.py @@ -23,12 +23,13 @@ async def update_aws_account( db_aws_account = await crud_aws.get_all_aws_profile(db=db, filters=filters) if not db_aws_account: raise HTTPException(status_code=404, detail="Account not found") + result = await crud_aws.update_aws_profile(db=db, aws_account_id=aws_account_id, updated_aws=aws) crud_activity.create_activity_log( db=db, username=current_user.username, squad=current_user.squad, action=f"Update AWS account {aws.squad} {aws.environment}", ) - return await crud_aws.update_aws_profile(db=db, aws_account_id=aws_account_id, updated_aws=aws) + return result except Exception as err: raise err From 441199167d56f88828fa8ecf1363d9dd0609affa Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Fri, 29 Dec 2023 02:44:46 +0100 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=94=A7refactor:=20aws=20ui=20add=20?= =?UTF-8?q?extra=20variables=20for=20new=20accounts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/aws/infrastructure/repositories.py | 18 +++---- .../src/deploy/api/container/plan/update.py | 2 +- sld-api-backend/test/config/api.py | 15 ++---- sld-dashboard/app/home/forms.py | 46 ++++++++-------- sld-dashboard/app/home/routes.py | 6 ++- .../app/home/templates/aws-list.html | 25 +++++++-- sld-dashboard/app/home/templates/aws-new.html | 54 +++++++++++++++---- 7 files changed, 109 insertions(+), 57 deletions(-) diff --git a/sld-api-backend/src/aws/infrastructure/repositories.py b/sld-api-backend/src/aws/infrastructure/repositories.py index 83b34ae8..0333b764 100644 --- a/sld-api-backend/src/aws/infrastructure/repositories.py +++ b/sld-api-backend/src/aws/infrastructure/repositories.py @@ -44,7 +44,7 @@ async def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> s async def update_aws_profile(db: Session, aws_account_id: int, updated_aws: schemas_aws.AwsAccountUpdate) -> schemas_aws.AwsAccountResponse: - + db_aws = db.query(models.Aws_provider).filter(models.Aws_provider.id == aws_account_id).first() if db_aws: if updated_aws.access_key_id: @@ -72,13 +72,13 @@ async def update_aws_profile(db: Session, aws_account_id: int, updated_aws: sche async def get_credentials_aws_profile(db: Session, environment: str, squad: str) -> schemas_aws.AwsAccountResponseRepo: - aws_provider_data = ( + db_aws = ( db.query(models.Aws_provider) .filter(models.Aws_provider.environment == environment) .filter(models.Aws_provider.squad == squad) .first() ) - return schemas_aws.AwsAccountResponseRepo.model_validate(obj=aws_provider_data) + return schemas_aws.AwsAccountResponseRepo.model_validate(obj=db_aws) async def get_all_aws_profile( @@ -95,10 +95,10 @@ async def get_all_aws_profile( else: query = query.filter(getattr(models.Aws_provider, field) == value) - results = query.order_by(desc(models.Aws_provider.id)).offset(skip).limit(limit).all() + db_aws = query.order_by(desc(models.Aws_provider.id)).offset(skip).limit(limit).all() aws_profiles = [] - for result in results: + for result in db_aws: aws_profile = schemas_aws.AwsAccountResponse( id=result.id, squad=result.squad, @@ -117,13 +117,13 @@ async def get_all_aws_profile( async def delete_aws_profile_by_id(db: Session, aws_account_id: int) -> schemas_aws.AwsAccountResponse: try: - aws_profile = db.query(models.Aws_provider).filter( + db_aws = db.query(models.Aws_provider).filter( models.Aws_provider.id == aws_account_id ).first() - if aws_profile: - db.delete(aws_profile) + if db_aws: + db.delete(db_aws) db.commit() - response_data = schemas_aws.AwsAccountResponse.model_validate(aws_profile) + response_data = schemas_aws.AwsAccountResponse.model_validate(db_aws) return response_data else: raise f"AWS profile with id {aws_account_id} not found" diff --git a/sld-api-backend/src/deploy/api/container/plan/update.py b/sld-api-backend/src/deploy/api/container/plan/update.py index e2332f1d..cd72f1a2 100644 --- a/sld-api-backend/src/deploy/api/container/plan/update.py +++ b/sld-api-backend/src/deploy/api/container/plan/update.py @@ -40,7 +40,7 @@ async def update_plan_by_id( status_code=403, detail=f"Not enough permissions in {squad}" ) # Get credentials by providers supported - secreto = check_prefix( + secreto = await check_prefix( db, stack_name=stack_name, environment=environment, squad=squad ) # Get info from stack data diff --git a/sld-api-backend/test/config/api.py b/sld-api-backend/test/config/api.py index 2afa5d74..f46cbedf 100644 --- a/sld-api-backend/test/config/api.py +++ b/sld-api-backend/test/config/api.py @@ -120,9 +120,7 @@ class Settings(BaseSettings): "access_key_id": os.getenv("AWS_ACCESS_KEY_ID"), "secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"), "default_region": "eu-west-1", - "profile_name": "string", - "role_arn": "string", - "source_profile": "string", + "extra_variables": {"TF_VAR_aws_account_id": "1234567890", "TF_VAR_aws_secret": "1234"}, } AWS_TEST_ACCOUNT_PRO: dict = { "squad": "squad1", @@ -130,9 +128,8 @@ class Settings(BaseSettings): "access_key_id": os.getenv("AWS_ACCESS_KEY_ID"), "secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"), "default_region": "eu-west-1", - "profile_name": "string", - "role_arn": "string", - "source_profile": "string", + "role_arn": "arn:aws:iam::1234567890:role/role_name", + "extra_variables": {"TF_VAR_aws_account_id": "1234567890", "TF_VAR_aws_secret": "1234"}, } AWS_TEST_ACCOUNT_SQUAD2: dict = { "squad": "squad2", @@ -140,9 +137,8 @@ class Settings(BaseSettings): "access_key_id": os.getenv("AWS_ACCESS_KEY_ID"), "secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"), "default_region": "eu-west-1", - "profile_name": "string", - "role_arn": "string", - "source_profile": "string", + "role_arn": "arn:aws:iam::1234567890:role/role_name", + "extra_variables": {"TF_VAR_aws_account_id": "1234567890", "TF_VAR_aws_secret": "1234", "TF_VAR_db_password": "1234"}, } AWS_TEST_ACCOUNT_SQUAD2_PRO: dict = { "squad": "squad2", @@ -151,7 +147,6 @@ class Settings(BaseSettings): "secret_access_key": os.getenv("AWS_SECRET_ACCESS_KEY"), "default_region": "eu-west-1", "profile_name": "string", - "role_arn": "string", "source_profile": "string", } DEPLOY_URI: str = "?tf_ver=1.0.7" diff --git a/sld-dashboard/app/home/forms.py b/sld-dashboard/app/home/forms.py index 28289f50..c3663018 100644 --- a/sld-dashboard/app/home/forms.py +++ b/sld-dashboard/app/home/forms.py @@ -1,12 +1,26 @@ # -*- encoding: utf-8 -*- from flask_wtf import FlaskForm from wtforms import (BooleanField, PasswordField, StringField, TextAreaField, SelectField, - validators) + FormField, FieldList, validators) from wtforms.fields import EmailField from wtforms.validators import DataRequired -# login and registration +class DictField(StringField): + def process_formdata(self, valuelist): + if valuelist: + data = valuelist[0] + try: + # Try to parse the input as a dictionary + self.data = dict(eval(data)) + except (SyntaxError, ValueError): + self.data = None + raise ValueError("Invalid dictionary format") + + +class ExtraVariableForm(FlaskForm): + key = StringField('Key') + value = StringField('Value') class StackForm(FlaskForm): @@ -193,6 +207,13 @@ class AwsForm(FlaskForm): validators.DataRequired(message="Squad Name requerid."), ], ) + environment = StringField( + "Environment *", + [ + validators.length(min=2, max=250, message="Environment out of reange."), + validators.DataRequired(message="Environment requerid."), + ], + ) access_key_id = StringField( "Access_key_id *", [ @@ -216,31 +237,14 @@ class AwsForm(FlaskForm): validators.DataRequired(message="default_region."), ], ) - profile_name = StringField( - "Profile_name", - [ - validators.length(min=4, max=50, message="profile_name out of reange."), - ], - ) role_arn = StringField( "Role_arn", [ validators.length(min=4, max=50, message="Role arn out of reange."), ], ) - source_profile = StringField( - "Source_profile", - [ - validators.length(min=4, max=50, message="source_profile out of reange."), - ], - ) - environment = StringField( - "Environment *", - [ - validators.length(min=2, max=250, message="Branch out of reange."), - validators.DataRequired(message="Environment requerid."), - ], - ) + extra_variables = FieldList(FormField(ExtraVariableForm), label='Extra Variables') + class GcpForm(FlaskForm): diff --git a/sld-dashboard/app/home/routes.py b/sld-dashboard/app/home/routes.py index a750e7d9..62c3b326 100644 --- a/sld-dashboard/app/home/routes.py +++ b/sld-dashboard/app/home/routes.py @@ -1506,15 +1506,17 @@ def new_aws_account(): # Check if token no expired check_unauthorized_token(token) if request.method == "POST": + key_list = request.values.getlist("sld_key") + value_list = request.values.getlist("sld_value") new_user: dict = { "squad": form.squad.data.replace(" ",""), "environment": form.environment.data.replace(" ",""), "access_key_id": form.access_key_id.data.replace(" ",""), "secret_access_key": form.secret_access_key.data.replace(" ",""), "default_region": form.default_region.data.replace(" ",""), - "profile_name": form.profile_name.data.replace(" ",""), "role_arn": form.role_arn.data.replace(" ",""), - "source_profile": form.source_profile.data.replace(" ",""), + "extra_variables": dict(list(zip(key_list, value_list))) + } response = request_url( verb="POST", diff --git a/sld-dashboard/app/home/templates/aws-list.html b/sld-dashboard/app/home/templates/aws-list.html index e0bb93fa..a27df862 100644 --- a/sld-dashboard/app/home/templates/aws-list.html +++ b/sld-dashboard/app/home/templates/aws-list.html @@ -71,9 +71,8 @@

    All aws accounts

    Squad Environment Default Region - Profile Name Role Arn - Source Profile + Extra Variables @@ -87,9 +86,25 @@

    All aws accounts

    {{ aws_account.squad }} {{ aws_account.environment }} {{ aws_account.default_region }} - {{ aws_account.profile_name }} - {{ aws_account.role_arn }} - {{ aws_account.source_profile }} + + + {% if aws_account.role_arn %} + {{ aws_account.role_arn }} + {% else %} + - + {% endif %} + + + + + {% if aws_account.extra_variables %} + {% set truncated_variables = aws_account.extra_variables.keys() | join(', ') | truncate(30, True, '...') %} + {{ truncated_variables }} + {% else %} + - + {% endif %} + +
    {% if "yoda" in current_user.role %} diff --git a/sld-dashboard/app/home/templates/aws-new.html b/sld-dashboard/app/home/templates/aws-new.html index ce2a05a7..e452c33b 100644 --- a/sld-dashboard/app/home/templates/aws-new.html +++ b/sld-dashboard/app/home/templates/aws-new.html @@ -67,18 +67,27 @@

    Add New AWS Account

    {{ render_field(form.default_region, class='form-control',value='eu-west-1') }}
    -
    - {{ render_field(form.profile_name, class='form-control', - placeholder='profile_name') }} -
    {{ render_field(form.role_arn, class='form-control', placeholder='role_arn') }}
    -
    - {{ render_field(form.source_profile, class='form-control', - placeholder='source_profile') }} -
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + @@ -99,4 +108,31 @@

    Add New AWS Account

    {% endblock content %} -{% block javascripts %}{% endblock javascripts %} \ No newline at end of file +{% block javascripts %} + +{% endblock javascripts %} \ No newline at end of file From 1244981708213a17f7c11ffa7cb39aab81cd220f Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Fri, 29 Dec 2023 23:42:21 +0100 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=94=A7refactor:=20aws=20update=20ex?= =?UTF-8?q?tra=20varibles=20add=20feature=20for=20edit=20key=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/aws/api/container/delete.py | 23 +-- .../src/aws/infrastructure/repositories.py | 31 +++- sld-api-backend/src/shared/domain/__init__.py | 0 .../src/shared/domain/exeptions/__init__.py | 0 .../src/shared/domain/exeptions/in_use.py | 4 + sld-dashboard/app/home/routes.py | 59 ++++++- .../app/home/templates/aws-edit.html | 145 ++++++++++++++++++ .../app/home/templates/aws-list.html | 2 +- sld-dashboard/app/home/templates/aws-new.html | 9 +- 9 files changed, 251 insertions(+), 22 deletions(-) create mode 100644 sld-api-backend/src/shared/domain/__init__.py create mode 100644 sld-api-backend/src/shared/domain/exeptions/__init__.py create mode 100644 sld-api-backend/src/shared/domain/exeptions/in_use.py create mode 100644 sld-dashboard/app/home/templates/aws-edit.html diff --git a/sld-api-backend/src/aws/api/container/delete.py b/sld-api-backend/src/aws/api/container/delete.py index 022f1d2b..d940ec90 100644 --- a/sld-api-backend/src/aws/api/container/delete.py +++ b/sld-api-backend/src/aws/api/container/delete.py @@ -7,6 +7,7 @@ from src.shared.security import deps from src.users.domain.entities import users as schemas_users from src.users.infrastructure import repositories as crud_users +from src.shared.domain.exeptions.in_use import ResourceInUseError async def aws_account_by_id( @@ -22,12 +23,16 @@ async def aws_account_by_id( db_aws_account = await crud_aws.get_all_aws_profile(db=db, filters=filters) if not db_aws_account: raise HTTPException(status_code=404, detail="Account not found") - - result = await crud_aws.delete_aws_profile_by_id(db=db, aws_account_id=aws_account_id) - crud_activity.create_activity_log( - db=db, - username=current_user.username, - squad=current_user.squad, - action=f"Delete AWS account {aws_account_id}", - ) - return result + try: + result = await crud_aws.delete_aws_profile_by_id(db=db, aws_account_id=aws_account_id) + crud_activity.create_activity_log( + db=db, + username=current_user.username, + squad=current_user.squad, + action=f"Delete AWS account {aws_account_id}", + ) + return result + except ResourceInUseError as err: + raise HTTPException(status_code=409, detail=str(err)) + except Exception as err: + raise err diff --git a/sld-api-backend/src/aws/infrastructure/repositories.py b/sld-api-backend/src/aws/infrastructure/repositories.py index 0333b764..5e2b3cf3 100644 --- a/sld-api-backend/src/aws/infrastructure/repositories.py +++ b/sld-api-backend/src/aws/infrastructure/repositories.py @@ -6,8 +6,10 @@ import src.aws.infrastructure.models as models +from src.deploy.infrastructure.models import Deploy from src.aws.domain.entities import aws as schemas_aws -from src.shared.security.vault import vault_encrypt +from src.shared.domain.exeptions.in_use import ResourceInUseError +from src.shared.security.vault import vault_encrypt, vault_decrypt @vault_encrypt @@ -17,6 +19,13 @@ def encrypt(secreto): except Exception as err: raise err +@vault_decrypt +def decrypt(secreto): + try: + return secreto + except Exception as err: + raise err + async def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> schemas_aws.AwsAccountResponse: encrypt_access_key_id = encrypt(aws.access_key_id) @@ -44,16 +53,25 @@ async def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> s async def update_aws_profile(db: Session, aws_account_id: int, updated_aws: schemas_aws.AwsAccountUpdate) -> schemas_aws.AwsAccountResponse: - db_aws = db.query(models.Aws_provider).filter(models.Aws_provider.id == aws_account_id).first() + if db_aws: if updated_aws.access_key_id: db_aws.access_key_id = encrypt(updated_aws.access_key_id) if updated_aws.secret_access_key: db_aws.secret_access_key = encrypt(updated_aws.secret_access_key) + if updated_aws.extra_variables: - db_aws.extra_variables = {key: encrypt(val) for key, val in updated_aws.extra_variables.items()} + current_extra_variables = db_aws.extra_variables or {} + for key, value in current_extra_variables.items(): + current_extra_variables[key] = decrypt(value) + + for key, value in updated_aws.extra_variables.items(): + if "***" not in value: + current_extra_variables[key] = value + encrypted_extra_variables = {key: encrypt(value) for key, value in current_extra_variables.items()} + db_aws.extra_variables = encrypted_extra_variables db_aws.environment = updated_aws.environment db_aws.default_region = updated_aws.default_region db_aws.role_arn = updated_aws.role_arn @@ -120,6 +138,13 @@ async def delete_aws_profile_by_id(db: Session, aws_account_id: int) -> schemas_ db_aws = db.query(models.Aws_provider).filter( models.Aws_provider.id == aws_account_id ).first() + db_deploy = ( + db.query(Deploy) + .filter(Deploy.squad == db_aws.squad) + .filter(Deploy.environment == db_aws.environment) + .first()) + if db_deploy: + raise ResourceInUseError(aws_account_id) if db_aws: db.delete(db_aws) db.commit() diff --git a/sld-api-backend/src/shared/domain/__init__.py b/sld-api-backend/src/shared/domain/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sld-api-backend/src/shared/domain/exeptions/__init__.py b/sld-api-backend/src/shared/domain/exeptions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/sld-api-backend/src/shared/domain/exeptions/in_use.py b/sld-api-backend/src/shared/domain/exeptions/in_use.py new file mode 100644 index 00000000..14be10c8 --- /dev/null +++ b/sld-api-backend/src/shared/domain/exeptions/in_use.py @@ -0,0 +1,4 @@ +class ResourceInUseError(Exception): + def __init__(self, resource_name: str): + self.resource_name = resource_name + super().__init__(f"Resource {resource_name} is being used and cannot be deleted") diff --git a/sld-dashboard/app/home/routes.py b/sld-dashboard/app/home/routes.py index 62c3b326..b14b313b 100644 --- a/sld-dashboard/app/home/routes.py +++ b/sld-dashboard/app/home/routes.py @@ -1444,7 +1444,7 @@ def edit_user(user_id): json=data, ) if response.get("status_code") == 200: - flash(f"User Updated ") + flash("User Updated ") else: flash(response["json"].get("detail"), "error") return redirect( @@ -1508,7 +1508,7 @@ def new_aws_account(): if request.method == "POST": key_list = request.values.getlist("sld_key") value_list = request.values.getlist("sld_value") - new_user: dict = { + aws_account_request: dict = { "squad": form.squad.data.replace(" ",""), "environment": form.environment.data.replace(" ",""), "access_key_id": form.access_key_id.data.replace(" ",""), @@ -1522,7 +1522,7 @@ def new_aws_account(): verb="POST", uri="accounts/aws/", headers={"Authorization": f"Bearer {token}"}, - json=new_user, + json=aws_account_request, ) if response.get("status_code") == 200: flash( @@ -1544,6 +1544,59 @@ def new_aws_account(): return redirect(url_for("base_blueprint.logout")) +@blueprint.route("/aws-edit", methods=["GET", "POST"], defaults={"account_id": None}) +@blueprint.route("/aws-edit/", methods=["GET", "POST"]) +@login_required +def edit_aws_account(account_id): + try: + form = AwsForm(request.form) + token = decrypt(r.get(current_user.id)) + # Check if token no expired + check_unauthorized_token(token) + endpoint = f"accounts/aws/?id={account_id}" + response = request_url( + verb="GET", uri=f"{endpoint}", headers={"Authorization": f"Bearer {token}"} + ) + vars_json = response["json"][0] + if request.method == "POST": + key_list = request.values.getlist("sld_key") + value_list = request.values.getlist("sld_value") + print(request.values) + aws_account_request: dict = { + "squad": form.squad.data.replace(" ",""), + "environment": form.environment.data.replace(" ",""), + "access_key_id": form.access_key_id.data.replace(" ","") if "*" not in form.access_key_id.data else None, + "secret_access_key": form.secret_access_key.data.replace(" ","") if "*" not in form.secret_access_key.data else None, + "default_region": form.default_region.data.replace(" ",""), + "role_arn": form.role_arn.data.replace(" ",""), + "extra_variables": dict(list(zip(key_list, value_list))), + } + response = request_url( + verb="PATCH", + uri=f"accounts/aws/{account_id}", + headers={"Authorization": f"Bearer {token}"}, + json=aws_account_request, + ) + if response.get("status_code") == 200: + flash( + f"Updated aws account for environment {form.environment.data} in {form.squad.data} " + ) + elif response.get("status_code") == 409: + flash(response["json"].get("detail"), "error") + else: + flash(response["json"], "error") + + return render_template( + "/aws-edit.html", + title="Edit aws account", + form=form, + active="edit_aws_account", + data_json=vars_json, + external_api_dns=external_api_dns, + ) + except ValueError: + return redirect(url_for("base_blueprint.logout")) + @blueprint.route("/aws-list") @login_required def list_aws_account(): diff --git a/sld-dashboard/app/home/templates/aws-edit.html b/sld-dashboard/app/home/templates/aws-edit.html new file mode 100644 index 00000000..0619059e --- /dev/null +++ b/sld-dashboard/app/home/templates/aws-edit.html @@ -0,0 +1,145 @@ +{% extends "layouts/base.html" %} + +{% from "helpers/_forms.html" import render_field %} + +{% block title %} New AWS Account {% endblock %} + + +{% block stylesheets %}{% endblock stylesheets %} +{% block content %} +
    + + {% include 'includes/navigation.html' %} +
    + Volt logo +
    + +
    + +
    +
    +

    Edit AWS Account

    +

    Edit account by squad and environment

    +
    +
    + Accounts Docs +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + {{data_json}} +
    +
    +
    + {{ render_field(form.squad, class='form-control', value=data_json.squad) }} +
    + +
    + {{ render_field(form.environment, class='form-control', value=data_json.environment) }} +
    + +
    + {{ render_field(form.access_key_id, class='form-control', value="*************", placeholder='aws access_key_id') }} +
    + +
    + {{ render_field(form.secret_access_key, class='form-control',value="************", placeholder='aws secret_access_key') }} +
    + +
    + {{ render_field(form.default_region, class='form-control',value=data_json.default_region) }} +
    + +
    + {{ render_field(form.role_arn, class='form-control',value=data_json.role_arn,placeholder='role_arn') }} +
    + +
    +
    +
    +
    + + {% for key, value in data_json.extra_variables.items() %} +
    +
    + +
    +
    + +
    +
    + +
    +
    + {% endfor %} +
    + +
    + +
    +
    +
    + + + +
    + + +
    +
    +
    +
    +
    + + {% include 'includes/footer.html' %} + +
    + +{% endblock content %} + + +{% block javascripts %} + +{% endblock javascripts %} \ No newline at end of file diff --git a/sld-dashboard/app/home/templates/aws-list.html b/sld-dashboard/app/home/templates/aws-list.html index a27df862..1c789aea 100644 --- a/sld-dashboard/app/home/templates/aws-list.html +++ b/sld-dashboard/app/home/templates/aws-list.html @@ -42,6 +42,7 @@

    All aws accounts

    aria-label="Search" aria-describedby="basic-addon2"> +
    {% endif %}
    diff --git a/sld-dashboard/app/home/templates/aws-new.html b/sld-dashboard/app/home/templates/aws-new.html index e452c33b..c7788913 100644 --- a/sld-dashboard/app/home/templates/aws-new.html +++ b/sld-dashboard/app/home/templates/aws-new.html @@ -49,18 +49,15 @@

    Add New AWS Account

    - {{ render_field(form.environment, class='form-control', placeholder='Environment - Name') }} + {{ render_field(form.environment, class='form-control', placeholder='Environment Name') }}
    - {{ render_field(form.access_key_id, class='form-control', placeholder='aws - access_key_id') }} + {{ render_field(form.access_key_id, class='form-control', placeholder='aws access_key_id') }}
    - {{ render_field(form.secret_access_key, class='form-control', placeholder='aws - secret_access_key') }} + {{ render_field(form.secret_access_key, class='form-control', placeholder='aws secret_access_key') }}
    From 3198ed60bfe5f7ae5c693ad80f708b9291ecba9b Mon Sep 17 00:00:00 2001 From: d10s <79284025+D10S0VSkY-OSS@users.noreply.github.com> Date: Sat, 30 Dec 2023 01:27:05 +0100 Subject: [PATCH 09/11] =?UTF-8?q?=F0=9F=94=A7refactor:=20aws=20update=20ch?= =?UTF-8?q?eck=20if=20use=20by=20deployment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/aws/api/container/update.py | 3 + .../src/aws/infrastructure/repositories.py | 11 +++- sld-dashboard/app/home/routes.py | 4 +- .../app/home/templates/aws-edit.html | 59 +++++++++++-------- .../app/home/templates/aws-list.html | 3 + 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/sld-api-backend/src/aws/api/container/update.py b/sld-api-backend/src/aws/api/container/update.py index e379483b..20fa4825 100644 --- a/sld-api-backend/src/aws/api/container/update.py +++ b/sld-api-backend/src/aws/api/container/update.py @@ -7,6 +7,7 @@ from src.shared.security import deps from src.users.domain.entities import users as schemas_users from src.users.infrastructure import repositories as crud_users +from src.shared.domain.exeptions.in_use import ResourceInUseError async def update_aws_account( @@ -31,5 +32,7 @@ async def update_aws_account( action=f"Update AWS account {aws.squad} {aws.environment}", ) return result + except ResourceInUseError as err: + raise HTTPException(status_code=409, detail=str(err)) except Exception as err: raise err diff --git a/sld-api-backend/src/aws/infrastructure/repositories.py b/sld-api-backend/src/aws/infrastructure/repositories.py index 5e2b3cf3..39fd107e 100644 --- a/sld-api-backend/src/aws/infrastructure/repositories.py +++ b/sld-api-backend/src/aws/infrastructure/repositories.py @@ -54,6 +54,13 @@ async def create_aws_profile(db: Session, aws: schemas_aws.AwsAsumeProfile) -> s async def update_aws_profile(db: Session, aws_account_id: int, updated_aws: schemas_aws.AwsAccountUpdate) -> schemas_aws.AwsAccountResponse: db_aws = db.query(models.Aws_provider).filter(models.Aws_provider.id == aws_account_id).first() + db_deploy = ( + db.query(Deploy) + .filter(Deploy.squad == db_aws.squad) + .filter(Deploy.environment == db_aws.environment) + .first()) + if db_deploy and updated_aws.squad != db_aws.squad or updated_aws.environment != db_aws.environment: + raise ResourceInUseError(aws_account_id) if db_aws: if updated_aws.access_key_id: @@ -65,11 +72,11 @@ async def update_aws_profile(db: Session, aws_account_id: int, updated_aws: sche current_extra_variables = db_aws.extra_variables or {} for key, value in current_extra_variables.items(): current_extra_variables[key] = decrypt(value) + current_extra_variables = {key: value for key, value in current_extra_variables.items() if key in updated_aws.extra_variables} for key, value in updated_aws.extra_variables.items(): - if "***" not in value: + if key and value and "***" not in value: current_extra_variables[key] = value - encrypted_extra_variables = {key: encrypt(value) for key, value in current_extra_variables.items()} db_aws.extra_variables = encrypted_extra_variables db_aws.environment = updated_aws.environment diff --git a/sld-dashboard/app/home/routes.py b/sld-dashboard/app/home/routes.py index b14b313b..e51e492b 100644 --- a/sld-dashboard/app/home/routes.py +++ b/sld-dashboard/app/home/routes.py @@ -1561,7 +1561,6 @@ def edit_aws_account(account_id): if request.method == "POST": key_list = request.values.getlist("sld_key") value_list = request.values.getlist("sld_value") - print(request.values) aws_account_request: dict = { "squad": form.squad.data.replace(" ",""), "environment": form.environment.data.replace(" ",""), @@ -1581,6 +1580,8 @@ def edit_aws_account(account_id): flash( f"Updated aws account for environment {form.environment.data} in {form.squad.data} " ) + return redirect(url_for("home_blueprint.route_template", template="aws-list")) + elif response.get("status_code") == 409: flash(response["json"].get("detail"), "error") else: @@ -1613,7 +1614,6 @@ def list_aws_account(): return render_template( "aws-list.html", name="Name", aws=content, external_api_dns=external_api_dns ) - except ValueError: return redirect(url_for("base_blueprint.logout")) diff --git a/sld-dashboard/app/home/templates/aws-edit.html b/sld-dashboard/app/home/templates/aws-edit.html index 0619059e..78df6b18 100644 --- a/sld-dashboard/app/home/templates/aws-edit.html +++ b/sld-dashboard/app/home/templates/aws-edit.html @@ -42,7 +42,6 @@

    Edit AWS Account

    - {{data_json}}
    @@ -74,19 +73,19 @@

    Edit AWS Account

    - {% for key, value in data_json.extra_variables.items() %} -
    -
    - -
    -
    - -
    -
    - -
    -
    - {% endfor %} +{% for key, value in data_json.extra_variables.items() %} +
    +
    + +
    +
    + +
    +
    + +
    +
    +{% endfor %}
    @@ -95,10 +94,12 @@

    Edit AWS Account

    - + - @@ -119,18 +120,17 @@

    Edit AWS Account

    + + {% endblock javascripts %} \ No newline at end of file diff --git a/sld-dashboard/app/home/templates/aws-list.html b/sld-dashboard/app/home/templates/aws-list.html index 1c789aea..2161dc0e 100644 --- a/sld-dashboard/app/home/templates/aws-list.html +++ b/sld-dashboard/app/home/templates/aws-list.html @@ -117,6 +117,9 @@

    All aws accounts

    Toggle Dropdown '; html += '
    '; - html += ''; + html += ''; html += '
    '; html += '
    '; html += '
    '; @@ -139,9 +142,14 @@

    Edit AWS Account

    // remove row $(document).on('click', '.removeRow', function () { - $(this).closest('.dynamic-row').remove(); + if ($('.dynamic-row').length > 1) { + $(this).closest('.dynamic-row').remove(); + } else { + $(this).closest('.dynamic-row').find('input[type="text"]').val(''); + } }); + + {% endblock javascripts %} \ No newline at end of file