The beat schedule is set to once per minute for each of the three environment provisioning tasks. Adding a beat schedule surfaced two problems that are addressed here with the following changes: - Commit the SQLALchemy session in order to release the environment lock. Otherwise the change to the `claimed_until` field is not persisted. - Set `none_as_null` on the JSOB fields on the `Environment`. This avoids problems with querying on Postgres JSON fields that are empty. This also adds a small change to the development command for the Celery worker. Multiple child processes were executing the beat jobs, which lead to exceptions for environment locks and confusing log output. This contrains the dev command to a single Celery worker.
83 lines
2.3 KiB
Python
83 lines
2.3 KiB
Python
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 import Base
|
|
from atst.models.types import Id
|
|
from atst.models import mixins
|
|
|
|
|
|
class Environment(
|
|
Base, mixins.TimestampsMixin, mixins.AuditableMixin, mixins.DeletableMixin
|
|
):
|
|
__tablename__ = "environments"
|
|
|
|
id = 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))
|
|
baseline_info = Column(JSONB(none_as_null=True))
|
|
|
|
claimed_until = Column(TIMESTAMP(timezone=True))
|
|
|
|
job_failures = relationship("EnvironmentJobFailure")
|
|
|
|
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
|
|
or self.baseline_info is None
|
|
):
|
|
return self.ProvisioningStatus.PENDING
|
|
else:
|
|
return self.ProvisioningStatus.COMPLETED
|
|
|
|
def __repr__(self):
|
|
return "<Environment(name='{}', num_users='{}', application='{}', portfolio='{}', id='{}')>".format(
|
|
self.name,
|
|
self.num_users,
|
|
self.application.name,
|
|
self.application.portfolio.name,
|
|
self.id,
|
|
)
|
|
|
|
@property
|
|
def history(self):
|
|
return self.get_changes()
|