From ef651a3a21b821367f90b989cd522c8d0409138f Mon Sep 17 00:00:00 2001 From: Joe Garcia Date: Wed, 26 Oct 2022 11:54:09 -0400 Subject: [PATCH 01/32] Add Web Service ID & update branding --- awx/main/credential_plugins/aim.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/awx/main/credential_plugins/aim.py b/awx/main/credential_plugins/aim.py index 95bf767508..7e30b1b69d 100644 --- a/awx/main/credential_plugins/aim.py +++ b/awx/main/credential_plugins/aim.py @@ -13,6 +13,12 @@ aim_inputs = { 'type': 'string', 'format': 'url', }, + { + 'id': 'webservice_id', + 'label': _('Web Service ID'), + 'type': 'string', + 'help_text': _('The AIM Web Service ID. Default: AIMWebService'), + }, { 'id': 'app_id', 'label': _('Application ID'), @@ -64,6 +70,7 @@ def aim_backend(**kwargs): client_cert = kwargs.get('client_cert', None) client_key = kwargs.get('client_key', None) verify = kwargs['verify'] + webservice_id = kwargs.get('webservice_id', 'AIMWebService') app_id = kwargs['app_id'] object_query = kwargs['object_query'] object_query_format = kwargs['object_query_format'] @@ -78,7 +85,7 @@ def aim_backend(**kwargs): query_params['reason'] = reason request_qs = '?' + urlencode(query_params, quote_via=quote) - request_url = urljoin(url, '/'.join(['AIMWebService', 'api', 'Accounts'])) + request_url = urljoin(url, '/'.join([webservice_id, 'api', 'Accounts'])) with CertFiles(client_cert, client_key) as cert: res = requests.get( @@ -92,4 +99,4 @@ def aim_backend(**kwargs): return res.json()['Content'] -aim_plugin = CredentialPlugin('CyberArk AIM Central Credential Provider Lookup', inputs=aim_inputs, backend=aim_backend) +aim_plugin = CredentialPlugin('CyberArk Central Credential Provider Lookup', inputs=aim_inputs, backend=aim_backend) From 9d77c54612aea9714eca915d060bea1f86eec195 Mon Sep 17 00:00:00 2001 From: Joe Garcia Date: Wed, 26 Oct 2022 12:32:12 -0400 Subject: [PATCH 02/32] Remove references to AIM everywhere --- awx/main/credential_plugins/aim.py | 4 ++-- .../screens/Credential/shared/data.credentialTypes.json | 2 +- awx_collection/plugins/modules/credential.py | 2 +- .../targets/credential_input_source/tasks/main.yml | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/awx/main/credential_plugins/aim.py b/awx/main/credential_plugins/aim.py index 7e30b1b69d..be0232357f 100644 --- a/awx/main/credential_plugins/aim.py +++ b/awx/main/credential_plugins/aim.py @@ -9,7 +9,7 @@ aim_inputs = { 'fields': [ { 'id': 'url', - 'label': _('CyberArk AIM URL'), + 'label': _('CyberArk CCP URL'), 'type': 'string', 'format': 'url', }, @@ -17,7 +17,7 @@ aim_inputs = { 'id': 'webservice_id', 'label': _('Web Service ID'), 'type': 'string', - 'help_text': _('The AIM Web Service ID. Default: AIMWebService'), + 'help_text': _('The CCP Web Service ID. Leave blank to default to AIMWebService.'), }, { 'id': 'app_id', diff --git a/awx/ui/src/screens/Credential/shared/data.credentialTypes.json b/awx/ui/src/screens/Credential/shared/data.credentialTypes.json index 98c375aa2c..f67ed8ac68 100644 --- a/awx/ui/src/screens/Credential/shared/data.credentialTypes.json +++ b/awx/ui/src/screens/Credential/shared/data.credentialTypes.json @@ -465,7 +465,7 @@ }, "created": "2020-05-18T21:53:35.370730Z", "modified": "2020-05-18T21:54:05.436400Z", - "name": "CyberArk AIM Central Credential Provider Lookup", + "name": "CyberArk Central Credential Provider Lookup", "description": "", "kind": "external", "namespace": "aim", diff --git a/awx_collection/plugins/modules/credential.py b/awx_collection/plugins/modules/credential.py index 8c962ce82e..4e7f02e558 100644 --- a/awx_collection/plugins/modules/credential.py +++ b/awx_collection/plugins/modules/credential.py @@ -52,7 +52,7 @@ options: - The credential type being created. - Can be a built-in credential type such as "Machine", or a custom credential type such as "My Credential Type" - Choices include Amazon Web Services, Ansible Galaxy/Automation Hub API Token, Centrify Vault Credential Provider Lookup, - Container Registry, CyberArk AIM Central Credential Provider Lookup, CyberArk Conjur Secret Lookup, Google Compute Engine, + Container Registry, CyberArk Central Credential Provider Lookup, CyberArk Conjur Secret Lookup, Google Compute Engine, GitHub Personal Access Token, GitLab Personal Access Token, GPG Public Key, HashiCorp Vault Secret Lookup, HashiCorp Vault Signed SSH, Insights, Machine, Microsoft Azure Key Vault, Microsoft Azure Resource Manager, Network, OpenShift or Kubernetes API Bearer Token, OpenStack, Red Hat Ansible Automation Platform, Red Hat Satellite 6, Red Hat Virtualization, Source Control, diff --git a/awx_collection/tests/integration/targets/credential_input_source/tasks/main.yml b/awx_collection/tests/integration/targets/credential_input_source/tasks/main.yml index 03557ee0e1..e9066a0f2a 100644 --- a/awx_collection/tests/integration/targets/credential_input_source/tasks/main.yml +++ b/awx_collection/tests/integration/targets/credential_input_source/tasks/main.yml @@ -14,7 +14,7 @@ credential: description: Credential for Testing Source name: "{{ src_cred_name }}" - credential_type: CyberArk AIM Central Credential Provider Lookup + credential_type: CyberArk Central Credential Provider Lookup inputs: url: "https://cyberark.example.com" app_id: "My-App-ID" @@ -58,7 +58,7 @@ credential: description: Credential for Testing Source Change name: "{{ src_cred_name }}-2" - credential_type: CyberArk AIM Central Credential Provider Lookup + credential_type: CyberArk Central Credential Provider Lookup inputs: url: "https://cyberark-prod.example.com" app_id: "My-App-ID" @@ -92,7 +92,7 @@ credential: name: "{{ src_cred_name }}" organization: Default - credential_type: CyberArk AIM Central Credential Provider Lookup + credential_type: CyberArk Central Credential Provider Lookup state: absent register: result @@ -100,7 +100,7 @@ credential: name: "{{ src_cred_name }}-2" organization: Default - credential_type: CyberArk AIM Central Credential Provider Lookup + credential_type: CyberArk Central Credential Provider Lookup state: absent register: result From 2cc971a43f54939d3445959d1341e4f51233c72e Mon Sep 17 00:00:00 2001 From: Joe Garcia Date: Wed, 26 Oct 2022 12:41:15 -0400 Subject: [PATCH 03/32] default to AIMWebService if no val provided --- awx/main/credential_plugins/aim.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/awx/main/credential_plugins/aim.py b/awx/main/credential_plugins/aim.py index be0232357f..32a3a8173d 100644 --- a/awx/main/credential_plugins/aim.py +++ b/awx/main/credential_plugins/aim.py @@ -70,11 +70,13 @@ def aim_backend(**kwargs): client_cert = kwargs.get('client_cert', None) client_key = kwargs.get('client_key', None) verify = kwargs['verify'] - webservice_id = kwargs.get('webservice_id', 'AIMWebService') + webservice_id = kwargs.get('webservice_id', None) app_id = kwargs['app_id'] object_query = kwargs['object_query'] object_query_format = kwargs['object_query_format'] reason = kwargs.get('reason', None) + if webservice_id is None: + webservice_id = 'AIMWebService' query_params = { 'AppId': app_id, From 878035c13bd9fbfc49c8d936c27499101733241e Mon Sep 17 00:00:00 2001 From: Joe Garcia Date: Wed, 26 Oct 2022 12:45:59 -0400 Subject: [PATCH 04/32] Fixed webservice_id check to string --- awx/main/credential_plugins/aim.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/main/credential_plugins/aim.py b/awx/main/credential_plugins/aim.py index 32a3a8173d..96487dcced 100644 --- a/awx/main/credential_plugins/aim.py +++ b/awx/main/credential_plugins/aim.py @@ -70,12 +70,12 @@ def aim_backend(**kwargs): client_cert = kwargs.get('client_cert', None) client_key = kwargs.get('client_key', None) verify = kwargs['verify'] - webservice_id = kwargs.get('webservice_id', None) + webservice_id = kwargs['webservice_id'] app_id = kwargs['app_id'] object_query = kwargs['object_query'] object_query_format = kwargs['object_query_format'] reason = kwargs.get('reason', None) - if webservice_id is None: + if webservice_id == '': webservice_id = 'AIMWebService' query_params = { From 2832f280146fa705ec565f6ce5ef94fc5c9b6e5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Dec 2022 15:30:50 +0000 Subject: [PATCH 05/32] Bump luxon from 3.0.3 to 3.1.1 in /awx/ui Bumps [luxon](https://github.com/moment/luxon) from 3.0.3 to 3.1.1. - [Release notes](https://github.com/moment/luxon/releases) - [Changelog](https://github.com/moment/luxon/blob/master/CHANGELOG.md) - [Commits](https://github.com/moment/luxon/compare/3.0.3...3.1.1) --- updated-dependencies: - dependency-name: luxon dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- awx/ui/package-lock.json | 14 +++++++------- awx/ui/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/awx/ui/package-lock.json b/awx/ui/package-lock.json index ea8733527b..0deb4ee001 100644 --- a/awx/ui/package-lock.json +++ b/awx/ui/package-lock.json @@ -22,7 +22,7 @@ "has-ansi": "5.0.1", "html-entities": "2.3.2", "js-yaml": "4.1.0", - "luxon": "^3.0.3", + "luxon": "^3.1.1", "prop-types": "^15.8.1", "react": "17.0.2", "react-ace": "^10.1.0", @@ -15468,9 +15468,9 @@ } }, "node_modules/luxon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.3.tgz", - "integrity": "sha512-+EfHWnF+UT7GgTnq5zXg3ldnTKL2zdv7QJgsU5bjjpbH17E3qi/puMhQyJVYuCq+FRkogvB5WB6iVvUr+E4a7w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.1.tgz", + "integrity": "sha512-Ah6DloGmvseB/pX1cAmjbFvyU/pKuwQMQqz7d0yvuDlVYLTs2WeDHQMpC8tGjm1da+BriHROW/OEIT/KfYg6xw==", "engines": { "node": ">=12" } @@ -34210,9 +34210,9 @@ } }, "luxon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.3.tgz", - "integrity": "sha512-+EfHWnF+UT7GgTnq5zXg3ldnTKL2zdv7QJgsU5bjjpbH17E3qi/puMhQyJVYuCq+FRkogvB5WB6iVvUr+E4a7w==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.1.tgz", + "integrity": "sha512-Ah6DloGmvseB/pX1cAmjbFvyU/pKuwQMQqz7d0yvuDlVYLTs2WeDHQMpC8tGjm1da+BriHROW/OEIT/KfYg6xw==" }, "lz-string": { "version": "1.4.4", diff --git a/awx/ui/package.json b/awx/ui/package.json index 0c117173df..a1e4944c56 100644 --- a/awx/ui/package.json +++ b/awx/ui/package.json @@ -22,7 +22,7 @@ "has-ansi": "5.0.1", "html-entities": "2.3.2", "js-yaml": "4.1.0", - "luxon": "^3.0.3", + "luxon": "^3.1.1", "prop-types": "^15.8.1", "react": "17.0.2", "react-ace": "^10.1.0", From 58734a33c4230b1ac024568050b207fc57c73cdf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Dec 2022 15:33:23 +0000 Subject: [PATCH 06/32] Bump @patternfly/react-core from 4.250.1 to 4.264.0 in /awx/ui Bumps [@patternfly/react-core](https://github.com/patternfly/patternfly-react) from 4.250.1 to 4.264.0. - [Release notes](https://github.com/patternfly/patternfly-react/releases) - [Commits](https://github.com/patternfly/patternfly-react/compare/@patternfly/react-core@4.250.1...@patternfly/react-core@4.264.0) --- updated-dependencies: - dependency-name: "@patternfly/react-core" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- awx/ui/package-lock.json | 65 ++++++++++++++++++++++++---------------- awx/ui/package.json | 2 +- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/awx/ui/package-lock.json b/awx/ui/package-lock.json index ea8733527b..128c1e39c8 100644 --- a/awx/ui/package-lock.json +++ b/awx/ui/package-lock.json @@ -8,7 +8,7 @@ "dependencies": { "@lingui/react": "3.14.0", "@patternfly/patternfly": "4.217.1", - "@patternfly/react-core": "^4.250.1", + "@patternfly/react-core": "^4.264.0", "@patternfly/react-icons": "4.92.10", "@patternfly/react-table": "4.108.0", "ace-builds": "^1.10.1", @@ -3752,13 +3752,13 @@ "integrity": "sha512-uN7JgfQsyR16YHkuGRCTIcBcnyKIqKjGkB2SGk9x1XXH3yYGenL83kpAavX9Xtozqp17KppOlybJuzcKvZMrgw==" }, "node_modules/@patternfly/react-core": { - "version": "4.250.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.250.1.tgz", - "integrity": "sha512-vAOZPQdZzYXl/vkHnHMIt1eC3nrPDdsuuErPatkNPwmSvilXuXmWP5wxoJ36FbSNRRURkprFwx52zMmWS3iHJA==", + "version": "4.264.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.264.0.tgz", + "integrity": "sha512-tK0BMWxw8nhukev40HZ6q6d02pDnjX7oyA91vHa18aakJUKBWMaerqpG4NZVMoh0tPKX3aLNj+zyCwDALFAZZw==", "dependencies": { - "@patternfly/react-icons": "^4.92.6", - "@patternfly/react-styles": "^4.91.6", - "@patternfly/react-tokens": "^4.93.6", + "@patternfly/react-icons": "^4.93.0", + "@patternfly/react-styles": "^4.92.0", + "@patternfly/react-tokens": "^4.94.0", "focus-trap": "6.9.2", "react-dropzone": "9.0.0", "tippy.js": "5.1.2", @@ -3769,6 +3769,15 @@ "react-dom": "^16.8 || ^17 || ^18" } }, + "node_modules/@patternfly/react-core/node_modules/@patternfly/react-icons": { + "version": "4.93.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.93.0.tgz", + "integrity": "sha512-OH0vORVioL+HLWMEog8/3u8jsiMCeJ0pFpvRKRhy5Uk4CdAe40k1SOBvXJP6opr+O8TLbz0q3bm8Jsh/bPaCuQ==", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18", + "react-dom": "^16.8 || ^17 || ^18" + } + }, "node_modules/@patternfly/react-core/node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -3784,9 +3793,9 @@ } }, "node_modules/@patternfly/react-styles": { - "version": "4.91.10", - "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.91.10.tgz", - "integrity": "sha512-fAG4Vjp63ohiR92F4e/Gkw5q1DSSckHKqdnEF75KUpSSBORzYP0EKMpupSd6ItpQFJw3iWs3MJi3/KIAAfU1Jw==" + "version": "4.92.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.92.0.tgz", + "integrity": "sha512-B/f6iyu8UEN1+wRxdC4sLIhvJeyL8SqInDXZmwOIqK8uPJ8Lze7qrbVhkkVzbMF37/oDPVa6dZH8qZFq062LEA==" }, "node_modules/@patternfly/react-table": { "version": "4.108.0", @@ -3811,9 +3820,9 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/@patternfly/react-tokens": { - "version": "4.93.10", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.93.10.tgz", - "integrity": "sha512-F+j1irDc9M6zvY6qNtDryhbpnHz3R8ymHRdGelNHQzPTIK88YSWEnT1c9iUI+uM/iuZol7sJmO5STtg2aPIDRQ==" + "version": "4.94.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.94.0.tgz", + "integrity": "sha512-fYXxUJZnzpn89K2zzHF0cSncZZVGKrohdb5f5T1wzxwU2NZPVGpvr88xhm+V2Y/fSrrTPwXcP3IIdtNOOtJdZw==" }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.4", @@ -25094,19 +25103,25 @@ "integrity": "sha512-uN7JgfQsyR16YHkuGRCTIcBcnyKIqKjGkB2SGk9x1XXH3yYGenL83kpAavX9Xtozqp17KppOlybJuzcKvZMrgw==" }, "@patternfly/react-core": { - "version": "4.250.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.250.1.tgz", - "integrity": "sha512-vAOZPQdZzYXl/vkHnHMIt1eC3nrPDdsuuErPatkNPwmSvilXuXmWP5wxoJ36FbSNRRURkprFwx52zMmWS3iHJA==", + "version": "4.264.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.264.0.tgz", + "integrity": "sha512-tK0BMWxw8nhukev40HZ6q6d02pDnjX7oyA91vHa18aakJUKBWMaerqpG4NZVMoh0tPKX3aLNj+zyCwDALFAZZw==", "requires": { - "@patternfly/react-icons": "^4.92.6", - "@patternfly/react-styles": "^4.91.6", - "@patternfly/react-tokens": "^4.93.6", + "@patternfly/react-icons": "^4.93.0", + "@patternfly/react-styles": "^4.92.0", + "@patternfly/react-tokens": "^4.94.0", "focus-trap": "6.9.2", "react-dropzone": "9.0.0", "tippy.js": "5.1.2", "tslib": "^2.0.0" }, "dependencies": { + "@patternfly/react-icons": { + "version": "4.93.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.93.0.tgz", + "integrity": "sha512-OH0vORVioL+HLWMEog8/3u8jsiMCeJ0pFpvRKRhy5Uk4CdAe40k1SOBvXJP6opr+O8TLbz0q3bm8Jsh/bPaCuQ==", + "requires": {} + }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -25121,9 +25136,9 @@ "requires": {} }, "@patternfly/react-styles": { - "version": "4.91.10", - "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.91.10.tgz", - "integrity": "sha512-fAG4Vjp63ohiR92F4e/Gkw5q1DSSckHKqdnEF75KUpSSBORzYP0EKMpupSd6ItpQFJw3iWs3MJi3/KIAAfU1Jw==" + "version": "4.92.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.92.0.tgz", + "integrity": "sha512-B/f6iyu8UEN1+wRxdC4sLIhvJeyL8SqInDXZmwOIqK8uPJ8Lze7qrbVhkkVzbMF37/oDPVa6dZH8qZFq062LEA==" }, "@patternfly/react-table": { "version": "4.108.0", @@ -25146,9 +25161,9 @@ } }, "@patternfly/react-tokens": { - "version": "4.93.10", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.93.10.tgz", - "integrity": "sha512-F+j1irDc9M6zvY6qNtDryhbpnHz3R8ymHRdGelNHQzPTIK88YSWEnT1c9iUI+uM/iuZol7sJmO5STtg2aPIDRQ==" + "version": "4.94.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.94.0.tgz", + "integrity": "sha512-fYXxUJZnzpn89K2zzHF0cSncZZVGKrohdb5f5T1wzxwU2NZPVGpvr88xhm+V2Y/fSrrTPwXcP3IIdtNOOtJdZw==" }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.4", diff --git a/awx/ui/package.json b/awx/ui/package.json index 0c117173df..2be86ac2dc 100644 --- a/awx/ui/package.json +++ b/awx/ui/package.json @@ -8,7 +8,7 @@ "dependencies": { "@lingui/react": "3.14.0", "@patternfly/patternfly": "4.217.1", - "@patternfly/react-core": "^4.250.1", + "@patternfly/react-core": "^4.264.0", "@patternfly/react-icons": "4.92.10", "@patternfly/react-table": "4.108.0", "ace-builds": "^1.10.1", From ed74d80ecb1ae08e7a44037248cb81e69839f118 Mon Sep 17 00:00:00 2001 From: Vidya Nambiar Date: Wed, 7 Dec 2022 13:40:00 -0500 Subject: [PATCH 07/32] Fixes 'Not Found' error on looking up credentials remove redundant console logs typo Signed-off-by: Vidya Nambiar --- awx/ui/package.json | 2 +- .../LaunchPrompt/steps/CredentialsStep.js | 4 ++ .../steps/CredentialsStep.test.js | 36 ++++++++++++++ .../Lookup/MultiCredentialsLookup.js | 4 ++ .../Lookup/MultiCredentialsLookup.test.js | 48 +++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/awx/ui/package.json b/awx/ui/package.json index 0c117173df..57289b4d94 100644 --- a/awx/ui/package.json +++ b/awx/ui/package.json @@ -74,7 +74,7 @@ "prestart-instrumented": "lingui compile", "pretest": "lingui compile", "pretest-watch": "lingui compile", - "start": "GENERATE_SOURCEMAP=false ESLINT_NO_DEV_ERRORS=true PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts start", + "start": "GENERATE_SOURCEMAP=false ESLINT_NO_DEV_ERRORS=true PORT=3003 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts start", "start-instrumented": "ESLINT_NO_DEV_ERRORS=true DEBUG=instrument-cra PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts -r @cypress/instrument-cra start", "build": "INLINE_RUNTIME_CHUNK=false react-scripts build", "test": "TZ='UTC' react-scripts test --watchAll=false", diff --git a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js index a79f04405c..35d9ad19ab 100644 --- a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js +++ b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.js @@ -153,6 +153,10 @@ function CredentialsStep({ }))} value={selectedType && selectedType.id} onChange={(e, id) => { + // Reset query params when the category of credentials is changed + history.replace({ + search: '', + }); setSelectedType(types.find((o) => o.id === parseInt(id, 10))); }} /> diff --git a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js index 0b403607ff..c29ec246cb 100644 --- a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js +++ b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js @@ -4,6 +4,7 @@ import { Formik } from 'formik'; import { CredentialsAPI, CredentialTypesAPI } from 'api'; import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; import CredentialsStep from './CredentialsStep'; +import { createMemoryHistory } from 'history'; jest.mock('../../../api/models/CredentialTypes'); jest.mock('../../../api/models/Credentials'); @@ -164,6 +165,41 @@ describe('CredentialsStep', () => { }); }); + test('should reset query params (credential.page) when selected credential type is changed', async () => { + let wrapper; + const history = createMemoryHistory({ + initialEntries: ['?credential.page=2'], + }); + await act(async () => { + wrapper = mountWithContexts( + + + , + { + context: { router: { history } }, + } + ); + }); + wrapper.update(); + + expect(CredentialsAPI.read).toHaveBeenCalledWith({ + credential_type: 1, + order_by: 'name', + page: 2, + page_size: 5, + }); + + await act(async () => { + wrapper.find('AnsibleSelect').invoke('onChange')({}, 3); + }); + expect(CredentialsAPI.read).toHaveBeenCalledWith({ + credential_type: 3, + order_by: 'name', + page: 1, + page_size: 5, + }); + }); + test("error should be shown when a credential that prompts for passwords is selected on a step that doesn't allow it", async () => { let wrapper; await act(async () => { diff --git a/awx/ui/src/components/Lookup/MultiCredentialsLookup.js b/awx/ui/src/components/Lookup/MultiCredentialsLookup.js index 31598e1f5b..ef0f3ef745 100644 --- a/awx/ui/src/components/Lookup/MultiCredentialsLookup.js +++ b/awx/ui/src/components/Lookup/MultiCredentialsLookup.js @@ -173,6 +173,10 @@ function MultiCredentialsLookup({ }))} value={selectedType && selectedType.id} onChange={(e, id) => { + // Reset query params when the category of credentials is changed + history.replace({ + search: '', + }); setSelectedType( credentialTypes.find((o) => o.id === parseInt(id, 10)) ); diff --git a/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js b/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js index 34c066d0fa..a5cb20f3a3 100644 --- a/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js +++ b/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js @@ -7,6 +7,7 @@ import { waitForElement, } from '../../../testUtils/enzymeHelpers'; import MultiCredentialsLookup from './MultiCredentialsLookup'; +import { createMemoryHistory } from 'history'; jest.mock('../../api'); @@ -228,6 +229,53 @@ describe('', () => { ]); }); + test('should reset query params (credentials.page) when selected credential type is changed', async () => { + const history = createMemoryHistory({ + initialEntries: ['?credentials.page=2'], + }); + await act(async () => { + wrapper = mountWithContexts( + + {}} + onError={() => {}} + /> + , + { + context: { router: { history } }, + } + ); + }); + const searchButton = await waitForElement( + wrapper, + 'Button[aria-label="Search"]' + ); + await act(async () => { + searchButton.invoke('onClick')(); + }); + expect(CredentialsAPI.read).toHaveBeenCalledWith({ + credential_type: 400, + order_by: 'name', + page: 2, + page_size: 5, + }); + + const select = await waitForElement(wrapper, 'AnsibleSelect'); + await act(async () => { + select.invoke('onChange')({}, 500); + }); + wrapper.update(); + + expect(CredentialsAPI.read).toHaveBeenCalledWith({ + credential_type: 500, + order_by: 'name', + page: 1, + page_size: 5, + }); + }); + test('should only add 1 credential per credential type except vault(see below)', async () => { const onChange = jest.fn(); await act(async () => { From 36ff9cbc6d54fbb9aed36a97661370fb5cfbb012 Mon Sep 17 00:00:00 2001 From: Vidya Nambiar Date: Wed, 7 Dec 2022 15:03:40 -0500 Subject: [PATCH 08/32] revert change to package.json Signed-off-by: Vidya Nambiar --- awx/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/package.json b/awx/ui/package.json index 57289b4d94..0c117173df 100644 --- a/awx/ui/package.json +++ b/awx/ui/package.json @@ -74,7 +74,7 @@ "prestart-instrumented": "lingui compile", "pretest": "lingui compile", "pretest-watch": "lingui compile", - "start": "GENERATE_SOURCEMAP=false ESLINT_NO_DEV_ERRORS=true PORT=3003 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts start", + "start": "GENERATE_SOURCEMAP=false ESLINT_NO_DEV_ERRORS=true PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts start", "start-instrumented": "ESLINT_NO_DEV_ERRORS=true DEBUG=instrument-cra PORT=3001 HTTPS=true DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts -r @cypress/instrument-cra start", "build": "INLINE_RUNTIME_CHUNK=false react-scripts build", "test": "TZ='UTC' react-scripts test --watchAll=false", From 15b7ad3570b5d84f14a2ee0bcccf9d4491524e16 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Wed, 7 Dec 2022 15:57:20 -0500 Subject: [PATCH 09/32] Add a post_migrate signal handler to rebuild the Org roles particularly, the execution_environment_admin_role. --- awx/main/signals.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/awx/main/signals.py b/awx/main/signals.py index 58ab17c95e..1b4a1b0b76 100644 --- a/awx/main/signals.py +++ b/awx/main/signals.py @@ -17,6 +17,7 @@ from django.db.models.signals import ( pre_delete, post_delete, m2m_changed, + post_migrate, ) from django.dispatch import receiver from django.contrib.auth import SESSION_KEY @@ -109,6 +110,19 @@ def emit_update_inventory_on_created_or_deleted(sender, **kwargs): connection.on_commit(lambda: update_inventory_computed_fields.delay(inventory.id)) +def fixup_missing_org_ee_admin_roles(app_config, **kwargs): + if app_config.label != 'main': + return + + print("Fixing up missing EE admin roles.") + with disable_activity_stream(): + for org in Organization.objects.all(): + org.save() + + +post_migrate.connect(fixup_missing_org_ee_admin_roles) + + def rebuild_role_ancestor_list(reverse, model, instance, pk_set, action, **kwargs): 'When a role parent is added or removed, update our role hierarchy list' if action == 'post_add': From cec2d2dfb93a74b10ef18ce8e17bf3318deee001 Mon Sep 17 00:00:00 2001 From: Vidya Nambiar Date: Thu, 8 Dec 2022 10:52:20 -0500 Subject: [PATCH 10/32] minor rearrangement of imports Signed-off-by: Vidya Nambiar --- .../src/components/LaunchPrompt/steps/CredentialsStep.test.js | 2 +- awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js index c29ec246cb..8c17ce432d 100644 --- a/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js +++ b/awx/ui/src/components/LaunchPrompt/steps/CredentialsStep.test.js @@ -3,8 +3,8 @@ import { act } from 'react-dom/test-utils'; import { Formik } from 'formik'; import { CredentialsAPI, CredentialTypesAPI } from 'api'; import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; -import CredentialsStep from './CredentialsStep'; import { createMemoryHistory } from 'history'; +import CredentialsStep from './CredentialsStep'; jest.mock('../../../api/models/CredentialTypes'); jest.mock('../../../api/models/Credentials'); diff --git a/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js b/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js index a5cb20f3a3..7efa248bf8 100644 --- a/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js +++ b/awx/ui/src/components/Lookup/MultiCredentialsLookup.test.js @@ -6,8 +6,8 @@ import { mountWithContexts, waitForElement, } from '../../../testUtils/enzymeHelpers'; -import MultiCredentialsLookup from './MultiCredentialsLookup'; import { createMemoryHistory } from 'history'; +import MultiCredentialsLookup from './MultiCredentialsLookup'; jest.mock('../../api'); From e524d3df3e2c312f3414e44fc807ea38895cb8b0 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Wed, 7 Dec 2022 16:19:28 -0500 Subject: [PATCH 11/32] Replace the role fixup post_migrate handler with a data migration --- .../0174_ensure_org_ee_admin_roles.py | 18 ++++++++++++++++++ awx/main/signals.py | 14 -------------- 2 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 awx/main/migrations/0174_ensure_org_ee_admin_roles.py diff --git a/awx/main/migrations/0174_ensure_org_ee_admin_roles.py b/awx/main/migrations/0174_ensure_org_ee_admin_roles.py new file mode 100644 index 0000000000..6792b10cc1 --- /dev/null +++ b/awx/main/migrations/0174_ensure_org_ee_admin_roles.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.16 on 2022-12-07 21:11 + +from django.db import migrations + +from awx.main.migrations import _rbac as rbac +from awx.main.migrations import _migration_utils as migration_utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0173_instancegroup_max_limits'), + ] + + operations = [ + migrations.RunPython(migration_utils.set_current_apps_for_migrations), + migrations.RunPython(rbac.create_roles), + ] diff --git a/awx/main/signals.py b/awx/main/signals.py index 1b4a1b0b76..58ab17c95e 100644 --- a/awx/main/signals.py +++ b/awx/main/signals.py @@ -17,7 +17,6 @@ from django.db.models.signals import ( pre_delete, post_delete, m2m_changed, - post_migrate, ) from django.dispatch import receiver from django.contrib.auth import SESSION_KEY @@ -110,19 +109,6 @@ def emit_update_inventory_on_created_or_deleted(sender, **kwargs): connection.on_commit(lambda: update_inventory_computed_fields.delay(inventory.id)) -def fixup_missing_org_ee_admin_roles(app_config, **kwargs): - if app_config.label != 'main': - return - - print("Fixing up missing EE admin roles.") - with disable_activity_stream(): - for org in Organization.objects.all(): - org.save() - - -post_migrate.connect(fixup_missing_org_ee_admin_roles) - - def rebuild_role_ancestor_list(reverse, model, instance, pk_set, action, **kwargs): 'When a role parent is added or removed, update our role hierarchy list' if action == 'post_add': From 7b2938f515ad306a396338c52b34a0b0591e1511 Mon Sep 17 00:00:00 2001 From: Manas Maiti Date: Mon, 12 Dec 2022 18:01:15 +0100 Subject: [PATCH 12/32] fix typo --- awx_collection/plugins/lookup/controller_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx_collection/plugins/lookup/controller_api.py b/awx_collection/plugins/lookup/controller_api.py index e7ac8829e7..94111c816d 100644 --- a/awx_collection/plugins/lookup/controller_api.py +++ b/awx_collection/plugins/lookup/controller_api.py @@ -74,7 +74,7 @@ EXAMPLES = """ - name: Load the UI settings specifying the connection info set_fact: - controller_settings: "{{ lookup('awx.awx.controller_api', 'settings/ui' host='controller.example.com', + controller_settings: "{{ lookup('awx.awx.controller_api', 'settings/ui', host='controller.example.com', username='admin', password=my_pass_var, verify_ssl=False) }}" - name: Report the usernames of all users with admin privs From beaf6b6058fe616bdffa2a19f0caada9e573a2c7 Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Tue, 13 Dec 2022 16:38:25 -0500 Subject: [PATCH 13/32] Fill in rest of ask_tags handling for WFJT module --- awx_collection/plugins/modules/workflow_job_template.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/awx_collection/plugins/modules/workflow_job_template.py b/awx_collection/plugins/modules/workflow_job_template.py index 09635175d6..e1667b3b21 100644 --- a/awx_collection/plugins/modules/workflow_job_template.py +++ b/awx_collection/plugins/modules/workflow_job_template.py @@ -789,6 +789,7 @@ def main(): allow_simultaneous=dict(type='bool'), ask_variables_on_launch=dict(type='bool'), ask_labels_on_launch=dict(type='bool', aliases=['ask_labels']), + ask_tags_on_launch=dict(type='bool'), ask_skip_tags_on_launch=dict(type='bool', aliases=['ask_skip_tags']), inventory=dict(), limit=dict(), @@ -873,6 +874,7 @@ def main(): 'ask_limit_on_launch', 'ask_variables_on_launch', 'ask_labels_on_launch', + 'ask_tags_on_launch', 'ask_skip_tags_on_launch', 'webhook_service', 'job_tags', From 51f8e362dc8e21febebe5a1dd4144dbd91be44c1 Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Wed, 14 Dec 2022 09:10:15 -0500 Subject: [PATCH 14/32] Add tags prompt to integration test --- .../integration/targets/workflow_job_template/tasks/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml b/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml index 27de3947d7..1477193e6c 100644 --- a/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml +++ b/awx_collection/tests/integration/targets/workflow_job_template/tasks/main.yml @@ -245,6 +245,7 @@ ask_inventory_on_launch: true ask_scm_branch_on_launch: true ask_limit_on_launch: true + ask_tags_on_launch: true ask_variables_on_launch: true register: result @@ -263,6 +264,7 @@ ask_inventory_on_launch: true ask_scm_branch_on_launch: true ask_limit_on_launch: true + ask_tags_on_launch: true ask_variables_on_launch: true register: bad_label_results ignore_errors: true @@ -278,6 +280,7 @@ ask_inventory_on_launch: false ask_scm_branch_on_launch: false ask_limit_on_launch: false + ask_tags_on_launch: false ask_variables_on_launch: false state: present From a4b950f79b96d61d21f7d8af531849d91d70bdfd Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Thu, 15 Dec 2022 14:09:40 +0100 Subject: [PATCH 15/32] Set AWS_SESSION_TOKEN in addition to AWS_SECURITY_TOKEN (#13297) * Set AWS_SESSION_TOKEN in addition to AWS_SECURITY_TOKEN * added AWS_SESSION_TOKEN to inventoryupdate-1 test --- awx/main/models/credential/injectors.py | 1 + awx/main/tests/data/inventory/plugins/ec2/env.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/awx/main/models/credential/injectors.py b/awx/main/models/credential/injectors.py index afbb30811b..93c1a37d8b 100644 --- a/awx/main/models/credential/injectors.py +++ b/awx/main/models/credential/injectors.py @@ -15,6 +15,7 @@ def aws(cred, env, private_data_dir): if cred.has_input('security_token'): env['AWS_SECURITY_TOKEN'] = cred.get_input('security_token', default='') + env['AWS_SESSION_TOKEN'] = env['AWS_SECURITY_TOKEN'] def gce(cred, env, private_data_dir): diff --git a/awx/main/tests/data/inventory/plugins/ec2/env.json b/awx/main/tests/data/inventory/plugins/ec2/env.json index 57e9c67a3b..77cedd003e 100644 --- a/awx/main/tests/data/inventory/plugins/ec2/env.json +++ b/awx/main/tests/data/inventory/plugins/ec2/env.json @@ -3,5 +3,6 @@ "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", "AWS_ACCESS_KEY_ID": "fooo", "AWS_SECRET_ACCESS_KEY": "fooo", - "AWS_SECURITY_TOKEN": "fooo" + "AWS_SECURITY_TOKEN": "fooo", + "AWS_SESSION_TOKEN": "fooo" } \ No newline at end of file From 7129f3e8cdac1b2ee9e3a938459cc9552210b64f Mon Sep 17 00:00:00 2001 From: John Westcott IV <32551173+john-westcott-iv@users.noreply.github.com> Date: Thu, 15 Dec 2022 10:15:09 -0500 Subject: [PATCH 16/32] Updating python3-saml (#13263) Moved to forked version to get latest lxml to allow other pacakges to update --- licenses/pkgconfig.txt | 19 ------------------- requirements/requirements.in | 4 ---- requirements/requirements.txt | 16 +++++----------- requirements/requirements_git.txt | 1 + 4 files changed, 6 insertions(+), 34 deletions(-) delete mode 100644 licenses/pkgconfig.txt diff --git a/licenses/pkgconfig.txt b/licenses/pkgconfig.txt deleted file mode 100644 index 716f12754d..0000000000 --- a/licenses/pkgconfig.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2013 Matthias Vogelgesang - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/requirements/requirements.in b/requirements/requirements.in index bb0b915ff7..ef4122991d 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -38,7 +38,6 @@ psycopg2 psutil pygerduty pyparsing==2.4.6 # Upgrading to v3 of pyparsing introduce errors on smart host filtering: Expected 'or' term, found 'or' (at char 15), (line:1, col:16) -python3-saml==1.13.0 python-dsv-sdk python-tss-sdk==1.0.0 python-ldap @@ -59,9 +58,6 @@ wheel pip==21.2.4 # see UPGRADE BLOCKERs setuptools # see UPGRADE BLOCKERs setuptools_scm[toml] # see UPGRADE BLOCKERs, xmlsec build dep -xmlsec==1.3.12 # xmlsec 1.3.13 removed the ability to use lxml 4.7.0 but python3-saml requires lxml 4.7.0 so we need to pin xmlsec -lxml>=3.8 # xmlsec build dep -pkgconfig>=1.5.1 # xmlsec build dep setuptools-rust >= 0.11.4 # cryptography build dep # Temporarily added to use ansible-runner from git branch, to be removed diff --git a/requirements/requirements.txt b/requirements/requirements.txt index a56ec5b7b4..a567675c62 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -198,15 +198,14 @@ jinja2==3.1.2 # via -r /awx_devel/requirements/requirements.in json-log-formatter==0.5.1 # via -r /awx_devel/requirements/requirements.in -jsonschema==4.17.1 +jsonschema==4.17.3 # via -r /awx_devel/requirements/requirements.in kubernetes==25.3.0 # via openshift lockfile==0.12.2 # via python-daemon -lxml==4.7.0 +lxml==4.9.1 # via - # -r /awx_devel/requirements/requirements.in # python3-saml # xmlsec markdown==3.4.1 @@ -251,8 +250,6 @@ pexpect==4.7.0 # via # -r /awx_devel/requirements/requirements.in # ansible-runner -pkgconfig==1.5.5 - # via -r /awx_devel/requirements/requirements.in prometheus-client==0.15.0 # via -r /awx_devel/requirements/requirements.in psutil==5.9.4 @@ -315,8 +312,7 @@ python-tss-sdk==1.0.0 # via -r /awx_devel/requirements/requirements.in python3-openid==3.2.0 # via social-auth-core -python3-saml==1.13.0 - # via -r /awx_devel/requirements/requirements.in + # via -r /awx_devel/requirements/requirements_git.txt pytz==2022.6 # via # django @@ -435,10 +431,8 @@ websocket-client==1.4.2 # via kubernetes wheel==0.38.4 # via -r /awx_devel/requirements/requirements.in -xmlsec==1.3.12 - # via - # -r /awx_devel/requirements/requirements.in - # python3-saml +xmlsec==1.3.13 + # via python3-saml yarl==1.8.1 # via aiohttp zipp==3.11.0 diff --git a/requirements/requirements_git.txt b/requirements/requirements_git.txt index ab13d9aed2..df424cca95 100644 --- a/requirements/requirements_git.txt +++ b/requirements/requirements_git.txt @@ -4,3 +4,4 @@ git+https://github.com/ansible/ansible-runner.git@devel#egg=ansible-runner # django-radius has an aggressive pin of future==0.16.0, see https://github.com/robgolding/django-radius/pull/25 git+https://github.com/ansible/django-radius.git@develop#egg=django-radius git+https://github.com/PythonCharmers/python-future@master#egg=future +git+https://github.com/ansible/python3-saml.git@devel#egg=python3-saml From 71a6baccdb303fa608581e86ada53ffa5da38439 Mon Sep 17 00:00:00 2001 From: Jake Jackson Date: Thu, 15 Dec 2022 16:40:51 -0500 Subject: [PATCH 17/32] Fix lookup plugins sanity (#13238) * fix pytz * fix NameError * fix tests and add sanity ignore files for import test until distutils replaced * change static method to regular method and update test to instantiate class --- .../plugins/lookup/schedule_rrule.py | 75 ++++++++-------- .../plugins/lookup/schedule_rruleset.py | 70 ++++++++------- awx_collection/test/awx/test_schedule.py | 6 +- awx_collection/tests/sanity/ignore-2.13.txt | 88 +++++++++++++++++++ awx_collection/tests/sanity/ignore-2.14.txt | 88 +++++++++++++++++++ 5 files changed, 253 insertions(+), 74 deletions(-) create mode 100644 awx_collection/tests/sanity/ignore-2.13.txt create mode 100644 awx_collection/tests/sanity/ignore-2.14.txt diff --git a/awx_collection/plugins/lookup/schedule_rrule.py b/awx_collection/plugins/lookup/schedule_rrule.py index c72a9ee6dc..b623dfc86e 100644 --- a/awx_collection/plugins/lookup/schedule_rrule.py +++ b/awx_collection/plugins/lookup/schedule_rrule.py @@ -101,39 +101,39 @@ else: class LookupModule(LookupBase): - frequencies = { - 'none': rrule.DAILY, - 'minute': rrule.MINUTELY, - 'hour': rrule.HOURLY, - 'day': rrule.DAILY, - 'week': rrule.WEEKLY, - 'month': rrule.MONTHLY, - } - - weekdays = { - 'monday': rrule.MO, - 'tuesday': rrule.TU, - 'wednesday': rrule.WE, - 'thursday': rrule.TH, - 'friday': rrule.FR, - 'saturday': rrule.SA, - 'sunday': rrule.SU, - } - - set_positions = { - 'first': 1, - 'second': 2, - 'third': 3, - 'fourth': 4, - 'last': -1, - } - # plugin constructor def __init__(self, *args, **kwargs): if LIBRARY_IMPORT_ERROR: raise_from(AnsibleError('{0}'.format(LIBRARY_IMPORT_ERROR)), LIBRARY_IMPORT_ERROR) super().__init__(*args, **kwargs) + self.frequencies = { + 'none': rrule.DAILY, + 'minute': rrule.MINUTELY, + 'hour': rrule.HOURLY, + 'day': rrule.DAILY, + 'week': rrule.WEEKLY, + 'month': rrule.MONTHLY, + } + + self.weekdays = { + 'monday': rrule.MO, + 'tuesday': rrule.TU, + 'wednesday': rrule.WE, + 'thursday': rrule.TH, + 'friday': rrule.FR, + 'saturday': rrule.SA, + 'sunday': rrule.SU, + } + + self.set_positions = { + 'first': 1, + 'second': 2, + 'third': 3, + 'fourth': 4, + 'last': -1, + } + @staticmethod def parse_date_time(date_string): try: @@ -149,14 +149,13 @@ class LookupModule(LookupBase): return self.get_rrule(frequency, kwargs) - @staticmethod - def get_rrule(frequency, kwargs): + def get_rrule(self, frequency, kwargs): - if frequency not in LookupModule.frequencies: + if frequency not in self.frequencies: raise AnsibleError('Frequency of {0} is invalid'.format(frequency)) rrule_kwargs = { - 'freq': LookupModule.frequencies[frequency], + 'freq': self.frequencies[frequency], 'interval': kwargs.get('every', 1), } @@ -187,9 +186,9 @@ class LookupModule(LookupBase): days = [] for day in kwargs['on_days'].split(','): day = day.strip() - if day not in LookupModule.weekdays: - raise AnsibleError('Parameter on_days must only contain values {0}'.format(', '.join(LookupModule.weekdays.keys()))) - days.append(LookupModule.weekdays[day]) + if day not in self.weekdays: + raise AnsibleError('Parameter on_days must only contain values {0}'.format(', '.join(self.weekdays.keys()))) + days.append(self.weekdays[day]) rrule_kwargs['byweekday'] = days @@ -214,13 +213,13 @@ class LookupModule(LookupBase): except Exception as e: raise_from(AnsibleError('on_the parameter must be two words separated by a space'), e) - if weekday not in LookupModule.weekdays: + if weekday not in self.weekdays: raise AnsibleError('Weekday portion of on_the parameter is not valid') - if occurance not in LookupModule.set_positions: + if occurance not in self.set_positions: raise AnsibleError('The first string of the on_the parameter is not valid') - rrule_kwargs['byweekday'] = LookupModule.weekdays[weekday] - rrule_kwargs['bysetpos'] = LookupModule.set_positions[occurance] + rrule_kwargs['byweekday'] = self.weekdays[weekday] + rrule_kwargs['bysetpos'] = self.set_positions[occurance] my_rule = rrule.rrule(**rrule_kwargs) diff --git a/awx_collection/plugins/lookup/schedule_rruleset.py b/awx_collection/plugins/lookup/schedule_rruleset.py index ead49bbc2a..a32b9d51cb 100644 --- a/awx_collection/plugins/lookup/schedule_rruleset.py +++ b/awx_collection/plugins/lookup/schedule_rruleset.py @@ -136,40 +136,44 @@ try: import pytz from dateutil import rrule except ImportError as imp_exc: - raise_from(AnsibleError('{0}'.format(imp_exc)), imp_exc) + LIBRARY_IMPORT_ERROR = imp_exc +else: + LIBRARY_IMPORT_ERROR = None class LookupModule(LookupBase): - frequencies = { - 'none': rrule.DAILY, - 'minute': rrule.MINUTELY, - 'hour': rrule.HOURLY, - 'day': rrule.DAILY, - 'week': rrule.WEEKLY, - 'month': rrule.MONTHLY, - } - - weekdays = { - 'monday': rrule.MO, - 'tuesday': rrule.TU, - 'wednesday': rrule.WE, - 'thursday': rrule.TH, - 'friday': rrule.FR, - 'saturday': rrule.SA, - 'sunday': rrule.SU, - } - - set_positions = { - 'first': 1, - 'second': 2, - 'third': 3, - 'fourth': 4, - 'last': -1, - } - # plugin constructor def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + if LIBRARY_IMPORT_ERROR: + raise_from(AnsibleError('{0}'.format(LIBRARY_IMPORT_ERROR)), LIBRARY_IMPORT_ERROR) + super().__init__(*args, **kwargs) + + self.frequencies = { + 'none': rrule.DAILY, + 'minute': rrule.MINUTELY, + 'hour': rrule.HOURLY, + 'day': rrule.DAILY, + 'week': rrule.WEEKLY, + 'month': rrule.MONTHLY, + } + + self.weekdays = { + 'monday': rrule.MO, + 'tuesday': rrule.TU, + 'wednesday': rrule.WE, + 'thursday': rrule.TH, + 'friday': rrule.FR, + 'saturday': rrule.SA, + 'sunday': rrule.SU, + } + + self.set_positions = { + 'first': 1, + 'second': 2, + 'third': 3, + 'fourth': 4, + 'last': -1, + } @staticmethod def parse_date_time(date_string): @@ -260,11 +264,11 @@ class LookupModule(LookupBase): frequency = rule.get('frequency', None) if not frequency: raise AnsibleError("Rule {0} is missing a frequency".format(rule_number)) - if frequency not in LookupModule.frequencies: + if frequency not in self.frequencies: raise AnsibleError('Frequency of rule {0} is invalid {1}'.format(rule_number, frequency)) rrule_kwargs = { - 'freq': LookupModule.frequencies[frequency], + 'freq': self.frequencies[frequency], 'interval': rule.get('interval', 1), 'dtstart': start_date, } @@ -287,7 +291,7 @@ class LookupModule(LookupBase): ) if 'bysetpos' in rule: - rrule_kwargs['bysetpos'] = self.process_list('bysetpos', rule, LookupModule.set_positions, rule_number) + rrule_kwargs['bysetpos'] = self.process_list('bysetpos', rule, self.set_positions, rule_number) if 'bymonth' in rule: rrule_kwargs['bymonth'] = self.process_integer('bymonth', rule, 1, 12, rule_number) @@ -302,7 +306,7 @@ class LookupModule(LookupBase): rrule_kwargs['byweekno'] = self.process_integer('byweekno', rule, 1, 52, rule_number) if 'byweekday' in rule: - rrule_kwargs['byweekday'] = self.process_list('byweekday', rule, LookupModule.weekdays, rule_number) + rrule_kwargs['byweekday'] = self.process_list('byweekday', rule, self.weekdays, rule_number) if 'byhour' in rule: rrule_kwargs['byhour'] = self.process_integer('byhour', rule, 0, 23, rule_number) diff --git a/awx_collection/test/awx/test_schedule.py b/awx_collection/test/awx/test_schedule.py index 13d70311ac..13f14c8145 100644 --- a/awx_collection/test/awx/test_schedule.py +++ b/awx_collection/test/awx/test_schedule.py @@ -81,7 +81,7 @@ def test_delete_same_named_schedule(run_module, project, inventory, admin_user): ], ) def test_rrule_lookup_plugin(collection_import, freq, kwargs, expect): - LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule + LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule() generated_rule = LookupModule.get_rrule(freq, kwargs) assert generated_rule == expect rrule_checker = SchedulePreviewSerializer() @@ -92,7 +92,7 @@ def test_rrule_lookup_plugin(collection_import, freq, kwargs, expect): @pytest.mark.parametrize("freq", ('none', 'minute', 'hour', 'day', 'week', 'month')) def test_empty_schedule_rrule(collection_import, freq): - LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule + LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule() if freq == 'day': pfreq = 'DAILY' elif freq == 'none': @@ -136,7 +136,7 @@ def test_empty_schedule_rrule(collection_import, freq): ], ) def test_rrule_lookup_plugin_failure(collection_import, freq, kwargs, msg): - LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule + LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule() with pytest.raises(AnsibleError) as e: assert LookupModule.get_rrule(freq, kwargs) assert msg in str(e.value) diff --git a/awx_collection/tests/sanity/ignore-2.13.txt b/awx_collection/tests/sanity/ignore-2.13.txt new file mode 100644 index 0000000000..cd98399548 --- /dev/null +++ b/awx_collection/tests/sanity/ignore-2.13.txt @@ -0,0 +1,88 @@ +plugins/module_utils/awxkit.py import-3.9 +plugins/module_utils/controller_api.py import-3.9 +plugins/modules/ad_hoc_command.py import-3.9 +plugins/modules/ad_hoc_command_cancel.py import-3.9 +plugins/modules/ad_hoc_command_wait.py import-3.9 +plugins/modules/application.py import-3.9 +plugins/modules/controller_meta.py import-3.9 +plugins/modules/credential.py import-3.92 +plugins/modules/credential_input_source.py import-3.9 +plugins/modules/credential_type.py import-3.9 +plugins/modules/execution_environment.py import-3.9 +plugins/modules/export.py import-3.9 +plugins/modules/group.py import-3.9 +plugins/modules/host.py import-3.9 +plugins/modules/import.py import-3.9 +plugins/modules/instance.py import-3.9 +plugins/modules/instance_group.py import-3.9 +plugins/modules/inventory.py import-3.9 +plugins/modules/inventory_source.py import-3.9 +plugins/modules/inventory_source_update.py import-3.9 +plugins/modules/job_cancel.py import-3.9 +plugins/modules/job_launch.py import-3.9 +plugins/modules/job_list.py import-3.9 +plugins/modules/job_template.py import-3.93 +plugins/modules/job_wait.py import-3.9 +plugins/modules/label.py import-3.9 +plugins/modules/license.py import-3.9 +plugins/modules/notification_template.py import-3.9 +plugins/modules/organization.py import-3.9 +plugins/modules/project.py import-3.92 +plugins/modules/project_update.py import-3.9 +plugins/modules/role.py import-3.9 +plugins/modules/schedule.py import-3.9 +plugins/modules/settings.py import-3.9 +plugins/modules/subscriptions.py import-3.9 +plugins/modules/team.py import-3.9 +plugins/modules/token.py import-3.9 +plugins/modules/user.py import-3.9 +plugins/modules/workflow_approval.py import-3.9 +plugins/modules/workflow_job_template.py import-3.9 +plugins/modules/workflow_job_template_node.py import-3.9 +plugins/modules/workflow_launch.py import-3.9 +plugins/modules/workflow_node_wait.py import-3.9 +plugins/inventory/controller.py import-3.10 +plugins/lookup/controller_api.py import-3.10 +plugins/module_utils/awxkit.py import-3.10 +plugins/module_utils/controller_api.py import-3.10 +plugins/modules/ad_hoc_command.py import-3.10 +plugins/modules/ad_hoc_command_cancel.py import-3.10 +plugins/modules/ad_hoc_command_wait.py import-3.10 +plugins/modules/application.py import-3.10 +plugins/modules/controller_meta.py import-3.10 +plugins/modules/credential.py import-3.10 +plugins/modules/credential_input_source.py import-3.10 +plugins/modules/credential_type.py import-3.10 +plugins/modules/execution_environment.py import-3.10 +plugins/modules/export.py import-3.10 +plugins/modules/group.py import-3.10 +plugins/modules/host.py import-3.10 +plugins/modules/import.py import-3.10 +plugins/modules/instance.py import-3.10 +plugins/modules/instance_group.py import-3.10 +plugins/modules/inventory.py import-3.10 +plugins/modules/inventory_source.py import-3.10 +plugins/modules/inventory_source_update.py import-3.10 +plugins/modules/job_cancel.py import-3.10 +plugins/modules/job_launch.py import-3.10 +plugins/modules/job_list.py import-3.10 +plugins/modules/job_template.py import-3.10 +plugins/modules/job_wait.py import-3.10 +plugins/modules/label.py import-3.10 +plugins/modules/license.py import-3.10 +plugins/modules/notification_template.py import-3.10 +plugins/modules/organization.py import-3.10 +plugins/modules/project.py import-3.10 +plugins/modules/project_update.py import-3.10 +plugins/modules/role.py import-3.10 +plugins/modules/schedule.py import-3.10 +plugins/modules/settings.py import-3.10 +plugins/modules/subscriptions.py import-3.10 +plugins/modules/team.py import-3.10 +plugins/modules/token.py import-3.10 +plugins/modules/user.py import-3.10 +plugins/modules/workflow_approval.py import-3.10 +plugins/modules/workflow_job_template.py import-3.10 +plugins/modules/workflow_job_template_node.py import-3.10 +plugins/modules/workflow_launch.py import-3.10 +plugins/modules/workflow_node_wait.py import-3.10 diff --git a/awx_collection/tests/sanity/ignore-2.14.txt b/awx_collection/tests/sanity/ignore-2.14.txt new file mode 100644 index 0000000000..cd98399548 --- /dev/null +++ b/awx_collection/tests/sanity/ignore-2.14.txt @@ -0,0 +1,88 @@ +plugins/module_utils/awxkit.py import-3.9 +plugins/module_utils/controller_api.py import-3.9 +plugins/modules/ad_hoc_command.py import-3.9 +plugins/modules/ad_hoc_command_cancel.py import-3.9 +plugins/modules/ad_hoc_command_wait.py import-3.9 +plugins/modules/application.py import-3.9 +plugins/modules/controller_meta.py import-3.9 +plugins/modules/credential.py import-3.92 +plugins/modules/credential_input_source.py import-3.9 +plugins/modules/credential_type.py import-3.9 +plugins/modules/execution_environment.py import-3.9 +plugins/modules/export.py import-3.9 +plugins/modules/group.py import-3.9 +plugins/modules/host.py import-3.9 +plugins/modules/import.py import-3.9 +plugins/modules/instance.py import-3.9 +plugins/modules/instance_group.py import-3.9 +plugins/modules/inventory.py import-3.9 +plugins/modules/inventory_source.py import-3.9 +plugins/modules/inventory_source_update.py import-3.9 +plugins/modules/job_cancel.py import-3.9 +plugins/modules/job_launch.py import-3.9 +plugins/modules/job_list.py import-3.9 +plugins/modules/job_template.py import-3.93 +plugins/modules/job_wait.py import-3.9 +plugins/modules/label.py import-3.9 +plugins/modules/license.py import-3.9 +plugins/modules/notification_template.py import-3.9 +plugins/modules/organization.py import-3.9 +plugins/modules/project.py import-3.92 +plugins/modules/project_update.py import-3.9 +plugins/modules/role.py import-3.9 +plugins/modules/schedule.py import-3.9 +plugins/modules/settings.py import-3.9 +plugins/modules/subscriptions.py import-3.9 +plugins/modules/team.py import-3.9 +plugins/modules/token.py import-3.9 +plugins/modules/user.py import-3.9 +plugins/modules/workflow_approval.py import-3.9 +plugins/modules/workflow_job_template.py import-3.9 +plugins/modules/workflow_job_template_node.py import-3.9 +plugins/modules/workflow_launch.py import-3.9 +plugins/modules/workflow_node_wait.py import-3.9 +plugins/inventory/controller.py import-3.10 +plugins/lookup/controller_api.py import-3.10 +plugins/module_utils/awxkit.py import-3.10 +plugins/module_utils/controller_api.py import-3.10 +plugins/modules/ad_hoc_command.py import-3.10 +plugins/modules/ad_hoc_command_cancel.py import-3.10 +plugins/modules/ad_hoc_command_wait.py import-3.10 +plugins/modules/application.py import-3.10 +plugins/modules/controller_meta.py import-3.10 +plugins/modules/credential.py import-3.10 +plugins/modules/credential_input_source.py import-3.10 +plugins/modules/credential_type.py import-3.10 +plugins/modules/execution_environment.py import-3.10 +plugins/modules/export.py import-3.10 +plugins/modules/group.py import-3.10 +plugins/modules/host.py import-3.10 +plugins/modules/import.py import-3.10 +plugins/modules/instance.py import-3.10 +plugins/modules/instance_group.py import-3.10 +plugins/modules/inventory.py import-3.10 +plugins/modules/inventory_source.py import-3.10 +plugins/modules/inventory_source_update.py import-3.10 +plugins/modules/job_cancel.py import-3.10 +plugins/modules/job_launch.py import-3.10 +plugins/modules/job_list.py import-3.10 +plugins/modules/job_template.py import-3.10 +plugins/modules/job_wait.py import-3.10 +plugins/modules/label.py import-3.10 +plugins/modules/license.py import-3.10 +plugins/modules/notification_template.py import-3.10 +plugins/modules/organization.py import-3.10 +plugins/modules/project.py import-3.10 +plugins/modules/project_update.py import-3.10 +plugins/modules/role.py import-3.10 +plugins/modules/schedule.py import-3.10 +plugins/modules/settings.py import-3.10 +plugins/modules/subscriptions.py import-3.10 +plugins/modules/team.py import-3.10 +plugins/modules/token.py import-3.10 +plugins/modules/user.py import-3.10 +plugins/modules/workflow_approval.py import-3.10 +plugins/modules/workflow_job_template.py import-3.10 +plugins/modules/workflow_job_template_node.py import-3.10 +plugins/modules/workflow_launch.py import-3.10 +plugins/modules/workflow_node_wait.py import-3.10 From f04ac3c7981374c79211e5edfcd73c4225fe2e55 Mon Sep 17 00:00:00 2001 From: Shane McDonald Date: Thu, 15 Dec 2022 18:07:42 -0500 Subject: [PATCH 18/32] Remove unneeded pass_env in tox config I don't recall us ever using Travis so I'm not sure why this is here. https://tox.wiki/en/latest/changelog.html#v4-0-6-2022-12-10 --- awxkit/tox.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/awxkit/tox.ini b/awxkit/tox.ini index 3e63d73673..dc14051b7d 100644 --- a/awxkit/tox.ini +++ b/awxkit/tox.ini @@ -9,7 +9,6 @@ skip_missing_interpreters = true [testenv] basepython = python3.9 -passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH setenv = PYTHONPATH = {toxinidir}:{env:PYTHONPATH:}:. deps = From e363ddf47055a8f3a77319c9bd5f1bb2e8634344 Mon Sep 17 00:00:00 2001 From: Satoe Imaishi Date: Thu, 15 Dec 2022 16:39:21 -0500 Subject: [PATCH 19/32] Add back pkgconfig for offline build --- licenses/pkgconfig.txt | 19 +++++++++++++++++++ requirements/requirements.in | 1 + requirements/requirements.txt | 2 ++ 3 files changed, 22 insertions(+) create mode 100644 licenses/pkgconfig.txt diff --git a/licenses/pkgconfig.txt b/licenses/pkgconfig.txt new file mode 100644 index 0000000000..716f12754d --- /dev/null +++ b/licenses/pkgconfig.txt @@ -0,0 +1,19 @@ +Copyright (c) 2013 Matthias Vogelgesang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/requirements/requirements.in b/requirements/requirements.in index ef4122991d..ae0ba7768d 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -59,6 +59,7 @@ pip==21.2.4 # see UPGRADE BLOCKERs setuptools # see UPGRADE BLOCKERs setuptools_scm[toml] # see UPGRADE BLOCKERs, xmlsec build dep setuptools-rust >= 0.11.4 # cryptography build dep +pkgconfig>=1.5.1 # xmlsec build dep - needed for offline build # Temporarily added to use ansible-runner from git branch, to be removed # when ansible-runner moves from requirements_git.txt to here diff --git a/requirements/requirements.txt b/requirements/requirements.txt index a567675c62..afb43f659a 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -250,6 +250,8 @@ pexpect==4.7.0 # via # -r /awx_devel/requirements/requirements.in # ansible-runner +pkgconfig==1.5.5 + # via -r /awx_devel/requirements/requirements.in prometheus-client==0.15.0 # via -r /awx_devel/requirements/requirements.in psutil==5.9.4 From c2a3c3b28597676f9153ef7d4e108eb8c3d6414e Mon Sep 17 00:00:00 2001 From: Gabe Muniz Date: Thu, 15 Dec 2022 09:41:55 -0500 Subject: [PATCH 20/32] The current behavior of workflow job templates is to pass in an empty string as scm_branch on allsaves and edits. This becomes problematic when using job templates/workflows which allow prompt on launch for scm_branch as it may override the scm_branch set for the individual workflow nodes to an empty string. That behavior limits the usefulness of prompting scm branch as it can no longer by selected while creating workflows as they'll be overwritten. --- .../Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.js | 2 ++ .../Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.js b/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.js index 8d6e7badc4..d6990920fa 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.js @@ -24,6 +24,7 @@ function WorkflowJobTemplateAdd() { limit, job_tags, skip_tags, + scm_branch, ...templatePayload } = values; templatePayload.inventory = inventory?.id; @@ -32,6 +33,7 @@ function WorkflowJobTemplateAdd() { templatePayload.limit = limit === '' ? null : limit; templatePayload.job_tags = job_tags === '' ? null : job_tags; templatePayload.skip_tags = skip_tags === '' ? null : skip_tags; + templatePayload.scm_branch = scm_branch === '' ? null : scm_branch; const organizationId = organization?.id || inventory?.summary_fields?.organization.id; try { diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.js b/awx/ui/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.js index d4929ec663..417451212a 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.js @@ -30,6 +30,7 @@ function WorkflowJobTemplateEdit({ template }) { limit, job_tags, skip_tags, + scm_branch, ...templatePayload } = values; templatePayload.inventory = inventory?.id || null; @@ -38,6 +39,7 @@ function WorkflowJobTemplateEdit({ template }) { templatePayload.limit = limit === '' ? null : limit; templatePayload.job_tags = job_tags === '' ? null : job_tags; templatePayload.skip_tags = skip_tags === '' ? null : skip_tags; + templatePayload.scm_branch = scm_branch === '' ? null : scm_branch; const formOrgId = organization?.id || inventory?.summary_fields?.organization.id || null; From cc336e791cce212c0cec7faacc7b141c6ed99a46 Mon Sep 17 00:00:00 2001 From: Gabe Muniz Date: Thu, 15 Dec 2022 11:55:57 -0500 Subject: [PATCH 21/32] fix expected test result --- .../WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.js b/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.js index 8eaab645fc..1640b9cf4e 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.js @@ -119,7 +119,7 @@ describe('', () => { job_tags: null, limit: null, organization: undefined, - scm_branch: '', + scm_branch: null, skip_tags: null, webhook_credential: undefined, webhook_service: '', From e87e041a2a2a6d168a84d3eeea6664985f1c8ab8 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Fri, 16 Dec 2022 13:11:14 -0500 Subject: [PATCH 22/32] Break up and conditionally add the RBAC checks for ActivityStream (#13279) This should vastly improve the queries executed when accessing any of the activity stream endpoints as a normal user, in many cases. --- awx/main/access.py | 88 ++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/awx/main/access.py b/awx/main/access.py index fed80f87f8..71e49d4623 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -2697,46 +2697,66 @@ class ActivityStreamAccess(BaseAccess): # 'job_template', 'job', 'project', 'project_update', 'workflow_job', # 'inventory_source', 'workflow_job_template' - inventory_set = Inventory.accessible_objects(self.user, 'read_role') - credential_set = Credential.accessible_objects(self.user, 'read_role') + q = Q(user=self.user) + inventory_set = Inventory.accessible_pk_qs(self.user, 'read_role') + if inventory_set: + q |= ( + Q(ad_hoc_command__inventory__in=inventory_set) + | Q(inventory__in=inventory_set) + | Q(host__inventory__in=inventory_set) + | Q(group__inventory__in=inventory_set) + | Q(inventory_source__inventory__in=inventory_set) + | Q(inventory_update__inventory_source__inventory__in=inventory_set) + ) + + credential_set = Credential.accessible_pk_qs(self.user, 'read_role') + if credential_set: + q |= Q(credential__in=credential_set) + auditing_orgs = ( (Organization.accessible_objects(self.user, 'admin_role') | Organization.accessible_objects(self.user, 'auditor_role')) .distinct() .values_list('id', flat=True) ) - project_set = Project.accessible_objects(self.user, 'read_role') - jt_set = JobTemplate.accessible_objects(self.user, 'read_role') - team_set = Team.accessible_objects(self.user, 'read_role') - wfjt_set = WorkflowJobTemplate.accessible_objects(self.user, 'read_role') - app_set = OAuth2ApplicationAccess(self.user).filtered_queryset() - token_set = OAuth2TokenAccess(self.user).filtered_queryset() + if auditing_orgs: + q |= ( + Q(user__in=auditing_orgs.values('member_role__members')) + | Q(organization__in=auditing_orgs) + | Q(notification_template__organization__in=auditing_orgs) + | Q(notification__notification_template__organization__in=auditing_orgs) + | Q(label__organization__in=auditing_orgs) + | Q(role__in=Role.objects.filter(ancestors__in=self.user.roles.all()) if auditing_orgs else []) + ) - return qs.filter( - Q(ad_hoc_command__inventory__in=inventory_set) - | Q(o_auth2_application__in=app_set) - | Q(o_auth2_access_token__in=token_set) - | Q(user__in=auditing_orgs.values('member_role__members')) - | Q(user=self.user) - | Q(organization__in=auditing_orgs) - | Q(inventory__in=inventory_set) - | Q(host__inventory__in=inventory_set) - | Q(group__inventory__in=inventory_set) - | Q(inventory_source__inventory__in=inventory_set) - | Q(inventory_update__inventory_source__inventory__in=inventory_set) - | Q(credential__in=credential_set) - | Q(team__in=team_set) - | Q(project__in=project_set) - | Q(project_update__project__in=project_set) - | Q(job_template__in=jt_set) - | Q(job__job_template__in=jt_set) - | Q(workflow_job_template__in=wfjt_set) - | Q(workflow_job_template_node__workflow_job_template__in=wfjt_set) - | Q(workflow_job__workflow_job_template__in=wfjt_set) - | Q(notification_template__organization__in=auditing_orgs) - | Q(notification__notification_template__organization__in=auditing_orgs) - | Q(label__organization__in=auditing_orgs) - | Q(role__in=Role.objects.filter(ancestors__in=self.user.roles.all()) if auditing_orgs else []) - ).distinct() + project_set = Project.accessible_pk_qs(self.user, 'read_role') + if project_set: + q |= Q(project__in=project_set) | Q(project_update__project__in=project_set) + + jt_set = JobTemplate.accessible_pk_qs(self.user, 'read_role') + if jt_set: + q |= Q(job_template__in=jt_set) | Q(job__job_template__in=jt_set) + + wfjt_set = WorkflowJobTemplate.accessible_pk_qs(self.user, 'read_role') + if wfjt_set: + q |= ( + Q(workflow_job_template__in=wfjt_set) + | Q(workflow_job_template_node__workflow_job_template__in=wfjt_set) + | Q(workflow_job__workflow_job_template__in=wfjt_set) + ) + + team_set = Team.accessible_pk_qs(self.user, 'read_role') + if team_set: + q |= Q(team__in=team_set) + + app_set = OAuth2ApplicationAccess(self.user).filtered_queryset() + if app_set: + q |= Q(o_auth2_application__in=app_set) + + token_set = OAuth2TokenAccess(self.user).filtered_queryset() + if token_set: + q |= Q(o_auth2_access_token__in=token_set) + + return qs.filter(q).distinct() def can_add(self, data): return False From b7f2825909a4a0960d2849c2defef5c6a189afb1 Mon Sep 17 00:00:00 2001 From: John Westcott IV <32551173+john-westcott-iv@users.noreply.github.com> Date: Sat, 17 Dec 2022 12:15:27 -0500 Subject: [PATCH 23/32] Throw a warning if custom secret key was specified but not given (#13128) * Throw a warning if custom secret key was specified but not given * Fixing unit tests --- .../management/commands/regenerate_secret_key.py | 10 ++++++++-- .../commands/test_secret_key_regeneration.py | 12 ++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/awx/main/management/commands/regenerate_secret_key.py b/awx/main/management/commands/regenerate_secret_key.py index 9c86ef4e6e..248256eb7e 100644 --- a/awx/main/management/commands/regenerate_secret_key.py +++ b/awx/main/management/commands/regenerate_secret_key.py @@ -32,8 +32,14 @@ class Command(BaseCommand): def handle(self, **options): self.old_key = settings.SECRET_KEY custom_key = os.environ.get("TOWER_SECRET_KEY") - if options.get("use_custom_key") and custom_key: - self.new_key = custom_key + if options.get("use_custom_key"): + if custom_key: + self.new_key = custom_key + else: + print("Use custom key was specified but the env var TOWER_SECRET_KEY was not available") + import sys + + sys.exit(1) else: self.new_key = base64.encodebytes(os.urandom(33)).decode().rstrip() self._notification_templates() diff --git a/awx/main/tests/functional/commands/test_secret_key_regeneration.py b/awx/main/tests/functional/commands/test_secret_key_regeneration.py index f223f5d80d..808fefbdc9 100644 --- a/awx/main/tests/functional/commands/test_secret_key_regeneration.py +++ b/awx/main/tests/functional/commands/test_secret_key_regeneration.py @@ -171,13 +171,17 @@ class TestKeyRegeneration: def test_use_custom_key_with_empty_tower_secret_key_env_var(self): os.environ['TOWER_SECRET_KEY'] = '' - new_key = call_command('regenerate_secret_key', '--use-custom-key') - assert settings.SECRET_KEY != new_key + with pytest.raises(SystemExit) as e: + call_command('regenerate_secret_key', '--use-custom-key') + assert e.type == SystemExit + assert e.value.code == 1 def test_use_custom_key_with_no_tower_secret_key_env_var(self): os.environ.pop('TOWER_SECRET_KEY', None) - new_key = call_command('regenerate_secret_key', '--use-custom-key') - assert settings.SECRET_KEY != new_key + with pytest.raises(SystemExit) as e: + call_command('regenerate_secret_key', '--use-custom-key') + assert e.type == SystemExit + assert e.value.code == 1 def test_with_tower_secret_key_env_var(self): custom_key = 'MXSq9uqcwezBOChl/UfmbW1k4op+bC+FQtwPqgJ1u9XV' From 8f6849fc223cc3f3981ddbba311bc0f7895ff064 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Mon, 19 Dec 2022 12:16:05 -0500 Subject: [PATCH 24/32] Include listener_port in the defaults for Instance.objects.register (#13328) --- awx/main/managers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/awx/main/managers.py b/awx/main/managers.py index 7fc5361e62..32d6ed7f5b 100644 --- a/awx/main/managers.py +++ b/awx/main/managers.py @@ -158,7 +158,11 @@ class InstanceManager(models.Manager): return (False, instance) # Create new instance, and fill in default values - create_defaults = {'node_state': Instance.States.INSTALLED, 'capacity': 0} + create_defaults = { + 'node_state': Instance.States.INSTALLED, + 'capacity': 0, + 'listener_port': 27199, + } if defaults is not None: create_defaults.update(defaults) uuid_option = {} From 94b34b801cdbefd0ce001b8dfcc2a6184dcc3060 Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Mon, 19 Dec 2022 11:19:38 -0500 Subject: [PATCH 25/32] Avoid unbounded kwargs by fetching subtasks inside handle_work_error Update tests to new handle_work_error call pattern Handle blame correctly with multiple serial deps add new test case corresponding to this scenario --- awx/main/scheduler/task_manager.py | 21 +++---- awx/main/tasks/system.py | 63 +++++++++---------- .../task_management/test_rampart_groups.py | 12 ++-- .../task_management/test_scheduler.py | 28 ++++----- awx/main/tests/functional/test_tasks.py | 18 +++++- 5 files changed, 72 insertions(+), 70 deletions(-) diff --git a/awx/main/scheduler/task_manager.py b/awx/main/scheduler/task_manager.py index 3610ecb89a..880d1e9e71 100644 --- a/awx/main/scheduler/task_manager.py +++ b/awx/main/scheduler/task_manager.py @@ -507,7 +507,7 @@ class TaskManager(TaskBase): return None @timeit - def start_task(self, task, instance_group, dependent_tasks=None, instance=None): + def start_task(self, task, instance_group, instance=None): # Just like for process_running_tasks, add the job to the dependency graph and # ask the TaskManagerInstanceGroups object to update consumed capacity on all # implicated instances and container groups. @@ -524,14 +524,6 @@ class TaskManager(TaskBase): ScheduleTaskManager().schedule() from awx.main.tasks.system import handle_work_error, handle_work_success - dependent_tasks = dependent_tasks or [] - - task_actual = { - 'type': get_type_for_model(type(task)), - 'id': task.id, - } - dependencies = [{'type': get_type_for_model(type(t)), 'id': t.id} for t in dependent_tasks] - task.status = 'waiting' (start_status, opts) = task.pre_start() @@ -563,6 +555,7 @@ class TaskManager(TaskBase): # apply_async does a NOTIFY to the channel dispatcher is listening to # postgres will treat this as part of the transaction, which is what we want if task.status != 'failed' and type(task) is not WorkflowJob: + task_actual = {'type': get_type_for_model(type(task)), 'id': task.id} task_cls = task._get_task_class() task_cls.apply_async( [task.pk], @@ -570,7 +563,7 @@ class TaskManager(TaskBase): queue=task.get_queue_name(), uuid=task.celery_task_id, callbacks=[{'task': handle_work_success.name, 'kwargs': {'task_actual': task_actual}}], - errbacks=[{'task': handle_work_error.name, 'args': [task.celery_task_id], 'kwargs': {'subtasks': [task_actual] + dependencies}}], + errbacks=[{'task': handle_work_error.name, 'kwargs': {'task_actual': task_actual}}], ) # In exception cases, like a job failing pre-start checks, we send the websocket status message @@ -609,7 +602,7 @@ class TaskManager(TaskBase): if isinstance(task, WorkflowJob): # Previously we were tracking allow_simultaneous blocking both here and in DependencyGraph. # Double check that using just the DependencyGraph works for Workflows and Sliced Jobs. - self.start_task(task, None, task.get_jobs_fail_chain(), None) + self.start_task(task, None, None) continue found_acceptable_queue = False @@ -637,7 +630,7 @@ class TaskManager(TaskBase): execution_instance = self.tm_models.instances[control_instance.hostname].obj task.log_lifecycle("controller_node_chosen") task.log_lifecycle("execution_node_chosen") - self.start_task(task, self.controlplane_ig, task.get_jobs_fail_chain(), execution_instance) + self.start_task(task, self.controlplane_ig, execution_instance) found_acceptable_queue = True continue @@ -645,7 +638,7 @@ class TaskManager(TaskBase): if not self.tm_models.instance_groups[instance_group.name].has_remaining_capacity(task): continue if instance_group.is_container_group: - self.start_task(task, instance_group, task.get_jobs_fail_chain(), None) + self.start_task(task, instance_group, None) found_acceptable_queue = True break @@ -670,7 +663,7 @@ class TaskManager(TaskBase): ) ) execution_instance = self.tm_models.instances[execution_instance.hostname].obj - self.start_task(task, instance_group, task.get_jobs_fail_chain(), execution_instance) + self.start_task(task, instance_group, execution_instance) found_acceptable_queue = True break else: diff --git a/awx/main/tasks/system.py b/awx/main/tasks/system.py index ee3293beae..482c168af2 100644 --- a/awx/main/tasks/system.py +++ b/awx/main/tasks/system.py @@ -52,6 +52,7 @@ from awx.main.constants import ACTIVE_STATES from awx.main.dispatch.publish import task from awx.main.dispatch import get_local_queuename, reaper from awx.main.utils.common import ( + get_type_for_model, ignore_inventory_computed_fields, ignore_inventory_group_removal, ScheduleWorkflowManager, @@ -720,45 +721,43 @@ def handle_work_success(task_actual): @task(queue=get_local_queuename) -def handle_work_error(task_id, *args, **kwargs): - subtasks = kwargs.get('subtasks', None) - logger.debug('Executing error task id %s, subtasks: %s' % (task_id, str(subtasks))) - first_instance = None - first_instance_type = '' - if subtasks is not None: - for each_task in subtasks: - try: - instance = UnifiedJob.get_instance_by_type(each_task['type'], each_task['id']) - if not instance: - # Unknown task type - logger.warning("Unknown task type: {}".format(each_task['type'])) - continue - except ObjectDoesNotExist: - logger.warning('Missing {} `{}` in error callback.'.format(each_task['type'], each_task['id'])) - continue +def handle_work_error(task_actual): + try: + instance = UnifiedJob.get_instance_by_type(task_actual['type'], task_actual['id']) + except ObjectDoesNotExist: + logger.warning('Missing {} `{}` in error callback.'.format(task_actual['type'], task_actual['id'])) + return + if not instance: + return - if first_instance is None: - first_instance = instance - first_instance_type = each_task['type'] + subtasks = instance.get_jobs_fail_chain() # reverse of dependent_jobs mostly + logger.debug(f'Executing error task id {task_actual["id"]}, subtasks: {[subtask.id for subtask in subtasks]}') - if instance.celery_task_id != task_id and not instance.cancel_flag and not instance.status in ('successful', 'failed'): - instance.status = 'failed' - instance.failed = True - if not instance.job_explanation: - instance.job_explanation = 'Previous Task Failed: {"job_type": "%s", "job_name": "%s", "job_id": "%s"}' % ( - first_instance_type, - first_instance.name, - first_instance.id, - ) - instance.save() - instance.websocket_emit_status("failed") + deps_of_deps = {} + + for subtask in subtasks: + if subtask.celery_task_id != instance.celery_task_id and not subtask.cancel_flag and not subtask.status in ('successful', 'failed'): + # If there are multiple in the dependency chain, A->B->C, and this was called for A, blame B for clarity + blame_job = deps_of_deps.get(subtask.id, instance) + subtask.status = 'failed' + subtask.failed = True + if not subtask.job_explanation: + subtask.job_explanation = 'Previous Task Failed: {"job_type": "%s", "job_name": "%s", "job_id": "%s"}' % ( + get_type_for_model(type(blame_job)), + blame_job.name, + blame_job.id, + ) + subtask.save() + subtask.websocket_emit_status("failed") + + for sub_subtask in subtask.get_jobs_fail_chain(): + deps_of_deps[sub_subtask.id] = subtask # We only send 1 job complete message since all the job completion message # handling does is trigger the scheduler. If we extend the functionality of # what the job complete message handler does then we may want to send a # completion event for each job here. - if first_instance: - schedule_manager_success_or_error(first_instance) + schedule_manager_success_or_error(instance) @task(queue=get_local_queuename) diff --git a/awx/main/tests/functional/task_management/test_rampart_groups.py b/awx/main/tests/functional/task_management/test_rampart_groups.py index 6bed591147..48ea9edb08 100644 --- a/awx/main/tests/functional/task_management/test_rampart_groups.py +++ b/awx/main/tests/functional/task_management/test_rampart_groups.py @@ -23,7 +23,7 @@ def test_multi_group_basic_job_launch(instance_factory, controlplane_instance_gr mock_task_impact.return_value = 500 with mocker.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_has_calls([mock.call(j1, ig1, [], i1), mock.call(j2, ig2, [], i2)]) + TaskManager.start_task.assert_has_calls([mock.call(j1, ig1, i1), mock.call(j2, ig2, i2)]) @pytest.mark.django_db @@ -54,7 +54,7 @@ def test_multi_group_with_shared_dependency(instance_factory, controlplane_insta DependencyManager().schedule() TaskManager().schedule() pu = p.project_updates.first() - TaskManager.start_task.assert_called_once_with(pu, controlplane_instance_group, [j1, j2], controlplane_instance_group.instances.all()[0]) + TaskManager.start_task.assert_called_once_with(pu, controlplane_instance_group, controlplane_instance_group.instances.all()[0]) pu.finished = pu.created + timedelta(seconds=1) pu.status = "successful" pu.save() @@ -62,8 +62,8 @@ def test_multi_group_with_shared_dependency(instance_factory, controlplane_insta DependencyManager().schedule() TaskManager().schedule() - TaskManager.start_task.assert_any_call(j1, ig1, [], i1) - TaskManager.start_task.assert_any_call(j2, ig2, [], i2) + TaskManager.start_task.assert_any_call(j1, ig1, i1) + TaskManager.start_task.assert_any_call(j2, ig2, i2) assert TaskManager.start_task.call_count == 2 @@ -75,7 +75,7 @@ def test_workflow_job_no_instancegroup(workflow_job_template_factory, controlpla wfj.save() with mocker.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(wfj, None, [], None) + TaskManager.start_task.assert_called_once_with(wfj, None, None) assert wfj.instance_group is None @@ -150,7 +150,7 @@ def test_failover_group_run(instance_factory, controlplane_instance_group, mocke mock_task_impact.return_value = 500 with mock.patch.object(TaskManager, "start_task", wraps=tm.start_task) as mock_job: tm.schedule() - mock_job.assert_has_calls([mock.call(j1, ig1, [], i1), mock.call(j1_1, ig2, [], i2)]) + mock_job.assert_has_calls([mock.call(j1, ig1, i1), mock.call(j1_1, ig2, i2)]) assert mock_job.call_count == 2 diff --git a/awx/main/tests/functional/task_management/test_scheduler.py b/awx/main/tests/functional/task_management/test_scheduler.py index f362841033..42d144d5cc 100644 --- a/awx/main/tests/functional/task_management/test_scheduler.py +++ b/awx/main/tests/functional/task_management/test_scheduler.py @@ -18,7 +18,7 @@ def test_single_job_scheduler_launch(hybrid_instance, controlplane_instance_grou j = create_job(objects.job_template) with mocker.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, [], instance) + TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @pytest.mark.django_db @@ -240,12 +240,12 @@ def test_multi_jt_capacity_blocking(hybrid_instance, job_template_factory, mocke mock_task_impact.return_value = 505 with mock.patch.object(TaskManager, "start_task", wraps=tm.start_task) as mock_job: tm.schedule() - mock_job.assert_called_once_with(j1, controlplane_instance_group, [], instance) + mock_job.assert_called_once_with(j1, controlplane_instance_group, instance) j1.status = "successful" j1.save() with mock.patch.object(TaskManager, "start_task", wraps=tm.start_task) as mock_job: tm.schedule() - mock_job.assert_called_once_with(j2, controlplane_instance_group, [], instance) + mock_job.assert_called_once_with(j2, controlplane_instance_group, instance) @pytest.mark.django_db @@ -337,12 +337,12 @@ def test_single_job_dependencies_project_launch(controlplane_instance_group, job pu = [x for x in p.project_updates.all()] assert len(pu) == 1 TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(pu[0], controlplane_instance_group, [j], instance) + TaskManager.start_task.assert_called_once_with(pu[0], controlplane_instance_group, instance) pu[0].status = "successful" pu[0].save() with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, [], instance) + TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @pytest.mark.django_db @@ -365,12 +365,12 @@ def test_single_job_dependencies_inventory_update_launch(controlplane_instance_g iu = [x for x in ii.inventory_updates.all()] assert len(iu) == 1 TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(iu[0], controlplane_instance_group, [j], instance) + TaskManager.start_task.assert_called_once_with(iu[0], controlplane_instance_group, instance) iu[0].status = "successful" iu[0].save() with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, [], instance) + TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @pytest.mark.django_db @@ -412,7 +412,7 @@ def test_job_dependency_with_already_updated(controlplane_instance_group, job_te mock_iu.assert_not_called() with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, [], instance) + TaskManager.start_task.assert_called_once_with(j, controlplane_instance_group, instance) @pytest.mark.django_db @@ -442,9 +442,7 @@ def test_shared_dependencies_launch(controlplane_instance_group, job_template_fa TaskManager().schedule() pu = p.project_updates.first() iu = ii.inventory_updates.first() - TaskManager.start_task.assert_has_calls( - [mock.call(iu, controlplane_instance_group, [j1, j2], instance), mock.call(pu, controlplane_instance_group, [j1, j2], instance)] - ) + TaskManager.start_task.assert_has_calls([mock.call(iu, controlplane_instance_group, instance), mock.call(pu, controlplane_instance_group, instance)]) pu.status = "successful" pu.finished = pu.created + timedelta(seconds=1) pu.save() @@ -453,9 +451,7 @@ def test_shared_dependencies_launch(controlplane_instance_group, job_template_fa iu.save() with mock.patch("awx.main.scheduler.TaskManager.start_task"): TaskManager().schedule() - TaskManager.start_task.assert_has_calls( - [mock.call(j1, controlplane_instance_group, [], instance), mock.call(j2, controlplane_instance_group, [], instance)] - ) + TaskManager.start_task.assert_has_calls([mock.call(j1, controlplane_instance_group, instance), mock.call(j2, controlplane_instance_group, instance)]) pu = [x for x in p.project_updates.all()] iu = [x for x in ii.inventory_updates.all()] assert len(pu) == 1 @@ -479,7 +475,7 @@ def test_job_not_blocking_project_update(controlplane_instance_group, job_templa project_update.status = "pending" project_update.save() TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(project_update, controlplane_instance_group, [], instance) + TaskManager.start_task.assert_called_once_with(project_update, controlplane_instance_group, instance) @pytest.mark.django_db @@ -503,7 +499,7 @@ def test_job_not_blocking_inventory_update(controlplane_instance_group, job_temp DependencyManager().schedule() TaskManager().schedule() - TaskManager.start_task.assert_called_once_with(inventory_update, controlplane_instance_group, [], instance) + TaskManager.start_task.assert_called_once_with(inventory_update, controlplane_instance_group, instance) @pytest.mark.django_db diff --git a/awx/main/tests/functional/test_tasks.py b/awx/main/tests/functional/test_tasks.py index 6de551cf9f..8abe5579eb 100644 --- a/awx/main/tests/functional/test_tasks.py +++ b/awx/main/tests/functional/test_tasks.py @@ -5,8 +5,8 @@ import tempfile import shutil from awx.main.tasks.jobs import RunJob -from awx.main.tasks.system import execution_node_health_check, _cleanup_images_and_files -from awx.main.models import Instance, Job +from awx.main.tasks.system import execution_node_health_check, _cleanup_images_and_files, handle_work_error +from awx.main.models import Instance, Job, InventoryUpdate, ProjectUpdate @pytest.fixture @@ -74,3 +74,17 @@ def test_does_not_run_reaped_job(mocker, mock_me): job.refresh_from_db() assert job.status == 'failed' mock_run.assert_not_called() + + +@pytest.mark.django_db +def test_handle_work_error_nested(project, inventory_source): + pu = ProjectUpdate.objects.create(status='failed', project=project, celery_task_id='1234') + iu = InventoryUpdate.objects.create(status='pending', inventory_source=inventory_source, source='scm') + job = Job.objects.create(status='pending') + iu.dependent_jobs.add(pu) + job.dependent_jobs.add(pu, iu) + handle_work_error({'type': 'project_update', 'id': pu.id}) + iu.refresh_from_db() + job.refresh_from_db() + assert iu.job_explanation == f'Previous Task Failed: {{"job_type": "project_update", "job_name": "", "job_id": "{pu.id}"}}' + assert job.job_explanation == f'Previous Task Failed: {{"job_type": "inventory_update", "job_name": "", "job_id": "{iu.id}"}}' From ac8cff75ce3afbf2b3423088a6b9a9b932b1dbfd Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Tue, 20 Dec 2022 16:06:25 -0500 Subject: [PATCH 26/32] Run collection sanity tests in CI (#13356) * Run collection sanity tests in CI This requires adding a Makefile install of ansible-core Fake the version to make semver check happy * Fixes from ansible-test sanity failures * Exclude the export module due to awxkit requirement * Fix broken ansible-test rule exceptions remove Ansible 2.14 exclusions that make ansible-test ERROR, saying they are not needed --- .github/workflows/ci.yml | 3 + Makefile | 16 +++- .../plugins/inventory/controller.py | 1 - .../plugins/lookup/controller_api.py | 2 +- .../plugins/lookup/schedule_rrule.py | 2 +- .../plugins/lookup/schedule_rruleset.py | 13 +-- .../plugins/module_utils/controller_api.py | 12 ++- .../plugins/modules/ad_hoc_command.py | 1 - .../plugins/modules/ad_hoc_command_cancel.py | 1 + .../plugins/modules/execution_environment.py | 4 +- awx_collection/plugins/modules/export.py | 10 +++ .../plugins/modules/job_template.py | 2 +- awx_collection/plugins/modules/project.py | 2 - awx_collection/plugins/modules/schedule.py | 1 - .../plugins/modules/subscriptions.py | 1 + awx_collection/plugins/modules/token.py | 1 - .../plugins/modules/workflow_job_template.py | 23 +++-- .../modules/workflow_job_template_node.py | 1 - awx_collection/test/awx/conftest.py | 2 +- awx_collection/test/awx/test_project.py | 2 +- awx_collection/tests/sanity/ignore-2.14.txt | 88 ------------------- .../roles/template_galaxy/tasks/main.yml | 7 ++ 22 files changed, 73 insertions(+), 122 deletions(-) delete mode 100644 awx_collection/tests/sanity/ignore-2.14.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b47efc0c3a..5e9a72392f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,9 @@ jobs: - name: awx-collection command: /start_tests.sh test_collection_all label: Run Collection Tests + - name: awx-collection-sanity + command: /start_tests.sh test_collection_sanity + label: Run Ansible core Collection Sanity tests - name: api-schema label: Check API Schema command: /start_tests.sh detect-schema-change SCHEMA_DIFF_BASE_BRANCH=${{ github.event.pull_request.base.ref }} diff --git a/Makefile b/Makefile index a7709849e3..3a85428e93 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,9 @@ CHROMIUM_BIN=/tmp/chrome-linux/chrome GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) MANAGEMENT_COMMAND ?= awx-manage VERSION := $(shell $(PYTHON) tools/scripts/scm_version.py) -COLLECTION_VERSION := $(shell $(PYTHON) tools/scripts/scm_version.py | cut -d . -f 1-3) + +# ansible-test requires semver compatable version, so we allow overrides to hack it +COLLECTION_VERSION ?= $(shell $(PYTHON) tools/scripts/scm_version.py | cut -d . -f 1-3) # NOTE: This defaults the container image version to the branch that's active COMPOSE_TAG ?= $(GIT_BRANCH) @@ -300,7 +302,8 @@ test_collection: if [ "$(VENV_BASE)" ]; then \ . $(VENV_BASE)/awx/bin/activate; \ fi && \ - pip install ansible-core && \ + if ! [ -x "$(shell command -v ansible-playbook)" ]; then pip install ansible-core; fi + ansible --version py.test $(COLLECTION_TEST_DIRS) -v # The python path needs to be modified so that the tests can find Ansible within the container # First we will use anything expility set as PYTHONPATH @@ -330,8 +333,13 @@ install_collection: build_collection rm -rf $(COLLECTION_INSTALL) ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(COLLECTION_VERSION).tar.gz -test_collection_sanity: install_collection - cd $(COLLECTION_INSTALL) && ansible-test sanity +test_collection_sanity: + rm -rf awx_collection_build/ + rm -rf $(COLLECTION_INSTALL) + if ! [ -x "$(shell command -v ansible-test)" ]; then pip install ansible-core; fi + ansible --version + COLLECTION_VERSION=1.0.0 make install_collection + cd $(COLLECTION_INSTALL) && ansible-test sanity --exclude=plugins/modules/export.py test_collection_integration: install_collection cd $(COLLECTION_INSTALL) && ansible-test integration $(COLLECTION_TEST_TARGET) diff --git a/awx_collection/plugins/inventory/controller.py b/awx_collection/plugins/inventory/controller.py index 9cf36550a1..ee049c80fd 100644 --- a/awx_collection/plugins/inventory/controller.py +++ b/awx_collection/plugins/inventory/controller.py @@ -7,7 +7,6 @@ __metaclass__ = type DOCUMENTATION = ''' name: controller -plugin_type: inventory author: - Matthew Jones (@matburt) - Yunfan Zhang (@YunfanZhang42) diff --git a/awx_collection/plugins/lookup/controller_api.py b/awx_collection/plugins/lookup/controller_api.py index 94111c816d..6f0d07a4d7 100644 --- a/awx_collection/plugins/lookup/controller_api.py +++ b/awx_collection/plugins/lookup/controller_api.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ -lookup: controller_api +name: controller_api author: John Westcott IV (@john-westcott-iv) short_description: Search the API for objects requirements: diff --git a/awx_collection/plugins/lookup/schedule_rrule.py b/awx_collection/plugins/lookup/schedule_rrule.py index b623dfc86e..5f1d34c0ae 100644 --- a/awx_collection/plugins/lookup/schedule_rrule.py +++ b/awx_collection/plugins/lookup/schedule_rrule.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ - lookup: schedule_rrule + name: schedule_rrule author: John Westcott IV (@john-westcott-iv) short_description: Generate an rrule string which can be used for Schedules requirements: diff --git a/awx_collection/plugins/lookup/schedule_rruleset.py b/awx_collection/plugins/lookup/schedule_rruleset.py index a32b9d51cb..63d8f97fcc 100644 --- a/awx_collection/plugins/lookup/schedule_rruleset.py +++ b/awx_collection/plugins/lookup/schedule_rruleset.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ - lookup: schedule_rruleset + name: schedule_rruleset author: John Westcott IV (@john-westcott-iv) short_description: Generate an rruleset string requirements: @@ -31,7 +31,8 @@ DOCUMENTATION = """ rules: description: - Array of rules in the rruleset - type: array + type: list + elements: dict required: True suboptions: frequency: @@ -192,14 +193,14 @@ class LookupModule(LookupBase): # something: [1,2,3] - A list of ints return_values = [] # If they give us a single int, lets make it a list of ints - if type(rule[field_name]) == int: + if isinstance(rule[field_name], int): rule[field_name] = [rule[field_name]] # If its not a list, we need to split it into a list - if type(rule[field_name]) != list: + if isinstance(rule[field_name], list): rule[field_name] = rule[field_name].split(',') for value in rule[field_name]: # If they have a list of strs we want to strip the str incase its space delineated - if type(value) == str: + if isinstance(value, str): value = value.strip() # If value happens to be an int (from a list of ints) we need to coerce it into a str for the re.match if not re.match(r"^\d+$", str(value)) or int(value) < min_value or int(value) > max_value: @@ -209,7 +210,7 @@ class LookupModule(LookupBase): def process_list(self, field_name, rule, valid_list, rule_number): return_values = [] - if type(rule[field_name]) != list: + if isinstance(rule[field_name], list): rule[field_name] = rule[field_name].split(',') for value in rule[field_name]: value = value.strip() diff --git a/awx_collection/plugins/module_utils/controller_api.py b/awx_collection/plugins/module_utils/controller_api.py index 50d10f8104..92c36b5415 100644 --- a/awx_collection/plugins/module_utils/controller_api.py +++ b/awx_collection/plugins/module_utils/controller_api.py @@ -4,6 +4,7 @@ __metaclass__ = type from ansible.module_utils.basic import AnsibleModule, env_fallback from ansible.module_utils.urls import Request, SSLValidationError, ConnectionError +from ansible.module_utils.parsing.convert_bool import boolean as strtobool from ansible.module_utils.six import PY2 from ansible.module_utils.six import raise_from, string_types from ansible.module_utils.six.moves import StringIO @@ -11,14 +12,21 @@ from ansible.module_utils.six.moves.urllib.error import HTTPError from ansible.module_utils.six.moves.http_cookiejar import CookieJar from ansible.module_utils.six.moves.urllib.parse import urlparse, urlencode from ansible.module_utils.six.moves.configparser import ConfigParser, NoOptionError -from distutils.version import LooseVersion as Version from socket import getaddrinfo, IPPROTO_TCP import time import re from json import loads, dumps from os.path import isfile, expanduser, split, join, exists, isdir from os import access, R_OK, getcwd -from distutils.util import strtobool + + +try: + from ansible.module_utils.compat.version import LooseVersion as Version +except ImportError: + try: + from distutils.version import LooseVersion as Version + except ImportError: + raise AssertionError('To use this plugin or module with ansible-core 2.11, you need to use Python < 3.12 with distutils.version present') try: import yaml diff --git a/awx_collection/plugins/modules/ad_hoc_command.py b/awx_collection/plugins/modules/ad_hoc_command.py index cb6e24a255..f453cef2f8 100644 --- a/awx_collection/plugins/modules/ad_hoc_command.py +++ b/awx_collection/plugins/modules/ad_hoc_command.py @@ -55,7 +55,6 @@ options: description: - The arguments to pass to the module. type: str - default: "" forks: description: - The number of forks to use for this ad hoc execution. diff --git a/awx_collection/plugins/modules/ad_hoc_command_cancel.py b/awx_collection/plugins/modules/ad_hoc_command_cancel.py index 98a0d414cb..12cdaeaaf9 100644 --- a/awx_collection/plugins/modules/ad_hoc_command_cancel.py +++ b/awx_collection/plugins/modules/ad_hoc_command_cancel.py @@ -42,6 +42,7 @@ options: - Maximum time in seconds to wait for a job to finish. - Not specifying means the task will wait until the controller cancels the command. type: int + default: 0 extends_documentation_fragment: awx.awx.auth ''' diff --git a/awx_collection/plugins/modules/execution_environment.py b/awx_collection/plugins/modules/execution_environment.py index 5544225ab2..8401944693 100644 --- a/awx_collection/plugins/modules/execution_environment.py +++ b/awx_collection/plugins/modules/execution_environment.py @@ -80,9 +80,9 @@ def main(): name=dict(required=True), new_name=dict(), image=dict(required=True), - description=dict(default=''), + description=dict(), organization=dict(), - credential=dict(default=''), + credential=dict(), state=dict(choices=['present', 'absent'], default='present'), pull=dict(choices=['always', 'missing', 'never'], default='missing'), ) diff --git a/awx_collection/plugins/modules/export.py b/awx_collection/plugins/modules/export.py index 8e737b14b9..d04e996056 100644 --- a/awx_collection/plugins/modules/export.py +++ b/awx_collection/plugins/modules/export.py @@ -86,6 +86,16 @@ options: - workflow names to export type: list elements: str + applications: + description: + - OAuth2 application names to export + type: list + elements: str + schedules: + description: + - schedule names to export + type: list + elements: str requirements: - "awxkit >= 9.3.0" notes: diff --git a/awx_collection/plugins/modules/job_template.py b/awx_collection/plugins/modules/job_template.py index 84d0450767..98c35f52f2 100644 --- a/awx_collection/plugins/modules/job_template.py +++ b/awx_collection/plugins/modules/job_template.py @@ -266,6 +266,7 @@ options: description: - Maximum time in seconds to wait for a job to finish (server-side). type: int + default: 0 job_slice_count: description: - The number of jobs to slice into at runtime. Will cause the Job Template to launch a workflow if value is greater than 1. @@ -287,7 +288,6 @@ options: description: - Branch to use in job run. Project default used if blank. Only allowed if project allow_override field is set to true. type: str - default: '' labels: description: - The labels applied to this job template diff --git a/awx_collection/plugins/modules/project.py b/awx_collection/plugins/modules/project.py index 4a7c7a4ffd..c224f309f0 100644 --- a/awx_collection/plugins/modules/project.py +++ b/awx_collection/plugins/modules/project.py @@ -60,12 +60,10 @@ options: description: - The branch to use for the SCM resource. type: str - default: '' scm_refspec: description: - The refspec to use for the SCM resource. type: str - default: '' credential: description: - Name of the credential to use with this SCM resource. diff --git a/awx_collection/plugins/modules/schedule.py b/awx_collection/plugins/modules/schedule.py index d0fac2384e..5bf821025d 100644 --- a/awx_collection/plugins/modules/schedule.py +++ b/awx_collection/plugins/modules/schedule.py @@ -51,7 +51,6 @@ options: - Specify C(extra_vars) for the template. required: False type: dict - default: {} forks: description: - Forks applied as a prompt, assuming job template prompts for forks diff --git a/awx_collection/plugins/modules/subscriptions.py b/awx_collection/plugins/modules/subscriptions.py index 4cb2506af9..146ef7c451 100644 --- a/awx_collection/plugins/modules/subscriptions.py +++ b/awx_collection/plugins/modules/subscriptions.py @@ -39,6 +39,7 @@ options: - Note This is a client side search, not an API side search required: False type: dict + default: {} extends_documentation_fragment: awx.awx.auth ''' diff --git a/awx_collection/plugins/modules/token.py b/awx_collection/plugins/modules/token.py index 27e72fe68d..c0089240f4 100644 --- a/awx_collection/plugins/modules/token.py +++ b/awx_collection/plugins/modules/token.py @@ -35,7 +35,6 @@ options: - Optional description of this access token. required: False type: str - default: '' application: description: - The application tied to this token. diff --git a/awx_collection/plugins/modules/workflow_job_template.py b/awx_collection/plugins/modules/workflow_job_template.py index e1667b3b21..ba4d5cf102 100644 --- a/awx_collection/plugins/modules/workflow_job_template.py +++ b/awx_collection/plugins/modules/workflow_job_template.py @@ -214,7 +214,8 @@ options: type: int job_slice_count: description: - - The number of jobs to slice into at runtime, if job template prompts for job slices. Will cause the Job Template to launch a workflow if value is greater than 1. + - The number of jobs to slice into at runtime, if job template prompts for job slices. + - Will cause the Job Template to launch a workflow if value is greater than 1. type: int default: '1' timeout: @@ -328,42 +329,46 @@ options: - Nodes that will run after this node completes. - List of node identifiers. type: list + elements: dict suboptions: identifier: description: - Identifier of Node that will run after this node completes given this option. - elements: str + type: str success_nodes: description: - Nodes that will run after this node on success. - List of node identifiers. type: list + elements: dict suboptions: identifier: description: - Identifier of Node that will run after this node completes given this option. - elements: str + type: str failure_nodes: description: - Nodes that will run after this node on failure. - List of node identifiers. type: list + elements: dict suboptions: identifier: description: - Identifier of Node that will run after this node completes given this option. - elements: str + type: str credentials: description: - Credentials to be applied to job as launch-time prompts. - List of credential names. - Uniqueness is not handled rigorously. type: list + elements: dict suboptions: name: description: - Name Credentials to be applied to job as launch-time prompts. - elements: str + type: str organization: description: - Name of key for use in model for organizational reference @@ -379,11 +384,12 @@ options: - List of Label names. - Uniqueness is not handled rigorously. type: list + elements: dict suboptions: name: description: - Name Labels to be applied to job as launch-time prompts. - elements: str + type: str organization: description: - Name of key for use in model for organizational reference @@ -399,11 +405,12 @@ options: - List of Instance group names. - Uniqueness is not handled rigorously. type: list + elements: dict suboptions: name: description: - Name of Instance groups to be applied to job as launch-time prompts. - elements: str + type: str destroy_current_nodes: description: - Set in order to destroy current workflow_nodes on the workflow. @@ -789,7 +796,7 @@ def main(): allow_simultaneous=dict(type='bool'), ask_variables_on_launch=dict(type='bool'), ask_labels_on_launch=dict(type='bool', aliases=['ask_labels']), - ask_tags_on_launch=dict(type='bool'), + ask_tags_on_launch=dict(type='bool', aliases=['ask_tags']), ask_skip_tags_on_launch=dict(type='bool', aliases=['ask_skip_tags']), inventory=dict(), limit=dict(), diff --git a/awx_collection/plugins/modules/workflow_job_template_node.py b/awx_collection/plugins/modules/workflow_job_template_node.py index f91d308282..61f713f843 100644 --- a/awx_collection/plugins/modules/workflow_job_template_node.py +++ b/awx_collection/plugins/modules/workflow_job_template_node.py @@ -30,7 +30,6 @@ options: - Variables to apply at launch time. - Will only be accepted if job template prompts for vars or has a survey asking for those vars. type: dict - default: {} inventory: description: - Inventory applied as a prompt, if job template prompts for inventory diff --git a/awx_collection/test/awx/conftest.py b/awx_collection/test/awx/conftest.py index 42325da6fb..626f859363 100644 --- a/awx_collection/test/awx/conftest.py +++ b/awx_collection/test/awx/conftest.py @@ -159,7 +159,7 @@ def run_module(request, collection_import): elif getattr(resource_module, 'TowerLegacyModule', None): resource_class = resource_module.TowerLegacyModule else: - raise ("The module has neither a TowerLegacyModule, ControllerAWXKitModule or a ControllerAPIModule") + raise RuntimeError("The module has neither a TowerLegacyModule, ControllerAWXKitModule or a ControllerAPIModule") with mock.patch.object(resource_class, '_load_params', new=mock_load_params): # Call the test utility (like a mock server) instead of issuing HTTP requests diff --git a/awx_collection/test/awx/test_project.py b/awx_collection/test/awx/test_project.py index 9f6da405db..8ec3e8816e 100644 --- a/awx_collection/test/awx/test_project.py +++ b/awx_collection/test/awx/test_project.py @@ -14,7 +14,7 @@ def test_create_project(run_module, admin_user, organization, silence_warning): dict(name='foo', organization=organization.name, scm_type='git', scm_url='https://foo.invalid', wait=False, scm_update_cache_timeout=5), admin_user, ) - silence_warning.assert_called_once_with('scm_update_cache_timeout will be ignored since scm_update_on_launch ' 'was not set to true') + silence_warning.assert_called_once_with('scm_update_cache_timeout will be ignored since scm_update_on_launch was not set to true') assert result.pop('changed', None), result diff --git a/awx_collection/tests/sanity/ignore-2.14.txt b/awx_collection/tests/sanity/ignore-2.14.txt deleted file mode 100644 index cd98399548..0000000000 --- a/awx_collection/tests/sanity/ignore-2.14.txt +++ /dev/null @@ -1,88 +0,0 @@ -plugins/module_utils/awxkit.py import-3.9 -plugins/module_utils/controller_api.py import-3.9 -plugins/modules/ad_hoc_command.py import-3.9 -plugins/modules/ad_hoc_command_cancel.py import-3.9 -plugins/modules/ad_hoc_command_wait.py import-3.9 -plugins/modules/application.py import-3.9 -plugins/modules/controller_meta.py import-3.9 -plugins/modules/credential.py import-3.92 -plugins/modules/credential_input_source.py import-3.9 -plugins/modules/credential_type.py import-3.9 -plugins/modules/execution_environment.py import-3.9 -plugins/modules/export.py import-3.9 -plugins/modules/group.py import-3.9 -plugins/modules/host.py import-3.9 -plugins/modules/import.py import-3.9 -plugins/modules/instance.py import-3.9 -plugins/modules/instance_group.py import-3.9 -plugins/modules/inventory.py import-3.9 -plugins/modules/inventory_source.py import-3.9 -plugins/modules/inventory_source_update.py import-3.9 -plugins/modules/job_cancel.py import-3.9 -plugins/modules/job_launch.py import-3.9 -plugins/modules/job_list.py import-3.9 -plugins/modules/job_template.py import-3.93 -plugins/modules/job_wait.py import-3.9 -plugins/modules/label.py import-3.9 -plugins/modules/license.py import-3.9 -plugins/modules/notification_template.py import-3.9 -plugins/modules/organization.py import-3.9 -plugins/modules/project.py import-3.92 -plugins/modules/project_update.py import-3.9 -plugins/modules/role.py import-3.9 -plugins/modules/schedule.py import-3.9 -plugins/modules/settings.py import-3.9 -plugins/modules/subscriptions.py import-3.9 -plugins/modules/team.py import-3.9 -plugins/modules/token.py import-3.9 -plugins/modules/user.py import-3.9 -plugins/modules/workflow_approval.py import-3.9 -plugins/modules/workflow_job_template.py import-3.9 -plugins/modules/workflow_job_template_node.py import-3.9 -plugins/modules/workflow_launch.py import-3.9 -plugins/modules/workflow_node_wait.py import-3.9 -plugins/inventory/controller.py import-3.10 -plugins/lookup/controller_api.py import-3.10 -plugins/module_utils/awxkit.py import-3.10 -plugins/module_utils/controller_api.py import-3.10 -plugins/modules/ad_hoc_command.py import-3.10 -plugins/modules/ad_hoc_command_cancel.py import-3.10 -plugins/modules/ad_hoc_command_wait.py import-3.10 -plugins/modules/application.py import-3.10 -plugins/modules/controller_meta.py import-3.10 -plugins/modules/credential.py import-3.10 -plugins/modules/credential_input_source.py import-3.10 -plugins/modules/credential_type.py import-3.10 -plugins/modules/execution_environment.py import-3.10 -plugins/modules/export.py import-3.10 -plugins/modules/group.py import-3.10 -plugins/modules/host.py import-3.10 -plugins/modules/import.py import-3.10 -plugins/modules/instance.py import-3.10 -plugins/modules/instance_group.py import-3.10 -plugins/modules/inventory.py import-3.10 -plugins/modules/inventory_source.py import-3.10 -plugins/modules/inventory_source_update.py import-3.10 -plugins/modules/job_cancel.py import-3.10 -plugins/modules/job_launch.py import-3.10 -plugins/modules/job_list.py import-3.10 -plugins/modules/job_template.py import-3.10 -plugins/modules/job_wait.py import-3.10 -plugins/modules/label.py import-3.10 -plugins/modules/license.py import-3.10 -plugins/modules/notification_template.py import-3.10 -plugins/modules/organization.py import-3.10 -plugins/modules/project.py import-3.10 -plugins/modules/project_update.py import-3.10 -plugins/modules/role.py import-3.10 -plugins/modules/schedule.py import-3.10 -plugins/modules/settings.py import-3.10 -plugins/modules/subscriptions.py import-3.10 -plugins/modules/team.py import-3.10 -plugins/modules/token.py import-3.10 -plugins/modules/user.py import-3.10 -plugins/modules/workflow_approval.py import-3.10 -plugins/modules/workflow_job_template.py import-3.10 -plugins/modules/workflow_job_template_node.py import-3.10 -plugins/modules/workflow_launch.py import-3.10 -plugins/modules/workflow_node_wait.py import-3.10 diff --git a/awx_collection/tools/roles/template_galaxy/tasks/main.yml b/awx_collection/tools/roles/template_galaxy/tasks/main.yml index aaa21a023f..3a213f5997 100644 --- a/awx_collection/tools/roles/template_galaxy/tasks/main.yml +++ b/awx_collection/tools/roles/template_galaxy/tasks/main.yml @@ -1,4 +1,11 @@ --- +- name: Sanity assertions, that some variables have a non-blank value + assert: + that: + - collection_version + - collection_package + - collection_path + - name: Set the collection version in the controller_api.py file replace: path: "{{ collection_path }}/plugins/module_utils/controller_api.py" From 5dd0eab8060c16623bf6c5395767cd421dc09c4d Mon Sep 17 00:00:00 2001 From: Rick Elrod Date: Tue, 20 Dec 2022 17:05:44 -0600 Subject: [PATCH 27/32] Pin channels-redis to 4.3.1 to fix an async issue (#13348) Refs django/channels_redis#332 Refs #13313 Signed-off-by: Rick Elrod --- licenses/aioredis.txt | 22 ++++++++++++++++++++++ licenses/hiredis.txt | 29 +++++++++++++++++++++++++++++ requirements/README.md | 9 +++++++++ requirements/requirements.in | 2 +- requirements/requirements.txt | 16 +++++++++++----- 5 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 licenses/aioredis.txt create mode 100644 licenses/hiredis.txt diff --git a/licenses/aioredis.txt b/licenses/aioredis.txt new file mode 100644 index 0000000000..4d8920e897 --- /dev/null +++ b/licenses/aioredis.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2017 Alexey Popravka +Copyright (c) 2021 Sean Stewart + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/hiredis.txt b/licenses/hiredis.txt new file mode 100644 index 0000000000..a5fc973955 --- /dev/null +++ b/licenses/hiredis.txt @@ -0,0 +1,29 @@ +Copyright (c) 2009-2011, Salvatore Sanfilippo +Copyright (c) 2010-2011, Pieter Noordhuis + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of Redis nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/requirements/README.md b/requirements/README.md index 1207ee3924..556c402e7a 100644 --- a/requirements/README.md +++ b/requirements/README.md @@ -148,6 +148,15 @@ in the top-level Makefile. If modifying this library make sure testing with the offline build is performed to confirm it is functionally working. +### channels-redis + +Due to an upstream bug (linked below), we see `RuntimeError: Event loop is closed` errors with newer versions of `channels-redis`. +Upstream is aware of the bug and it is likely to be fixed in the next release according to the issue linked below. +For now, we pin to the old version, 3.4.1 + +* https://github.com/django/channels_redis/issues/332 +* https://github.com/ansible/awx/issues/13313 + ## Library Notes ### pexpect diff --git a/requirements/requirements.in b/requirements/requirements.in index ae0ba7768d..d2d2cca62d 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -4,7 +4,7 @@ asciichartpy asn1 azure-keyvault==1.1.0 # see UPGRADE BLOCKERs channels -channels-redis +channels-redis==3.4.1 # see UPGRADE BLOCKERs cryptography Cython<3 # Since the bump to PyYAML 5.4.1 this is now a mandatory dep daphne diff --git a/requirements/requirements.txt b/requirements/requirements.txt index afb43f659a..231f8b8881 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -2,6 +2,8 @@ adal==1.2.7 # via msrestazure aiohttp==3.8.3 # via -r /awx_devel/requirements/requirements.in +aioredis==1.3.1 + # via channels-redis aiosignal==1.3.1 # via aiohttp # via -r /awx_devel/requirements/requirements_git.txt @@ -20,6 +22,7 @@ asn1==2.6.0 async-timeout==4.0.2 # via # aiohttp + # aioredis # redis attrs==22.1.0 # via @@ -51,11 +54,11 @@ cachetools==5.2.0 # requests cffi==1.15.1 # via cryptography -channels==4.0.0 +channels==3.0.5 # via # -r /awx_devel/requirements/requirements.in # channels-redis -channels-redis==4.0.0 +channels-redis==3.4.1 # via -r /awx_devel/requirements/requirements.in charset-normalizer==2.1.1 # via @@ -76,8 +79,10 @@ cryptography==38.0.4 # social-auth-core cython==0.29.32 # via -r /awx_devel/requirements/requirements.in -daphne==4.0.0 - # via -r /awx_devel/requirements/requirements.in +daphne==3.0.2 + # via + # -r /awx_devel/requirements/requirements.in + # channels dataclasses==0.6 # via # python-dsv-sdk @@ -153,6 +158,8 @@ gitpython==3.1.29 # via -r /awx_devel/requirements/requirements.in google-auth==2.14.1 # via kubernetes +hiredis==2.1.0 + # via aioredis hyperlink==21.0.0 # via # autobahn @@ -334,7 +341,6 @@ receptorctl==1.2.3 redis==4.3.5 # via # -r /awx_devel/requirements/requirements.in - # channels-redis # django-redis requests==2.28.1 # via From d968b648deaff425dfa755df297b0ae52dfa2992 Mon Sep 17 00:00:00 2001 From: Rick Elrod Date: Tue, 20 Dec 2022 17:40:08 -0600 Subject: [PATCH 28/32] Run sanity tests outside of our container Also just ignore one sanity test for the export module, instead of ignoring all of them. Also use latest ansible-test, and make it work on GHA (by using podman instead of docker). Signed-off-by: Rick Elrod --- .github/workflows/ci.yml | 21 ++++- .github/workflows/e2e_test.yml | 4 +- Makefile | 2 +- awx_collection/tests/config.yml | 3 + awx_collection/tests/sanity/ignore-2.13.txt | 88 --------------------- awx_collection/tests/sanity/ignore-2.14.txt | 1 + 6 files changed, 24 insertions(+), 95 deletions(-) create mode 100644 awx_collection/tests/config.yml delete mode 100644 awx_collection/tests/sanity/ignore-2.13.txt create mode 100644 awx_collection/tests/sanity/ignore-2.14.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e9a72392f..97df2050cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,9 +28,6 @@ jobs: - name: awx-collection command: /start_tests.sh test_collection_all label: Run Collection Tests - - name: awx-collection-sanity - command: /start_tests.sh test_collection_sanity - label: Run Ansible core Collection Sanity tests - name: api-schema label: Check API Schema command: /start_tests.sh detect-schema-change SCHEMA_DIFF_BASE_BRANCH=${{ github.event.pull_request.base.ref }} @@ -148,3 +145,21 @@ jobs: env: AWX_TEST_IMAGE: awx AWX_TEST_VERSION: ci + + collection-sanity: + name: awx_collection sanity + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v2 + + - name: Upgrade ansible-core + run: python3 -m pip install --upgrade ansible-core + + - name: Run sanity tests + run: make test_collection_sanity + env: + # needed due to cgroupsv2. This is fixed, but a stable release + # with the fix has not been made yet. + ANSIBLE_TEST_PREFER_PODMAN: 1 diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml index 22890fcf53..788042baed 100644 --- a/.github/workflows/e2e_test.yml +++ b/.github/workflows/e2e_test.yml @@ -6,7 +6,7 @@ env: on: pull_request_target: types: [labeled] -jobs: +jobs: e2e-test: if: contains(github.event.pull_request.labels.*.name, 'qe:e2e') runs-on: ubuntu-latest @@ -107,5 +107,3 @@ jobs: with: name: AWX-logs-${{ matrix.job }} path: make-docker-compose-output.log - - diff --git a/Makefile b/Makefile index 3a85428e93..d86e9779a4 100644 --- a/Makefile +++ b/Makefile @@ -339,7 +339,7 @@ test_collection_sanity: if ! [ -x "$(shell command -v ansible-test)" ]; then pip install ansible-core; fi ansible --version COLLECTION_VERSION=1.0.0 make install_collection - cd $(COLLECTION_INSTALL) && ansible-test sanity --exclude=plugins/modules/export.py + cd $(COLLECTION_INSTALL) && ansible-test sanity --docker test_collection_integration: install_collection cd $(COLLECTION_INSTALL) && ansible-test integration $(COLLECTION_TEST_TARGET) diff --git a/awx_collection/tests/config.yml b/awx_collection/tests/config.yml new file mode 100644 index 0000000000..fdb7c5055c --- /dev/null +++ b/awx_collection/tests/config.yml @@ -0,0 +1,3 @@ +--- +modules: + python_requires: '>3' diff --git a/awx_collection/tests/sanity/ignore-2.13.txt b/awx_collection/tests/sanity/ignore-2.13.txt deleted file mode 100644 index cd98399548..0000000000 --- a/awx_collection/tests/sanity/ignore-2.13.txt +++ /dev/null @@ -1,88 +0,0 @@ -plugins/module_utils/awxkit.py import-3.9 -plugins/module_utils/controller_api.py import-3.9 -plugins/modules/ad_hoc_command.py import-3.9 -plugins/modules/ad_hoc_command_cancel.py import-3.9 -plugins/modules/ad_hoc_command_wait.py import-3.9 -plugins/modules/application.py import-3.9 -plugins/modules/controller_meta.py import-3.9 -plugins/modules/credential.py import-3.92 -plugins/modules/credential_input_source.py import-3.9 -plugins/modules/credential_type.py import-3.9 -plugins/modules/execution_environment.py import-3.9 -plugins/modules/export.py import-3.9 -plugins/modules/group.py import-3.9 -plugins/modules/host.py import-3.9 -plugins/modules/import.py import-3.9 -plugins/modules/instance.py import-3.9 -plugins/modules/instance_group.py import-3.9 -plugins/modules/inventory.py import-3.9 -plugins/modules/inventory_source.py import-3.9 -plugins/modules/inventory_source_update.py import-3.9 -plugins/modules/job_cancel.py import-3.9 -plugins/modules/job_launch.py import-3.9 -plugins/modules/job_list.py import-3.9 -plugins/modules/job_template.py import-3.93 -plugins/modules/job_wait.py import-3.9 -plugins/modules/label.py import-3.9 -plugins/modules/license.py import-3.9 -plugins/modules/notification_template.py import-3.9 -plugins/modules/organization.py import-3.9 -plugins/modules/project.py import-3.92 -plugins/modules/project_update.py import-3.9 -plugins/modules/role.py import-3.9 -plugins/modules/schedule.py import-3.9 -plugins/modules/settings.py import-3.9 -plugins/modules/subscriptions.py import-3.9 -plugins/modules/team.py import-3.9 -plugins/modules/token.py import-3.9 -plugins/modules/user.py import-3.9 -plugins/modules/workflow_approval.py import-3.9 -plugins/modules/workflow_job_template.py import-3.9 -plugins/modules/workflow_job_template_node.py import-3.9 -plugins/modules/workflow_launch.py import-3.9 -plugins/modules/workflow_node_wait.py import-3.9 -plugins/inventory/controller.py import-3.10 -plugins/lookup/controller_api.py import-3.10 -plugins/module_utils/awxkit.py import-3.10 -plugins/module_utils/controller_api.py import-3.10 -plugins/modules/ad_hoc_command.py import-3.10 -plugins/modules/ad_hoc_command_cancel.py import-3.10 -plugins/modules/ad_hoc_command_wait.py import-3.10 -plugins/modules/application.py import-3.10 -plugins/modules/controller_meta.py import-3.10 -plugins/modules/credential.py import-3.10 -plugins/modules/credential_input_source.py import-3.10 -plugins/modules/credential_type.py import-3.10 -plugins/modules/execution_environment.py import-3.10 -plugins/modules/export.py import-3.10 -plugins/modules/group.py import-3.10 -plugins/modules/host.py import-3.10 -plugins/modules/import.py import-3.10 -plugins/modules/instance.py import-3.10 -plugins/modules/instance_group.py import-3.10 -plugins/modules/inventory.py import-3.10 -plugins/modules/inventory_source.py import-3.10 -plugins/modules/inventory_source_update.py import-3.10 -plugins/modules/job_cancel.py import-3.10 -plugins/modules/job_launch.py import-3.10 -plugins/modules/job_list.py import-3.10 -plugins/modules/job_template.py import-3.10 -plugins/modules/job_wait.py import-3.10 -plugins/modules/label.py import-3.10 -plugins/modules/license.py import-3.10 -plugins/modules/notification_template.py import-3.10 -plugins/modules/organization.py import-3.10 -plugins/modules/project.py import-3.10 -plugins/modules/project_update.py import-3.10 -plugins/modules/role.py import-3.10 -plugins/modules/schedule.py import-3.10 -plugins/modules/settings.py import-3.10 -plugins/modules/subscriptions.py import-3.10 -plugins/modules/team.py import-3.10 -plugins/modules/token.py import-3.10 -plugins/modules/user.py import-3.10 -plugins/modules/workflow_approval.py import-3.10 -plugins/modules/workflow_job_template.py import-3.10 -plugins/modules/workflow_job_template_node.py import-3.10 -plugins/modules/workflow_launch.py import-3.10 -plugins/modules/workflow_node_wait.py import-3.10 diff --git a/awx_collection/tests/sanity/ignore-2.14.txt b/awx_collection/tests/sanity/ignore-2.14.txt new file mode 100644 index 0000000000..19512ea0c1 --- /dev/null +++ b/awx_collection/tests/sanity/ignore-2.14.txt @@ -0,0 +1 @@ +plugins/modules/export.py validate-modules:nonexistent-parameter-documented # needs awxkit to construct argspec From cf1ec07eabbc6f64895e1896668dd97d2843acb2 Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Wed, 21 Dec 2022 09:53:18 -0500 Subject: [PATCH 29/32] Changes to run sanity tests locally Use a Makefile arg for the ansible-test sanity CLI args defaults to --docker in the future we probably need to customize python versions Copy the rule exception for Ansible 2.15 this helps people who are running from Ansible devel --- Makefile | 20 ++++++++++++-------- awx_collection/tests/sanity/ignore-2.15.txt | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 awx_collection/tests/sanity/ignore-2.15.txt diff --git a/Makefile b/Makefile index d86e9779a4..1185666e76 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,17 @@ VERSION := $(shell $(PYTHON) tools/scripts/scm_version.py) # ansible-test requires semver compatable version, so we allow overrides to hack it COLLECTION_VERSION ?= $(shell $(PYTHON) tools/scripts/scm_version.py | cut -d . -f 1-3) +# args for the ansible-test sanity command +COLLECTION_SANITY_ARGS ?= --docker +# collection unit testing directories +COLLECTION_TEST_DIRS ?= awx_collection/test/awx +# collection integration test directories (defaults to all) +COLLECTION_TEST_TARGET ?= +# args for collection install +COLLECTION_PACKAGE ?= awx +COLLECTION_NAMESPACE ?= awx +COLLECTION_INSTALL = ~/.ansible/collections/ansible_collections/$(COLLECTION_NAMESPACE)/$(COLLECTION_PACKAGE) +COLLECTION_TEMPLATE_VERSION ?= false # NOTE: This defaults the container image version to the branch that's active COMPOSE_TAG ?= $(GIT_BRANCH) @@ -290,13 +301,6 @@ test: cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3 awx-manage check_migrations --dry-run --check -n 'missing_migration_file' -COLLECTION_TEST_DIRS ?= awx_collection/test/awx -COLLECTION_TEST_TARGET ?= -COLLECTION_PACKAGE ?= awx -COLLECTION_NAMESPACE ?= awx -COLLECTION_INSTALL = ~/.ansible/collections/ansible_collections/$(COLLECTION_NAMESPACE)/$(COLLECTION_PACKAGE) -COLLECTION_TEMPLATE_VERSION ?= false - test_collection: rm -f $(shell ls -d $(VENV_BASE)/awx/lib/python* | head -n 1)/no-global-site-packages.txt if [ "$(VENV_BASE)" ]; then \ @@ -339,7 +343,7 @@ test_collection_sanity: if ! [ -x "$(shell command -v ansible-test)" ]; then pip install ansible-core; fi ansible --version COLLECTION_VERSION=1.0.0 make install_collection - cd $(COLLECTION_INSTALL) && ansible-test sanity --docker + cd $(COLLECTION_INSTALL) && ansible-test sanity $(COLLECTION_SANITY_ARGS) test_collection_integration: install_collection cd $(COLLECTION_INSTALL) && ansible-test integration $(COLLECTION_TEST_TARGET) diff --git a/awx_collection/tests/sanity/ignore-2.15.txt b/awx_collection/tests/sanity/ignore-2.15.txt new file mode 100644 index 0000000000..19512ea0c1 --- /dev/null +++ b/awx_collection/tests/sanity/ignore-2.15.txt @@ -0,0 +1 @@ +plugins/modules/export.py validate-modules:nonexistent-parameter-documented # needs awxkit to construct argspec From f739908ccf8c897321b3f70981eba7527fc10cb7 Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Wed, 21 Dec 2022 09:57:00 -0500 Subject: [PATCH 30/32] Add comment about Ansible-core being installed by default Co-authored-by: John R Barker --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97df2050cd..faa2b02192 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,6 +154,7 @@ jobs: steps: - uses: actions/checkout@v2 + # The containers that GitHub Actions use have Ansible installed, so upgrade to make sure we have the latest version. - name: Upgrade ansible-core run: python3 -m pip install --upgrade ansible-core From 239827a9cf717820b72f4328a56de9fa3afceba3 Mon Sep 17 00:00:00 2001 From: Dimitri Savineau Date: Wed, 21 Dec 2022 10:23:57 -0500 Subject: [PATCH 31/32] Pin hiredis to 2.0.0 The hiredis 2.1.0 release doesn't provide source distribution on PyPi so users can't build that python package from sources. Signed-off-by: Dimitri Savineau --- requirements/README.md | 9 +++++++++ requirements/requirements.in | 1 + requirements/requirements.txt | 6 ++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/requirements/README.md b/requirements/README.md index 556c402e7a..6b77e3b01a 100644 --- a/requirements/README.md +++ b/requirements/README.md @@ -157,6 +157,15 @@ For now, we pin to the old version, 3.4.1 * https://github.com/django/channels_redis/issues/332 * https://github.com/ansible/awx/issues/13313 +### hiredis + +The hiredis 2.1.0 release doesn't provide source distribution on PyPI which prevents users to build that python package from the +sources. +Downgrading to 2.0.0 (which provides source distribution) until the channels-redis issue is fixed or a newer hiredis version is +available on PyPi with source distribution. + +* https://github.com/redis/hiredis-py/issues/138 + ## Library Notes ### pexpect diff --git a/requirements/requirements.in b/requirements/requirements.in index d2d2cca62d..405aa1d5ab 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -26,6 +26,7 @@ djangorestframework==3.13.1 djangorestframework-yaml filelock GitPython +hiredis==2.0.0 # see UPGRADE BLOCKERs irc jinja2 JSON-log-formatter diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 231f8b8881..91ea6a86b5 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -158,8 +158,10 @@ gitpython==3.1.29 # via -r /awx_devel/requirements/requirements.in google-auth==2.14.1 # via kubernetes -hiredis==2.1.0 - # via aioredis +hiredis==2.0.0 + # via + # -r /awx_devel/requirements/requirements.in + # aioredis hyperlink==21.0.0 # via # autobahn From 3543644e0e73e1b1333ee9ad29bb560ed72c9284 Mon Sep 17 00:00:00 2001 From: Seth Foster Date: Wed, 21 Dec 2022 13:36:11 -0500 Subject: [PATCH 32/32] bump receptorctl version to 1.3.0 --- requirements/requirements.in | 2 +- requirements/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/requirements.in b/requirements/requirements.in index d2d2cca62d..700ee52705 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -42,7 +42,7 @@ python-dsv-sdk python-tss-sdk==1.0.0 python-ldap pyyaml -receptorctl==1.2.3 +receptorctl==1.3.0 schedule==0.6.0 social-auth-core[openidconnect]==4.3.0 # see UPGRADE BLOCKERs social-auth-app-django==5.0.0 # see UPGRADE BLOCKERs diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 231f8b8881..72a3f95b55 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -336,7 +336,7 @@ pyyaml==6.0 # djangorestframework-yaml # kubernetes # receptorctl -receptorctl==1.2.3 +receptorctl==1.3.0 # via -r /awx_devel/requirements/requirements.in redis==4.3.5 # via