Edit AWS Account
+Edit account by squad and environment
+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/18] =?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/18] =?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/18] =?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 @@
Edit account by squad and environment
+Error loading the README.md file, check that it exists in the repository and on the selected branch
" - # When user push data with POST verb if request.method == "POST": - # Data dend to deploy squad_acces_form = form.squad_access_edit.data squad_acces_form_to_list = squad_acces_form.split(",") update_stack = { - "stack_name": form.name.data.replace(" ",""), - "git_repo": form.git.data.replace(" ",""), - "branch": form.branch.data.replace(" ",""), + "stack_name": form.name.data.replace(" ", ""), + "git_repo": form.git.data.replace(" ", ""), + "branch": form.branch.data.replace(" ", ""), "squad_access": squad_acces_form_to_list, "iac_type": form.iac_type.data, - "tf_version": form.tf_version.data.replace(" ",""), - "project_path": form.project_path.data.replace(" ",""), + "tf_version": form.tf_version.data.replace(" ", ""), + "project_path": form.project_path.data.replace(" ", ""), "description": form.description.data, "icon_path": request.form.get("icon_path"), } @@ -1042,7 +1038,6 @@ def delete_stack(view_mode, stack_name): else: flash(response["json"]["detail"], "error") - # Redirección basada en el parámetro 'view_mode' if view_mode == "table": return redirect(url_for("home_blueprint.route_template", template="stacks-list")) elif view_mode == "cards": @@ -1061,10 +1056,8 @@ def delete_stack(view_mode, stack_name): def resync_stack(view_mode, stack_id): try: token = decrypt(r.get(current_user.id)) - # Check if token not expired check_unauthorized_token(token) endpoint = f"stacks/{stack_id}" - # Get deploy data vars and set var for render response = request_url( verb="GET", uri=f"{endpoint}", headers={"Authorization": f"Bearer {token}"} ) @@ -1094,7 +1087,6 @@ def resync_stack(view_mode, stack_id): else: flash(response.get("json").get("detail"), "error") - # Redirección basada en el parámetro 'view_mode' if view_mode == "table": return redirect(url_for("home_blueprint.route_template", template="stacks-list")) elif view_mode == "cards": @@ -1113,54 +1105,45 @@ def resync_stack(view_mode, stack_id): def deploy_stack(stack_id): try: token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) form = DeployForm(request.form) - # Get data from aws accounts aws_response = request_url( verb="GET", - uri=f"accounts/aws/", + uri="accounts/aws/", headers={"Authorization": f"Bearer {token}"}, ) aws_content = aws_response.get("json") - # Get data from gcp accounts gcp_response = request_url( verb="GET", - uri=f"accounts/gcp/", + uri="accounts/gcp/", headers={"Authorization": f"Bearer {token}"}, ) gcp_content = gcp_response.get("json") - # Get data from azure accounts azure_response = request_url( verb="GET", - uri=f"accounts/azure/", + uri="accounts/azure/", headers={"Authorization": f"Bearer {token}"}, ) azure_content = azure_response.get("json") - # Get data from custom providers accounts custom_response = request_url( verb="GET", - uri=f"accounts/custom_providers/", + uri="accounts/custom_providers/", headers={"Authorization": f"Bearer {token}"}, ) custom_content = custom_response.get("json") - # Get data from stack stack = request_url( verb="GET", uri=f"stacks/{stack_id}", headers={"Authorization": f"Bearer {token}"}, ) stack_name = stack["json"]["stack_name"] - # Get vars from stack data_json = request_url( verb="GET", uri=f"variables/json?stack={stack_name}", headers={"Authorization": f"Bearer {token}"}, ) vars_json = data_json["json"] - # Push data vars to api for deploy if request.method == "POST": - # Define list for exclude vars in variables data form_vars = [ "csrf_token", "environment", @@ -1182,22 +1165,21 @@ def deploy_stack(stack_id): } variables = ast.literal_eval(json.dumps(convert_to_dict(data_raw))) data = { - "name": form.deploy_name.data.replace(" ",""), + "name": form.deploy_name.data.replace(" ", ""), "stack_name": stack["json"]["stack_name"], "start_time": form.start_time.data, "destroy_time": form.destroy_time.data, "squad": request.form.get("squad"), "environment": request.form.get("environment"), - "stack_branch": request.form.get("branch").replace(" ",""), - "tfvar_file": request.form.get("tfvar_file").replace(" ",""), - "project_path": request.form.get("project_path").replace(" ",""), + "stack_branch": request.form.get("branch").replace(" ", ""), + "tfvar_file": request.form.get("tfvar_file").replace(" ", ""), + "project_path": request.form.get("project_path").replace(" ", ""), "variables": variables, } - endpoint = f"plan" - if not "plan" in request.form.get("button"): - endpoint = f"deploy" + endpoint = "plan" + if "plan" not in request.form.get("button"): + endpoint = "deploy" - # Deploy response = request_url( verb="POST", uri=f"{endpoint}", @@ -1232,7 +1214,6 @@ def deploy_stack(stack_id): def get_task(task_id): try: token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) response = request_url( verb="GET", @@ -1261,11 +1242,10 @@ def get_task(task_id): def list_tasks(limit): try: token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) endpoint = f"tasks/all?limit={limit}" if limit == 0: - endpoint = f"tasks/all" + endpoint = "tasks/all" response = request_url( verb="GET", uri=f"{endpoint}", headers={"Authorization": f"Bearer {token}"} ) @@ -1286,7 +1266,6 @@ def list_tasks(limit): def list_task(task_id): try: token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) endpoint = f"tasks/id/{task_id}" response = request_url( @@ -1305,11 +1284,10 @@ def list_task(task_id): def list_activity(limit): try: token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) - endpoint = f"activity/all?limit={limit}" + endpoint = "activity/all?limit={limit}" if limit == 0: - endpoint = f"activity/all" + endpoint = "activity/all" response = request_url( verb="GET", uri=f"{endpoint}", headers={"Authorization": f"Bearer {token}"} ) @@ -1331,19 +1309,18 @@ def new_user(): try: form = UserForm(request.form) token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) if request.method == "POST": new_user: dict = { - "username": form.username.data.replace(" ",""), + "username": form.username.data.replace(" ", ""), "fullname": form.fullname.data, "password": form.password.data, - "email": form.email.data.replace(" ",""), + "email": form.email.data.replace(" ", ""), "squad": form.squad.data.split(","), "role": request.form.get("role").split(","), "is_active": form.is_active.data, } - endpoint = f"users/" + endpoint = "users/" response = request_url( verb="POST", uri=f"{endpoint}", @@ -1372,11 +1349,10 @@ def new_user(): def list_users(limit): try: token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) endpoint = f"users/?limit={limit}" if limit == 0: - endpoint = f"users/" + endpoint = "users/" response = request_url( verb="GET", uri=f"{endpoint}", headers={"Authorization": f"Bearer {token}"} ) @@ -1396,10 +1372,9 @@ def list_users(limit): def delete_user(user_name): try: token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) endpoint = f"users/{user_name}" - response = request_url( + request_url( verb="DELETE", uri=f"{endpoint}", headers={"Authorization": f"Bearer {token}"}, @@ -1416,9 +1391,7 @@ def edit_user(user_id): try: form = UserForm(request.form) token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) - # Get user info by id endpoint = f"users/{user_id}" response = request_url( verb="GET", uri=f"{endpoint}", headers={"Authorization": f"Bearer {token}"} @@ -1435,7 +1408,6 @@ def edit_user(user_id): "role": request.form.get("role").split(","), "is_active": request.form.get("is_active"), } - # Apply user change endpoint = f"users/{user_id}" response = request_url( verb="PATCH", @@ -1463,7 +1435,6 @@ def setting_user(): try: form = UserForm(request.form) token = decrypt(r.get(current_user.id)) - # Check if token no expired check_unauthorized_token(token) if request.method == "POST": user_data: dict = { @@ -1471,12 +1442,12 @@ def setting_user(): } response = request_url( verb="PATCH", - uri=f"users/reset/", + uri="users/reset/", headers={"Authorization": f"Bearer {token}"}, json=user_data, ) if response.get("status_code") == 200: - flash(f"Password Updated ") + flash("Password Updated ") else: flash(response.get("json").get("detail"), "error") return redirect( @@ -1503,18 +1474,17 @@ def new_aws_account(): try: form = AwsForm(request.form) token = decrypt(r.get(current_user.id)) - # 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") aws_account_request: 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(" ",""), - "role_arn": form.role_arn.data.replace(" ",""), + "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(" ", ""), + "role_arn": form.role_arn.data.replace(" ", ""), "extra_variables": dict(list(zip(key_list, value_list))) } @@ -1551,7 +1521,6 @@ 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( @@ -1562,12 +1531,12 @@ def edit_aws_account(account_id): key_list = request.values.getlist("sld_key") value_list = request.values.getlist("sld_value") 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(" ",""), + "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( @@ -1607,7 +1576,7 @@ def list_aws_account(): check_unauthorized_token(token) response = request_url( verb="GET", - uri=f"accounts/aws/", + uri="accounts/aws/", headers={"Authorization": f"Bearer {token}"}, ) content = response.get("json") @@ -1655,16 +1624,19 @@ def new_gcp_account(): # Check if token no expired check_unauthorized_token(token) if request.method == "POST": - new_user: dict = { - "squad": form.squad.data.replace(" ",""), - "environment": form.environment.data.replace(" ",""), + key_list = request.values.getlist("sld_key") + value_list = request.values.getlist("sld_value") + new_account: dict = { + "squad": form.squad.data.replace(" ", ""), + "environment": form.environment.data.replace(" ", ""), "gcloud_keyfile_json": ast.literal_eval(form.gcloud_keyfile_json.data), + "extra_variables": dict(list(zip(key_list, value_list))), } response = request_url( verb="POST", uri="accounts/gcp/", headers={"Authorization": f"Bearer {token}"}, - json=new_user, + json=new_account, ) if response.get("status_code") == 200: flash( @@ -1686,6 +1658,57 @@ def new_gcp_account(): return redirect(url_for("base_blueprint.logout")) +@blueprint.route("/gcp-edit", methods=["GET", "POST"], defaults={"account_id": None}) +@blueprint.route("/gcp-edit/Edit account by squad and environment
+Edit account by squad and environment
+Id | Stack | diff --git a/sld-dashboard/app/home/templates/gcp-list.html b/sld-dashboard/app/home/templates/gcp-list.html index 11972789..3e9d8787 100644 --- a/sld-dashboard/app/home/templates/gcp-list.html +++ b/sld-dashboard/app/home/templates/gcp-list.html @@ -157,4 +157,5 @@
---|