mirror of
https://github.com/ansible/awx.git
synced 2026-02-21 05:00:07 -03:30
switch to UJT method of creating new jobs
This commit is contained in:
@@ -124,6 +124,14 @@ class WorkflowNodeBase(CreatedModifiedModel):
|
|||||||
data['missing'] = missing_dict
|
data['missing'] = missing_dict
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_workflow_job_field_names(cls):
|
||||||
|
'''
|
||||||
|
Return field names that should be copied from template node to job node.
|
||||||
|
'''
|
||||||
|
return ['workflow_job', 'unified_job_template',
|
||||||
|
'inventory', 'credential', 'char_prompts']
|
||||||
|
|
||||||
class WorkflowJobTemplateNode(WorkflowNodeBase):
|
class WorkflowJobTemplateNode(WorkflowNodeBase):
|
||||||
# TODO: Ensure the API forces workflow_job_template being set
|
# TODO: Ensure the API forces workflow_job_template being set
|
||||||
workflow_job_template = models.ForeignKey(
|
workflow_job_template = models.ForeignKey(
|
||||||
@@ -138,6 +146,18 @@ class WorkflowJobTemplateNode(WorkflowNodeBase):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('api:workflow_job_template_node_detail', args=(self.pk,))
|
return reverse('api:workflow_job_template_node_detail', args=(self.pk,))
|
||||||
|
|
||||||
|
def create_workflow_job_node(self, **kwargs):
|
||||||
|
'''
|
||||||
|
Create a new workflow job node based on this workflow node.
|
||||||
|
'''
|
||||||
|
create_kwargs = {}
|
||||||
|
for field_name in self._get_workflow_job_field_names():
|
||||||
|
if field_name in kwargs:
|
||||||
|
create_kwargs[field_name] = kwargs[field_name]
|
||||||
|
elif hasattr(self, field_name):
|
||||||
|
create_kwargs[field_name] = getattr(self, field_name)
|
||||||
|
return WorkflowJobNode.objects.create(**create_kwargs)
|
||||||
|
|
||||||
class WorkflowJobNode(WorkflowNodeBase):
|
class WorkflowJobNode(WorkflowNodeBase):
|
||||||
job = models.ForeignKey(
|
job = models.ForeignKey(
|
||||||
'UnifiedJob',
|
'UnifiedJob',
|
||||||
@@ -278,11 +298,7 @@ class WorkflowJobInheritNodesMixin(object):
|
|||||||
Create a WorkflowJobNode for each WorkflowJobTemplateNode
|
Create a WorkflowJobNode for each WorkflowJobTemplateNode
|
||||||
'''
|
'''
|
||||||
def _create_workflow_job_nodes(self, old_nodes):
|
def _create_workflow_job_nodes(self, old_nodes):
|
||||||
return [WorkflowJobNode.objects.create(
|
return [old_node.create_workflow_job_node(workflow_job=self) for old_node in old_nodes]
|
||||||
workflow_job=self, unified_job_template=old_node.unified_job_template,
|
|
||||||
inventory=old_node.inventory, credential=old_node.credential,
|
|
||||||
char_prompts=old_node.char_prompts
|
|
||||||
) for old_node in old_nodes]
|
|
||||||
|
|
||||||
def _map_workflow_job_nodes(self, old_nodes, new_nodes):
|
def _map_workflow_job_nodes(self, old_nodes, new_nodes):
|
||||||
node_ids_map = {}
|
node_ids_map = {}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import pytest
|
|||||||
from awx.main.models.jobs import JobTemplate
|
from awx.main.models.jobs import JobTemplate
|
||||||
from awx.main.models import Inventory, Credential, Project
|
from awx.main.models import Inventory, Credential, Project
|
||||||
from awx.main.models.workflow import (
|
from awx.main.models.workflow import (
|
||||||
WorkflowJobTemplateNode, WorkflowJobInheritNodesMixin,
|
WorkflowJobTemplate, WorkflowJobTemplateNode, WorkflowJobInheritNodesMixin,
|
||||||
WorkflowJob, WorkflowJobNode
|
WorkflowJob, WorkflowJobNode
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,15 +18,13 @@ class TestWorkflowJobInheritNodesMixin():
|
|||||||
return [WorkflowJobTemplateNode(unified_job_template=job_templates[i]) for i in range(0, 10)]
|
return [WorkflowJobTemplateNode(unified_job_template=job_templates[i]) for i in range(0, 10)]
|
||||||
|
|
||||||
def test__create_workflow_job_nodes(self, mocker, job_template_nodes):
|
def test__create_workflow_job_nodes(self, mocker, job_template_nodes):
|
||||||
workflow_job_node_create = mocker.patch('awx.main.models.WorkflowJobNode.objects.create')
|
workflow_job_node_create = mocker.patch('awx.main.models.WorkflowJobTemplateNode.create_workflow_job_node')
|
||||||
|
|
||||||
mixin = WorkflowJobInheritNodesMixin()
|
mixin = WorkflowJobInheritNodesMixin()
|
||||||
mixin._create_workflow_job_nodes(job_template_nodes)
|
mixin._create_workflow_job_nodes(job_template_nodes)
|
||||||
|
|
||||||
for job_template_node in job_template_nodes:
|
for job_template_node in job_template_nodes:
|
||||||
workflow_job_node_create.assert_any_call(
|
workflow_job_node_create.assert_any_call(workflow_job=mixin)
|
||||||
workflow_job=mixin, unified_job_template=job_template_node.unified_job_template,
|
|
||||||
credential=None, inventory=None, char_prompts={})
|
|
||||||
|
|
||||||
class TestMapWorkflowJobNodes():
|
class TestMapWorkflowJobNodes():
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -89,14 +87,18 @@ def workflow_job_unit():
|
|||||||
return WorkflowJob(name='workflow', status='new')
|
return WorkflowJob(name='workflow', status='new')
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def node_no_prompts(workflow_job_unit, job_template_factory):
|
def workflow_job_template_unit():
|
||||||
|
return WorkflowJobTemplate(name='workflow')
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def jt_ask(job_template_factory):
|
||||||
# note: factory sets ask_xxxx_on_launch to true for inventory & credential
|
# note: factory sets ask_xxxx_on_launch to true for inventory & credential
|
||||||
jt = job_template_factory(name='example-jt', persisted=False).job_template
|
jt = job_template_factory(name='example-jt', persisted=False).job_template
|
||||||
jt.ask_job_type_on_launch = True
|
jt.ask_job_type_on_launch = True
|
||||||
jt.ask_skip_tags_on_launch = True
|
jt.ask_skip_tags_on_launch = True
|
||||||
jt.ask_limit_on_launch = True
|
jt.ask_limit_on_launch = True
|
||||||
jt.ask_tags_on_launch = True
|
jt.ask_tags_on_launch = True
|
||||||
return WorkflowJobNode(workflow_job=workflow_job_unit, unified_job_template=jt)
|
return jt
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def project_unit():
|
def project_unit():
|
||||||
@@ -105,13 +107,49 @@ def project_unit():
|
|||||||
example_prompts = dict(job_type='check', job_tags='quack', limit='duck', skip_tags='oink')
|
example_prompts = dict(job_type='check', job_tags='quack', limit='duck', skip_tags='oink')
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def node_with_prompts(node_no_prompts):
|
def job_node_no_prompts(workflow_job_unit, jt_ask):
|
||||||
node_no_prompts.char_prompts = example_prompts
|
return WorkflowJobNode(workflow_job=workflow_job_unit, unified_job_template=jt_ask)
|
||||||
inv = Inventory(name='example-inv')
|
|
||||||
cred = Credential(name='example-inv', kind='ssh', username='asdf', password='asdf')
|
@pytest.fixture
|
||||||
node_no_prompts.inventory = inv
|
def job_node_with_prompts(job_node_no_prompts):
|
||||||
node_no_prompts.credential = cred
|
job_node_no_prompts.char_prompts = example_prompts
|
||||||
return node_no_prompts
|
job_node_no_prompts.inventory = Inventory(name='example-inv')
|
||||||
|
job_node_no_prompts.credential = Credential(name='example-inv', kind='ssh', username='asdf', password='asdf')
|
||||||
|
return job_node_no_prompts
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def wfjt_node_no_prompts(workflow_job_template_unit, jt_ask):
|
||||||
|
return WorkflowJobTemplateNode(workflow_job_template=workflow_job_template_unit, unified_job_template=jt_ask)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def wfjt_node_with_prompts(wfjt_node_no_prompts):
|
||||||
|
wfjt_node_no_prompts.char_prompts = example_prompts
|
||||||
|
wfjt_node_no_prompts.inventory = Inventory(name='example-inv')
|
||||||
|
wfjt_node_no_prompts.credential = Credential(name='example-inv', kind='ssh', username='asdf', password='asdf')
|
||||||
|
return wfjt_node_no_prompts
|
||||||
|
|
||||||
|
class TestWorkflowJobCreate:
|
||||||
|
|
||||||
|
def test_create_no_prompts(self, wfjt_node_no_prompts, workflow_job_unit, mocker):
|
||||||
|
mock_create = mocker.MagicMock()
|
||||||
|
with mocker.patch('awx.main.models.WorkflowJobNode.objects.create', mock_create):
|
||||||
|
wfjt_node_no_prompts.create_workflow_job_node(workflow_job=workflow_job_unit)
|
||||||
|
mock_create.assert_called_once_with(
|
||||||
|
char_prompts=wfjt_node_no_prompts.char_prompts,
|
||||||
|
inventory=None, credential=None,
|
||||||
|
unified_job_template=wfjt_node_no_prompts.unified_job_template,
|
||||||
|
workflow_job=workflow_job_unit)
|
||||||
|
|
||||||
|
def test_create_with_prompts(self, wfjt_node_with_prompts, workflow_job_unit, mocker):
|
||||||
|
mock_create = mocker.MagicMock()
|
||||||
|
with mocker.patch('awx.main.models.WorkflowJobNode.objects.create', mock_create):
|
||||||
|
wfjt_node_with_prompts.create_workflow_job_node(workflow_job=workflow_job_unit)
|
||||||
|
mock_create.assert_called_once_with(
|
||||||
|
char_prompts=wfjt_node_with_prompts.char_prompts,
|
||||||
|
inventory=wfjt_node_with_prompts.inventory,
|
||||||
|
credential=wfjt_node_with_prompts.credential,
|
||||||
|
unified_job_template=wfjt_node_with_prompts.unified_job_template,
|
||||||
|
workflow_job=workflow_job_unit)
|
||||||
|
|
||||||
class TestWorkflowJobNodeJobKWARGS:
|
class TestWorkflowJobNodeJobKWARGS:
|
||||||
"""
|
"""
|
||||||
@@ -119,33 +157,33 @@ class TestWorkflowJobNodeJobKWARGS:
|
|||||||
launching a new job that corresponds to a workflow node.
|
launching a new job that corresponds to a workflow node.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_null_kwargs(self, node_no_prompts):
|
def test_null_kwargs(self, job_node_no_prompts):
|
||||||
assert node_no_prompts.get_job_kwargs() == {}
|
assert job_node_no_prompts.get_job_kwargs() == {}
|
||||||
|
|
||||||
def test_inherit_workflow_job_extra_vars(self, node_no_prompts):
|
def test_inherit_workflow_job_extra_vars(self, job_node_no_prompts):
|
||||||
workflow_job = node_no_prompts.workflow_job
|
workflow_job = job_node_no_prompts.workflow_job
|
||||||
workflow_job.extra_vars = '{"a": 84}'
|
workflow_job.extra_vars = '{"a": 84}'
|
||||||
assert node_no_prompts.get_job_kwargs() == {'extra_vars': {'a': 84}}
|
assert job_node_no_prompts.get_job_kwargs() == {'extra_vars': {'a': 84}}
|
||||||
|
|
||||||
def test_char_prompts_and_res_node_prompts(self, node_with_prompts):
|
def test_char_prompts_and_res_node_prompts(self, job_node_with_prompts):
|
||||||
assert node_with_prompts.get_job_kwargs() == dict(
|
assert job_node_with_prompts.get_job_kwargs() == dict(
|
||||||
inventory=node_with_prompts.inventory.pk,
|
inventory=job_node_with_prompts.inventory.pk,
|
||||||
credential=node_with_prompts.credential.pk,
|
credential=job_node_with_prompts.credential.pk,
|
||||||
**example_prompts)
|
**example_prompts)
|
||||||
|
|
||||||
def test_reject_some_node_prompts(self, node_with_prompts):
|
def test_reject_some_node_prompts(self, job_node_with_prompts):
|
||||||
node_with_prompts.unified_job_template.ask_inventory_on_launch = False
|
job_node_with_prompts.unified_job_template.ask_inventory_on_launch = False
|
||||||
node_with_prompts.unified_job_template.ask_job_type_on_launch = False
|
job_node_with_prompts.unified_job_template.ask_job_type_on_launch = False
|
||||||
expect_kwargs = dict(inventory=node_with_prompts.inventory.pk,
|
expect_kwargs = dict(inventory=job_node_with_prompts.inventory.pk,
|
||||||
credential=node_with_prompts.credential.pk,
|
credential=job_node_with_prompts.credential.pk,
|
||||||
**example_prompts)
|
**example_prompts)
|
||||||
expect_kwargs.pop('inventory')
|
expect_kwargs.pop('inventory')
|
||||||
expect_kwargs.pop('job_type')
|
expect_kwargs.pop('job_type')
|
||||||
assert node_with_prompts.get_job_kwargs() == expect_kwargs
|
assert job_node_with_prompts.get_job_kwargs() == expect_kwargs
|
||||||
|
|
||||||
def test_no_accepted_project_node_prompts(self, node_with_prompts, project_unit):
|
def test_no_accepted_project_node_prompts(self, job_node_no_prompts, project_unit):
|
||||||
node_with_prompts.unified_job_template = project_unit
|
job_node_no_prompts.unified_job_template = project_unit
|
||||||
assert node_with_prompts.get_job_kwargs() == {}
|
assert job_node_no_prompts.get_job_kwargs() == {}
|
||||||
|
|
||||||
|
|
||||||
class TestWorkflowWarnings:
|
class TestWorkflowWarnings:
|
||||||
@@ -153,38 +191,38 @@ class TestWorkflowWarnings:
|
|||||||
Tests of warnings that show user errors in the construction of a workflow
|
Tests of warnings that show user errors in the construction of a workflow
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test_no_warn_project_node_no_prompts(self, node_no_prompts, project_unit):
|
def test_no_warn_project_node_no_prompts(self, job_node_no_prompts, project_unit):
|
||||||
node_no_prompts.unified_job_template = project_unit
|
job_node_no_prompts.unified_job_template = project_unit
|
||||||
assert node_no_prompts.get_prompts_warnings() == {}
|
assert job_node_no_prompts.get_prompts_warnings() == {}
|
||||||
|
|
||||||
def test_warn_project_node_reject_all_prompts(self, node_with_prompts, project_unit):
|
def test_warn_project_node_reject_all_prompts(self, job_node_with_prompts, project_unit):
|
||||||
node_with_prompts.unified_job_template = project_unit
|
job_node_with_prompts.unified_job_template = project_unit
|
||||||
assert 'ignored' in node_with_prompts.get_prompts_warnings()
|
assert 'ignored' in job_node_with_prompts.get_prompts_warnings()
|
||||||
assert 'all' in node_with_prompts.get_prompts_warnings()['ignored']
|
assert 'all' in job_node_with_prompts.get_prompts_warnings()['ignored']
|
||||||
|
|
||||||
def test_no_warn_accept_all_prompts(self, node_with_prompts):
|
def test_no_warn_accept_all_prompts(self, job_node_with_prompts):
|
||||||
assert node_with_prompts.get_prompts_warnings() == {}
|
assert job_node_with_prompts.get_prompts_warnings() == {}
|
||||||
|
|
||||||
def test_warn_reject_some_prompts(self, node_with_prompts):
|
def test_warn_reject_some_prompts(self, job_node_with_prompts):
|
||||||
node_with_prompts.unified_job_template.ask_credential_on_launch = False
|
job_node_with_prompts.unified_job_template.ask_credential_on_launch = False
|
||||||
node_with_prompts.unified_job_template.ask_job_type_on_launch = False
|
job_node_with_prompts.unified_job_template.ask_job_type_on_launch = False
|
||||||
assert 'ignored' in node_with_prompts.get_prompts_warnings()
|
assert 'ignored' in job_node_with_prompts.get_prompts_warnings()
|
||||||
assert 'job_type' in node_with_prompts.get_prompts_warnings()['ignored']
|
assert 'job_type' in job_node_with_prompts.get_prompts_warnings()['ignored']
|
||||||
assert 'credential' in node_with_prompts.get_prompts_warnings()['ignored']
|
assert 'credential' in job_node_with_prompts.get_prompts_warnings()['ignored']
|
||||||
assert len(node_with_prompts.get_prompts_warnings()['ignored']) == 2
|
assert len(job_node_with_prompts.get_prompts_warnings()['ignored']) == 2
|
||||||
|
|
||||||
def test_warn_scan_errors_node_prompts(self, node_with_prompts):
|
def test_warn_scan_errors_node_prompts(self, job_node_with_prompts):
|
||||||
node_with_prompts.unified_job_template.job_type = 'scan'
|
job_node_with_prompts.unified_job_template.job_type = 'scan'
|
||||||
node_with_prompts.job_type = 'run'
|
job_node_with_prompts.job_type = 'run'
|
||||||
node_with_prompts.inventory = Inventory(name='different-inventory', pk=23)
|
job_node_with_prompts.inventory = Inventory(name='different-inventory', pk=23)
|
||||||
assert 'ignored' in node_with_prompts.get_prompts_warnings()
|
assert 'ignored' in job_node_with_prompts.get_prompts_warnings()
|
||||||
assert 'job_type' in node_with_prompts.get_prompts_warnings()['ignored']
|
assert 'job_type' in job_node_with_prompts.get_prompts_warnings()['ignored']
|
||||||
assert 'inventory' in node_with_prompts.get_prompts_warnings()['ignored']
|
assert 'inventory' in job_node_with_prompts.get_prompts_warnings()['ignored']
|
||||||
assert len(node_with_prompts.get_prompts_warnings()['ignored']) == 2
|
assert len(job_node_with_prompts.get_prompts_warnings()['ignored']) == 2
|
||||||
|
|
||||||
def test_warn_missing_fields(self, node_no_prompts):
|
def test_warn_missing_fields(self, job_node_no_prompts):
|
||||||
node_no_prompts.inventory = None
|
job_node_no_prompts.inventory = None
|
||||||
assert 'missing' in node_no_prompts.get_prompts_warnings()
|
assert 'missing' in job_node_no_prompts.get_prompts_warnings()
|
||||||
assert 'inventory' in node_no_prompts.get_prompts_warnings()['missing']
|
assert 'inventory' in job_node_no_prompts.get_prompts_warnings()['missing']
|
||||||
assert 'credential' in node_no_prompts.get_prompts_warnings()['missing']
|
assert 'credential' in job_node_no_prompts.get_prompts_warnings()['missing']
|
||||||
assert len(node_no_prompts.get_prompts_warnings()['missing']) == 2
|
assert len(job_node_no_prompts.get_prompts_warnings()['missing']) == 2
|
||||||
|
|||||||
Reference in New Issue
Block a user