AT-AT needs to be able to track which user tasks failed and why. To accomplish this we: - Enabled Celery's results backend, which logs task results to a data store; a Postgres table, in our case. (https://docs.celeryproject.org/en/latest/userguide/tasks.html#result-backends) - Created tables to track the relationships between the relevant models (Environment, EnvironmentRole) and their task failures. - Added an `on_failure` hook that tasks can use. The hook will add records to the job failure tables. Now a resource like an `Environment` has access to it task failures through the corresponding failure table. Notes: - It might prove useful to use a real foreign key to the Celery results table eventually. I did not do it here because it requires that we explicitly store the Celery results table schema as a migration and add a model for it. In the current implementation, AT-AT can be agnostic about where the results live. - We store the task results indefinitely, so it is important to specify tasks for which we do not care about the results (like `send_mail`) via the `ignore_result` kwarg.
78 lines
2.3 KiB
Python
78 lines
2.3 KiB
Python
from enum import Enum
|
|
from sqlalchemy import Index, ForeignKey, Column, String
|
|
from sqlalchemy.dialects.postgresql import UUID
|
|
from sqlalchemy.orm import relationship
|
|
|
|
from atst.models import Base, types, mixins
|
|
|
|
|
|
class CSPRole(Enum):
|
|
BASIC_ACCESS = "Basic Access"
|
|
NETWORK_ADMIN = "Network Admin"
|
|
BUSINESS_READ = "Business Read-only"
|
|
TECHNICAL_READ = "Technical Read-only"
|
|
|
|
|
|
class EnvironmentRole(
|
|
Base, mixins.TimestampsMixin, mixins.AuditableMixin, mixins.DeletableMixin
|
|
):
|
|
__tablename__ = "environment_roles"
|
|
|
|
id = types.Id()
|
|
environment_id = Column(
|
|
UUID(as_uuid=True), ForeignKey("environments.id"), nullable=False
|
|
)
|
|
environment = relationship("Environment", backref="roles")
|
|
|
|
role = Column(String())
|
|
|
|
application_role_id = Column(
|
|
UUID(as_uuid=True), ForeignKey("application_roles.id"), nullable=False
|
|
)
|
|
application_role = relationship("ApplicationRole")
|
|
|
|
job_failures = relationship("EnvironmentRoleJobFailure")
|
|
|
|
def __repr__(self):
|
|
return "<EnvironmentRole(role='{}', user='{}', environment='{}', id='{}')>".format(
|
|
self.role, self.application_role.user_name, self.environment.name, self.id
|
|
)
|
|
|
|
@property
|
|
def history(self):
|
|
return self.get_changes()
|
|
|
|
@property
|
|
def portfolio_id(self):
|
|
return self.environment.application.portfolio_id
|
|
|
|
@property
|
|
def application_id(self):
|
|
return self.environment.application_id
|
|
|
|
@property
|
|
def displayname(self):
|
|
return self.role
|
|
|
|
@property
|
|
def event_details(self):
|
|
return {
|
|
"updated_user_name": self.application_role.user_name,
|
|
"updated_application_role_id": str(self.application_role_id),
|
|
"role": self.role,
|
|
"environment": self.environment.displayname,
|
|
"environment_id": str(self.environment_id),
|
|
"application": self.environment.application.name,
|
|
"application_id": str(self.environment.application_id),
|
|
"portfolio": self.environment.application.portfolio.name,
|
|
"portfolio_id": str(self.environment.application.portfolio.id),
|
|
}
|
|
|
|
|
|
Index(
|
|
"environments_role_user_environment",
|
|
EnvironmentRole.application_role_id,
|
|
EnvironmentRole.environment_id,
|
|
unique=True,
|
|
)
|