Skip to content
This repository has been archived by the owner on Nov 21, 2024. It is now read-only.

Commit

Permalink
adding functionality for restart workflows
Browse files Browse the repository at this point in the history
  • Loading branch information
DonHaul committed Jul 10, 2024
1 parent 9772db3 commit b97e2ac
Show file tree
Hide file tree
Showing 13 changed files with 519 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .envs/docker/.django
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ OPENSEARCH_HOST=opensearch:9200
OPENSEARCH_INDEX_PREFIX=backoffice-backend-local

# Airflow
AIRFLOW_BASE_URL=http://localhost:8080
AIRFLOW_BASE_URL=http://host.docker.internal:8082
AIRFLOW_TOKEN=CHANGE_ME
15 changes: 15 additions & 0 deletions backoffice/workflows/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,35 @@
from django_elasticsearch_dsl_drf.viewsets import BaseDocumentViewSet
from rest_framework import status, viewsets
from rest_framework.decorators import action
<<<<<<< HEAD
=======
from rest_framework.exceptions import APIException
>>>>>>> d1464d4 (wf: restart workflows)
from rest_framework.response import Response

from backoffice.utils.pagination import OSStandardResultsSetPagination
from backoffice.workflows import airflow_utils
from backoffice.workflows.documents import WorkflowDocument
from backoffice.workflows.models import Workflow, WorkflowTicket

<<<<<<< HEAD
from ..constants import WORKFLOW_DAG, ResolutionDags
from .serializers import (
AuthorResolutionSerializer,
WorkflowDocumentSerializer,
WorkflowSerializer,
WorkflowTicketSerializer,
)
=======
from ..constants import AUTHOR_DAGS, WORKFLOW_TYPES
from .serializers import WorkflowDocumentSerializer, WorkflowSerializer, WorkflowTicketSerializer
>>>>>>> d1464d4 (wf: restart workflows)


class ValidationError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = "Input Data Unrecognized"
default_code = "invalid_data"


class WorkflowViewSet(viewsets.ModelViewSet):
Expand Down
19 changes: 19 additions & 0 deletions backoffice/workflows/migrations/0006_workflow_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.6 on 2024-05-22 15:50

from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):
dependencies = [
("workflows", "0005_workflowticket_ticket_type_alter_workflow_status"),
]

operations = [
migrations.AddField(
model_name="workflow",
name="url",
field=models.URLField(default=django.utils.timezone.now),
preserve_default=False,
),
]
23 changes: 23 additions & 0 deletions backoffice/workflows/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django_elasticsearch_dsl_drf.serializers import DocumentSerializer
from rest_framework import serializers

from backoffice.workflows.documents import WorkflowDocument
from backoffice.workflows.models import Workflow, WorkflowTicket


class WorkflowSerializer(serializers.ModelSerializer):
class Meta:
model = Workflow
fields = "__all__"


class WorkflowTicketSerializer(serializers.ModelSerializer):
class Meta:
model = WorkflowTicket
fields = "__all__"


class WorkflowDocumentSerializer(DocumentSerializer):
class Meta:
document = WorkflowDocument
fields = "__all__"
98 changes: 98 additions & 0 deletions backoffice/workflows/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from django.apps import apps
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.urls import reverse
from rest_framework.test import APIClient
from rest_framework import status
from .models import Workflow, WorkflowTicket
from django.contrib.auth import get_user_model
import vcr
from django.urls import get_resolver

User = get_user_model()
# Workflow = apps.get_model(app_label="workflows", model_name="Workflow")
# WorkflowTicket = apps.get_model(app_label="workflows", model_name="WorkflowTicket")

def list_all_view_names():
resolver = get_resolver(None)
all_view_names = set()

# Iterate through all URL patterns
for pattern in resolver.url_patterns:
# Recursively traverse the resolver tree to find view names
_list_all_view_names(pattern, all_view_names)

return all_view_names

def _list_all_view_names(pattern, all_view_names):
# If the pattern has a name, add it to the set of view names
if hasattr(pattern, 'name') and pattern.name is not None:
all_view_names.add(pattern.name)

# Recursively traverse the resolver tree for included URL patterns
if hasattr(pattern, 'url_patterns'):
for sub_pattern in pattern.url_patterns:
_list_all_view_names(sub_pattern, all_view_names)



class FetchWorkflowErrorTestCase(TestCase):

fixtures = ["backoffice/fixtures/groups.json"]

def setUp(self):
# Create some test data
self.api_client = APIClient()

self.admin_group = Group.objects.get(name="admin")
self.admin = User.objects.create_user(email="[email protected]", password="12345")
self.admin.groups.add(self.admin_group)

self.api_client.force_authenticate(user=self.admin)

self.workflow = Workflow.objects.create(url='https://unusedfield.com',data={},core=False,is_update=False)
self.ticket1 = WorkflowTicket.objects.create(ticket_id='ticket1',workflow_id=self.workflow)
self.ticket2 = WorkflowTicket.objects.create(ticket_id='ticket2',workflow_id=self.workflow)

def test_fetchworkflow_tickets(self):


url = reverse('workflow_tickets_list', kwargs={'workflow_id': self.workflow.id})

self.api_client.force_authenticate(user=self.admin)
response = self.api_client.get(url)

# Check that the response is 200 OK
self.assertEqual(response.status_code, status.HTTP_200_OK)
# Check the number of tickets returned
self.assertEqual(len(response.data), 2)
# Check the content of the response
self.assertEqual(response.data[0]['ticket_id'], self.ticket1.ticket_id)
self.assertEqual(response.data[1]['ticket_id'], self.ticket2.ticket_id)


@vcr.use_cassette('backoffice/workflows/tests/cassettes/test_restart_full_dagrun.yaml')
def test_restart_full_dagrun(self):

url = reverse('workflow_restart',kwargs={'workflow_id': '0092dfb8-e754-46c2-b2f7-c4d116509107',
'dag_id':"author_create_initialization_dag"})

response = self.api_client.post(url)
self.assertEqual(response.status_code, 200)

@vcr.use_cassette('backoffice/workflows/tests/cassettes/test_restart_a_task.yaml')
def test_restart_a_task(self):
url = reverse('workflow_restart',kwargs={'workflow_id': '0092dfb8-e754-46c2-b2f7-c4d116509107',
'dag_id':"author_create_initialization_dag"})

response = self.api_client.post(url,json={'task_ids':["set_workflow_status_to_running"]})
self.assertEqual(response.status_code, 200)

@vcr.use_cassette('backoffice/workflows/tests/cassettes/test_restart_with_params.yaml')
def test_restart_with_params(self):
url = reverse('workflow_restart',kwargs={'workflow_id': '0092dfb8-e754-46c2-b2f7-c4d116509107',
'dag_id':"author_create_initialization_dag"})

response = self.api_client.post(url,json={'params':{'workflow_id': '0092dfb8-e754-46c2-b2f7-c4d116509107'}})
self.assertEqual(response.status_code, 200)
49 changes: 49 additions & 0 deletions backoffice/workflows/tests/cassettes/test_restart_a_task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
interactions:
- request:
body: '{"dry_run": false, "dag_run_id": "0092dfb8-e754-46c2-b2f7-c4d116509107",
"reset_dag_runs": false, "only_failed": false}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Basic YWlyZmxvdzphaXJmbG93
Connection:
- keep-alive
Content-Length:
- '119'
Content-Type:
- application/json
User-Agent:
- python-requests/2.31.0
method: POST
uri: http://airflow-webserver:8080/api/v1/dags/author_create_initialization_dag/clearTaskInstances
response:
body:
string: "{\n \"task_instances\": [\n {\n \"dag_id\": \"author_create_initialization_dag\",\n
\ \"dag_run_id\": \"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\":
\"2024-05-31T11:43:48.381010+00:00\",\n \"task_id\": \"create_author_create_user_ticket\"\n
\ },\n {\n \"dag_id\": \"author_create_initialization_dag\",\n \"dag_run_id\":
\"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\": \"2024-05-31T11:43:48.381010+00:00\",\n
\ \"task_id\": \"set_author_create_workflow_status_to_approval\"\n },\n
\ {\n \"dag_id\": \"author_create_initialization_dag\",\n \"dag_run_id\":
\"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\": \"2024-05-31T11:43:48.381010+00:00\",\n
\ \"task_id\": \"set_workflow_status_to_running\"\n }\n ]\n}\n"
headers:
Connection:
- close
Content-Length:
- '751'
Content-Type:
- application/json
Date:
- Fri, 31 May 2024 15:41:09 GMT
Server:
- gunicorn
X-Robots-Tag:
- noindex, nofollow
status:
code: 200
message: OK
version: 1
49 changes: 49 additions & 0 deletions backoffice/workflows/tests/cassettes/test_restart_full_dagrun.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
interactions:
- request:
body: '{"dry_run": false, "dag_run_id": "0092dfb8-e754-46c2-b2f7-c4d116509107",
"reset_dag_runs": false, "only_failed": false}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Basic YWlyZmxvdzphaXJmbG93
Connection:
- keep-alive
Content-Length:
- '119'
Content-Type:
- application/json
User-Agent:
- python-requests/2.31.0
method: POST
uri: http://airflow-webserver:8080/api/v1/dags/author_create_initialization_dag/clearTaskInstances
response:
body:
string: "{\n \"task_instances\": [\n {\n \"dag_id\": \"author_create_initialization_dag\",\n
\ \"dag_run_id\": \"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\":
\"2024-05-31T11:43:48.381010+00:00\",\n \"task_id\": \"create_author_create_user_ticket\"\n
\ },\n {\n \"dag_id\": \"author_create_initialization_dag\",\n \"dag_run_id\":
\"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\": \"2024-05-31T11:43:48.381010+00:00\",\n
\ \"task_id\": \"set_author_create_workflow_status_to_approval\"\n },\n
\ {\n \"dag_id\": \"author_create_initialization_dag\",\n \"dag_run_id\":
\"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\": \"2024-05-31T11:43:48.381010+00:00\",\n
\ \"task_id\": \"set_workflow_status_to_running\"\n }\n ]\n}\n"
headers:
Connection:
- close
Content-Length:
- '751'
Content-Type:
- application/json
Date:
- Fri, 31 May 2024 15:42:08 GMT
Server:
- gunicorn
X-Robots-Tag:
- noindex, nofollow
status:
code: 200
message: OK
version: 1
49 changes: 49 additions & 0 deletions backoffice/workflows/tests/cassettes/test_restart_with_params.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
interactions:
- request:
body: '{"dry_run": false, "dag_run_id": "0092dfb8-e754-46c2-b2f7-c4d116509107",
"reset_dag_runs": false, "only_failed": false}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Basic YWlyZmxvdzphaXJmbG93
Connection:
- keep-alive
Content-Length:
- '119'
Content-Type:
- application/json
User-Agent:
- python-requests/2.31.0
method: POST
uri: http://airflow-webserver:8080/api/v1/dags/author_create_initialization_dag/clearTaskInstances
response:
body:
string: "{\n \"task_instances\": [\n {\n \"dag_id\": \"author_create_initialization_dag\",\n
\ \"dag_run_id\": \"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\":
\"2024-05-31T11:43:48.381010+00:00\",\n \"task_id\": \"create_author_create_user_ticket\"\n
\ },\n {\n \"dag_id\": \"author_create_initialization_dag\",\n \"dag_run_id\":
\"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\": \"2024-05-31T11:43:48.381010+00:00\",\n
\ \"task_id\": \"set_author_create_workflow_status_to_approval\"\n },\n
\ {\n \"dag_id\": \"author_create_initialization_dag\",\n \"dag_run_id\":
\"0092dfb8-e754-46c2-b2f7-c4d116509107\",\n \"execution_date\": \"2024-05-31T11:43:48.381010+00:00\",\n
\ \"task_id\": \"set_workflow_status_to_running\"\n }\n ]\n}\n"
headers:
Connection:
- close
Content-Length:
- '751'
Content-Type:
- application/json
Date:
- Fri, 31 May 2024 15:41:40 GMT
Server:
- gunicorn
X-Robots-Tag:
- noindex, nofollow
status:
code: 200
message: OK
version: 1
Loading

0 comments on commit b97e2ac

Please sign in to comment.