diff --git a/AUTHORS.md b/AUTHORS.md index 38751a1..3da0059 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,6 +2,7 @@ The list of contributors in alphabetical order: +- [Alp Tuna](https://orcid.org/0009-0001-1915-3993) - [Audrius Mecionis](https://orcid.org/0000-0002-3759-1663) - [Camila Diaz](https://orcid.org/0000-0001-5543-797X) - [Daan Rosendal](https://orcid.org/0000-0002-3447-9000) diff --git a/reana_db/alembic/versions/20250117_1005_3d0994430da7_add_service_tables.py b/reana_db/alembic/versions/20250117_1005_3d0994430da7_add_service_tables.py new file mode 100644 index 0000000..457fdeb --- /dev/null +++ b/reana_db/alembic/versions/20250117_1005_3d0994430da7_add_service_tables.py @@ -0,0 +1,76 @@ +"""Add service tables. + +Revision ID: 3d0994430da7 +Revises: 2e82f33ee37d +Create Date: 2025-01-17 10:05:48.699316 + +""" + +import sqlalchemy_utils +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision = "3d0994430da7" +down_revision = "2e82f33ee37d" +branch_labels = None +depends_on = None + + +def upgrade(): + """Upgrade to 3d0994430da7 revision.""" + op.create_table( + "service", + sa.Column("id_", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), + sa.Column("name", sa.String(length=255), nullable=True), + sa.Column("uri", sa.Text(), nullable=True), + sa.Column( + "status", + sa.Enum( + "created", + "running", + "finished", + "failed", + "deleted", + "stopped", + "queued", + "pending", + name="servicestatus", + ), + nullable=False, + ), + sa.Column("owner_id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=True), + sa.Column("type_", sa.Enum("dask", name="servicetype"), nullable=False), + sa.ForeignKeyConstraint( + ["owner_id"], ["__reana.user_.id_"], name=op.f("fk_service_owner_id_user_") + ), + sa.PrimaryKeyConstraint("id_", name=op.f("pk_service")), + sa.UniqueConstraint("name", "uri", name=op.f("uq_service_name")), + schema="__reana", + ) + op.create_table( + "workflow_service", + sa.Column("workflow_id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=True), + sa.Column("service_id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), + sa.ForeignKeyConstraint( + ["service_id"], + ["__reana.service.id_"], + name=op.f("fk_workflow_service_service_id_service"), + ), + sa.ForeignKeyConstraint( + ["workflow_id"], + ["__reana.workflow.id_"], + name=op.f("fk_workflow_service_workflow_id_workflow"), + ), + sa.PrimaryKeyConstraint("service_id", name=op.f("pk_workflow_service")), + schema="__reana", + ) + + +def downgrade(): + """Downgrade to 2e82f33ee37d revision.""" + op.drop_table("workflow_service", schema="__reana") + op.drop_table("service", schema="__reana") + sa.Enum(name="servicestatus").drop(op.get_bind()) + sa.Enum(name="servicetype").drop(op.get_bind()) diff --git a/reana_db/models.py b/reana_db/models.py index 4097b5b..8bba0cd 100644 --- a/reana_db/models.py +++ b/reana_db/models.py @@ -470,6 +470,63 @@ def __repr__(self): return "" % self.name +class WorkflowService(Base): + """Workflow Service table.""" + + __tablename__ = "workflow_service" + __table_args__ = {"schema": "__reana"} + + workflow_id = Column(UUIDType, ForeignKey("__reana.workflow.id_"), nullable=True) + service_id = Column(UUIDType, ForeignKey("__reana.service.id_"), primary_key=True) + + def __repr__(self): + """Workflow Service string representation.""" + return f"" + + +class ServiceStatus(CleanUpDependingOnStatusMixin, enum.Enum): + """Enumeration of possible run statuses.""" + + created = 0 + running = 1 + finished = 2 + failed = 3 + deleted = 4 + stopped = 5 + queued = 6 + pending = 7 + + +class ServiceType(enum.Enum): + """Enumeration of service types.""" + + dask = 0 + + +class Service(Base): + """Service table.""" + + __tablename__ = "service" + id_ = Column(UUIDType, primary_key=True, default=generate_uuid) + name = Column(String(255)) + uri = Column(Text) # uri to access the service + status = Column(Enum(ServiceStatus), nullable=False, default=ServiceStatus.created) + owner_id = Column(UUIDType, ForeignKey("__reana.user_.id_")) + type_ = Column( + Enum(ServiceType), + nullable=False, + ) + + __table_args__ = ( + UniqueConstraint("name", "uri"), + {"schema": "__reana"}, + ) + + def __repr__(self): + """Service string representation.""" + return f"" + + class Workflow(Base, Timestamp, QuotaBase): """Workflow table.""" @@ -510,6 +567,13 @@ class Workflow(Base, Timestamp, QuotaBase): backref="workflow", cascade="all, delete", ) + services = relationship( + "Service", + secondary="__reana.workflow_service", + lazy="dynamic", + backref="workflow", + cascade="all, delete", + ) retention_rules = relationship( "WorkspaceRetentionRule", backref="workflow", lazy="dynamic" ) diff --git a/reana_db/version.py b/reana_db/version.py index 1c8b27b..06eb7e6 100644 --- a/reana_db/version.py +++ b/reana_db/version.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # This file is part of REANA. -# Copyright (C) 2018, 2019, 2020, 2021, 2022, 2023, 2024 CERN. +# Copyright (C) 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025 CERN. # # REANA is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. @@ -14,4 +14,4 @@ from __future__ import absolute_import, print_function -__version__ = "0.95.0a4" +__version__ = "0.95.0a5"