From d34f6af8308a46d0b3368c5fdf08f2dd5b0bf707 Mon Sep 17 00:00:00 2001 From: "Keith J. Grant" Date: Fri, 11 Nov 2022 14:55:36 -0800 Subject: [PATCH 1/9] fix traceback offset/counter # in UI --- awx/ui/src/screens/Job/JobOutput/JobEvent.js | 4 ++-- awx/ui/src/screens/Job/JobOutput/loadJobEvents.js | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/awx/ui/src/screens/Job/JobOutput/JobEvent.js b/awx/ui/src/screens/Job/JobOutput/JobEvent.js index 8f3dd81f8e..87f6f54fbf 100644 --- a/awx/ui/src/screens/Job/JobOutput/JobEvent.js +++ b/awx/ui/src/screens/Job/JobOutput/JobEvent.js @@ -41,7 +41,7 @@ function JobEvent({ if (lineNumber < 0) { return null; } - const canToggle = index === toggleLineIndex; + const canToggle = index === toggleLineIndex && !event.isTracebackOnly; return ( - {lineNumber} + {!event.isTracebackOnly ? lineNumber : ''} jobEvent.counter === 1); - if (firstIndex && events[firstIndex]?.stdout) { - const stdoutLines = events[firstIndex].stdout.split('\r\n'); + if (firstIndex > -1) { + if (!events[firstIndex].stdout) { + events[firstIndex].isTracebackOnly = true; + } + const stdoutLines = events[firstIndex].stdout?.split('\r\n') || []; stdoutLines[0] = tracebackEvent.stdout; events[firstIndex].stdout = stdoutLines.join('\r\n'); } else { From 6f6f04a0712eb43927f01629871fa09bd7cd00d6 Mon Sep 17 00:00:00 2001 From: "Keith J. Grant" Date: Tue, 18 Oct 2022 13:53:27 -0700 Subject: [PATCH 2/9] refresh events when first websocket event streams --- awx/ui/src/screens/Job/JobOutput/JobOutput.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/awx/ui/src/screens/Job/JobOutput/JobOutput.js b/awx/ui/src/screens/Job/JobOutput/JobOutput.js index c4949d1ffe..63c2110b52 100644 --- a/awx/ui/src/screens/Job/JobOutput/JobOutput.js +++ b/awx/ui/src/screens/Job/JobOutput/JobOutput.js @@ -251,6 +251,9 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { }); const updated = oldWsEvents.concat(newEvents); jobSocketCounter.current = updated.length; + if (!oldWsEvents.length && min > remoteRowCount + 1) { + loadJobEvents(min); + } return updated.sort((a, b) => a.counter - b.counter); }); setCssMap((prevCssMap) => ({ @@ -358,7 +361,7 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { } }; - const loadJobEvents = async () => { + const loadJobEvents = async (firstWsCounter = null) => { const [params, loadRange] = getEventRequestParams(job, 50, [1, 50]); if (isMounted.current) { @@ -371,6 +374,9 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { if (isFlatMode) { params.not__stdout = ''; } + if (firstWsCounter) { + params.counter__lt = firstWsCounter; + } const qsParams = parseQueryString(QS_CONFIG, location.search); const eventPromise = getJobModel(job.type).readEvents(job.id, { ...params, @@ -435,7 +441,7 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { if (getEvent(counter)) { return true; } - if (index > remoteRowCount && index < remoteRowCount + wsEvents.length) { + if (index >= remoteRowCount && index < remoteRowCount + wsEvents.length) { return true; } return currentlyLoading.includes(counter); @@ -462,7 +468,7 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { } if ( !event && - index > remoteRowCount && + index >= remoteRowCount && index < remoteRowCount + wsEvents.length ) { event = wsEvents[index - remoteRowCount]; From 03b0281fdef8adbdf237f1af0e8bb257e92aab85 Mon Sep 17 00:00:00 2001 From: "Keith J. Grant" Date: Mon, 7 Nov 2022 11:19:45 -0800 Subject: [PATCH 3/9] clean up follow mode quirks --- awx/ui/src/screens/Job/JobOutput/JobOutput.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/awx/ui/src/screens/Job/JobOutput/JobOutput.js b/awx/ui/src/screens/Job/JobOutput/JobOutput.js index 63c2110b52..12d541ffad 100644 --- a/awx/ui/src/screens/Job/JobOutput/JobOutput.js +++ b/awx/ui/src/screens/Job/JobOutput/JobOutput.js @@ -187,7 +187,9 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { useEffect(() => { const pendingRequests = Object.values(eventByUuidRequests.current || {}); setHasContentLoading(true); // prevents "no content found" screen from flashing - setIsFollowModeEnabled(false); + if (location.search) { + setIsFollowModeEnabled(false); + } Promise.allSettled(pendingRequests).then(() => { setRemoteRowCount(0); clearLoadedEvents(); @@ -635,10 +637,14 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { setIsFollowModeEnabled(false); }; - const scrollToEnd = () => { + const scrollToEnd = useCallback(() => { scrollToRow(-1); - setTimeout(() => scrollToRow(-1), 100); - }; + let timeout; + if (isFollowModeEnabled) { + setTimeout(() => scrollToRow(-1), 100); + } + return () => clearTimeout(timeout); + }, [isFollowModeEnabled]); const handleScrollLast = () => { scrollToEnd(); From 36c0d07b30c26eb58f244e44429391de13d653d4 Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Tue, 27 Sep 2022 11:10:01 -0400 Subject: [PATCH 4/9] Result_traceback should not include job stdout If a job fails, we do receptor work results and put that output into result_traceback. We should only do this if 1. Receptor unit has failed 2. Runner callback processed 0 events Otherwise we risk putting too much data into this field. --- awx/main/tasks/receptor.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/awx/main/tasks/receptor.py b/awx/main/tasks/receptor.py index 639abf671f..94568ebd6c 100644 --- a/awx/main/tasks/receptor.py +++ b/awx/main/tasks/receptor.py @@ -411,9 +411,11 @@ class AWXReceptorJob: unit_status = receptor_ctl.simple_command(f'work status {self.unit_id}') detail = unit_status.get('Detail', None) state_name = unit_status.get('StateName', None) + stdout_size = unit_status.get('StdoutSize', 0) except Exception: detail = '' state_name = '' + stdout_size = 0 logger.exception(f'An error was encountered while getting status for work unit {self.unit_id}') if 'exceeded quota' in detail: @@ -424,9 +426,16 @@ class AWXReceptorJob: return try: - resultsock = receptor_ctl.get_work_results(self.unit_id, return_sockfile=True) - lines = resultsock.readlines() - receptor_output = b"".join(lines).decode() + receptor_output = '' + if state_name == 'Failed' and self.task.runner_callback.event_ct == 0: + # if receptor work unit failed and no events were emitted, work results may + # contain useful information about why the job failed. In case stdout is + # massive, only ask for last 1000 bytes + startpos = max(stdout_size - 1000, 0) + resultsock, resultfile = receptor_ctl.get_work_results(self.unit_id, startpos=startpos, return_socket=True, return_sockfile=True) + resultsock.setblocking(False) # this makes resultfile reads non blocking + lines = resultfile.readlines() + receptor_output = b"".join(lines).decode() if receptor_output: self.task.runner_callback.delay_update(result_traceback=receptor_output) elif detail: From 68e555824d5dc4db95191c69dde77a1b35c27f0a Mon Sep 17 00:00:00 2001 From: Vidya Nambiar Date: Thu, 22 Dec 2022 11:23:03 -0500 Subject: [PATCH 5/9] Fix for Save button not responding on Job Settings page Signed-off-by: Vidya Nambiar --- .../screens/Setting/Jobs/JobsEdit/JobsEdit.js | 10 +++++----- .../Setting/Jobs/JobsEdit/JobsEdit.test.js | 18 ++++++++++++++++++ .../src/screens/Setting/shared/SharedFields.js | 5 ++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/awx/ui/src/screens/Setting/Jobs/JobsEdit/JobsEdit.js b/awx/ui/src/screens/Setting/Jobs/JobsEdit/JobsEdit.js index 6ae68c1c8d..52e216e41e 100644 --- a/awx/ui/src/screens/Setting/Jobs/JobsEdit/JobsEdit.js +++ b/awx/ui/src/screens/Setting/Jobs/JobsEdit/JobsEdit.js @@ -141,14 +141,14 @@ function JobsEdit() { ', () => { await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); expect(wrapper.find('ContentError').length).toBe(1); }); + + test('Form input fields that are invisible (due to being set manually via a settings file) should not prevent submitting the form', async () => { + const mockOptions = Object.assign({}, mockAllOptions); + // If AWX_ISOLATION_BASE_PATH has been set in a settings file it will be absent in the PUT options + delete mockOptions['actions']['PUT']['AWX_ISOLATION_BASE_PATH']; + await act(async () => { + wrapper = mountWithContexts( + + + + ); + }); + await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0); + await act(async () => { + wrapper.find('Form').invoke('onSubmit')(); + }); + expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1); + }); }); diff --git a/awx/ui/src/screens/Setting/shared/SharedFields.js b/awx/ui/src/screens/Setting/shared/SharedFields.js index 9fd1817bb8..06851e3b9e 100644 --- a/awx/ui/src/screens/Setting/shared/SharedFields.js +++ b/awx/ui/src/screens/Setting/shared/SharedFields.js @@ -397,7 +397,10 @@ const InputField = ({ name, config, type = 'text', isRequired = false }) => { }; InputField.propTypes = { name: string.isRequired, - config: shape({}).isRequired, + config: shape({}), +}; +InputField.defaultProps = { + config: null, }; const TextAreaField = ({ name, config, isRequired = false }) => { From 6cee99a9f9f5fa80f5e433ad44bfd96a0b1343dd Mon Sep 17 00:00:00 2001 From: Shane McDonald Date: Wed, 4 Jan 2023 01:13:31 -0500 Subject: [PATCH 6/9] Pin rsyslog to prevent crash With the latest version of rsyslog we had a test failing with: AssertionError: Response data: {'error': "b'rsyslog internal message (3,-2455): could not transfer the specified internal posix capabilities settings to the kernel, capng_apply=-5\\n [v8.2102.0-107.el9 try https://www.rsyslog.com/e/2455 ]\\n'"} Downgrading fixes it --- tools/ansible/roles/dockerfile/templates/Dockerfile.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 b/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 index a83a130283..166f24b79f 100644 --- a/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 +++ b/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 @@ -116,7 +116,7 @@ RUN dnf -y update && dnf install -y 'dnf-command(config-manager)' && \ python3-psycopg2 \ python3-setuptools \ rsync \ - "rsyslog >= 8.1911.0" \ + rsyslog-8.2102.0-106.el9 \ subversion \ sudo \ vim-minimal \ From 1aca9929ab2948ce03a275cc6708524abcaedcd0 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Tue, 15 Nov 2022 09:41:09 -0500 Subject: [PATCH 7/9] Adds support for exact name searching against related fields to the ui --- awx/ui/src/components/Search/RelatedLookupTypeInput.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/awx/ui/src/components/Search/RelatedLookupTypeInput.js b/awx/ui/src/components/Search/RelatedLookupTypeInput.js index effbc4199a..008c83164b 100644 --- a/awx/ui/src/components/Search/RelatedLookupTypeInput.js +++ b/awx/ui/src/components/Search/RelatedLookupTypeInput.js @@ -31,6 +31,12 @@ function RelatedLookupTypeInput({ value="name__icontains" description={t`Fuzzy search on name field.`} /> + Date: Tue, 3 Jan 2023 11:38:44 -0800 Subject: [PATCH 8/9] update test --- awx/ui/src/components/Search/AdvancedSearch.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/src/components/Search/AdvancedSearch.test.js b/awx/ui/src/components/Search/AdvancedSearch.test.js index 5050ff63af..8258ef6812 100644 --- a/awx/ui/src/components/Search/AdvancedSearch.test.js +++ b/awx/ui/src/components/Search/AdvancedSearch.test.js @@ -420,7 +420,7 @@ describe('', () => { const selectOptions = wrapper.find( 'Select[aria-label="Related search type"] SelectOption' ); - expect(selectOptions).toHaveLength(2); + expect(selectOptions).toHaveLength(3); expect( selectOptions.find('SelectOption[id="name-option-select"]').prop('value') ).toBe('name__icontains'); From 6492c039658cbba65729a12ac9f44ab66fed38fc Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Thu, 5 Jan 2023 12:55:20 -0500 Subject: [PATCH 9/9] Fix console color logs --- awx/main/utils/handlers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/awx/main/utils/handlers.py b/awx/main/utils/handlers.py index 1740a4c8f6..7f7116d78b 100644 --- a/awx/main/utils/handlers.py +++ b/awx/main/utils/handlers.py @@ -103,6 +103,10 @@ ColorHandler = logging.StreamHandler if settings.COLOR_LOGS is True: try: from logutils.colorize import ColorizingStreamHandler + import colorama + + colorama.deinit() + colorama.init(wrap=False, convert=False, strip=False) class ColorHandler(ColorizingStreamHandler): def colorize(self, line, record):