atst/atst/models/environment_role.py
dandds 7010bdb09c Record job failures with application context.
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.
2019-09-09 14:54:46 -04:00

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,
)