diff options
-rw-r--r-- | awx/main/models/ha.py | 11 | ||||
-rw-r--r-- | awx/main/tests/functional/test_instances.py | 20 | ||||
-rw-r--r-- | awx/ui/src/screens/Job/JobOutput/HostEventModal.js | 14 | ||||
-rw-r--r-- | awx/ui/src/screens/Job/JobOutput/HostEventModal.test.js | 48 |
4 files changed, 78 insertions, 15 deletions
diff --git a/awx/main/models/ha.py b/awx/main/models/ha.py index dbeb81dcac..f101a94d7a 100644 --- a/awx/main/models/ha.py +++ b/awx/main/models/ha.py @@ -233,11 +233,12 @@ class Instance(HasPolicyEditsMixin, BaseModel): if not isinstance(vargs.get('grace_period'), int): vargs['grace_period'] = 60 # grace period of 60 minutes, need to set because CLI default will not take effect if 'exclude_strings' not in vargs and vargs.get('file_pattern'): - active_pks = list( - UnifiedJob.objects.filter( - (models.Q(execution_node=self.hostname) | models.Q(controller_node=self.hostname)) & models.Q(status__in=('running', 'waiting')) - ).values_list('pk', flat=True) - ) + active_job_qs = UnifiedJob.objects.filter(status__in=('running', 'waiting')) + if self.node_type == 'execution': + active_job_qs = active_job_qs.filter(execution_node=self.hostname) + else: + active_job_qs = active_job_qs.filter(controller_node=self.hostname) + active_pks = list(active_job_qs.values_list('pk', flat=True)) if active_pks: vargs['exclude_strings'] = [JOB_FOLDER_PREFIX % job_id for job_id in active_pks] if 'remove_images' in vargs or 'image_prune' in vargs: diff --git a/awx/main/tests/functional/test_instances.py b/awx/main/tests/functional/test_instances.py index 8ce6524d38..df6d177868 100644 --- a/awx/main/tests/functional/test_instances.py +++ b/awx/main/tests/functional/test_instances.py @@ -1,7 +1,7 @@ import pytest from unittest import mock -from awx.main.models import AdHocCommand, InventoryUpdate, JobTemplate +from awx.main.models import AdHocCommand, InventoryUpdate, JobTemplate, Job from awx.main.models.activity_stream import ActivityStream from awx.main.models.ha import Instance, InstanceGroup from awx.main.tasks.system import apply_cluster_membership_policies @@ -16,6 +16,24 @@ def test_default_tower_instance_group(default_instance_group, job_factory): @pytest.mark.django_db +@pytest.mark.parametrize('node_type', ('execution', 'control')) +@pytest.mark.parametrize('active', (True, False)) +def test_get_cleanup_task_kwargs_active_jobs(node_type, active): + instance = Instance.objects.create(hostname='foobar', node_type=node_type) + job_kwargs = dict() + job_kwargs['controller_node' if node_type == 'control' else 'execution_node'] = instance.hostname + job_kwargs['status'] = 'running' if active else 'successful' + + job = Job.objects.create(**job_kwargs) + kwargs = instance.get_cleanup_task_kwargs() + + if active: + assert kwargs['exclude_strings'] == [f'awx_{job.pk}_'] + else: + assert 'exclude_strings' not in kwargs + + +@pytest.mark.django_db class TestPolicyTaskScheduling: """Tests make assertions about when the policy task gets scheduled""" diff --git a/awx/ui/src/screens/Job/JobOutput/HostEventModal.js b/awx/ui/src/screens/Job/JobOutput/HostEventModal.js index 57fe7ce05f..a7295c1692 100644 --- a/awx/ui/src/screens/Job/JobOutput/HostEventModal.js +++ b/awx/ui/src/screens/Job/JobOutput/HostEventModal.js @@ -70,7 +70,6 @@ const getStdOutValue = (hostEvent) => { function HostEventModal({ onClose, hostEvent = {}, isOpen = false }) { const [hostStatus, setHostStatus] = useState(null); const [activeTabKey, setActiveTabKey] = useState(0); - useEffect(() => { setHostStatus(processEventStatus(hostEvent)); }, [setHostStatus, hostEvent]); @@ -108,11 +107,11 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false }) { style={{ alignItems: 'center', marginTop: '20px' }} gutter="sm" > - <Detail label={t`Host`} value={hostEvent.host_name} /> - {hostEvent.summary_fields.host?.description ? ( + <Detail label={t`Host`} value={hostEvent.event_data?.host} /> + {hostEvent.summary_fields?.host?.description ? ( <Detail label={t`Description`} - value={hostEvent.summary_fields.host.description} + value={hostEvent.summary_fields?.host?.description} /> ) : null} {hostStatus ? ( @@ -125,12 +124,9 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false }) { <Detail label={t`Task`} value={hostEvent.task} /> <Detail label={t`Module`} - value={hostEvent.event_data.task_action || t`No result found`} - /> - <Detail - label={t`Command`} - value={hostEvent?.event_data?.res?.cmd} + value={hostEvent.event_data?.task_action || t`No result found`} /> + <Detail label={t`Command`} value={hostEvent.event_data?.res?.cmd} /> </DetailList> </Tab> <Tab diff --git a/awx/ui/src/screens/Job/JobOutput/HostEventModal.test.js b/awx/ui/src/screens/Job/JobOutput/HostEventModal.test.js index 96866c4b03..0b877b4e4c 100644 --- a/awx/ui/src/screens/Job/JobOutput/HostEventModal.test.js +++ b/awx/ui/src/screens/Job/JobOutput/HostEventModal.test.js @@ -52,6 +52,47 @@ const hostEvent = { }, }; +const partialHostEvent = { + changed: true, + event: 'runner_on_ok', + event_data: { + host: 'foo', + play: 'all', + playbook: 'run_command.yml', + res: { + ansible_loop_var: 'item', + changed: true, + item: '1', + msg: 'This is a debug message: 1', + stdout: + ' total used free shared buff/cache available\nMem: 7973 3005 960 30 4007 4582\nSwap: 1023 0 1023', + stderr: 'problems', + cmd: ['free', '-m'], + stderr_lines: [], + stdout_lines: [ + ' total used free shared buff/cache available', + 'Mem: 7973 3005 960 30 4007 4582', + 'Swap: 1023 0 1023', + ], + }, + task: 'command', + task_action: 'command', + }, + event_display: 'Host OK', + event_level: 3, + failed: false, + host: 1, + id: 123, + job: 4, + play: 'all', + playbook: 'run_command.yml', + stdout: `stdout: "[0;33mchanged: [localhost] => {"changed": true, "cmd": ["free", "-m"], "delta": "0:00:01.479609", "end": "2019-09-10 14:21:45.469533", "rc": 0, "start": "2019-09-10 14:21:43.989924", "stderr": "", "stderr_lines": [], "stdout": " total used free shared buff/cache available\nMem: 7973 3005 960 30 4007 4582\nSwap: 1023 0 1023", "stdout_lines": [" total used free shared buff/cache available", "Mem: 7973 3005 960 30 4007 4582", "Swap: 1023 0 1023"]}[0m" + `, + task: 'command', + type: 'job_event', + url: '/api/v2/job_events/123/', +}; + /* Some libraries return a list of string in stdout Example: https://github.com/ansible-collections/cisco.ios/blob/main/plugins/modules/ios_command.py#L124-L128 @@ -134,6 +175,13 @@ describe('HostEventModal', () => { expect(wrapper).toHaveLength(1); }); + test('renders successfully with partial data', () => { + const wrapper = shallow( + <HostEventModal hostEvent={partialHostEvent} onClose={() => {}} /> + ); + expect(wrapper).toHaveLength(1); + }); + test('should render all tabs', () => { const wrapper = shallow( <HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen /> |