from sqlalchemy import Column, ForeignKey, String, TIMESTAMP from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import JSONB from enum import Enum from atst.models.base import Base import atst.models.mixins as mixins import atst.models.types as types class Environment( Base, mixins.TimestampsMixin, mixins.AuditableMixin, mixins.DeletableMixin ): __tablename__ = "environments" id = types.Id() name = Column(String, nullable=False) application_id = Column(ForeignKey("applications.id"), nullable=False) application = relationship("Application") # User user.id as the foreign key here beacuse the Environment creator may # not have an application role. We may need to revisit this if we receive any # requirements around tracking an environment's custodian. creator_id = Column(ForeignKey("users.id"), nullable=False) creator = relationship("User") cloud_id = Column(String) root_user_info = Column(JSONB(none_as_null=True)) claimed_until = Column(TIMESTAMP(timezone=True)) job_failures = relationship("EnvironmentJobFailure") roles = relationship( "EnvironmentRole", back_populates="environment", primaryjoin="and_(EnvironmentRole.environment_id == Environment.id, EnvironmentRole.deleted == False)", ) class ProvisioningStatus(Enum): PENDING = "pending" COMPLETED = "completed" @property def users(self): return {r.application_role.user for r in self.roles} @property def num_users(self): return len(self.users) @property def displayname(self): return self.name @property def portfolio(self): return self.application.portfolio @property def portfolio_id(self): return self.application.portfolio_id @property def provisioning_status(self) -> ProvisioningStatus: if self.cloud_id is None or self.root_user_info is None: return self.ProvisioningStatus.PENDING else: return self.ProvisioningStatus.COMPLETED @property def is_pending(self): return self.provisioning_status == self.ProvisioningStatus.PENDING def __repr__(self): return "".format( self.name, self.num_users, self.application.name, self.application.portfolio.name, self.id, ) @property def history(self): return self.get_changes() @property def csp_credentials(self): return ( self.root_user_info.get("credentials") if self.root_user_info is not None else None )