From d87213705b7ce6f5cb9118a38edd81432f4f8267 Mon Sep 17 00:00:00 2001 From: Matthew Jones Date: Mon, 18 Apr 2016 15:57:31 -0400 Subject: [PATCH] Adjust job launch blocking logic Previously a job template would always block another job template launch regardless of the details of the job template. We now restrict that blocking logic to only block in the case that the job template was launched with the same inventory. We keep the exclusion where if the launch type is 'callback' and the limits differ then they won't be blocked --- awx/main/models/jobs.py | 13 ++++++------- awx/main/tests/functional/conftest.py | 11 +++++++++++ awx/main/tests/functional/test_jobs.py | 24 ++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 awx/main/tests/functional/test_jobs.py diff --git a/awx/main/models/jobs.py b/awx/main/models/jobs.py index dcac5e4a34..83d507615d 100644 --- a/awx/main/models/jobs.py +++ b/awx/main/models/jobs.py @@ -531,14 +531,13 @@ class Job(UnifiedJob, JobOptions): def is_blocked_by(self, obj): from awx.main.models import InventoryUpdate, ProjectUpdate if type(obj) == Job: - if obj.job_template is not None and obj.job_template == self.job_template: - if obj.launch_type == 'callback' and self.launch_type == 'callback': - if obj.limit != self.limit: - # NOTE: This is overriden by api/views.py.JobTemplateCallback.post() check - # which limits job runs on a JT to one per host in a callback scenario - # I'm leaving this here in case we change that + if obj.job_template is not None and obj.inventory is not None: + if obj.job_template == self.job_template and \ + obj.inventory == self.inventory: + if obj.launch_type == 'callback' and self.launch_type == 'callback' and \ + obj.limit != self.limit: return False - return True + return True return False if type(obj) == InventoryUpdate: if self.inventory == obj.inventory_source.inventory: diff --git a/awx/main/tests/functional/conftest.py b/awx/main/tests/functional/conftest.py index e187d8cd03..97e31c3269 100644 --- a/awx/main/tests/functional/conftest.py +++ b/awx/main/tests/functional/conftest.py @@ -28,6 +28,7 @@ from awx.main.models.credential import Credential from awx.main.models.jobs import JobTemplate from awx.main.models.inventory import ( Group, + Inventory, ) from awx.main.models.organization import ( Organization, @@ -175,6 +176,16 @@ def machine_credential(): def inventory(organization): return organization.inventories.create(name="test-inv") +@pytest.fixture +def inventory_factory(organization): + def factory(name, org=organization): + try: + inv = Inventory.objects.get(name=name, organization=org) + except Inventory.DoesNotExist: + inv = Inventory.objects.create(name=name, organization=org) + return inv + return factory + @pytest.fixture def label(organization): return organization.labels.create(name="test-label", description="test-label-desc") diff --git a/awx/main/tests/functional/test_jobs.py b/awx/main/tests/functional/test_jobs.py new file mode 100644 index 0000000000..aefb4e8bb7 --- /dev/null +++ b/awx/main/tests/functional/test_jobs.py @@ -0,0 +1,24 @@ +from awx.main.models import Job + +import pytest + +@pytest.mark.django_db +def test_job_blocking(get, post, job_template, inventory, inventory_factory): + j1 = Job.objects.create(job_template=job_template, + inventory=inventory) + j2 = Job.objects.create(job_template=job_template, + inventory=inventory) + assert j1.is_blocked_by(j2) + j2.inventory = inventory_factory(name='test-different-inventory') + assert not j1.is_blocked_by(j2) + j_callback_1 = Job.objects.create(job_template=job_template, + inventory=inventory, + launch_type='callback', + limit='a') + j_callback_2 = Job.objects.create(job_template=job_template, + inventory=inventory, + launch_type='callback', + limit='a') + assert j_callback_1.is_blocked_by(j_callback_2) + j_callback_2.limit = 'b' + assert not j_callback_1.is_blocked_by(j_callback_2)