Compare commits

..

844 Commits

Author SHA1 Message Date
Kersom
6a9de16cda Merge pull request #10869 from AlexSCorey/10822-fixReactWarnings
Fixes several react warnings
2021-08-12 12:44:09 -04:00
Alex Corey
9d648edc19 fixes several react warnings 2021-08-12 09:08:40 -04:00
Shane McDonald
9da383fe2d Merge pull request #10866 from ansible/fix-awx-ee-name
Fix name of default awx ee
2021-08-12 08:06:34 -04:00
Elijah DeLee
86600531e2 Fix name of default awx ee
we are now tracking the latest tag
2021-08-11 22:06:56 -04:00
Shane McDonald
7505ecd284 Merge pull request #10865 from shanemcd/19.3.0
Bump version and changelog
2021-08-11 21:02:26 -04:00
Shane McDonald
a22de5a9ee Bump version and changelog 2021-08-11 19:51:06 -04:00
Tiago Góes
514616ad6e Merge pull request #10864 from tiagodread/awxkit
Generate a small random title size on awxkit when necessary
2021-08-11 19:14:19 -03:00
Tiago
4f5909ad21 Generate a small random size when necessary 2021-08-11 18:58:07 -03:00
Shane McDonald
aa98a5b5e1 Merge pull request #10858 from rooftopcellist/devel-receptor-runner
Install receptor and ansible-runner from devel branch
2021-08-11 16:43:13 -04:00
Christian Adams
93ee0a362f Merge pull request #10861 from kdelee/awx-ee-latest
Use awx-ee:latest to get latest receptor and runner
2021-08-11 16:27:18 -04:00
Christian M. Adams
56fd5c435d Install receptor and ansible-runner from devel
Signed-off-by: Christian M. Adams <rooftopcellist@gmail.com>
2021-08-11 16:22:24 -04:00
Tiago Góes
ebe5fff992 Merge pull request #10856 from tiagodread/awxkit
Update awxkit random_title setting non_ascii to False
2021-08-11 14:26:53 -03:00
Tiago
2a56be77b3 fix lint 2021-08-11 14:02:46 -03:00
Tiago
bf70200550 Update awxkit random_title setting non_ascii to False 2021-08-11 13:38:30 -03:00
Elijah DeLee
9b2d2a1856 Use awx-ee:latest to get latest receptor and runner
We are updating the requirements to get the latest receptor and runner in the task container,
we should also have the latest in the EE
2021-08-11 11:36:42 -04:00
Sarah Akus
ec729a3f15 Merge pull request #10820 from AlexSCorey/10654-10739-10740-fix
Host List Expand All and Survey List -> Tables
2021-08-11 09:58:49 -04:00
Alex Corey
34d0595bab adds locators 2021-08-11 09:44:54 -04:00
Alex Corey
b4243c6f03 adds dragging functionality to modal 2021-08-11 09:43:50 -04:00
Alex Corey
0aa82c2784 Adds expand all to Host List, and moved Survey list to table view 2021-08-11 09:43:50 -04:00
Jake McDermott
80053cea83 Merge pull request #10845 from nixocio/ui_add_more_ids
Update Ids for Job Details page
2021-08-10 10:39:28 -04:00
nixocio
100c1cbbce Update Ids for Job Details page
Update Ids for job details page to ease testing.

Also, distinguish between Project and Inventory Source Project.

See: https://github.com/ansible/awx/issues/10786#issuecomment-893658516
2021-08-09 17:05:13 -04:00
Bianca Henderson
1173dca900 Merge pull request #10809 from beeankha/remove_deprecated_params
Remove Collections Module Parameters Deprecated in Controller 4.0.0
2021-08-09 15:33:21 -04:00
Alex Corey
205935bc38 Merge pull request #10703 from AlexSCorey/10683-fixstrings
Marks dashboard chart axis labels for translation
2021-08-09 14:42:40 -04:00
Alex Corey
7025bc2678 marks dashboard chart axis labels for translation 2021-08-09 14:00:13 -04:00
Kersom
6cc6442f0d Merge pull request #10832 from nixocio/ui_issue_8020
Update inventory source sync button on kebab
2021-08-09 11:02:27 -04:00
Alex Corey
071973d89e Merge pull request #10828 from AlexSCorey/10628-ConvergenceData_10549-fix
Addresses permission problem on host group list and adds convergence data to Prompt Detail
2021-08-09 09:24:35 -04:00
Alex Corey
13ddc78b7d Addresses permission problem on host group list and adds convergence data to Prompt Detail 2021-08-09 09:04:22 -04:00
nixocio
bc083089bb Update inventory source sync button on kebab
Update inventory source sync button on kebab

See: https://github.com/ansible/awx/issues/8020
2021-08-06 16:31:07 -04:00
Bianca Henderson
ec66ffb1eb Merge pull request #10826 from beeankha/fix_collection_name_issue
Point to the Correct Name for AAP Within Collections
2021-08-06 14:32:46 -04:00
Kersom
3a6b228f6f Merge pull request #10821 from nixocio/ui_ids
Add Ids to ease tests
2021-08-06 11:41:59 -04:00
beeankha
bc365e2d01 Point to the correct name for AAP within collections 2021-08-06 10:13:06 -04:00
nixocio
e9b9dd3072 Add Ids to ease tests
Add Ids to ease tests.

See: https://github.com/ansible/awx/issues/8680#issuecomment-893663314
2021-08-06 10:12:06 -04:00
Jake McDermott
7b065ae0a0 Merge pull request #10789 from phemmer/patch-1
add minikube to github bug template
2021-08-06 10:04:00 -04:00
Patrick Hemmer
c10d556f17 add minikube to github bug template 2021-08-06 09:36:00 -04:00
Keith Grant
1ea0ff611a Merge pull request #10819 from keithjgrant/8474-hide-search-clear-all
Remove Clear All button in search when filters cleared
2021-08-05 11:20:24 -07:00
Keith J. Grant
92e35978dc remove Clear All button in search when filters cleared 2021-08-05 10:46:43 -07:00
Kersom
8d06c64495 Merge pull request #10772 from nixocio/ui_upgrade_formik
Upgrade formik
2021-08-05 13:14:00 -04:00
nixocio
fe8cd7188c Upgrade formik
Upgrade formik
2021-08-05 10:56:00 -04:00
Kersom
c721fe0b37 Merge pull request #10794 from nixocio/ui_issue_8680
Show PAT as part of bulk delete list
2021-08-05 10:33:09 -04:00
Kersom
ba1f89b9d8 Merge pull request #10796 from nixocio/ui_issue_job_id
Add job id to job details screen
2021-08-05 10:32:24 -04:00
Kersom
d94eba7179 Merge pull request #10810 from nixocio/ui_update_npm_container
Bump npm version inside container
2021-08-05 09:54:45 -04:00
nixocio
f2e8b90628 Bump npm version inside container
Bump npm version inside container

See: https://docs.npmjs.com/cli/v7/configuring-npm/package-lock-json#lockfileversion
2021-08-04 15:34:27 -04:00
Tiago Góes
2f0b5fc20a Merge pull request #10722 from AlexSCorey/10706-DisappearingField
Ensures that field is on screen behind the confirmation modal
2021-08-04 14:21:35 -03:00
Alex Corey
53817d3cbe ensures that field is on screen behind the confirmation modal 2021-08-03 18:08:11 -04:00
Bianca Henderson
c23f7f5bdc Merge pull request #10807 from beeankha/collections_doc_error
Fix Broken Collections Docs
2021-08-03 17:05:29 -04:00
Tiago Góes
4277149a3f Merge pull request #10797 from tiagodread/workflow-e2e
Update workflow to use pull_request_target
2021-08-03 17:31:59 -03:00
Tiago
3ba00c7a72 Add CODEOWNERS for e2e_test.yml 2021-08-03 17:18:47 -03:00
nixocio
0d2bc750e8 Show PAT as part of bulk delete list
* Show PAT as part of bulk delete list
* Update tooltip message in how to create a Personal Access Token

See: https://github.com/ansible/awx/issues/8680
2021-08-03 16:12:46 -04:00
nixocio
97a4122ceb Add job id to job details screen
Add job id to job details screen

See: https://github.com/ansible/awx/issues/10786
2021-08-03 16:11:54 -04:00
Tiago
8b165b333e Update workflow to use pull_request_target 2021-08-03 16:34:42 -03:00
beeankha
ea71fef2bd Add required params to collections docs file 2021-08-03 15:06:53 -04:00
beeankha
9409dc0085 Remove Collections module parameters deprecated in Controller 4.0.0 2021-08-03 14:55:45 -04:00
Tiago Góes
dae3f1a164 Merge pull request #10592 from mabashian/2032-workflow-node-alias
Adds support for workflow node aliasing via identifier field
2021-08-03 15:50:18 -03:00
mabashian
0213fb5412 Fix linting errors 2021-08-03 14:08:00 -04:00
mabashian
a4f263bc92 Fix bug where identifier is undefined 2021-08-03 14:07:56 -04:00
mabashian
231cccbb19 Adds support for workflow node aliasing via identifier field 2021-08-03 14:07:50 -04:00
kialam
791d24bcb6 Merge pull request #10801 from kialam/add-instances-node-type-ui
Add Node Type to Instances page and modify "Type" to "Policy Type."
2021-08-03 14:01:02 -04:00
Kia Lam
729723205f Fix unit tests. 2021-08-03 13:06:35 -04:00
Kia Lam
2474f60e00 Add Node Type to Instances page and modify "Type" to "Policy Type." 2021-08-03 13:06:34 -04:00
Tiago Góes
dbb5715fea Merge pull request #10803 from akus062381/add-ouia-wfjt-survey-prompt
WFJT Prompt- Survey- add OUIA locators for testability
2021-08-03 11:57:07 -03:00
akus062381
86ebce6d3d adding ouiaId locators to Survey Prompt step within Node Prompt Modal for WFJT
adding ouiaId locators to Survey Prompt step within Node Prompt Modal for WFJT
2021-08-03 10:36:24 -04:00
Bianca Henderson
e84a629ada Merge pull request #10788 from beeankha/fix_sanity_errors_collections
Fix Collections Errors
2021-08-03 08:56:43 -04:00
Kersom
1907859827 Merge pull request #10724 from nixocio/ui_issue_10676
Merge ui and ui_next in one dir
2021-08-03 08:33:13 -04:00
beeankha
cf4a68c9b3 Revert "Add required params to deprecated docstrings"
This reverts commit dea2ce6fde.
2021-08-02 23:15:30 -04:00
beeankha
dea2ce6fde Add required params to deprecated docstrings 2021-08-02 20:03:02 -04:00
nixocio
f85b2b6352 Merge ui and ui_next in one dir
Merge ui and ui_next in one dir

See: https://github.com/ansible/awx/issues/10676

Update django .po files

Update django .po files

Run `awx-manage makemessages`.
2021-08-02 10:40:24 -04:00
beeankha
e88e81928c Fix sanity errors for collections 2021-07-30 10:53:44 -04:00
Rebeccah Hunter
d89719c740 Merge pull request #10757 from rebeccahhh/instance_node_type
add a node_type field to the instance model
2021-07-28 17:52:27 -04:00
Jake McDermott
eef80c8875 Merge pull request #10781 from tiagodread/update-e2e-workflow
Use cypress base image from a public repo in quay
2021-07-28 16:51:25 -04:00
Jake McDermott
34bd0588b4 Merge pull request #10777 from nixocio/ui_issue_10775
Update usage of useBrandName
2021-07-28 16:46:18 -04:00
Tiago
bf8d70e657 Use cypress base image from a public repo in quay 2021-07-28 17:39:16 -03:00
Tiago Góes
b349774f92 Merge pull request #10572 from mabashian/790-mgt-jobs-workflow
Add UI support for management jobs in workflows
2021-07-28 16:15:38 -03:00
nixocio
452848ff27 Update usage of useBrandName
useBrandName return variables were updated. Update a few places using
this custom hook.

See: https://github.com/ansible/awx/issues/10775
2021-07-28 14:53:49 -04:00
Sarah Akus
5d345c22b4 Merge pull request #10635 from nixocio/ui_issue_10613
Add extra step to confirm edition of login redirect URL
2021-07-28 14:29:21 -04:00
nixocio
33502daf45 Add extra step to allow edition of login redirect URL
Add extra step to allow edition of login redirect URL

closes: https://github.com/ansible/awx/issues/10613
2021-07-28 12:08:54 -04:00
Jake McDermott
07a4683f08 Merge pull request #10741 from AlexSCorey/10495-ActionBtnOnEmptyState
Improves empty state messages for improve UX
2021-07-28 10:18:49 -04:00
Jake McDermott
e207b424b1 Merge pull request #10768 from nixocio/ui_issue_8593
Remove all groups filter
2021-07-28 10:06:16 -04:00
Jake McDermott
50279478c8 Update job list message 2021-07-28 10:04:58 -04:00
Tiago Góes
7b6fa1815a Merge pull request #10692 from nixocio/ui_issue_10663_again
Add auto-populate inventory host form
2021-07-28 10:32:08 -03:00
nixocio
b57966677e Remove all groups filter
Remove all groups filter

See: https://github.com/ansible/awx/issues/8593
2021-07-27 16:18:56 -04:00
Jake McDermott
dc79d76444 Merge pull request #10761 from nixocio/ui_issue_6800
Add string to be translated
2021-07-27 15:20:06 -04:00
nixocio
3c1de8d683 Add auto-populate inventory host form
Add auto-populate inventory host form

closes:https://github.com/ansible/awx/issues/10663
2021-07-27 13:03:51 -04:00
nixocio
b077f186d1 Add string to be translated
Add string to be translated

closes: https://github.com/ansible/awx/issues/6800
2021-07-27 11:22:08 -04:00
Jake McDermott
63075976c2 Merge pull request #10662 from AlexSCorey/updatesProdDeps
Updates Several UI Production Dependencies
2021-07-27 11:14:04 -04:00
mabashian
5f7db084d3 Fix linting errors 2021-07-27 09:02:43 -04:00
mabashian
1e30e33d30 Fix bug where page crashed if attempting to view system job node without extra vars 2021-07-27 09:02:43 -04:00
mabashian
874b497794 Update label on days field 2021-07-27 09:02:42 -04:00
mabashian
8374533c5f Ensure that days is always an integer 2021-07-27 09:02:42 -04:00
mabashian
034c665c83 Adds Variables detail to node view when node is a system job template 2021-07-27 09:02:42 -04:00
mabashian
d7521efc91 Fix days to keep bug when editing a new node 2021-07-27 09:02:42 -04:00
mabashian
4db6eaf1aa Add UI support for management jobs in workflows 2021-07-27 09:02:42 -04:00
Rebeccah
fd6ce66906 edit the provision_instance awx-manage command to include node_type when provisioning a new instance. 2021-07-26 16:36:44 -04:00
Rebeccah
f11b73da12 update node_type to be read-only 2021-07-26 16:13:57 -04:00
Tiago Góes
cfa5d1b11d set timeout limit for e2e tests (#10756) 2021-07-26 20:00:00 +00:00
Rebeccah
706f3f97ea add a new field to the instance model for use with receptor changes (incoming) 2021-07-26 15:53:56 -04:00
Alex Corey
34fdf11217 fixes tests 2021-07-26 14:21:31 -04:00
Alex Corey
3dec379052 adds missing license text files 2021-07-26 14:21:23 -04:00
Alex Corey
56fb5479e2 removes unuse license text files 2021-07-26 14:21:19 -04:00
Alex Corey
0a64f3274e updates d3, ansi-t0-html, has-ansi, httml-entities, sanitize-html, styled-components 2021-07-26 14:21:03 -04:00
Jake McDermott
57fa2c03f7 Merge pull request #10753 from ansible/jakemcdermott-patch-readme
Update CI results status badge
2021-07-26 11:38:47 -04:00
Jake McDermott
3ef8008f91 Update CI results status badge 2021-07-26 11:19:54 -04:00
Jake McDermott
70f69b6c8b Merge pull request #10751 from tiagodread/e2e-workflow
Update e2e workflow to use variable for e2e project name
2021-07-26 11:06:15 -04:00
Tiago
c50c0d3f1e Update e2e workflow to use variable for e2e project name 2021-07-26 11:51:12 -03:00
Tiago Góes
6740785054 Merge pull request #10725 from ansible/e2e-tests
Add E2E tests workflow
2021-07-26 11:32:32 -03:00
Tiago
777d37c4b8 Add workflow to run e2e tests when the label needs_test is applied to the PR 2021-07-23 19:13:20 -03:00
Shane McDonald
41321d8ad5 Merge pull request #10716 from oweel/10392-return_404_ad_hoc_command_events
Return 404 for ad_hoc_command_events list api. Remove api endtpoint
2021-07-23 17:35:57 -04:00
Keith Grant
e9b7f9ac40 Merge pull request #10713 from keithjgrant/10563-a11y-fixes
Fix multiple accessibility violations
2021-07-23 10:36:21 -07:00
Alex Corey
f3b6291918 Merge pull request #10634 from AlexSCorey/5200-AboutModalUpdate
Updates product name in About modal
2021-07-23 13:20:13 -04:00
Alex Corey
3c6e7b0983 Improves empty state messages for improve UX 2021-07-23 11:34:03 -04:00
Shane McDonald
09479be4ba Merge pull request #10738 from shanemcd/fix-docker-clean-volumes
Fix docker-clean-volumes target when not using minikube
2021-07-23 11:06:13 -04:00
Shane McDonald
18a51d1dd0 Fix docker-clean-volumes target when not using minikube
Without this patch, you get:

```
tools/docker-compose-minikube/_sources/minikube delete
make: tools/docker-compose-minikube/_sources/minikube: No such file or directory
```
2021-07-23 09:09:33 -04:00
Shane McDonald
7882cb9008 Merge pull request #10668 from oweel/devel
Fix ignoring --no-color for awx-manage list_instances command
2021-07-22 20:46:02 -04:00
Shane McDonald
05c7d3a60e Merge pull request #10108 from saito-hideki/issue/10057
Fix to handle ask_* parameters correctly when set false
2021-07-22 20:25:14 -04:00
Shane McDonald
c09050d1f2 Merge pull request #9944 from AlanCoding/schedule_teardown
Allow stable use of AWXKIT_PREVENT_TEARDOWN by disabling schedules at the end
2021-07-22 20:19:35 -04:00
Shane McDonald
dd9c6270ba Dont fail when pre-built CI image is not available 2021-07-22 19:43:34 -04:00
Shane McDonald
18d9bfa06e Merge pull request #10573 from Tompage1994/collection_inv_src_proj
Default source_project to organization for inventory source
2021-07-22 17:14:32 -04:00
Shane McDonald
ef82c1ce01 Merge pull request #10566 from strollo/webhook-headers-patch
Headers missing in webhook notification request
2021-07-22 17:08:56 -04:00
Shane McDonald
6a7aa77033 Merge pull request #10484 from ansible/chrismeyersfsu-patch-1
only get active long running queries
2021-07-22 15:58:10 -04:00
Shane McDonald
f683c7159d Merge pull request #10481 from brigzzy/compose_up_fix
Reorder docker compose up options
2021-07-22 15:57:39 -04:00
Shane McDonald
cd33db037d Merge pull request #9703 from tchellomello/double_ldap
Avoid double LDAP updates
2021-07-22 15:54:29 -04:00
Shane McDonald
8609a637f9 Merge pull request #9365 from mcharanrm/aa-workloads-firehose
tools/scripts/firehose.py: capture all job ids, attach events to all jobs ids and distribute the events
2021-07-22 15:52:16 -04:00
Shane McDonald
99ffd3898c Merge pull request #8023 from velzend/improve_logging_migrating_or_instance_not_registered
improve logging migrate or instance not registered
2021-07-22 15:50:33 -04:00
Shane McDonald
c36821d6e1 Merge pull request #7273 from jamesmarshall24/devel
Remove query_parameters from page loop causing 414
2021-07-22 15:49:16 -04:00
Shane McDonald
b3604ed94a Merge pull request #10511 from fosterseth/fix_haproxy_permission
run dev cluster haproxy container as root
2021-07-22 15:45:28 -04:00
Shane McDonald
0e30c6639a Merge pull request #10583 from coolbry95/waitfordb
wait for database connection
2021-07-22 14:12:30 -04:00
Keith J. Grant
f6037f9df5 run changes through updated v of prettier 2021-07-22 10:57:49 -07:00
Shane McDonald
0aca4d658a Bash nitpick 2021-07-22 13:56:58 -04:00
Sarabraj Singh
ca14cbefaf Merge pull request #10425 from sarabrajsingh/bugfix/preflight-check-postgres-version-4940
introduced a pre-flight check for postgres 12
2021-07-22 13:56:58 -04:00
coolbry95
041e22f609 wait for migrations in awx-web container 2021-07-22 13:56:58 -04:00
coolbry95
a21dcec85d wait for database connection
Signed-off-by: coolbry95 <coolbry95@gmail.com>
2021-07-22 13:56:58 -04:00
Keith J. Grant
55a9a4ca46 update selectors in tests to match id changes 2021-07-22 09:55:01 -07:00
Keith J. Grant
e32471adbd fix a11y id issues in team list and jt form 2021-07-22 08:58:00 -07:00
Keith J. Grant
77f2729a76 fix settings pages a11y issues 2021-07-22 08:58:00 -07:00
Keith J. Grant
5fb1b604bf ensure unique ids on jobs list 2021-07-22 08:58:00 -07:00
Keith J. Grant
29753c6b9b fix lookup field ids 2021-07-22 08:58:00 -07:00
Jake McDermott
1aacd94cb5 Merge pull request #10711 from ansible/pip-boto
Install boto to ci ansible python env
2021-07-22 11:08:35 -04:00
Jake McDermott
7bfc1702ab Merge pull request #10632 from The-Migus-Group/tss-plugin-amigus
Add Thycotic SecretServer support
2021-07-22 08:57:39 -04:00
Kersom
d68c118fd4 Merge pull request #10570 from nixocio/ui_remove_with_router
Remove mix usage of hooks and HOC for router
2021-07-22 08:34:55 -04:00
Alexander Komarov
27543aed1d Return 404 for ad_hoc_command_events list api. Remove api endtpoint 2021-07-22 15:04:00 +05:00
Adam Migus
edd3554c36 Breakdown the compound statement in tss_backend 2021-07-21 22:03:34 -04:00
Adam Migus
2025426a1b Use a callable function instead of a lambda. 2021-07-21 22:03:34 -04:00
Adam Migus
77ab35e7a8 Extract the field from the secret. 2021-07-21 22:03:33 -04:00
endlesstrax
9dc84d69d5 Update required for SDK v1 compatability 2021-07-21 22:03:32 -04:00
endlesstrax
fa7867e8a7 Fixed import error 2021-07-21 22:03:31 -04:00
endlesstrax
e6ed7f95f1 Added licences fro dataclasses and python-tss-sdk 2021-07-21 22:03:30 -04:00
endlesstrax
28de50f14e Updated the required sdk version to latest release v1.0.0 2021-07-21 22:03:29 -04:00
Adam Migus
7ec56a56e5 Fixed it. 2021-07-21 22:03:29 -04:00
Adam C. Migus
b0b295ba1e My changes. 2021-07-21 22:03:28 -04:00
Ricky White
0cc6bf9b60 Updated backend code 2021-07-21 22:03:27 -04:00
Ricky White
14b767abc3 Added thycotic_tss to test credential 2021-07-21 22:03:26 -04:00
Ricky White
f06c6d349c Added base tss plugin code. Not tested 2021-07-21 22:03:25 -04:00
Ricky White
d6621470b3 Added tss credential plugin 2021-07-21 22:03:25 -04:00
Ricky White
68ab6e4853 Added python-tss-sdk to requirements 2021-07-21 22:03:24 -04:00
Jake McDermott
3980864151 Install boto to ci ansible python env 2021-07-21 18:01:09 -04:00
Tiago
0c8f4fc9e7 Revert "add e2e tests to ci.yml"
This reverts commit 4f428af515.
2021-07-21 18:52:14 -03:00
Tiago
4f428af515 add e2e tests to ci.yml 2021-07-21 18:35:02 -03:00
Kersom
5d20acaa92 Merge pull request #10709 from nixocio/ui_fix_lint
Run prettier and lint
2021-07-21 17:15:48 -04:00
nixocio
05e5cd6bf1 Run prettier
Run prettier
2021-07-21 17:00:05 -04:00
Sarah Akus
53251434f2 Merge pull request #10696 from nixocio/ui_status_label
Create map of strings to be translated
2021-07-21 15:41:56 -04:00
Keith Grant
9704c57d6b Merge pull request #10665 from keithjgrant/disallow-test-network-requests
Disallow network requests in tests
2021-07-21 09:32:47 -07:00
Sarah Akus
9b7ef9ba21 Merge pull request #10700 from nixocio/ui_misalignment
Fix misalignment node approval timeout
2021-07-21 12:05:41 -04:00
Alexander Komarov
e7f1d1d0c1 Fix ignoring --no-color for awx-manage list_instances command 2021-07-21 20:55:24 +05:00
Marcelo Moreira de Mello
c9259ac45b Merge pull request #10675 from tchellomello/minikube-hack-macos
Workaround Minikube issue on MacOS and enable preflights
2021-07-21 10:56:14 -04:00
Marcelo Moreira de Mello
7e46499e18 Workaround Minikube issue on MacOS and enable preflights 2021-07-21 10:39:51 -04:00
nixocio
c1b2428b5d Create map of strings to be translated
Create map of strings to be translated to StatusLabel

closes:https://github.com/ansible/awx/issues/8586
2021-07-21 09:53:37 -04:00
Tiago Góes
c073583663 Merge pull request #10658 from AlexSCorey/updatesESLint_and_Prettier_and_relatedDeps
Updates Several Dev Dependencies
2021-07-21 10:50:22 -03:00
Sarah Akus
66fc92a97f Merge pull request #10679 from AlexSCorey/10549-AuditorsCanAssociateHostWithGroup
Enforces Proper permissions for Host Groups List
2021-07-21 09:45:38 -04:00
nixocio
10c8480247 Fix misalignment node approval timeout
Fix misalignment node approval timeout

closes:https://github.com/ansible/awx/issues/10515
2021-07-21 09:30:58 -04:00
Alex Corey
cfcaa4271c hits correct api end point to get options data for host groups list 2021-07-21 09:30:10 -04:00
Jake McDermott
872513617e Merge pull request #10660 from nixocio/ui_issue_9554
Bump size of SSO icons login screen
2021-07-20 16:56:39 -04:00
Keith J. Grant
9237ca4809 fix path to useBrandName in test 2021-07-20 13:47:46 -07:00
nixocio
719c9e824b Remove mix usage of hooks and HOC for router
There were a few cases that hooks and HOC were being used at the same on
a certain component. Remove HOC from those ones.
2021-07-20 16:47:39 -04:00
Keith J. Grant
9d01334a86 remove withRouter where not needed 2021-07-20 13:01:32 -07:00
Keith J. Grant
4c62bf268d fix test warning about open worker process 2021-07-20 13:01:31 -07:00
Keith J. Grant
3e79fa2dcb fail tests that initiate network requests 2021-07-20 13:01:31 -07:00
Shane McDonald
6715b88633 Update upload_schema.yml 2021-07-20 15:32:11 -04:00
Shane McDonald
556f8aff17 Update upload_schema.yml 2021-07-20 15:14:36 -04:00
Shane McDonald
c8322ee2f1 Merge pull request #10672 from shanemcd/actions
Reimplement CI jobs in GitHub Actions
2021-07-20 12:55:06 -04:00
Shane McDonald
d2017feb55 Specify which region to upload schema to 2021-07-20 12:23:06 -04:00
Shane McDonald
aa934b1dda Add post-merge GHA job for uploading api schema to s3 2021-07-20 12:23:05 -04:00
Jake McDermott
dd510ab90c Set maxworkers to 4 2021-07-20 12:23:04 -04:00
Shane McDonald
3353b3f3b7 Split out UI test and linters into different GHA jobs 2021-07-20 12:23:04 -04:00
Shane McDonald
e22612fc3e Fix image push job 2021-07-20 12:23:03 -04:00
Shane McDonald
baca30ef83 Dont lint GHA files 2021-07-20 12:23:02 -04:00
Shane McDonald
2622a1e764 Port CI jobs to GitHub Actions 2021-07-20 12:23:01 -04:00
Alex Corey
3def23883e updates several dependencies 2021-07-20 12:19:27 -04:00
softwarefactory-project-zuul[bot]
e77d297a28 Merge pull request #10510 from AlexSCorey/10440-8660-fix
Renders Command Module in job detail view and improves Ad Hoc Commands execution permissions

SUMMARY
This closes #10440 and #8660.
On the job details view we now render the command module name, and the arguments.  We also remove the run command button for user that do not have permission to launch a ad hoc command.
ISSUE TYPE
-enhancement
COMPONENT NAME

UI

AWX VERSION
ADDITIONAL INFORMATION

Reviewed-by: Kersom <None>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-20 15:28:24 +00:00
softwarefactory-project-zuul[bot]
8183179850 Merge pull request #10576 from AlexSCorey/9399-revampAdHocCommandsWorkflow
Adds Ad Hoc Preview step and adds workflow similar to prompt on launch

SUMMARY
This closes #9399 it also introduce the same workflow that prompt on launch uses in the Ad Hoc Commands, where the user to go between steps as they wish.
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

UI

AWX VERSION
ADDITIONAL INFORMATION

Reviewed-by: Kersom <None>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-20 13:31:37 +00:00
nixocio
52777681d1 Bump size of SSO icons login screen
Bump size of SSO icons login screen

closes: https://github.com/ansible/awx/issues/9554
2021-07-20 08:59:57 -04:00
Alex Corey
71a3a816e2 improves permissions for ad hoc commands execution and tooltip handling 2021-07-20 08:57:25 -04:00
Alex Corey
d389362ca3 renders ad hoc command fields in job detail view 2021-07-20 08:57:25 -04:00
Alex Corey
87890234f8 Adds Ad Hoc Preview step and adds workflow similar to prompt on launch 2021-07-20 08:56:10 -04:00
Alex Corey
fb91c8fba1 updates product name in About modal 2021-07-20 08:27:33 -04:00
softwarefactory-project-zuul[bot]
3f44c5d18b Merge pull request #10639 from weidongkl/devel
Fix inaccurate translation

SUMMARY

Fix some inaccurate translation in zh meesage.po

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


UI

AWX VERSION

devel branch

ADDITIONAL INFORMATION

Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
Reviewed-by: weidong <None>
2021-07-20 02:17:50 +00:00
weidong
cf269fb337 Update Weekday's translation 2021-07-20 09:26:55 +08:00
softwarefactory-project-zuul[bot]
fd99b366c2 Merge pull request #10684 from rooftopcellist/compile-messages
Properly compile translated API strings

SUMMARY
Fixes: #10681
Now when make ui-devel is run, it will compile the API translated strings and display them to the client browser.
[chadams@chadams-work awx]$ make ui-devel
make[1]: Entering directory '/home/chadams/awx'
python3.8 tools/scripts/compilemessages.py
processing file django.po in /home/chadams/awx/awx/locale/fr/LC_MESSAGES
processing file django.po in /home/chadams/awx/awx/locale/zh/LC_MESSAGES
processing file django.po in /home/chadams/awx/awx/locale/en-us/LC_MESSAGES
processing file django.po in /home/chadams/awx/awx/locale/ja/LC_MESSAGES
processing file django.po in /home/chadams/awx/awx/locale/es/LC_MESSAGES
processing file django.po in /home/chadams/awx/awx/locale/nl/LC_MESSAGES
npm --prefix awx/ui_next --loglevel warn run compile-strings
...

ISSUE TYPE


Bugfix Pull Request

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
2021-07-19 22:33:34 +00:00
softwarefactory-project-zuul[bot]
001f66980f Merge pull request #10562 from jakemcdermott/fix-relatives-2
Fix relative imports in src code, relocate src

(Lots of files modified but the changes are low-risk and automated)
This PR is a follow-up to #6954, specifically the part where we removed webpack aliases to pick up react-scripts.
SUMMARY

 Add the jsconfig.json w/  baseUrl to enable absolute imports from src. Replaces all the ../../../../../ importing
  jsx -> js extension renaming
 hooks directory
[ ] ui_next -> ui see: #10676

For posterity, the script used to fix the relative imports is included in the commit history.
python3 tools/fixrelative.py awx/ui_next/src
npm --prefix=awx/ui_next run lint -- --fix
npm --prefix=awx/ui_next run prettier

import argparse
import glob
import os
from shutil import move, copymode
from tempfile import mkstemp


def get_new_import_string(old_import_str, root):
    if not root.startswith("./"):
        raise Exception("root must start with './'")
    name = root.replace("./", "")
    left, right = old_import_str.split("from")
    left += "from '"
    _, trailing = right.split(name)

    return left + name + trailing


roots = [
    "./api",
    "./components",
    # "./constants",
    "./contexts",
    "./screens",
    "./types",
    "./util",
]


def get_root(line):
    matched_root = None
    for root in roots:
        if root in line:
            matched_root = root
            break
    if "jest" in line:
        matched_root = None
    return matched_root


def find_and_replace_roots(file_path, root_dir, preview):
    fh, temp_path = mkstemp()
    has_logged_file_name = False
    with os.fdopen(fh, "w") as new_file:
        with open(file_path) as old_file:
            for (line_number, line) in enumerate(old_file):
                matched_root = get_root(line)
                if matched_root:
                    new_line = get_new_import_string(line, matched_root)
                    if not preview:
                        new_file.write(new_line)
                    if not has_logged_file_name:
                        log_file_replacement(root_dir, file_path)
                        has_logged_file_name = True
                    log_line_replacement(line_number, line, new_line)
                elif not preview:
                    new_file.write(line)

    if not preview:
        copymode(file_path, temp_path)
        os.remove(file_path)
        move(temp_path, file_path)


def log_line_replacement(line_number, line, new_line):
    display_line = line.replace(os.linesep, "")
    display_new_line = new_line.replace(os.linesep, "")
    print(f"\t (line {line_number}): {display_line} --> {display_new_line}")


def log_file_replacement(root_dir, file_path):
    display_path = os.path.relpath(file_path, root_dir)
    print("")
    print(f"{display_path}:")


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("root_dir", help="Root directory")
    parser.add_argument("--preview", help="Preview (no write)", action="store_true")
    args = parser.parse_args()
    return args


def run():
    args = parse_args()
    search_path = args.root_dir + "**/**/*.js*"

    for file_path in glob.iglob(search_path, recursive=True):
        find_and_replace_roots(file_path, args.root_dir, args.preview)


if __name__ == "__main__":
    run()

Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-19 21:57:27 +00:00
Christian M. Adams
2f6855262e Properly compile translated API strings 2021-07-19 17:52:28 -04:00
Jake McDermott
954be5dd32 Regenerate translation string files 2021-07-19 13:33:54 -04:00
Jake McDermott
6d71997b51 Relocate hooks to hooks directory
mkdir awx/ui_next/src/hooks
mv awx/ui_next/src/util/use* awx/ui_next/src/hooks/
find ./awx/ui_next/src -type f -exec sed -i -e 's/util\/use/hooks\/use/g' {} \;
find ./awx/ui_next/src/hooks -type f -exec sed -i -e 's/from \x27\.\//from \x27util\//g' {} \;
find ./awx/ui_next/src/hooks -type f -exec sed -i -e 's/from \x27util\/use/from \x27\.\/use/g' {} \;
npm --prefix=awx/ui_next run lint -- --fix
npm --prefix=awx/ui_next run prettier
2021-07-19 13:33:45 -04:00
Jake McDermott
021e98b14a Remove script to switch relative imports 2021-07-19 13:33:42 -04:00
Jake McDermott
c92fffaecc Rename .jsx -> .js 2021-07-19 13:33:38 -04:00
Jake McDermott
595cf192b7 Fix relative imports
python tools/fixrelative.py awx/ui_next/src
npm --prefix=awx/ui_next run lint -- --fix
npm --prefix=awx/ui_next run prettier
2021-07-19 13:33:35 -04:00
Jake McDermott
0ee7d22e9d Add script to switch relative imports 2021-07-19 13:33:30 -04:00
Jake McDermott
dc1b312672 Enable absolute imports 2021-07-19 13:33:24 -04:00
softwarefactory-project-zuul[bot]
9820c8cd81 Merge pull request #10671 from fosterseth/fix_minikube_start_by_default
Fix conditional to check that minikube should start

SUMMARY

make docker-compose tries to start container group without this fix

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


API

AWX VERSION

awx: 19.2.2

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Alan Rominger <arominge@redhat.com>
2021-07-19 15:46:53 +00:00
Seth Foster
d346dbb8ba Fix conditional to check that minikube should start 2021-07-19 11:05:05 -04:00
softwarefactory-project-zuul[bot]
81eb3be8d4 Merge pull request #10629 from nixocio/ui_issue_5687
Update User screens

Add modified field to user endpoints. The API returns the last login
date as the modified field to the users.
Modify user form layout to be as per mockups.
Remove last name and  first name from user row, since it is
already on the column title.


closes: #5687
closes: #9564

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 20:42:33 +00:00
softwarefactory-project-zuul[bot]
d01cd5517d Merge pull request #10606 from nixocio/ui_issue_10595
Display full keys advanced search smart inventory

Display full keys advanced search smart inventory

closes: #10595

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 20:42:27 +00:00
nixocio
faf295d7f2 Update User screens
* Add `modified` field to user endpoints. The API returns the last login
date as the `modified` field to the users.
* Add modified to user details.
* Modify user form layout to be as per mockups.
* Remove `last name` and  `first name` from user row, since it is
already on the column title.

closes: https://github.com/ansible/awx/issues/5687
closes: https://github.com/ansible/awx/issues/9564
2021-07-15 16:05:34 -04:00
softwarefactory-project-zuul[bot]
9bb7d918eb Merge pull request #10623 from AlexSCorey/4208-ExpandWholeList
Adds functionality for expand all 

SUMMARY
Closes #4208.  Adds basically the same work as useSelected, in a useExpanded hook.
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

UI

AWX VERSION
ADDITIONAL INFORMATION

Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 19:24:54 +00:00
softwarefactory-project-zuul[bot]
efed55d0c0 Merge pull request #10640 from nixocio/ui_issue_10095
Add edit icon to SurveyListItem

Add edit icon to SurveyListItem

closes: #10095

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 18:59:09 +00:00
softwarefactory-project-zuul[bot]
5f916e6237 Merge pull request #10622 from nixocio/ui_issue_10612
Update login redirect to a be text input field

Update login redirect to a be text input field. Allowing values like
/sso/login/saml/?idp=SSO
closes: #10612

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 18:59:05 +00:00
softwarefactory-project-zuul[bot]
d3143d9b1d Merge pull request #10621 from nixocio/ui_issue_10620
Fix close button alert modal

Fix close button alert modal
closes: #10620

Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 18:59:02 +00:00
softwarefactory-project-zuul[bot]
207eaaf9b4 Merge pull request #10608 from nixocio/ui_issue_10548
Disable remove button if row is being dragged

Disable remove button if row is being dragged.
Also, disable drag button there is just one item selected.
closes: #10548

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 18:58:59 +00:00
softwarefactory-project-zuul[bot]
f16626c808 Merge pull request #10604 from nixocio/ui_update_rbac
Update RBAC sidebar

Update RBAC sidebar. Do the following:

Expose read-only applications to normal users in the UI
Expose read-only credential types to normal users in the UI


closes: #10432
closes: #10433

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 18:06:05 +00:00
softwarefactory-project-zuul[bot]
6533a255a7 Merge pull request #10578 from wenottingham/spuds_mckenzicon
Point REST API favicon at the one the UI uses

SUMMARY
Don't  ship one that is only used for the API browser.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

API
UI

AWX VERSION
devel

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-07-15 17:34:19 +00:00
softwarefactory-project-zuul[bot]
f8ff9ffe62 Merge pull request #10598 from nixocio/ui_issue_10593
Identify sliced jobs on Job List and Job Details

Identify sliced jobs on Job List and Job details - for workflow jobs.
closes: #2479
closes: #10593
Jobs List

Job Details - Workflow Job

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 17:28:39 +00:00
nixocio
7cc3ac1a11 Identify sliced jobs on Job List and Job Details
Identify sliced jobs on Job List and Job details - for workflow jobs.

closes: https://github.com/ansible/awx/issues/2479
closes: https://github.com/ansible/awx/issues/10593
2021-07-15 12:51:53 -04:00
softwarefactory-project-zuul[bot]
9ed1f3bc0f Merge pull request #10636 from tchellomello/minikube-devel-hack
Incorporates Minikube to devel environment

SUMMARY

Incorporates Minikube to devel environment
This PR allows creating a smooth devel environment deploying Minikube connected to the AWX devel network interface using Docker.
Furthermore, both CredentialType  and Container Group gets created automatically.
Steps performed by the target make docker-compose-container-group

Downloads Minikube (currently supported Linux and MacOS)
Downloads kubectl (currently supported Linux and MacOS)
Starts Minikube using docker as backend
Creates a Service Account, Role and RoleBinding on Minikube
Exports Minikube ServiceAccount token to be used on AWX Credential
Creates Minikube AWX Credential
Creates Container Group to use Minikube backend
Starts regular AWX devel instances and connected with Minikube network

ISSUE TYPE


Feature Pull Request

COMPONENT NAME


API

AWX VERSION

devel

ADDITIONAL INFORMATION
Quick step-by-step to use this PR:
$ make docker-compose-container-group-clean  # this will remove your database and any old Minikube already deployed
$ make docker-compose-container-group
Verifying some work:
$ kubectl get serviceaccount awx-devel
NAME        SECRETS   AGE
awx-devel   1         130m

$ kubectl get roles
NAME        CREATED AT
awx-devel   2021-07-15T00:47:37Z

$ kubectl get rolebindings
NAME        ROLE             AGE
awx-devel   Role/awx-devel   131m
Credential

Container Instance Group

After updating a Job Template and assigning to the Container Instance Group
kubectl get pods -w
NAME                     READY   STATUS    RESTARTS   AGE
automation-job-6-w6rmh   0/1     Pending   0          0s
automation-job-6-w6rmh   0/1     Pending   0          0s
automation-job-6-w6rmh   0/1     ContainerCreating   0          0s
automation-job-6-w6rmh   1/1     Running             0          5s
automation-job-6-w6rmh   1/1     Terminating         0          6s

Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Elijah DeLee <kdelee@redhat.com>
Reviewed-by: Marcelo Moreira de Mello <tchello.mello@gmail.com>
Reviewed-by: Sarabraj Singh <singh.sarabraj@gmail.com>
2021-07-15 16:46:26 +00:00
softwarefactory-project-zuul[bot]
4b81df2ab4 Merge pull request #10651 from gabyfulchic/patch-1
Update kubernetes pod doc url

SUMMARY
Just a little change allowing users to find the Kubernetes pod core documentation.
ISSUE TYPE

Docs Pull Request

COMPONENT NAME

UI

AWX VERSION
N/A
ADDITIONAL INFORMATION
N/A

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-07-15 16:40:09 +00:00
softwarefactory-project-zuul[bot]
8d7bd5fb0f Merge pull request #10656 from ansible/bump-ee-version
Update defaults.py

we missed this...need it for container groups to work out of the box in the dev environment

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-07-15 16:05:38 +00:00
softwarefactory-project-zuul[bot]
62a1eddd1a Merge pull request #10597 from AlexSCorey/10547-fix
Fixes missing key values in ad hoc credental step advanced search

SUMMARY
Resolves #10547
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

AWX VERSION
ADDITIONAL INFORMATION

Reviewed-by: Kersom <None>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 15:47:50 +00:00
softwarefactory-project-zuul[bot]
6e88e094ee Merge pull request #10580 from AlexSCorey/10499-fix
Removes tabs from survey form

SUMMARY
Resolves #10499
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

AWX VERSION
ADDITIONAL INFORMATION

Reviewed-by: Kersom <None>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 15:46:23 +00:00
Marcelo Moreira de Mello
b63313a08b Using awx-manage shell produces a better stdout during bootstrap 2021-07-15 11:43:20 -04:00
Elijah DeLee
b431067aa8 also update control plane ee 2021-07-15 11:30:21 -04:00
softwarefactory-project-zuul[bot]
39522a35c6 Merge pull request #10577 from nixocio/ui_issue_9550
Display error message if schedule does not exist

Display error message if schedule does not exist when redirecting to
details page.

closes: #9550

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 15:29:34 +00:00
Elijah DeLee
718b3bab4a Update defaults.py 2021-07-15 11:27:55 -04:00
softwarefactory-project-zuul[bot]
7d01cc45bc Merge pull request #10525 from nixocio/ui_issue_10497
Update EE lookup title

Upated EE lookup name to be singular. Also, another reference that to EE
that should be singular.
Closes: #10497

Reviewed-by: Marliana Lara <marliana.lara@gmail.com>
Reviewed-by: Sarah Akus <sakus@redhat.com>
2021-07-15 15:09:14 +00:00
Marcelo Moreira de Mello
f6a71e770d Incorporates Minikube to devel environment 2021-07-15 10:42:04 -04:00
gabyf
c0e9ffd65a Update container_groups.md 2021-07-15 14:21:48 +02:00
gabyf
c511597c0f Update kubernetes pod doc url 2021-07-15 14:17:28 +02:00
softwarefactory-project-zuul[bot]
0e75193e3d Merge pull request #10614 from keithjgrant/test-cleanup
Test cleanup

SUMMARY

Makes a unit test fail if any errors or warnings are logged (see setupTest.js)
Updates/fixes all tests that were logging errors
Fixes a key cause of test flake caused by Jobs.test.jsx (I have still seen a rogue "Network error" cause a flaky failure once; which I will hopefully take care of in a subsequent PR)
Removes all unnecessary calls to wrapper.unmount() (this also surfaced several instances of tests leaving asynchronous code running after test completion, which are now fixed)

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Kersom <None>
Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-14 19:33:32 +00:00
Keith J. Grant
a307421b82 attempt to fix ci/merge test error 2021-07-14 11:53:24 -07:00
softwarefactory-project-zuul[bot]
65ddc8c0bd Merge pull request #10633 from jbradberry/conditional-polymorphic-setnull
Conditional polymorphic setnull

SUMMARY


ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


API

AWX VERSION



ADDITIONAL INFORMATION

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-07-14 18:42:42 +00:00
softwarefactory-project-zuul[bot]
7961bcb2cb Merge pull request #10631 from AlanCoding/inventory_delete
Wait until inventory is fully deleted in silent_delete

The silent_delete method does not appear to be used by the AWX CLI. I believe the only use is from:

  
    
      awx/awxkit/awxkit/api/pages/base.py
    
    
        Lines 185 to 187
      in
      eec4f8d
    
    
    
    

        
          
           def cleanup(self): 
        

        
          
               log.debug('{0.endpoint} cleaning up.'.format(self)) 
        

        
          
               return self._cleanup(self.delete) 
        
    
  


This is used in integration tests to cleanup at the end of a test. Whenever inventory gets deleted, this leads to various conflict scenarios and deadlocks. This tends to play out by:

DELETE request for the inventory object
DELETE request for the organization

within the request-response cycle, this cascade deletes other objects, or takes SET_NULL action



Because the actual inventory deletion happens in a separate task, this means that inventory and organization deletion cascades are happening simultaneously (dependent on timing and resources).
This is low-priority on our list of practical concerns, because the inventory object accurately reports that its deletion is in progress. Clients can workaround if needed - and that's what I'm trying to do here. In an effort to reduce the flakiness and erroneous errors in integration tests, I propose that this will basically serialize the teardown process (for a given test agent), and that will eliminate a large cluster of flaky errors.

Reviewed-by: Elijah DeLee <kdelee@redhat.com>
Reviewed-by: Jeff Bradberry <None>
2021-07-14 16:37:00 +00:00
nixocio
ef4feae9bf Add edit icon to SurveyListItem
Add edit icon to SurveyListItem

closes: https://github.com/ansible/awx/issues/10095
2021-07-14 10:57:26 -04:00
softwarefactory-project-zuul[bot]
df3a8d8718 Merge pull request #10591 from nixocio/ui_issue_2961
Update inventory prompt string for workflows

Update inventory prompt string for workflows
closes: #2961

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-14 14:10:33 +00:00
softwarefactory-project-zuul[bot]
4eca133080 Merge pull request #10581 from AlexSCorey/10544-fix
Prevents submission of jtform if name is > 512 characters

SUMMARY
This addresses #10544 by adding a maxLength validator to the name field on the Job Template form
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

AWX VERSION
ADDITIONAL INFORMATION

Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-14 13:46:07 +00:00
weidong
b7855a3c74 Fix inaccurate translation 2021-07-14 14:00:47 +08:00
Alan Rominger
397fab793d Avoid waiting for deletion in error cases 2021-07-13 13:49:09 -04:00
Jeff Bradberry
b0c511a7a2 Make non-polymorphic refs that slip through still work with our SET_NULL 2021-07-13 13:41:44 -04:00
Jeff Bradberry
d0d9266dd1 Revert "Null iso IG jobs before deleting (#5122)"
This reverts commit 1831b2591a.
2021-07-13 13:41:36 -04:00
Jeff Bradberry
7d97ad021f Revert "Development of patch for inventory source migration error"
This reverts commit 8772ca2e3a.
2021-07-13 13:40:44 -04:00
softwarefactory-project-zuul[bot]
4e97492ed6 Merge pull request #10619 from wenottingham/dont-think-we-need-this
Delete some old code related to the reencryption migration

We've moved past the point where this code would still be live.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

API

AWX VERSION
current

ADDITIONAL INFORMATION
We could probably squash more of these?

Reviewed-by: Alan Rominger <arominge@redhat.com>
2021-07-13 16:46:33 +00:00
softwarefactory-project-zuul[bot]
45a6d03dcd Merge pull request #10590 from shanemcd/downstream-fixes
Downstream fixes

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-07-13 16:24:59 +00:00
Shane McDonald
b0fe3d7f85 Bump ansible-runner to 2.0.1 2021-07-13 11:47:02 -04:00
Elijah DeLee
b8239c1b84 bump receptor to 1.0.0 GA 2021-07-13 11:47:02 -04:00
mabashian
994175f386 Properly set use_tls initial value to bool (false) 2021-07-13 11:47:02 -04:00
Alan Rominger
8772ca2e3a Development of patch for inventory source migration error 2021-07-13 11:47:01 -04:00
mabashian
3c43ed6d2d Update base docs string 2021-07-13 11:47:01 -04:00
mabashian
667121d325 Change dev brand name to Ansible AWX and remove Ansible string from about 2021-07-13 11:47:01 -04:00
Keith J. Grant
ed02f28cbe mark upload button strings for translation 2021-07-13 11:47:01 -04:00
Christian M. Adams
4ca6c1c6c5 Add more appropriate french translation for changing PROJECT_ROOTS 2021-07-13 11:47:01 -04:00
Christian M. Adams
35a5c4153c Corrected dynamic variables that got translated by accident
- Fixed extra braces & lack of braces
  - Fixed plural/singular notation that got translated by accident
2021-07-13 11:47:01 -04:00
ansible-translation-bot
11e7387055 UI translation strings for release_4.0 branch 2021-07-13 11:47:00 -04:00
Sarabraj Singh
0f51c56980 Merge pull request #10425 from sarabrajsingh/bugfix/preflight-check-postgres-version-4940
introduced a pre-flight check for postgres 12
2021-07-13 11:46:10 -04:00
Alan Rominger
3e6cbd5114 Wait until inventory is fully deleted in silent_delete 2021-07-13 07:50:58 -04:00
softwarefactory-project-zuul[bot]
486d6688e1 Merge pull request #10559 from nixocio/ui_mark_string
Mark string to be translated

Mark string to be translated

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-12 19:04:34 +00:00
softwarefactory-project-zuul[bot]
a08ca15f13 Merge pull request #10543 from nixocio/ui_issue_10553
Update last name for Resource Access List

Update last name for Resource Access List

Closes: #10533

Reviewed-by: Marliana Lara <marliana.lara@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-12 18:57:23 +00:00
softwarefactory-project-zuul[bot]
13a94dd7ac Merge pull request #10523 from nixocio/ui_fix_settings
Fix Job Settings Page Break on Firefox

Fix Job Settings Page Break on Firefox
Closes: #10332
Firefox:

Chrome:

Reviewed-by: Marliana Lara <marliana.lara@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-12 18:44:40 +00:00
Alex Corey
8198f045f9 removes unnecessary prop 2021-07-12 14:42:38 -04:00
Alex Corey
6a717a8f3c Adds functionality for expand all in lists that have list items that can be expanded 2021-07-12 14:42:19 -04:00
nixocio
212e924f9b Update EE lookup title
Update EE lookup title to be singular. Also, another reference that to EE
that should be singular.

Closes: https://github.com/ansible/awx/issues/10497
2021-07-12 14:39:30 -04:00
softwarefactory-project-zuul[bot]
45740b5ed0 Merge pull request #10520 from nixocio/ui_issue_6351
Remove custom component

Remove custom component since PF issue is now fixed.
Closes: #6351

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-12 18:32:38 +00:00
softwarefactory-project-zuul[bot]
6b865da025 Merge pull request #10512 from nixocio/ui_issue_5236
Add job status on expand row for hosts

Add job status on expand row for hosts

See: #5236

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-12 18:24:33 +00:00
softwarefactory-project-zuul[bot]
c1913b0d44 Merge pull request #10504 from nixocio/ui_issue_7524
Encode/decode question variables

Encode/decode question variables
See: #7524

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-12 17:57:50 +00:00
softwarefactory-project-zuul[bot]
e65f11c95e Merge pull request #10502 from mabashian/7668-disabled-node
Fix disabled node cover dimensions

SUMMARY
Closes #7668

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-07-12 17:38:41 +00:00
Keith J. Grant
09751efe95 fail tests if warning is logged 2021-07-09 13:19:15 -07:00
softwarefactory-project-zuul[bot]
f05827df69 Merge pull request #10617 from AlanCoding/collection_flake8
Run flake8 on the AWX collection in CI

We kind of assumed that linter issues like this would be picked up by ansible-test sanity, but they're not.
This seems to provide meaningful value. Unused variables are reflecting a lot of history of changes, and it's good to move on to leave those in the past.

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-07-09 20:17:34 +00:00
nixocio
70ec4b915c Update login redirect to a be text input field
Update login redirect to a be text input field. Allowing values like
`/sso/login/saml/?idp=SSO`

closes: https://github.com/ansible/awx/issues/10612
2021-07-09 16:08:13 -04:00
nixocio
5964ff6c93 Fix close button alert modal
Fix close button alert modal

closes: https://github.com/ansible/awx/issues/10620
2021-07-09 15:44:56 -04:00
Keith J. Grant
0185269d97 remove 4th batch of unmount() calls 2021-07-09 11:50:19 -07:00
Keith J. Grant
81c16f4fa7 remove 3rd batch of unmount calls 2021-07-09 11:04:18 -07:00
Alan Rominger
122f282e5d Add back in fixture 2021-07-09 13:32:31 -04:00
Alan Rominger
9b319cf2bf Fix pep8 failure 2021-07-09 13:08:57 -04:00
Alan Rominger
cb8441ed3d Remove added assertion that was wrong 2021-07-09 12:30:06 -04:00
Alan Rominger
08cb497689 Run flake8 on the AWX collection in CI 2021-07-09 12:01:28 -04:00
softwarefactory-project-zuul[bot]
68e309ee32 Merge pull request #10607 from AlanCoding/unused_exception
Remove unused exception about custom venvs

random cleanup

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-07-09 15:43:00 +00:00
Bill Nottingham
84b32a91f0 Delete some old code related to reencryption
We've moved past the point where this code would still be live.
2021-07-08 23:20:33 -04:00
Keith J. Grant
bf7663a0a1 remove 2nd batch of unecessary unmount calls 2021-07-08 17:06:15 -07:00
Keith J. Grant
86fcfdf69a remove 1st batch of unnecessary unmount calls 2021-07-08 16:51:46 -07:00
Keith J. Grant
58d64045a1 fix About test network call 2021-07-08 15:52:21 -07:00
Keith J. Grant
0e12c7deb4 fix flakey unit tests I hope 2021-07-08 14:33:38 -07:00
Keith J. Grant
78d6e21256 fix final logged errors in tests 2021-07-08 14:33:38 -07:00
Keith J. Grant
226ffafbd6 fix test errors (Sort, CredentialEdit, InventoryHost, JobTemplateEdit, etc) 2021-07-08 14:33:38 -07:00
Keith J. Grant
1b5fa9c799 fix errors logged in tests (scheduls/organization) 2021-07-08 14:33:38 -07:00
Keith J. Grant
ad2f042f97 fix tests with errors 2021-07-08 14:33:38 -07:00
Keith J. Grant
4b41bbbf34 fail tests if anything logs an error 2021-07-08 14:33:37 -07:00
nixocio
fb64df21c5 Disable remove button if row is being dragged
Disable remove button if row is being dragged.
Also, disable drag button there is just one item selected.

closes: https://github.com/ansible/awx/issues/10548
2021-07-08 15:13:29 -04:00
softwarefactory-project-zuul[bot]
adb6661015 Merge pull request #10589 from AlanCoding/null_traceback
No result_traceback is blank, not null

I kept staring at a failure where:

cannot create resource

was expected in result_traceback, but it was blank. The job had "error" status, sure enough.
Then I re-created, sure enough, the job was right there - error status, no explanation, no traceback, no indication of what happened. We did have logs though (which I still can't fully disambiguate).
After that initial confusion, I realized this is a server-side bug. The test is happy with what happens after this change.
I can re-organize this diff if needed.

Reviewed-by: Elijah DeLee <kdelee@redhat.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-07-07 19:41:27 +00:00
Alan Rominger
17f9b57028 Remove unused exception about custom venvs 2021-07-07 11:38:37 -04:00
Alan Rominger
e96080a512 No result_traceback is blank, not null 2021-07-07 11:37:30 -04:00
nixocio
9295496949 Display full keys advanced search smart inventory
Display full keys advanced search smart inventory

closes: https://github.com/ansible/awx/issues/10595
2021-07-07 11:33:20 -04:00
tpage
62fc62a3c5 Default source_project for inventory source to organization
Signed-off-by: tpage <tpage@redhat.com>
2021-07-07 15:31:32 +01:00
nixocio
267f0a7bbd Update RBAC sidebar
Update RBAC sidebar. Do the following:

* Expose read-only applications to normal users in the UI
* Expose read-only credential types to normal users in the UI

closes:https://github.com/ansible/awx/issues/10432
closes:https://github.com/ansible/awx/issues/10433
2021-07-07 10:18:45 -04:00
nixocio
6d9996cd0e Update inventory prompt string for workflows
Update inventory prompt string for workflows

closes: https://github.com/ansible/awx/issues/2961
2021-07-06 17:16:24 -04:00
Alex Corey
0a0c635de8 fixes missing key values in ad hoc credental step advanced search 2021-07-06 16:34:47 -04:00
Alex Corey
869b649b66 prevents submission of jtform if name is > 512 characters 2021-07-02 14:17:51 -04:00
Alex Corey
b41e70f9aa removes tabs from survey form 2021-07-02 09:40:22 -04:00
Bill Nottingham
a98ae2a87d Point REST API favicon at the one the UI uses 2021-07-01 16:10:33 -04:00
nixocio
f422677145 Display error message if schedule does not exist
Display error message if schedule does not exist when redirecting to
details page.

See: https://github.com/ansible/awx/issues/9550
2021-07-01 15:15:22 -04:00
softwarefactory-project-zuul[bot]
bc8e19b51d Merge pull request #10575 from AlexSCorey/fixesFailingUnitTest
Fixes failing test

SUMMARY
Fixes a failing unit test

Reviewed-by: Keith Grant <keithjgrant@gmail.com>
2021-07-01 17:16:38 +00:00
softwarefactory-project-zuul[bot]
64631fca56 Merge pull request #10574 from ansible/jakemcdermott-patch-bug-template-2
Remove bug template title field

Leaving it blank disables the template.

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
2021-07-01 16:22:12 +00:00
Alex Corey
49c84e6ca9 fixes failing test 2021-07-01 11:56:32 -04:00
Jake McDermott
c0f587a2bf Remove title field from bug template 2021-07-01 11:44:26 -04:00
softwarefactory-project-zuul[bot]
28147b71c5 Merge pull request #10567 from ansible/jakemcdermott-patch-bug-template
Remove default text from bug title

SUMMARY
We use labels for these, so the extra text isn't needed.
ADDITIONAL INFORMATION

Reviewed-by: Kersom <None>
2021-07-01 14:19:38 +00:00
softwarefactory-project-zuul[bot]
be93178e65 Merge pull request #10564 from sarabrajsingh/bump-django-to-2.2.20
bumped django version to 2.2.20 in devel

SUMMARY


Bumped Django version from 2.2.16 -> 2.2.20 for the devel environment. All builds, tests and tests consuming the AWX_USE_FIPS flag passed in Jenkins.
AWX Issue - ansible/tower#4930
ISSUE TYPE


Feature Pull Request

COMPONENT NAME


API

AWX VERSION

awx: 19.2.2

Reviewed-by: Alan Rominger <arominge@redhat.com>
2021-07-01 14:11:15 +00:00
Jake McDermott
147e50730d Remove default text from bug title 2021-07-01 09:01:45 -04:00
softwarefactory-project-zuul[bot]
f88b3806f2 Merge pull request #10508 from jakemcdermott/bug-report-form
Add bug report form for github issues

SUMMARY

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-07-01 12:39:57 +00:00
daniele strollo
24a8653fab Update webhook_backend.py
At the request via webhook just uses default pre configured headers (with Agent/ContentType) by ignoring at all customer provided headers (self.headers).
Thus the OAuth authentication via Bearer cannot be implemented since custom headers are not sent to service so receiving Unauthorized response.

Solution is merging the default headers with custom ones (custom headers will override default ones in case of key clash).
2021-07-01 12:08:14 +02:00
Hideki Saito
70f9d6f015 Fix to handle parameters with Boolean values correctly
* Addresses the issue #10057

Signed-off-by: Hideki Saito <saito@fgrep.org>
2021-07-01 13:39:51 +09:00
Sarabraj Singh
46cd62f3f0 bumped django version to 2.2.20 in devel 2021-06-30 17:10:40 -04:00
nixocio
6f6f601ca8 Fix Job Settings Page Break on Firefox
Fix Job Settings Page Break on Firefox

Closes: https://github.com/ansible/awx/issues/10332
2021-06-30 16:11:58 -04:00
softwarefactory-project-zuul[bot]
9ea6696bf9 Merge pull request #10561 from fosterseth/fix_collection_sanity_pylint
Fix pylint 2.9 errors in awx collection

SUMMARY

fixes errors like these
ERROR: plugins/modules/workflow_launch.py:131:4: consider-using-dict-items: Consider iterating with .items()

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


API

AWX VERSION

awx: 19.2.2

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-30 20:08:57 +00:00
Seth Foster
a9013c43fa fix pylint 2.9 errors in awx collection 2021-06-30 14:28:35 -04:00
nixocio
48dc1dfa17 Mark string to be translated
Mark string to be translated
2021-06-30 11:25:29 -04:00
softwarefactory-project-zuul[bot]
a58d571858 Merge pull request #10422 from AlanCoding/quay_default
Make quay.io the registry URL default

SUMMARY
It's unclear what format the registry "Authentication URL" should be.

It's too late to change the strings because of translations, ping @rooftopcellist, but this change would clarify the format without adding wording.
ISSUE TYPE

Feature Pull Request
Docs Pull Request

COMPONENT NAME

API

ADDITIONAL INFORMATION
Seems to behave pretty good in the UI.

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Jeff Bradberry <None>
Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-29 18:06:39 +00:00
Alan Rominger
b329d9cbf4 Make quay.io the registry URL default 2021-06-29 13:26:51 -04:00
nixocio
5c0c788d10 Update last name for Resource Access List
Update last name for Resource Access List

Closes: https://github.com/ansible/awx/issues/10533
2021-06-29 13:14:14 -04:00
softwarefactory-project-zuul[bot]
772e9f0d6b Merge pull request #10430 from AlanCoding/awxkit_tox
Run flake8 on awxkit

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-29 16:09:09 +00:00
Alan Rominger
f0cd6b2457 Run flake8 on awxkit 2021-06-29 11:32:59 -04:00
softwarefactory-project-zuul[bot]
9cd5566869 Merge pull request #10538 from AlanCoding/collection_pep
Fix ansible-test pep8 bug and add notable release

Fixes
Error Message
The test `ansible-test sanity --test pep8` failed with 1 error:
Stacktrace
test/awx/test_project.py:28:1: E302: expected 2 blank lines, found 1

And add a notable release to the https://galaxy.ansible.com/awx/awx page

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Seth Foster <None>
Reviewed-by: Alan Rominger <arominge@redhat.com>
2021-06-29 15:13:14 +00:00
softwarefactory-project-zuul[bot]
747231d350 Merge pull request #10537 from chrismeyersfsu/fix-fork
reload settings on fork or new thread

Reloading settings will re-import cache. Django cache is thread aware,
but keeping an old reference to the cache avoids the awareness.

The performance team that was hitting this every time before. With this change they are unable to recreated.

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-29 12:53:30 +00:00
Alan Rominger
b8f5dda6da Fix ansible-test pep8 bug and add notable release 2021-06-28 22:37:10 -04:00
nixocio
21de95862e Add job status on expand row for hosts
Add job status on expand row for hosts.

Also, update HostDetail to remove the addition of `type=job` since it is
already present on the API hosts endpoint.

See: https://github.com/ansible/awx/issues/5236
2021-06-28 16:01:59 -04:00
Chris Meyers
84116349ab reload settings on fork or new thread
* Reloading settings will re-import cache. Django cache is thread aware,
but keeping an old reference to the cache avoids the awareness.
2021-06-28 13:53:11 -04:00
softwarefactory-project-zuul[bot]
c09cad3e6d Merge pull request #10522 from AlanCoding/close_file
Close file before returning

Resolves
/home/alancoding/repos/tower-qa/tests/lib/plugins/pytest_restqa/plugin.py:122: ResourceWarning: unclosed file <_io.TextIOWrapper name='/home/alancoding/repos/tower-qa/scripts/resource_loading/data_latest_loading.yml' mode='r' encoding='UTF-8'>
  qe_config.resources = PseudoNamespace(yaml_file.load_file(config.option.resource_file))

We have this same pattern earlier in the file.

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-28 17:52:37 +00:00
softwarefactory-project-zuul[bot]
ce20c8e77b Merge pull request #10536 from shanemcd/bump-19.2.2
Bump versions for AWX 19.2.2

Reviewed-by: Seth Foster <None>
Reviewed-by: Elijah DeLee <kdelee@redhat.com>
Reviewed-by: Rebeccah Hunter <rhunter@redhat.com>
2021-06-28 17:15:41 +00:00
Shane McDonald
73bb475503 Bump version + changelog 2021-06-28 12:25:44 -04:00
Shane McDonald
6df5c0331a Use Ansible Runner 2.0.0 release 2021-06-28 12:25:19 -04:00
softwarefactory-project-zuul[bot]
dc7bd73431 Merge pull request #10532 from shanemcd/downstream-fixes
Downstream fixes

Reviewed-by: Elijah DeLee <kdelee@redhat.com>
Reviewed-by: Alan Rominger <arominge@redhat.com>
2021-06-28 15:31:31 +00:00
softwarefactory-project-zuul[bot]
017bb63023 Merge pull request #10528 from fosterseth/fix_collection_copy_from_error
Fix awx collections copy_item warning keyword error

SUMMARY


warn() does not take keyword 'msg'
add testing around the copy_from parameter for project creation


ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


API

AWX VERSION

awx: 19.2.1

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-28 15:16:51 +00:00
softwarefactory-project-zuul[bot]
5d4fc9613d Merge pull request #10524 from beeankha/ee_test_playbook
Add Integration Test Playbook for execution_environment Collections Module

SUMMARY

Adressing Issue #10454

Reviewed-by: Alan Rominger <arominge@redhat.com>
2021-06-28 15:06:20 +00:00
Alan Rominger
f126a6343b Fix bug setting execution_node to null (not blank) (#5169) 2021-06-28 10:51:06 -04:00
Jeff Bradberry
40f5ff362c Bump ansible-runner to 2.0.0.0rc3 2021-06-28 10:51:06 -04:00
Shane McDonald
1ed170fff0 Dont overwrite result_traceback if it was already set. 2021-06-28 10:51:06 -04:00
Jeff Bradberry
d5deedc822 Make sure that validation of managed EEs makes sense
- missing fields in a patch request should be ignored
- compare the organization pks, if present
2021-06-28 10:51:05 -04:00
Alex Corey
9992bf03b0 resolves crashing details view 2021-06-28 10:51:05 -04:00
Alex Corey
04839a037a prevent delete of instance groups list item controlplan and default 2021-06-28 10:51:05 -04:00
Marliana Lara
f541fe9904 Add comment to explain why we resolve the promises sequentially 2021-06-28 10:51:05 -04:00
Marliana Lara
162ea776fd Add order selected list to instance group lookups 2021-06-28 10:51:05 -04:00
Alan Rominger
f1273d5810 Show tracebacks from dependency failures (#5154) 2021-06-28 10:51:05 -04:00
Alan Rominger
390e1f9a0a Fix obvious logical bug with project folder pre-creation (#5155) 2021-06-28 10:51:04 -04:00
Keith J. Grant
8dc788dbcb clean up responsive behavior of advanced search 2021-06-28 10:51:04 -04:00
Shane McDonald
397908543d Disable activity stream for updates in status handler 2021-06-28 10:51:04 -04:00
Jeff Bradberry
3be29d54ad Bump ansible-runner to 2.0.0.0rc2 and receptorctl to 1.0.0.0rc1 2021-06-28 10:51:04 -04:00
Shane McDonald
03fb12d4c2 Force system jobs to always run on control plane 2021-06-28 10:51:04 -04:00
Tiago
69388edaf9 fix lint 2021-06-28 10:51:04 -04:00
Marliana Lara
1e750cfed9 Add datalist test selectors 2021-06-28 10:51:04 -04:00
Shane McDonald
1ba51c0357 Fix unit tests
Signed-off-by: Shane McDonald <me@shanemcd.com>
2021-06-28 10:51:03 -04:00
Shane McDonald
2fa27000ab Prevent inventory updates started via projects from running on controlplane 2021-06-28 10:51:03 -04:00
nixocio
057bd6e625 Remove plus button job output
Remove plus button job output since this feature was not implemented yet.
And it will be evaluated for a future release.

See: https://github.com/ansible/awx/issues/6613
2021-06-28 10:51:03 -04:00
Alan Rominger
d0b7d970c4 Create partition for 2 job types that bypass TM (#5138)
* Create partition for 2 job types that bypass TM

* Mock create_partition in unit tests
2021-06-28 10:51:03 -04:00
Christian M. Adams
5ffffebe34 Attempt to check/wait for migrations 30x (~12 min)
- the task container needs to wait longer for migrations to complete for fresh installs before starting services
  - otherwise, services start prematurely and clutter the logs with errors because migrations are mid-flight
2021-06-28 10:51:03 -04:00
Marliana Lara
b98544264b Rename draggable prop and fix typos 2021-06-28 10:51:03 -04:00
Shane McDonald
0d7ef709bf Prevent jobs from trying to run on controlplane in k8s 2021-06-28 10:51:02 -04:00
Jake McDermott
1211faf8df Only derive row count from max counter when job is running. 2021-06-28 10:51:02 -04:00
Jake McDermott
dc327ceaeb Autofix problematic dependencies 2021-06-28 10:51:02 -04:00
Shane McDonald
0f25720634 Update minikube docs 2021-06-28 10:51:02 -04:00
Alex Corey
28a62ea774 properly validates credential password fields 2021-06-28 10:51:02 -04:00
Kia Lam
d3c5397721 Add link to project update job details on job details page. 2021-06-28 10:51:02 -04:00
nixocio
f06490a5f8 Fix disparity of dev server and prod build
Fix disparity of dev server and prod build

See: https://github.com/ansible/awx/issues/9997
2021-06-28 10:51:02 -04:00
Marliana Lara
9fddf7c5cf Add draggable selected list to galaxy credential lookup 2021-06-28 10:51:01 -04:00
nixocio
673f722b71 Update inventory list filters
Update inventory list filters

See: https://github.com/ansible/awx/issues/7675
2021-06-28 10:51:01 -04:00
Jake McDermott
4de477686e Update help text for hashivault credential plugin 2021-06-28 10:51:01 -04:00
Jake McDermott
4cc734ce6e Enable instance group creation for non-k8s deployments only 2021-06-28 10:51:01 -04:00
Jake McDermott
f08bf4766d Add read-only settings for IS_K8S 2021-06-28 10:51:01 -04:00
nixocio
77b0b9a4e3 Disable edit fields for managed EE, except pull
Disable edit fields for managed EE, except pull options.

See: https://github.com/ansible/tower/issues/5016
2021-06-28 10:51:01 -04:00
Keith J. Grant
487d78cc72 Don't reload template when navigating to edit form 2021-06-28 10:51:00 -04:00
mabashian
f0a6567cd8 Hide host_filter search key when hiding smart inventories 2021-06-28 10:51:00 -04:00
mabashian
8246d4a298 Remove smart inventories from host form inv lookup 2021-06-28 10:51:00 -04:00
Bill Nottingham
cd83030668 Rename sosreport plugin 2021-06-28 10:51:00 -04:00
mabashian
88d492371b Link users to workflow approval details from workflow node 2021-06-28 10:51:00 -04:00
Keith J. Grant
9316ace3f6 delete commented line 2021-06-28 10:51:00 -04:00
Keith J. Grant
55b5060944 remove duplicate JT credential fetch 2021-06-28 10:51:00 -04:00
Keith J. Grant
0be68fe84f reduce duplicate network request in JT form 2021-06-28 10:50:59 -04:00
Seth Foster
5da02690c1 Fix copy_from warning message
- warn() does not take keyword 'msg'
- add testing around the copy_from parameter for project creation
2021-06-26 01:28:02 -04:00
beeankha
c417c5e219 Add test playbook for EE collections module 2021-06-25 18:01:26 -04:00
Alan Rominger
02cccbe608 Close file before returning 2021-06-25 14:47:44 -04:00
nixocio
18e63ae6da Remove custom component
Remove custom component since PF issue is now fixed.

See: https://github.com/ansible/awx/issues/6351
2021-06-25 13:47:40 -04:00
Jake McDermott
bb78a0b4ec Add bug report form 2021-06-25 08:41:54 -04:00
Seth Foster
7bc7c9c4bd haproxy specify user 2021-06-24 13:54:24 -04:00
nixocio
804bd840f1 Encode/decode question variables
Encode/decode question variables

See: https://github.com/ansible/awx/issues/7524
2021-06-23 16:08:33 -04:00
mabashian
e4a52703f9 Fix disabled node cover dimensions 2021-06-23 12:49:40 -04:00
softwarefactory-project-zuul[bot]
2afa406b7f Merge pull request #10490 from shanemcd/downstream-fixes
Downstream fixes

Reviewed-by: Rebeccah Hunter <rhunter@redhat.com>
Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
2021-06-22 17:24:12 +00:00
Alan Rominger
1831b2591a Null iso IG jobs before deleting (#5122)
This is a workaround for polymorphic SET_NULL bug
2021-06-22 10:57:16 -04:00
Alex Corey
3cdd35f2cf default credentials are selected on POL load 2021-06-22 10:49:41 -04:00
Alan Rominger
1422bb2043 Fix tower upgrade (#5114)
* Hack to avoid creating both tower and controller CredentialType

* Remove line used for testing
2021-06-22 10:49:41 -04:00
mabashian
695787be4e Fix broken test 2021-06-22 10:49:40 -04:00
mabashian
e1b8f30d8f Extract strings 2021-06-22 10:49:40 -04:00
mabashian
293924168f Make expanded view ee detail warning match unexpanded 2021-06-22 10:49:40 -04:00
mabashian
7c72be7025 Adds a link to the ee migration docs in a popover when ee is missing 2021-06-22 10:49:40 -04:00
Alan Rominger
4a85983eb7 Symlink modules for 2.9 compat (#5103)
* Symlink modules for 2.9 compat

* Avoid symlinks in completeness tests
2021-06-22 10:49:40 -04:00
Seth Foster
82c510e51e remove tower_token alias (#5110) 2021-06-22 10:49:39 -04:00
Alan Rominger
0508a9267c Minor patch to right wording for 400 error (#5109) 2021-06-22 10:49:39 -04:00
Elijah DeLee
11e416995a accept old env vars
this broke our build of the cli docs
2021-06-22 10:49:39 -04:00
Seth Foster
bb3fc3caa8 controller_token, alias tower_token 2021-06-22 10:49:39 -04:00
nixocio
ab40006535 Link to instance group from org details when present
Link to instance group from org details when present

See: https://github.com/ansible/awx/issues/4953
2021-06-22 10:49:39 -04:00
Alan Rominger
53fe08af61 Update collection inventory_source options 2021-06-22 10:49:38 -04:00
Alan Rominger
a8083296e6 Make safe variable duplications for rename (#5093)
* Make safe variable duplications to controller

* Back out some changes to be smarter

* Update test to new vars
2021-06-22 10:49:38 -04:00
nixocio
95e796a88a Remove URL params when closing wizard
Remove URL params when closing wizard

See: https://github.com/ansible/awx/issues/10240
2021-06-22 10:49:38 -04:00
Bill Nottingham
0c0028541d Update inventory/cred names in UI 2021-06-22 10:49:38 -04:00
Amol Gautam
32cc7e976a Refactored awx/settings/defaults.py 2021-06-22 10:49:38 -04:00
Alex Corey
3495f75fa0 adds verbosity to payload 2021-06-22 10:49:37 -04:00
Jeff Bradberry
493e6cc527 Make the isolated removal migration non-atomic
We are apparently running into problems with pending triggers under
some circumstances.
2021-06-22 10:49:37 -04:00
Amol Gautam
7510b243bb Fixed UI linting 2021-06-22 10:49:37 -04:00
Christian M. Adams
e06ebb1f11 Fix credential test for default cred test 2021-06-22 10:49:37 -04:00
Alan Rominger
cc616206b3 Pass current apps to CredentialType setup method 2021-06-22 10:49:37 -04:00
Christian M. Adams
06b04007a0 Rename managed_by_tower to managed 2021-06-22 10:49:36 -04:00
Alan Rominger
6db4732bf3 Rename the TOWER_ settings 2021-06-22 10:49:36 -04:00
Alan Rominger
ead7907173 Update another test for tower to controller rename 2021-06-22 10:49:36 -04:00
Amol Gautam
68f0ae612e Fixed Migration 2021-06-22 10:49:36 -04:00
Alan Rominger
8c1bc97c2f Fix up unit tests after tower to controller rename 2021-06-22 10:49:36 -04:00
Amol Gautam
b64c2d6861 Removed references to tower in InventorySource and Credentials
--- Removed reference to tower in  InventorySource and InventoryUpdate model
--- Added a migration for above change
--- Added new CONTROLLER* variables in awx/main/models/credentials/__init__.py
--- Migrated awxkit to new CONTROLLER* variables
--- Updated the tests to use new CONTROLLER* variables
--- Fix some issues with upgrade path, rename more cases
2021-06-22 10:49:35 -04:00
Yanis Guenane
645f7f6dac Expand sos report plugin compatibility
sos 4 now uses sos.report.plugin when sos 3 was using sos.plugins. This
change allows compatibility with both.
2021-06-22 10:49:35 -04:00
Chris Meyers
0a5e9da287 replace default oci runtime runc with crun
* Our tests could consistently get awx jobs into a deadlocked state
whenever the parallelism was high. Even podman ps would hang when the
system was in this state. We don't know exactly where in runc the bug is
but the deadlocks stopped happening when we changed the OCI runtime
environment to crun.
2021-06-22 10:49:35 -04:00
nixocio
a60abe38a8 Allow space on host filter for smart inventory
Allow space on host filter for smart inventory

Fix: https://github.com/ansible/tower/issues/4874
2021-06-22 10:49:35 -04:00
mabashian
51abbb9464 Fixes bug where UI wasn't handling an array of survey answer choices 2021-06-22 10:49:34 -04:00
Alex Corey
560b4ebf71 offers an empty values as a choice on single select survey questions that are not required.
Also changes the single select component to a <Select variant='single'> component
following patternfly design guidelines
2021-06-22 10:49:34 -04:00
Alan Rominger
5a7a1b8f20 Remove inventory_as_dict which would mess with downstream templating (#5085) 2021-06-22 10:49:34 -04:00
nixocio
f1ca272394 Remove test button from logging settings screen
Remove test button from logging settings screen

Closes: https://github.com/ansible/awx/issues/9409
2021-06-22 10:49:34 -04:00
mabashian
8697387d13 Fix failing test 2021-06-22 10:49:34 -04:00
Bill Nottingham
1e68519c99 Remove insights_credential from inventory 2021-06-22 10:49:33 -04:00
mabashian
0947d30682 Fixes visual bug where revert button showed up above input 2021-06-22 10:49:33 -04:00
mabashian
c993c8b3b9 Fixes bug where email notification ssl and tls were a dropdown instead of checkboxes 2021-06-22 10:49:33 -04:00
Alex Corey
2ce09d0dcc adds job id to job name in job list delete modal 2021-06-22 10:49:33 -04:00
Keith J. Grant
25bca532c2 delete commented code 2021-06-22 10:49:33 -04:00
Keith J. Grant
fb897891c9 delete PaginatedDataList, move toolbar buttons to PaginatedTable dir 2021-06-22 10:49:32 -04:00
Keith J. Grant
421d8f215c Convert lists to tables
- ProjectJobTemplatesList
- UserTokenList
2021-06-22 10:49:32 -04:00
Keith J. Grant
3db92ca668 Convert more lists to tables
- Smart Inventory Hosts List
- Organization EE List
- Organization Teams list
2021-06-22 10:49:32 -04:00
Keith J. Grant
c6fa85036e convert ee template list, host group list to tables 2021-06-22 10:49:32 -04:00
Keith J. Grant
0b4a296181 convert ApplicationTokenList, HostFilterLookup to tables 2021-06-22 10:49:32 -04:00
nixocio
1665acd58a Allow edit fields to custom credential types
The logic to disable certain fields is just valid for `encrypted`
fields. Since the multiline field - no secret, does not have a button to `replace`
the content to null  - it was always set to disabled.

Fix: https://github.com/ansible/awx/issues/10079
2021-06-22 10:49:31 -04:00
Seth Foster
75a27c38c2 Add a periodic task to reap unreleased receptor work units
- Add work_unit_id field to UnifiedJob
2021-06-22 10:49:31 -04:00
nixocio
7b9bcd0481 Remove EE from WorkflowJobTemplate screens
Remove EE from WorkflowJobTemplate screens

Related ansible/awx#10443
Related ansible/awx#10399
2021-06-22 10:49:31 -04:00
Alan Rominger
15444bef70 Show inventory source POST in OPTIONS for inventory admins (#5076) 2021-06-22 10:49:31 -04:00
mabashian
f4bc69d5f7 Fixes bug where cred password fiield was displaying ASK 2021-06-22 10:49:31 -04:00
mabashian
29d57ea403 Fixes bug where toolbar was hidden on user token list 2021-06-22 10:49:30 -04:00
Elijah DeLee
ea5bd45d03 log perf of requests at debug level 2021-06-22 10:31:15 -04:00
softwarefactory-project-zuul[bot]
165a529ae0 Merge pull request #10480 from mscherer/fix_freenode
Remove more freenode from docs

SUMMARY
Removing more mention of Freenode, since we moved to Libera.
ISSUE TYPE

Docs Pull Request

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-21 17:24:55 +00:00
Chris Meyers
5975082954 only get active long running queries
Getting all connections that have been alive > 5 minutes is noisy. Instead, we want only queries that are active and have been alive for more than 5 minutes. This will filter out any idle connections.
2021-06-21 09:57:29 -04:00
Brigzzy
c1409f3dc7 Reorder docker compose up options 2021-06-20 12:29:43 -07:00
Michael Scherer
1c31a56395 Remove more freenode from docs 2021-06-19 11:32:02 +02:00
softwarefactory-project-zuul[bot]
0c120782d4 Merge pull request #10463 from mayasd/patch-1
Update Dockerfile.j2

SUMMARY
Jobs unable to start because podman trying to use systemd cgroup manager. See error below :
WARN[0000] Failed to add conmon to systemd sandbox cgroup: dial unix /run/systemd/private: connect: no such file or directory
Error: OCI runtime error: systemd cgroup flag passed, but systemd support for managing cgroups is not available

related #10099


ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

API

AWX VERSION
awx: 19.0.0

ADDITIONAL INFORMATION

According to this PR containers/podman#7009, podman switch references from libpod.conf to containers.conf.
According to containers.conf man (https://github.com/containers/common/blob/main/docs/containers.conf.5.md), configuration file is a TOML file but engine section declaration is missing.

thanks to @Siorde too 👍

Reviewed-by: Chris Meyers <None>
Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-17 21:19:30 +00:00
Shane McDonald
6ba053d4ee Update release date in changelog for 19.2.1 2021-06-17 14:39:39 -04:00
softwarefactory-project-zuul[bot]
3ecd26b5d8 Merge pull request #10468 from wenottingham/platforms
List platforms that developers regularly run the dev env on

SUMMARY
Other platforms are generally untested.
ISSUE TYPE

Docs Pull Request

Reviewed-by: Julen Landa Alustiza <None>
Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-17 17:24:42 +00:00
Bill Nottingham
bdf753ce23 Update tools/docker-compose/README.md
Co-authored-by: Shane McDonald <me@shanemcd.com>
2021-06-17 11:56:29 -04:00
Bill Nottingham
0f54516b38 List platforms that developers regularly run the dev env 2021-06-17 11:50:36 -04:00
softwarefactory-project-zuul[bot]
a56e32b59b Merge pull request #10464 from AlanCoding/ee_docs
Update and expand docs/ folder for EEs

This has some new content about EE precedence, which I don't think we've documented anywhere else, thinking of @tvo318 here, content was developed by @jbradberry
(I think the numbers 2 and 3 in the global job default EE may still be subject to revision, just a warning)
@shanemcd #10324 is incorporated into this
This mentions @rebeccahhh's venv migration stuff, but I'm trying to write the absolute minimum possible while still mentioning migration.

Reviewed-by: Rebeccah Hunter <rhunter@redhat.com>
Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Jeff Bradberry <None>
2021-06-17 13:07:07 +00:00
softwarefactory-project-zuul[bot]
026d5e6bdb Merge pull request #10465 from shanemcd/downstream-fixes
Downstream fixes

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-16 21:44:52 +00:00
Shane McDonald
03e73156ea Allow inventory updates to run in container groups 2021-06-16 17:11:43 -04:00
Alan Rominger
0b6208047c Correct the function of the -q option for migration helper commands 2021-06-16 16:26:38 -04:00
Alan Rominger
f14129de9b Further copy editing of EE docs 2021-06-16 16:18:21 -04:00
Jeff Bradberry
6c1ba03235 Remove EE from the workflow job template collection module 2021-06-16 15:41:09 -04:00
Jeff Bradberry
85bb4e976f Execution environments are meaningless for workflows
so, remove them from the API endpoints for workflows.  Also, tear out
the WFJT.execution_environment step in the resolver.  If we want that
to be a thing, it ought to be a .default_environment instead.
2021-06-16 15:41:09 -04:00
Shane McDonald
d1d3711fee Add yamllint to dev dependencies 2021-06-16 15:41:09 -04:00
Shane McDonald
d671366cad Add flake8 back to requirements_dev.txt 2021-06-16 15:41:08 -04:00
Shane McDonald
f9043864ce Create make target for api linter tasks 2021-06-16 15:41:08 -04:00
nixocio
a1ded8db3f Linkify credentials on JobTemplate and Organization Details
Linkify credentials on JobTemplate and Organization Details.

See: https://github.com/ansible/awx/issues/385
2021-06-16 15:41:08 -04:00
Alex Corey
cf6b6d831f adds visualizer button to output toolbar 2021-06-16 15:41:08 -04:00
Alex Corey
736cd4df36 refetches smart inventory after edit save 2021-06-16 15:41:08 -04:00
nixocio
8d99f79de4 Hide Edit button for non system admin
Hide Edit button for non system admin

See: https://github.com/ansible/tower/issues/5032
2021-06-16 15:41:08 -04:00
Alex Corey
1c70773cc2 shows user type fields only for sys admins 2021-06-16 15:41:07 -04:00
mabashian
c76a7d638f Removes tooltip from user in page toolbar 2021-06-16 15:41:07 -04:00
mabashian
7a455d08d7 Change Options to Enabled Options in various details views 2021-06-16 15:41:07 -04:00
nixocio
2c5bcf268d Update UI to reflect new API EE changes
* Show resolved EE for job template details.
* Do not show EE if a certain job status still running, since EE on the
API is not set yet. It was causing the bug to temporarily show `missing
resource`.
* Fix discrepancy about job types for list and details.

See: https://github.com/ansible/awx/issues/10327
Also: https://github.com/ansible/awx/issues/10399
2021-06-16 15:41:07 -04:00
mabashian
32cee852f0 Swap underscore for hyphen 2021-06-16 15:41:07 -04:00
mabashian
8c1cd9ee71 Fixes bug where source list page would crash if first sync was running 2021-06-16 15:41:07 -04:00
Alex Corey
da951714d1 resolves iinfinite loop 2021-06-16 15:41:07 -04:00
Alan Rominger
2309feb6bd Make ExecutionEnvironment awxkit class able to handle null values in payload 2021-06-16 15:41:06 -04:00
nixocio
4d2c64ebb4 Add RBAC rules to the side-nav
Add RBAC rules to the side-nav

System Admin
System Auditor
Org Admin
Notification Admin
Execution Environment Admin
Normal User

Those are the user profiles taken in consideration when displaying the
side-nav.

See: https://github.com/ansible/awx/issues/4426
2021-06-16 15:37:25 -04:00
nixocio
04f6fe6cd2 Disable inventory field when editing host
Disable inventory field when editing host

See: https://github.com/ansible/awx/issues/10229
2021-06-16 15:37:25 -04:00
Bill Nottingham
372baa12a5 Update runner version. 2021-06-16 15:37:25 -04:00
mabashian
21e6e5701e Addresses bug where advanced search by groups wasn't working on host list 2021-06-16 15:37:25 -04:00
Alex Corey
276a18b339 fixes next button and internationalizes nav buttons on wizard 2021-06-16 15:37:25 -04:00
mabashian
666acb9756 Extract strings 2021-06-16 15:37:25 -04:00
mabashian
0eff3e6bac Pull brand name from default.strings.json 2021-06-16 15:37:24 -04:00
mabashian
9af16c18c9 Dont reconnect job output socket if it closes cleanly 2021-06-16 15:37:24 -04:00
Elijah DeLee
f0bcfc6024 add EE information to assert_status
This should help debugging to know what the EE was when an unexpected
status was found.
2021-06-16 15:37:24 -04:00
Elijah DeLee
d946103961 log perf of requests at debug level 2021-06-16 15:37:24 -04:00
Alan Rominger
52d6f36b7c Incorporate review comments about EE docs 2021-06-16 14:24:48 -04:00
softwarefactory-project-zuul[bot]
b10eb6f4c2 Merge pull request #10382 from AlanCoding/downstream_waterslide
Handle inventory types where Automation Hub collection names differ

Some collections will be moving, which is #10323
Yet, other collections will change name, which this is intended to address.

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Sarabraj Singh <singh.sarabraj@gmail.com>
Reviewed-by: Elijah DeLee <kdelee@redhat.com>
2021-06-16 18:15:08 +00:00
Alan Rominger
21aa1fc11f Handle inventory types where Automation Hub collection names differ
Move imports added by Bill to be in-line, because utils should not import models at top

Remove more get_licenser inline imports
2021-06-16 13:39:52 -04:00
softwarefactory-project-zuul[bot]
d4a3143b0e Merge pull request #10456 from jbradberry/danger-danger-will-robinson
Remove isolated instances and groups

SUMMARY
before we remove the fields that allow us to correctly identify them.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

API

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Jeff Bradberry <None>
Reviewed-by: Chris Meyers <None>
2021-06-16 15:30:48 +00:00
Alan Rominger
4478052b71 Update and expand docs/ folder for EEs 2021-06-16 11:23:59 -04:00
softwarefactory-project-zuul[bot]
b92c5076a2 Merge pull request #10446 from fosterseth/fix_a10431_validate_ee_image_field
Add validation for EE image field name

related #10431
SUMMARY

Adds validation for the EE image name

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


API

AWX VERSION

awx: 19.2.1

Reviewed-by: Seth Foster <None>
Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Rebeccah Hunter <rhunter@redhat.com>
Reviewed-by: Jeff Bradberry <None>
2021-06-16 14:34:45 +00:00
Tim
a3383716ab Update Dockerfile.j2
Jobs unable to start because podman trying to use systemd cgroup manager. See error below :

```
WARN[0000] Failed to add conmon to systemd sandbox cgroup: dial unix /run/systemd/private: connect: no such file or directory
Error: OCI runtime error: systemd cgroup flag passed, but systemd support for managing cgroups is not available
```

* According to this PR https://github.com/containers/podman/pull/7009, podman switch references from libpod.conf to containers.conf.
* According to containers.conf man (https://github.com/containers/common/blob/main/docs/containers.conf.5.md), configuration file is a TOML file but engine section declaration is missing.
2021-06-16 15:03:37 +02:00
Seth Foster
61846e88ca Add validator for ee image field name
awxkit default ee image name is now a fixed valid (but bogus) name, rather than random unicode
2021-06-15 20:06:49 -04:00
Jeff Bradberry
93e90228a2 Remove isolated instances and groups
before we remove the fields that allow us to correctly identify them.
2021-06-15 17:36:26 -04:00
softwarefactory-project-zuul[bot]
395af1b5e4 Merge pull request #10425 from sarabrajsingh/bugfix/preflight-check-postgres-version-4940
introduced a pre-flight check for postgres 12

SUMMARY


Introduced a pre-flight check to check the version of Postgres 12 before the application starts - ansible/tower#4940
ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


API

AWX VERSION

awx: 19.2.0

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Sarabraj Singh <singh.sarabraj@gmail.com>
Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-15 13:46:58 +00:00
softwarefactory-project-zuul[bot]
5d7bdb3cbc Merge pull request #10449 from mscherer/patch-1
Update irc server

SUMMARY

See ansible/community#613

ISSUE TYPE


Docs Pull Request

COMPONENT NAME


Doc

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-15 11:18:12 +00:00
mscherer
95d40f037d Update irc server
See https://github.com/ansible/community/issues/613
2021-06-15 10:19:40 +02:00
softwarefactory-project-zuul[bot]
ef67f9c65d Merge pull request #10436 from AlanCoding/installed_default
Prefer installer defaults over user-defined global EEs

The installer knows better than the user

Reviewed-by: Jeff Bradberry <None>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Elijah DeLee <kdelee@redhat.com>
2021-06-15 00:59:06 +00:00
softwarefactory-project-zuul[bot]
8a4421dc0c Merge pull request #10290 from amigus/dsv
Add Thycotic DevOps Secrets Vault support

SUMMARY
Add a Credential Plugin for Thycotic DevOps Secrets Vault
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

API
UI

AWX VERSION
awx: 19.1.0

Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Adam C. Migus <adam@migus.org>
Reviewed-by: Matthew Jones <bsdmatburt@gmail.com>
2021-06-14 19:22:59 +00:00
softwarefactory-project-zuul[bot]
2900bbbbd8 Merge pull request #10441 from shanemcd/bump-19.2.1
AWX 19.2.1

Reviewed-by: Jeff Bradberry <None>
Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-14 19:05:42 +00:00
softwarefactory-project-zuul[bot]
a6c09daf1e Merge pull request #10414 from sean-m-sullivan/devel
Add Job data to return on wait failures

SUMMARY
This adds the returned results to the returned data when jobs fail when waited on. This brings it inline with information returned on success.
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

awx collection

AWX VERSION
19.2.0

ADDITIONAL INFORMATION
before:
{
  "changed": false,
  "elapsed": 3.806,
  "finished": "2021-06-10T15:24:52.861344Z",
  "id": 153,
  "msg": "The Workflow Node - fail, failed",
  "started": "2021-06-10T15:24:49.055652Z",
  "status": "failed"
}
after:
{
  "changed": false,
  "elapsed": 3.806,
  "finished": "2021-06-10T15:24:52.861344Z",
  "id": 153,
  "job_data": {
    "allow_simultaneous": false,
    "artifacts": {
      "test": "fail"
    },
    "canceled_on": null,
    "controller_node": "",
    "created": "2021-06-10T15:24:48.504122Z",
    "custom_virtualenv": "/var/lib/awx/venv/ansible",
    "description": "",
    "diff_mode": false,
    "elapsed": 3.806,
    "event_processing_finished": true,
    "execution_node": "localhost",
    "extra_vars": "{\"fail\": \"workflow\"}",
    "failed": true,
    "finished": "2021-06-10T15:24:52.861344Z",
    "force_handlers": false,
    "forks": 0,
    "host_status_counts": {
      "failures": 1
    },
    "id": 153,
    "instance_group": 1,
    "inventory": 1,
    "job_args": "[\"bwrap\", \"--die-with-parent\", \"--unshare-pid\", \"--dev-bind\", \"/\", \"/\", \"--proc\", \"/proc\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmp5wid0rwm\", \"/etc/ssh\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmp5wmz8ule\", \"/etc/tower\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmp4akvmhfo\", \"/home\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmplpgjkbaw\", \"/tmp\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmpgrdxeea3\", \"/var/lib/awx\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmp2hidif23\", \"/var/lib/awx/job_status\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmps2sv03e3\", \"/var/lib/awx/projects\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmpoqb_xxh7\", \"/var/log\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/ansible_runner_pi_uai8yldi/tmpyjok4bi3\", \"/var/tmp\", \"--ro-bind\", \"/var/lib/awx/venv/ansible\", \"/var/lib/awx/venv/ansible\", \"--ro-bind\", \"/var/lib/awx/venv/awx\", \"/var/lib/awx/venv/awx\", \"--bind\", \"/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm\", \"/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm\", \"--chdir\", \"/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/project\", \"ssh-agent\", \"sh\", \"-c\", \"ssh-add /tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/artifacts/153/ssh_key_data && rm -f /tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/artifacts/153/ssh_key_data && ansible-playbook -u excalibrax --ask-pass -i /tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/tmp93bq8ck1 -e @/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/env/extravars fail.yml\"]",
    "job_cwd": "/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/project",
    "job_env": {
      "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/ansible_runner/callbacks",
      "ANSIBLE_COLLECTIONS_PATHS": "/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/requirements_collections:~/.ansible/collections:/usr/share/ansible/collections",
      "ANSIBLE_FORCE_COLOR": "True",
      "ANSIBLE_HOST_KEY_CHECKING": "False",
      "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
      "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
      "ANSIBLE_RETRY_FILES_ENABLED": "False",
      "ANSIBLE_ROLES_PATH": "/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/requirements_roles:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles",
      "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/cp",
      "ANSIBLE_STDOUT_CALLBACK": "awx_display",
      "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible",
      "AWX_HOST": "https://10.42.42.212",
      "AWX_ISOLATED_DATA_DIR": "/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm/artifacts/153",
      "AWX_PRIVATE_DATA_DIR": "/tmp/bwrap_153_uqo3h55g/awx_153_rvlvv4nm",
      "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199",
      "DJANGO_SETTINGS_MODULE": "awx.settings.production",
      "HOME": "/var/lib/awx",
      "INVENTORY_ID": "1",
      "INVOCATION_ID": "6dfbb88bc6484622a4f44ffbc1196b44",
      "JOB_ID": "153",
      "JOURNAL_STREAM": "9:24634",
      "LANG": "en_US.UTF-8",
      "MAX_EVENT_RES": "700000",
      "PATH": "/var/lib/awx/venv/ansible/bin:/var/lib/awx/venv/awx/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
      "PROJECT_REVISION": "debeb7bd98d23a5d69103f024280ac5f8927d58a",
      "PROOT_TMP_DIR": "/tmp",
      "PS1": "(awx) ",
      "PWD": "/var/lib/awx",
      "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python3.6/site-packages:",
      "RUNNER_OMIT_EVENTS": "False",
      "RUNNER_ONLY_FAILED_EVENTS": "False",
      "SHLVL": "0",
      "SUPERVISOR_ENABLED": "1",
      "SUPERVISOR_GROUP_NAME": "tower-processes",
      "SUPERVISOR_PROCESS_NAME": "awx-dispatcher",
      "SUPERVISOR_SERVER_URL": "unix:///var/run/supervisor/supervisor.sock",
      "TZ": "UTC",
      "USER": "awx",
      "VIRTUAL_ENV": "/var/lib/awx/venv/ansible"
    },
    "job_explanation": "",
    "job_slice_count": 1,
    "job_slice_number": 0,
    "job_tags": "",
    "job_template": 14,
    "job_type": "run",
    "launch_type": "workflow",
    "limit": "",
    "modified": "2021-06-10T15:24:48.953892Z",
    "name": "fail",
    "organization": 1,
    "passwords_needed_to_start": [
      
    ],
    "playbook": "fail.yml",
    "playbook_counts": {
      "play_count": 1,
      "task_count": 3
    },
    "project": 13,
    "related": {
      "activity_stream": "/api/v2/jobs/153/activity_stream/",
      "cancel": "/api/v2/jobs/153/cancel/",
      "create_schedule": "/api/v2/jobs/153/create_schedule/",
      "created_by": "/api/v2/users/1/",
      "credentials": "/api/v2/jobs/153/credentials/",
      "inventory": "/api/v2/inventories/1/",
      "job_events": "/api/v2/jobs/153/job_events/",
      "job_host_summaries": "/api/v2/jobs/153/job_host_summaries/",
      "job_template": "/api/v2/job_templates/14/",
      "labels": "/api/v2/jobs/153/labels/",
      "notifications": "/api/v2/jobs/153/notifications/",
      "organization": "/api/v2/organizations/1/",
      "project": "/api/v2/projects/13/",
      "relaunch": "/api/v2/jobs/153/relaunch/",
      "source_workflow_job": "/api/v2/workflow_jobs/152/",
      "stdout": "/api/v2/jobs/153/stdout/",
      "unified_job_template": "/api/v2/job_templates/14/"
    },
    "result_traceback": "",
    "scm_branch": "",
    "scm_revision": "debeb7bd98d23a5d69103f024280ac5f8927d58a",
    "skip_tags": "",
    "start_at_task": "",
    "started": "2021-06-10T15:24:49.055652Z",
    "status": "failed",
    "summary_fields": {
      "created_by": {
        "first_name": "",
        "id": 1,
        "last_name": "",
        "username": "admin"
      },
      "credentials": [
        {
          "cloud": false,
          "description": "",
          "id": 1,
          "kind": "ssh",
          "name": "Demo Credential"
        }
      ],
      "instance_group": {
        "id": 1,
        "is_containerized": false,
        "name": "tower"
      },
      "inventory": {
        "description": "",
        "has_active_failures": true,
        "has_inventory_sources": false,
        "hosts_with_active_failures": 1,
        "id": 1,
        "inventory_sources_with_failures": 0,
        "kind": "",
        "name": "Demo Inventory",
        "organization_id": 1,
        "total_groups": 0,
        "total_hosts": 1,
        "total_inventory_sources": 0
      },
      "job_template": {
        "description": "",
        "id": 14,
        "name": "fail"
      },
      "labels": {
        "count": 0,
        "results": [
          
        ]
      },
      "organization": {
        "description": "",
        "id": 1,
        "name": "Default"
      },
      "project": {
        "description": "",
        "id": 13,
        "name": "fail",
        "scm_type": "git",
        "status": "successful"
      },
      "source_workflow_job": {
        "description": "",
        "elapsed": 4.89,
        "failed": true,
        "id": 152,
        "name": "fail_workflow",
        "status": "failed"
      },
      "unified_job_template": {
        "description": "",
        "id": 14,
        "name": "fail",
        "unified_job_type": "job"
      },
      "user_capabilities": {
        "delete": true,
        "start": true
      }
    },
    "timeout": 0,
    "type": "job",
    "unified_job_template": 14,
    "url": "/api/v2/jobs/153/",
    "use_fact_cache": false,
    "verbosity": 0,
    "webhook_credential": null,
    "webhook_guid": "",
    "webhook_service": ""
  },
  "msg": "The Workflow Node - fail, failed",
  "started": "2021-06-10T15:24:49.055652Z",
  "status": "failed"
}

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-14 18:58:38 +00:00
Alan Rominger
92c6ddf13c Prefer installer defaults over user-defined global EEs
Add a basic level of testing around get_default_execution_environment
2021-06-14 14:13:39 -04:00
Jake McDermott
c6ac2f56dc Update CHANGELOG.md 2021-06-14 14:09:53 -04:00
Sarabraj Singh
7a130a0616 flipped MODE switch for postgres check 2021-06-14 13:55:11 -04:00
Shane McDonald
188f0417d2 Fix typo 2021-06-14 13:38:41 -04:00
Shane McDonald
d38401fd18 Bump version to 19.2.1 2021-06-14 12:32:20 -04:00
Shane McDonald
dadf8940cc Remove outdated info from changelog 2021-06-14 12:32:10 -04:00
softwarefactory-project-zuul[bot]
6a36f802c2 Merge pull request #10434 from wenottingham/runner-update
Update runner to 2.0b1

SUMMARY
Newly released.

Reviewed-by: Elijah DeLee <kdelee@redhat.com>
2021-06-12 04:26:17 +00:00
Adam Migus
5509686f5b Remove unused imports to fix build. 2021-06-11 23:49:45 -04:00
Adam Migus
1ee241199e Refactor to simplify
- Remove eval and the expression metadata attribute
- Remove locale conditional on the tld field
2021-06-11 23:49:45 -04:00
Adam Migus
67d828cf80 Backout accidential changes to settings/defaults 2021-06-11 23:49:45 -04:00
Adam Migus
86c91509b3 Add Thycotic DevOps Secrets Vault support 2021-06-11 23:49:45 -04:00
Adam Migus
bfd1abd79c Add license for python-dsv-sdk to docs/licenses 2021-06-11 23:49:44 -04:00
Adam Migus
c169cf6d58 Fix test_credential.py
- Add 'thycotic_dsv' to the list of expected credential types
2021-06-11 23:49:44 -04:00
Adam Migus
9679c154f3 Backout accidential changes to settings/defaults 2021-06-11 23:49:44 -04:00
Adam Migus
a317b6bede Add Thycotic DevOps Secrets Vault support 2021-06-11 23:49:44 -04:00
Sarabraj Singh
f73de11acc introduced a pre-flight check for postgres 12 2021-06-11 23:18:38 -04:00
softwarefactory-project-zuul[bot]
6f16d64929 Merge pull request #10429 from AlanCoding/teardown_global_ee
Make ExecutionEnvironment awxkit class able to handle null values in …

This is how the Project class does it, and I can confirm it makes factories.execution_environment(organization=None) work correctly.

Reviewed-by: Jeff Bradberry <None>
2021-06-11 20:36:47 +00:00
softwarefactory-project-zuul[bot]
8a6656aa90 Merge pull request #10417 from mabashian/10411-inv-src-sync-details
Fixes bug where source list page would crash if first sync was running

SUMMARY
link #10411
The ID being passed to the cancel button was incorrect as well.  We want to reference current_job not last_job.

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Kersom <None>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-11 20:33:33 +00:00
Bill Nottingham
95ba6de172 Update runner to 2.0b1 2021-06-11 15:04:43 -04:00
softwarefactory-project-zuul[bot]
63aacd4e38 Merge pull request #10416 from mabashian/10400-search-keys
Addresses bug where advanced search by groups wasn't working on host list

SUMMARY
link #10400
OK so this got a bit more complicated than I wanted it to but I think on the whole this is a nice improvement.  In the initial bug report it was noted that we were ignoring the or/not operators when searching on a related key (in this case it was groups).  We were also ignoring the modifier at the end (icontains, exact, startswith, etc).  Since we were always defaulting to __search for these types of keys this was actually valid.  The API doesn't like us attempting to do something like ?or__groups__search=foo or ?groups__search__icontains because they aren't valid.  So, I changed the UX a little bit.  A user can still do a fuzzy search on a related key but the prefix is disabled in this case:

I changed the third dropdown (specifically for related keys) to contain the following options: search, id, name__icontains which I think would be the three most general cases.  id and name__icontains do allow for prefixing (or, not, and).
This should make searching on related keys a little bit easier and a little bit more flexible since name and id weren't possible in the UI before.
Once place where this is a little different is the host filter in the smart inventory form.  Using __search currently throws an error when the user attempts to save.  I believe this is an API bug and will file it as such but for now I prevent users from attempting to use __search by removing it as an option for this particular list.  When this bug gets fixed in the API we can remove this logic.
I also noticed that there was a bug where or__ search terms were being converted to and when using the Smart Inventory button on the host list so I fixed that.
Here's the fix in action:

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-11 18:12:01 +00:00
Alan Rominger
b39b80b036 Make ExecutionEnvironment awxkit class able to handle null values in payload 2021-06-11 13:32:46 -04:00
sean-m-ssullivan
214c27a5cf add job data to filed wait jobs 2021-06-11 09:45:28 -04:00
mabashian
ae83032ff3 Swap underscore for hyphen 2021-06-10 16:42:03 -04:00
softwarefactory-project-zuul[bot]
2e0dd61bb6 Merge pull request #10413 from AlexSCorey/10404-RoleAccessSaveButton
fixes next button and internationalizes nav buttons on wizard

SUMMARY
Resolves #10404 and it internationalizes the next button.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

AWX VERSION
ADDITIONAL INFORMATION

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-10 19:13:19 +00:00
mabashian
25aae9abc6 Fixes bug where source list page would crash if first sync was running 2021-06-10 15:06:13 -04:00
mabashian
8b20d770a2 Addresses bug where advanced search by groups wasn't working on host list 2021-06-10 13:46:27 -04:00
Alex Corey
6726b72fe2 fixes next button and internationalizes nav buttons on wizard 2021-06-10 11:21:57 -04:00
softwarefactory-project-zuul[bot]
e610b77f8d Merge pull request #10397 from mabashian/job-output-socket-reconnect
Don't reconnect job output socket if it closes cleanly

SUMMARY
See #9795 (comment)
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-10 14:51:14 +00:00
softwarefactory-project-zuul[bot]
2490929fd5 Merge pull request #10394 from mabashian/brand-name
Pull brand name from default.strings.json

SUMMARY
We were pulling this string from variables.js.
There were several places where the brand name was not being pulled dynamically - this PR addresses that.  This changes the way we set the document title a little bit.  Since we needed access to a dynamic string, I went down the JS route to set this.

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-09 23:07:37 +00:00
softwarefactory-project-zuul[bot]
29ec0dc82a Merge pull request #10376 from mabashian/3831-settings-changes
Changes settings revert all to send DELETE on individual endpoint rather than PATCHing

SUMMARY
Resolves #3831
#3831 (comment) is a good explanation of the state of the new UI as well as the old.  The Misc System settings were the most problematic part of this since that form pulled fields from both /api/v2/settings/system and /api/v2/settings/authentication.  In order to revert these fields with a DELETE request I needed to split this form up into Miscellaneous System and Miscellaneous Authentication.  The Activity Stream Settings also needed to be absorbed by the Miscellaneous System Settings.
All settings forms (except noted below) will now issue a DELETE request to revert all the fields for a particular settings subsection.
There was one form that I did not change the Revert All functionality on and that was the LDAP Settings form(s).  The UI splits these fields out into 5 different subforms and reverting one (issuing a DELETE on /api/v2/settings/ldap) would revert all the ldap settings which I think is undesirable.
This fix has the added benefit of cleaning up future activity stream entries for reverting an entire settings category.
I also consulted with @wenottingham and @gamuniz on some fields that were present in the api but missing in the ui and I added those.
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

UI

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-09 21:29:06 +00:00
Shane McDonald
301d7a02c2 Update README.md 2021-06-09 17:21:39 -04:00
Shane McDonald
81e6ead99c Update README.md 2021-06-09 17:20:44 -04:00
softwarefactory-project-zuul[bot]
158fe23d7c Merge pull request #8650 from wenottingham/discovering-new-insights
Add support for Insights as an inventory source

SUMMARY
Use the insights inventory plugin as an inventory source.
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

API

ADDITIONAL INFORMATION
Requires at minimum RedHatInsights/ansible-collections-insights#14

Reviewed-by: Bill Nottingham <None>
Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Chris Meyers <None>
2021-06-09 21:08:35 +00:00
softwarefactory-project-zuul[bot]
b3705357ba Merge pull request #10403 from nixocio/ui_issue_8890
Fix host filter chips on smart inventory

Fix host filter chips on smart inventory

See: #8890

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-09 20:58:34 +00:00
Bill Nottingham
f460f70513 Remove host insights view 2021-06-09 16:34:32 -04:00
Bill Nottingham
b6ced2b8dc Add UI bits 2021-06-09 16:34:32 -04:00
Bill Nottingham
be18803250 Add support for Insights as an inventory source 2021-06-09 16:34:32 -04:00
softwarefactory-project-zuul[bot]
f26d975005 Merge pull request #10378 from jbradberry/control-plane-ee
Control plane EE

SUMMARY
Per discussion, we are now going to have privileged execution environments for use on the control plane, and these will not be allowed to be edited or deleted.
related ansible/tower#5016
TODO

 reinstate the restrictive RBAC for managed_by_tower=True EEs
 convert any EEs automatically installed prior into managed_by_tower=False EEs
 change the resolver so that ordinary jobs do not get a managed EE, and project updates only get a managed EE
 allow sysadmin users to edit the pull field for managed EEs
 automatically disassociate EEs that get deleted from the DEFAULT_EXECUTION_ENVIRONMENT setting #10363

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

API

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Jeff Bradberry <None>
Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Seth Foster <None>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-09 20:25:37 +00:00
mabashian
a7a17a2063 Extract strings 2021-06-09 16:13:20 -04:00
mabashian
9e657059f3 Pull brand name from default.strings.json 2021-06-09 16:11:04 -04:00
Jeff Bradberry
486bcd80f8 Make sure that the delete capability isn't hardcoded to be the same as edit 2021-06-09 15:45:02 -04:00
softwarefactory-project-zuul[bot]
e4f21ec294 Merge pull request #10291 from AlexSCorey/10152-AddsPFDatePicker-v2
Resolves issue where FireFox users could not schedule a job template

SUMMARY
This addresses #10152 and #6214
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

ADDITIONAL INFORMATION

Reviewed-by: Michael Abashian <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-09 18:52:29 +00:00
softwarefactory-project-zuul[bot]
3cb3819be9 Merge pull request #10395 from mabashian/10333-default-galaxy-cred
Preselect default galaxy cred when creating new org

SUMMARY
link #10333

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Kersom <None>
Reviewed-by: Yago Marques <yagomarquesja@gmail.com>
2021-06-09 18:16:52 +00:00
softwarefactory-project-zuul[bot]
122b36dcc5 Merge pull request #10388 from jakemcdermott/fix-favico
Use favicon for dev and prod builds

SUMMARY

Reviewed-by: Michael Abashian <None>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-09 18:10:39 +00:00
Jeff Bradberry
2d1a859719 Remove unused import 2021-06-09 13:48:23 -04:00
Shane McDonald
f882ac420d Fix tests 2021-06-09 13:48:23 -04:00
Shane McDonald
373cd9c20b Remove usage of AWXReceptorJob in metadata.py 2021-06-09 13:48:23 -04:00
Shane McDonald
673afdf1b5 Only install ansible-core for collection tests
Faster!
2021-06-09 13:48:23 -04:00
Jeff Bradberry
7a16782ebf Fix a problem with using PrimaryKeyRelatedField in our settings registry
DRF, when using this field, short-circuits the call to
.to_representation() when the value is None, since clearly you aren't
going to be able to get the .pk attribute off of it in that case.  We
were previously unconditionally calling .to_representation() which
throws an error when we try to clear the value of
DEFAULT_EXECUTION_ENVIRONMENT.
2021-06-09 13:48:23 -04:00
Jeff Bradberry
8ede74a7f6 Deal with the possibility of get_default_pod_spec not finding an EE 2021-06-09 13:48:23 -04:00
Jeff Bradberry
19da9955ce Make sure that managed EEs can't be deleted 2021-06-09 13:48:23 -04:00
Jeff Bradberry
e6e1f97048 Add a signal handler to remove the default EE if it gets deleted 2021-06-09 13:48:16 -04:00
softwarefactory-project-zuul[bot]
0a63c2d4a0 Merge pull request #10385 from mabashian/version_context_processor
Adds version context processor back in to fix api browser doc link

SUMMARY
Here's what it looks like on devel now (note the URL in the bottom left):

Here's what it looks like after the change (note the URL in the bottom left):

I dropped this in as it was before the removal of the old UI.  I believe the new UI needs access to some of these variables as well to force assets to be refetched after upgrade.
Also of note: I have no idea what I'm doing with django so please help me to become educated if I've done something silly here.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

API

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-09 15:44:45 +00:00
softwarefactory-project-zuul[bot]
493109782d Merge pull request #10402 from AlexSCorey/10350-TeamAddLoop
Stops infinte REST calls on ResourcesAccessAdd workflow

SUMMARY
resolves #10350
There is no functionality changes, I just moved the location of the variables so they are defined outside of the component.
E2E test triggered
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Kersom <None>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-09 15:33:11 +00:00
mabashian
0195bab931 Drop in favicon.ico from old app 2021-06-09 11:22:40 -04:00
Jake McDermott
e570810bdb Use favicon for dev and prod builds 2021-06-09 11:22:40 -04:00
Jeff Bradberry
9f1e8a1ae2 Allow sysadmins to be able to change the pull field for managed EEs 2021-06-09 11:11:56 -04:00
nixocio
9a0c159943 Fix host filter chips on smart inventory
Fix host filter chips on smart inventory

See: https://github.com/ansible/awx/issues/8890
2021-06-09 10:26:18 -04:00
Jeff Bradberry
9aa56b1247 Update the EE resolver logic
so that the control plane managed EE is kept separate.
2021-06-09 10:03:35 -04:00
Jeff Bradberry
d4d21a1511 Remove the managed flag from all existing EEs
This flag henceforth is going to be used only for the "control plane"
execution environments, which sysadmins will not be allowed to alter.
2021-06-09 10:03:35 -04:00
Alex Corey
27a2c842ac resolve infinite api calls 2021-06-09 07:50:00 -04:00
softwarefactory-project-zuul[bot]
87dcc49429 Merge pull request #10380 from nixocio/ui_remove_not
Do not show `not` as choice for Advanced Search on Smart Inventory

Do not show not set type as a  choice for Advanced Search on Smart Inventory since
this feature is not implemented on the API side yet.

See: #2817

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-08 21:43:54 +00:00
softwarefactory-project-zuul[bot]
805ca53765 Merge pull request #10390 from rooftopcellist/update-translations
Update translation make target for ui_next

SUMMARY
This adds the --clean flag to the extract-strings command (cleans up obsolete strings) and separates out the extract-template command.
ISSUE TYPE


Feature Pull Request

COMPONENT NAME


Translation Automation

AWX VERSION

19.2.0

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
2021-06-08 21:36:02 +00:00
Shane McDonald
070034047c Merge pull request #10377 from kdelee/control_plane_ee
Break out control plane EE as its own thing
2021-06-08 17:25:01 -04:00
softwarefactory-project-zuul[bot]
53c50947d1 Merge pull request #10347 from nixocio/ui_issue_9232
Update advanced search for Smart Inventories

Update advanced search for Smart Inventories
Update usage of conditional operators for advanced search for Smart Inventories
Not operator is not supported yet - See: #2817
See: #9232

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-08 21:16:35 +00:00
softwarefactory-project-zuul[bot]
108a6e11f4 Merge pull request #10384 from keithjgrant/6189-instance-list-table
Convert InstanceList to table

SUMMARY
Converts InstanceList to Paginated Table
addresses #6189 and #10160
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

UI

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Kersom <None>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-08 21:04:22 +00:00
softwarefactory-project-zuul[bot]
a4bc306b96 Merge pull request #9084 from marshmalien/5057-launched-by
Extend launched by details to handle scheduled JTs and WFJTs

SUMMARY
Issue: #5057
Launched By detail should link to the schedule that launched the job.

ISSUE TYPE


Enhancement Pull Request

COMPONENT NAME


UI

Reviewed-by: Kersom <None>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-08 20:49:39 +00:00
softwarefactory-project-zuul[bot]
9106c3f813 Merge pull request #10373 from AlanCoding/limit_docs
Add OPTIONS documentation for new job limit feature

Looking at the docs and stuff from #10023
I'm sure this is somewhere else too, but this is the place that users should naturally expect it to be.

Reviewed-by: Chris Meyers <None>
2021-06-08 20:22:55 +00:00
softwarefactory-project-zuul[bot]
3340ef9c91 Merge pull request #10053 from AlanCoding/dropsies
Intentionally drop job event websocket messages in excess of 30 per second (configurable)

SUMMARY
The UI no longer follows the latest job events from websocket messages. Because of that, there's no reason to send messages for all events if the job event rate is high.
I used 30 because this is the number of events that I guesstimate will show in one page in the UI.
Needs the setting added in the UI.
This adds skip_websocket_message to event event_data. We could promote it to a top-level key for job events, if that is preferable aesthetically. Doing this allows us to test this feature without having to connect a websocket client. Ping @mabashian @chrismeyersfsu
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

API
UI

ADDITIONAL INFORMATION
Scenario walkthrough:
a job is producing 1,000 events per second. User launches it, the screen fills up in, say 1/4 of a second. The scrollbar indicates content beyond the bottom of the screen. Now, for 3/4ths of a second, the scrollbar stays still. After that, it updates the scrollbar to the current line number that the job is on. The scrollbar continues to update the length of the output effectively once per second.

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Chris Meyers <None>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-08 20:10:45 +00:00
mabashian
fc171deb79 Dont reconnect job output socket if it closes cleanly 2021-06-08 16:08:39 -04:00
Elijah DeLee
f2dac36dd1 Remove the cred too if not passed
NOW....should be idempotent and remove the the cred if it is not passed
2021-06-08 15:52:53 -04:00
Christian M. Adams
fb1a5c0db5 Update translation make target for ui_next 2021-06-08 15:26:00 -04:00
mabashian
d6a06c40f1 Preselect default galaxy cred when creating new org 2021-06-08 15:19:36 -04:00
softwarefactory-project-zuul[bot]
a6383e7f79 Merge pull request #10324 from shanemcd/default_queue_name
Introduce distinct controlplane instance group

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Matthew Jones <bsdmatburt@gmail.com>
Reviewed-by: Yanis Guenane <None>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-08 19:18:35 +00:00
Shane McDonald
3063073395 Merge pull request #9980 from fosterseth/fix_t4958_rename_collection
Rename awx_collection modules
2021-06-08 15:12:04 -04:00
Seth Foster
9eda6359f0 False to false to fix linter 2021-06-08 14:33:30 -04:00
Seth Foster
1deaf55ba4 syntax error in runtime.yml 2021-06-08 14:33:30 -04:00
Seth Foster
44c50bbbf7 add redirect for lookup and inventory plugins 2021-06-08 14:33:29 -04:00
Seth Foster
c9e7747f2d black ignore awx_collection 2021-06-08 14:33:29 -04:00
Seth Foster
199b4b6b47 fixed up jinja2 templating and documentation 2021-06-08 14:33:29 -04:00
Seth Foster
f06485feca fqcn redirects, and raise from sanity test fix 2021-06-08 14:33:29 -04:00
Seth Foster
4bd910493a sanity tests 2021-06-08 14:33:28 -04:00
Seth Foster
cd100fd770 fix super and kwargs 2021-06-08 14:33:28 -04:00
Seth Foster
157adb828e various sanity fixes 2021-06-08 14:33:28 -04:00
Seth Foster
b26e33ca34 remove eula_accepted 2021-06-08 14:33:28 -04:00
Sarabraj Singh
27a1254883 fixed ansible-test sanity import tests; removed sanity-ignore files 2021-06-08 14:33:28 -04:00
Sarabraj Singh
535bbfcc39 fixed validate-modules sanity tests 2021-06-08 14:33:27 -04:00
Sarabraj Singh
d2d511f596 switched to semenatic versioning for version numbers in plugins, library and tools packages 2021-06-08 14:33:27 -04:00
Sarabraj Singh
25ca8d22d6 added collection name to module.deprecate() calls; fixed pep8 linting issues 2021-06-08 14:33:27 -04:00
Sarabraj Singh
378a0711c2 linted AUTH_ARGSPEC to make it easier to read (<180 characters in the same line) 2021-06-08 14:33:26 -04:00
Sarabraj Singh
8fd9225629 removed un-reference-able python modules from ignore-2.9.txt 2021-06-08 14:33:26 -04:00
Seth Foster
ee8c1638c5 remove deprecated modules 2021-06-08 14:33:26 -04:00
Seth Foster
4add72b9d2 actually make use of option aliases 2021-06-08 14:33:25 -04:00
Seth Foster
54dd24b96b auth_plugin env alternative 2021-06-08 14:33:25 -04:00
Seth Foster
7d06fc74dd tower_username to controller_username, etc 2021-06-08 14:33:25 -04:00
Seth Foster
1a2e56c785 restore tower_legacy.py, update examples to include CONTROLLER_HOST 2021-06-08 14:33:25 -04:00
Seth Foster
a7b29f6112 controller_inventory.yml in addition to tower_inventory.yml 2021-06-08 14:33:24 -04:00
Seth Foster
39b26c8f0e Added env variable CONTROLLER_HOST, et al. Add awx.awx namespace to the runtime.yml redirects, and added templating task to change to ansible.controller 2021-06-08 14:33:24 -04:00
Seth Foster
1ade9b3a7d various references to tower 2021-06-08 14:33:24 -04:00
Seth Foster
82c5803e59 mostly includes renaming non-syntax references to tower 2021-06-08 14:33:24 -04:00
Seth Foster
9f4172ce7b upstream 2021-06-08 14:33:23 -04:00
Seth Foster
ef56571772 controller_meta, templating 2021-06-08 14:33:23 -04:00
Seth Foster
6911a59f39 fix unit tests 2021-06-08 14:33:23 -04:00
Seth Foster
7a63785255 more rename, mostly in test 2021-06-08 14:33:23 -04:00
Seth Foster
a695274cb6 regex replace tower_*: to '' 2021-06-08 14:33:22 -04:00
Seth Foster
44fed1d7c1 pycharm refactor rename files and class, linux rename tower_ controller_ 2021-06-08 14:33:22 -04:00
nixocio
be48d3eefd Update advanced search for Smart Inventories
Update usage of conditional operators for advanced search for Smart Inventories

Not is not supported yet - See: https://github.com/ansible/awx/issues/2817

See: https://github.com/ansible/awx/issues/9232
2021-06-08 13:41:06 -04:00
mabashian
3cc6a4cf44 Go back to tracking currentlyLoading via state and not ref 2021-06-08 13:33:54 -04:00
mabashian
ddf4fbc4ce Fix linting errors 2021-06-08 13:33:54 -04:00
mabashian
f0e7f2dbcd Adds logic to try to keep visible page accurate in follow mode 2021-06-08 13:33:54 -04:00
Alan Rominger
579d49033a Remove debugging log message 2021-06-08 13:33:54 -04:00
Alan Rominger
210d5084f0 Move skip flag up from event_data and pop it off 2021-06-08 13:33:54 -04:00
Alan Rominger
53e8a9e709 Fix bug 2021-06-08 13:33:53 -04:00
Alan Rominger
15effd7ade Add some conditions for always-send and never-send event types
Always send websocket messages for
  high priority events like playbook_on_stats

Never send websocket messages for
  events with no output
  unless they are a high priority event type
2021-06-08 13:33:53 -04:00
Alan Rominger
b919befc90 Add option to record websocket received time 2021-06-08 13:33:53 -04:00
Jake McDermott
faded278e3 Disable follow mode on scroll 2021-06-08 13:33:53 -04:00
Jake McDermott
768ac01f58 Add basic output tailing
When follow mode is enabled, fix the scroll position to the highest row
so that the output panel is always displaying the latest events.
2021-06-08 13:33:53 -04:00
Alan Rominger
4052603238 make sure log format does not error 2021-06-08 13:33:53 -04:00
Alan Rominger
b306c6f258 Put new setting in defaults so unit tests will run 2021-06-08 13:33:52 -04:00
Alan Rominger
4b6b8f2bdd Finish up the immediate or average rate method 2021-06-08 13:33:52 -04:00
Alan Rominger
70420dc3e4 THIS DOES NOT WORK pass events if they fit either timing criteria 2021-06-08 13:33:52 -04:00
Alan Rominger
50ca2d47ce Further log adjustments 2021-06-08 13:33:52 -04:00
Alan Rominger
faa0a6cf9a fix up log wording 2021-06-08 13:33:52 -04:00
Alan Rominger
01228cea02 Implement max event websocket rate as setting 2021-06-08 13:33:50 -04:00
Alan Rominger
cbb461ab71 Fix bug 2021-06-08 13:33:23 -04:00
Alan Rominger
b551608f16 Move websocket skip logic into event_handler 2021-06-08 13:33:22 -04:00
Marliana Lara
7a25f22078 Remove i18n prop 2021-06-08 13:33:03 -04:00
Alan Rominger
b43d8e2c7f Enforce a 30-per-second max event websocket rate 2021-06-08 13:32:05 -04:00
softwarefactory-project-zuul[bot]
2ad84b60b3 Merge pull request #10381 from AlanCoding/tox_configish
Enter flake8 rules in tox config as actual config entries

I really like to do things like
flake8 awx/main/models

but this is made impractical where running flake8 for the project carries with it an assumption that you will pass a specific set of options.
https://flake8.pycqa.org/en/latest/user/configuration.html
Blessedly, flake8 is flexible in their config options so that it may weather the storm of python project config wars.

Reviewed-by: Jeff Bradberry <None>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-08 15:49:01 +00:00
Marliana Lara
d1981fcb4a Extend launched by details to handle scheduled JTs and WFJTs 2021-06-08 11:34:58 -04:00
softwarefactory-project-zuul[bot]
df8ce801cf Merge pull request #10325 from wenottingham/count-von-count
Add a field for hosts automated across to the subscription info

SUMMARY
This is populated by the new table we've added.
Update the subs check to check against this, not imported hosts.

ISSUE TYPE

Feature Pull Request
Bugfix Pull Request

COMPONENT NAME

API
UI

Reviewed-by: Bill Nottingham <None>
Reviewed-by: Amol Gautam <amol_gautam25@yahoo.co.in>
Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Chris Meyers <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-08 15:30:43 +00:00
nixocio
50e6348bef Do not show not as choice for Advanced Search on Smart Inventory
Do not show `not` as choice for Advanced Search on Smart Inventory since
this feature is not implemented on the API side yet.

See: https://github.com/ansible/awx/issues/2817
2021-06-08 11:17:01 -04:00
Alan Rominger
5ab449c90f Add event-specific template to all event types 2021-06-08 11:01:14 -04:00
softwarefactory-project-zuul[bot]
66a9ffc376 Merge pull request #10339 from mabashian/8596-websocket-connecting-state
Only attempt to reconnect socket if connection wasn't closed cleanly

SUMMARY
link #8596
After some investigation, I believe that this error is caused by the reconnect logic that we have.  When the component that references the ws hook unmounts, we disconnect the socket.  There's some logic in the onclose method that attempts to reconnect the socket but if we've disconnected cleanly we shouldn't try to reconnect (because we probably meant to disconnect in the first place).
This should clean up the console errors that we've been seeing about the socket already being in a connected state since we won't have timers running past the lifecycle of the component.
cc @keithjgrant does this sound good to you?
Here's the spec for the disconnect event https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#properties
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-08 14:36:41 +00:00
Alex Corey
16c6e2d716 uses pf date and time picker to schedule form 2021-06-08 10:32:38 -04:00
softwarefactory-project-zuul[bot]
ac5b53b13c Merge pull request #10334 from mabashian/outdated-revision
Adds ability to refresh project revision on sync'd rows in the project list

SUMMARY
This PR also adds the revision to the project details view as well as handles updating the revision on the project details view when the project is done syncing.
Since the project revision is not included in the websocket payload, when a project is done syncing the displayed revision may be out of date.  As such, we wanted to expose that information to the user and give them the ability to "refresh" and fetch the new revision.
Here's what that flow looks like:

When a particular row finishes syncing the user should see this in place of the revision:

Clicking on that refresh button goes out and fetches the updated project (and with it the potentially updated revision).
We don't do this automatically on the projects list (and force the user to click on the refresh button) is due to issues we've had in the past with the UI triggering API calls based on websocket events.
The flow when a user is on the project details view is a little different because I wasn't as worried about spamming the API with requests.
When a project finishes syncing and the user is viewing the details I do go ahead and automatically refresh the project data (and with it, the revision).  Here's what that looks like:

A few other notes:

@tiagodread @akus062381 @one-t I'm almost certain this is going to break some tests because I removed the ClipboardCopyButton in favor of PF's ClipboardCopy component.  This component looks and behaves slightly differently from our home grown solution.  Additionally, the PF ClipboardCopy button does not expose the ouiaId prop so I had to add a data-cy on that component.  You'll likely have to use that identifier to then grab the button inside in order to test out the clipboard copy functionality.
Source Control Revision is a net-new detail in the project details.  I think this was simply missed on our initial build of this page.

Here are the identifiers on the various bits:



Note that the identifiers on the project rows have the id of the project appended to them for uniqueness.
ISSUE TYPE

Feature Pull Request

COMPONENT NAME

UI

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Michael Abashian <None>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-08 14:14:54 +00:00
softwarefactory-project-zuul[bot]
6d433cc42a Merge pull request #10379 from jakemcdermott/fix-logout-reload2
Avoid reload on manual logout

SUMMARY
#10383
Instead of reloading, set the authRedirectTo context variable to "/logout" and handle it as a special case when routing

Reviewed-by: Marliana Lara <marliana.lara@gmail.com>
2021-06-08 13:58:14 +00:00
softwarefactory-project-zuul[bot]
7c442f3f50 Merge pull request #10359 from AlanCoding/stop_setting_venv
Remove uses of ansible_virtualenv_path

Run a job with recent AWX, then inspect:
In [2]: Job.objects.order_by('-created').first().custom_virtualenv
Out[2]: '/var/lib/awx/venv/ansible'

We shouldn't do this. The job was ran after the custom_virtualenv field has become entirely informative / non-functional. It is very arguable whether jobs should keep this field. For pre-migration jobs, it is an accurate record of fact, so I'm not going out of my way to argue for removal.
With this change, new jobs will record a blank value for custom_virtualenv, which is more correct, because we don't do this.
I have carefully looked over @rebeccahhh's #10090, and I don't see any way that ansible_virtualenv_path is used. Model use is reported for templates, so that doesn't block removing the field on jobs either.

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Rebeccah Hunter <rhunter@redhat.com>
Reviewed-by: Bill Nottingham <None>
Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-08 12:26:38 +00:00
Alan Rominger
d79f73ab7a Remove references to Ansible venv path because it does not exist 2021-06-07 21:14:35 -04:00
Alan Rominger
b26eaa3bd2 Remove uses of ansible_virtualenv_path 2021-06-07 21:14:35 -04:00
mabashian
de46fb409e Adds version context processor back in to fix api browser doc link 2021-06-07 19:52:01 -04:00
Keith J. Grant
8078daa733 convert InstanceList to table 2021-06-07 15:06:12 -07:00
softwarefactory-project-zuul[bot]
e4931bde6c Merge pull request #10346 from jakemcdermott/fix-9905
Disable cancel button on http 405

SUMMARY
for #9905
When a 405 is received, it means the job is already cancelled. Treat the
request as a success and don't show an error modal.
We disable the button to handle a rare scenario where we receive the 405 long before
the job status is properly updated to "cancelled" over websockets. We want to prevent
more cancel requests when this happens. We're disabling instead of hiding the button
because, assuming the status hasn't changed over sockets, the buttons that usually
replace the cancel button on the toolbar won't be shown yet and we don't want to
needlessly flicker and shift button positions around by rapidly loading and unloading
a different number of buttons onto the bar.

Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Sarah Akus <sarah.akus@gmail.com>
2021-06-07 21:25:05 +00:00
Elijah DeLee
e2b0a4f7a7 Make changed result accurate for credentials 2021-06-07 17:16:14 -04:00
Jake McDermott
5da6b02801 Avoid reload on manual logout 2021-06-07 16:51:06 -04:00
Elijah DeLee
326184da0f fixup changed behavior for EEso its accurate 2021-06-07 16:50:53 -04:00
Alan Rominger
dad5533816 Enter flake8 rules in tox config as actual config entries 2021-06-07 16:21:50 -04:00
Bill Nottingham
ca07946c24 Adjust subscription calculation & warning behavior
- Add a field for hosts automated across

  This is populated by the new table we've added.
- Update the subs check to check against this, not imported hosts.
- Reword messages on inventory import
2021-06-07 15:47:55 -04:00
Elijah DeLee
2ce276455a Break out control plane EE as its own thing 2021-06-07 15:39:20 -04:00
mabashian
4db6b8c1fe Rolls back aggressive find/replace on fetchProjects 2021-06-07 14:21:34 -04:00
mabashian
03209fe2f2 Updates onCopy functions to use navigator.clipboard instead of deprecated execCommand 2021-06-07 14:18:27 -04:00
softwarefactory-project-zuul[bot]
7832639c25 Merge pull request #10361 from nixocio/ui_issue_10355
Update message for missing EE for Job pages

Update message for missing EE for Job pages
See: #10355

Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Kersom <None>
Reviewed-by: Michael Abashian <None>
2021-06-07 18:18:15 +00:00
mabashian
121db42699 Fix data-cy 2021-06-07 13:33:08 -04:00
mabashian
ddb6c775b1 Adds dataCy to revision copy in project details 2021-06-07 13:33:07 -04:00
mabashian
7467779ea9 Remove clipboard copy button component 2021-06-07 13:33:07 -04:00
mabashian
66f140bb70 Adds ability to get latest revision from project list when a project is done syncing. Automatically refresh project data on project detail when it's done syncing. 2021-06-07 13:33:06 -04:00
mabashian
151f9e79ed Move debug message inside if statement so that it only triggers when we try to reconnect 2021-06-07 13:30:19 -04:00
mabashian
f83343592b Only attempt to reconnect socket if connection wasn't closed cleanly 2021-06-07 13:29:14 -04:00
mabashian
12504c9bc3 Changes settings revert all to send DELETE on individual endpoint rather than PATCHing 2021-06-07 13:19:16 -04:00
Shane McDonald
023cc68ba2 Surface default instance group names in /api/v2/settings/all 2021-06-07 12:22:58 -04:00
Shane McDonald
ec8ac6f1a7 Introduce distinct controlplane instance group 2021-06-07 11:25:59 -04:00
Yanis Guenane
82c4f6bb88 Define a DEFAULT_QUEUE_NAME 2021-06-07 11:25:23 -04:00
Alan Rominger
5beb68f527 Remove templates from views that were removed 2021-06-07 11:15:19 -04:00
Alan Rominger
2eb1e4bbe3 Add OPTIONS documentation for new job limit feature 2021-06-07 11:11:22 -04:00
Shane McDonald
d3b20e6585 Merge pull request #10362 from shanemcd/runner-alpha-5
Bump to Ansible Runner alpha 5 release
2021-06-04 16:51:19 -04:00
nixocio
310cc2fd03 Update message for missing EE for Job pages
Update message for missing EE for Job pages

See: https://github.com/ansible/awx/issues/10355
2021-06-04 16:04:39 -04:00
softwarefactory-project-zuul[bot]
1fd6ba0bfc Merge pull request #10349 from AlexSCorey/8401-MoreFiltersonDashboard
Adds more filters to dashboard chart

SUMMARY
Resolves #8401 and #10356
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

AWX VERSION



ADDITIONAL INFORMATION

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-04 19:56:10 +00:00
softwarefactory-project-zuul[bot]
b64f966db1 Merge pull request #10090 from rebeccahhh/custom_venv_command
add a new awx-manage command `custom_venvs`

add an awx-manage command that gets pip freeze data from custom_venv and outputs to command line stdout
SUMMARY

part of #7062  - this command is a glorified pip freeze + some extra stuff, people could navigate to each of their custom virtual environments themselves and run a pip freeze, but this allows them to not, and everyone likes their life to be easier. The extra stuff allows users to see the connections that their existing virtual envs have in awx to things like organizations, jobs, inventory updates, and projects.

ISSUE TYPE


Feature Pull Request

COMPONENT NAME


API

AWX VERSION

awx: 19.1.0

ADDITIONAL INFORMATION

This is built off of existing code and there is a line that gets custom venv paths from the settings module, that line does not seem to be working. I have written around that but want to make a note of it.

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Rebeccah Hunter <rhunter@redhat.com>
Reviewed-by: Jeff Bradberry <None>
Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Elijah DeLee <kdelee@redhat.com>
2021-06-04 18:44:52 +00:00
softwarefactory-project-zuul[bot]
891eeb22a5 Merge pull request #10343 from chrismeyersfsu/doc-job_event_performance
add docs on debugging job event perf

related to ansible/tower#4985

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Bianca Henderson <beeankha@gmail.com>
2021-06-04 17:17:16 +00:00
softwarefactory-project-zuul[bot]
0f6e221c14 Merge pull request #10023 from ansible/db_partition_analytics_cmeyers2
Db partition analytics cmeyers2

Keep old primary key based analytics gathering for unpartitioned
tables.
Use created time on new partitioned tables.

80 million partitioned + 1.5 million unpartitioned Events



Query
awx-manage gather_analytics --dry-run Time
Micro Benchmark Query Time*
Query Only Time**




sequential index scan, multiple ::json casts, 100,000 event batches
102m7.836s
6s
80 minutes


sequential index scan, optimized json cast, 100,000 event batches
48m9.276s
2.2s
30.4 minutes


sequential index scan, optimized json cast, 1,00,000 event batches
39m35.094s
10s
13.3 minutes


sequential table scan, optimized json cast, per-partition batch 600,000 ***
36m42.081s
11.5s
25.5 minutes



*micro benchmarking consists of simply copying a query, running it manually, and observing the runtime.
**micro benchmark time x (80 million / batch size)
**Note that this testing does NOT include the extra modified range query that is needed for correctness. We expect this to be quite fast and is only needed to catch edge case events.

Reviewed-by: Ladislav Smola <lsmola@redhat.com>
Reviewed-by: Elijah DeLee <kdelee@redhat.com>
2021-06-04 16:48:11 +00:00
Shane McDonald
239f20ede5 Bump to Ansible Runner alpha 5 release 2021-06-04 12:22:53 -04:00
Chris Meyers
ffbbcd2bf6 fix tests, add pagination tests
* job_created is a fake field as far as Django is concerned. Under the
hood, in postgres, this is the partition key so it is real. sqlite
doesn't support partitioning so we need to fake some things.
Specifically, we need to remove job_created from being auto-added to
get_event_queryset()
* Add pagination tests for <unified_job_name>/<id>/<job_events>?limit=x
endpoint to make sure the paginator is wired up.
2021-06-04 09:17:09 -07:00
Jake McDermott
b648957c8e Update pagination scheme for jobs
* Use an initial request for max event `counter` to get the total row count,
otherwise rely on websocket message counters to update remote row count

* For running jobs, request event ranges with counters to handle events getting
saved to db out of display order

* For jobs that are no longer running, continue to use page/pageSize scheme for
paging through the job events
2021-06-04 09:17:09 -07:00
Jim Ladd
31fe500921 move get_queryset handling to child view 2021-06-04 09:17:09 -07:00
Chris Meyers
2131703ca0 add/remove indexes, more get_event_querset()
* Do not cascade delete unified job events. We will clean those up in
cleanup_job runs
* Add limit pagination to all unified job events endpoints
2021-06-04 09:17:09 -07:00
Jim Ladd
c429563126 update view to handle hosts/N/ad_hoc_command_events 2021-06-04 09:17:09 -07:00
Chris Meyers
1a1d66d2a2 bump db partition migration 2021-06-04 09:17:09 -07:00
Chris Meyers
30871bd6cf close db and cache connection in new threads 2021-06-04 09:17:09 -07:00
Chris Meyers
321135da3d add limit pagination to jobs/<id>/job_events/
* trigger via jobs/<id>/job_events/?limit=10
* Can and should be used in conjunction with an indexed set of fields to
generate efficient pagination queries. i.e.
jobs/<id>/job_events?limit=10&start_line__gte=10
* If limit is not specified in the query params then the default
pagination will be used.
2021-06-04 09:17:09 -07:00
Jim Ladd
2a23b4c719 bump migration 2021-06-04 09:17:09 -07:00
Jim Ladd
f7d2f7a5e6 lint 2021-06-04 09:17:09 -07:00
Jim Ladd
e371de38ed update job cleanup tests for sqlite-based execution 2021-06-04 09:17:09 -07:00
Jim Ladd
84af610a1f remove rebase cruft 2021-06-04 09:17:09 -07:00
Jim Ladd
ef9f9129ba bump migration 2021-06-04 09:17:09 -07:00
Jim Ladd
7b188aafea lint 2021-06-04 09:17:09 -07:00
Chris Meyers
6ce227a6b6 bump migrations 2021-06-04 09:17:09 -07:00
Chris Meyers
1c97b9a046 no longer get the size of the gather set
* Before, we would get the min and max pk of the set we are to gather.
This changeset removes that.
* Before, we would, basically, know the size of the set we are to gather
and would query 100,000 of those job event records at a time. That logic
is now gone.
* Now, for unpartitioned job events we gather 4 hours at a time by
created time.
* Now, for partitioned job events we gather 4 hours at a time by
modified time.
2021-06-04 09:17:09 -07:00
Chris Meyers
137111351c bump migrations after devel rebase 2021-06-04 09:17:09 -07:00
Chris Meyers
c5a1e4c704 remove order by from partitioned events query
* The order by results in an in-memory sort that COULD blow out the
worker mem buffer and result in sorting having to take place on disk.
* This WILL happen with a default postgres 4MB mem buffer. We saw as
much as 20MB used. Note that AWX defaults postgres mem worker buffer to
3% of the DB memory on external installs and 1% on same-node installs.
So for a 16GB remote DB this would not be a problem.
* We are going to avoid this problem all together by NOT doing a sort
when gathering. Instead, we will sort remotely, in analytics.
2021-06-04 09:17:09 -07:00
Chris Meyers
4f058245e4 conditionally project job_created
* Old, _unpartitioned_main_jobevent table does not have the job_created
column
* New, main_jobevent does.
* Always in clude the job_created column. NULL if old, job_created if
new
* Bump events_table schema version from 1.2 to 1.3 because of the
job_created field
2021-06-04 09:17:08 -07:00
Chris Meyers
ecdf6cccf8 json cast optimization
* We found that having multiple `::json` casts in a query slows down
queries more and more by =~> 33%.
* This change coerces postgres into only casting once. Micro
benchmarking shows =~ 2-3x performance boost
2021-06-04 09:17:08 -07:00
Chris Meyers
4d7edbbad0 analytics support for db partitions
* Keep old primary key based analytics gathering for unpartitioned
tables.
* Use created time on new partitioned tables.
2021-06-04 09:17:08 -07:00
Jim Ladd
0f9f3f58e2 bump migration 2021-06-04 09:17:08 -07:00
Chris Meyers
34c4967d27 Revert "query for jobevents based on table location"
This reverts commit 278dc521fffb85d4faa023ccd634044cfd3b3d75.
2021-06-04 09:17:08 -07:00
Jim Ladd
6123b8e148 query for jobevents based on table location
* pre-migration jobevents live in unpartitioned table
  where only created field has index
* post-migration jobevents live in partitions
  where modified field has index
  (and should be used to ensure no events are missing)
2021-06-04 09:17:08 -07:00
Jim Ladd
b86d365dde collect job events based on job event modified time
* when collecting job events by creation time
  it is possible to miss events that were created
  at one point, but actually committed to the db
  much later.
* since events' modified time is set when they are
  committed to the db, we shouldn't miss any job events
* selecting job events by modified time wasn't possible
  beforehand because we didn't have an index for
  jobevent's modified field
2021-06-04 09:17:08 -07:00
Chris Meyers
4efbd45b3c add support for db partition in cleanup_jobs
Changes in old unpartitioned cleanup logic:
* Manually cascade delete events related to job(s)

(new partitions cleanup logic) For each event type:
* Get the event partitions that are within the cleanup date range
* Get a list of jobs to delete that are in the cutoff range.
* Jobs that are running, pending, or waiting in the job list are special.
* Use the special list to further filter the partition drop list.
* Drop partitions
* delete jobs
2021-06-04 09:17:08 -07:00
Jim Ladd
fb97687d14 lint 2021-06-04 09:17:08 -07:00
Jim Ladd
0f53d9b911 bump db partition migration 2021-06-04 09:17:08 -07:00
Jim Ladd
5a785798b0 is_partitioned should default to true when pk not set 2021-06-04 09:17:08 -07:00
Jim Ladd
14168297bd set event horizon to -1 for empty tables 2021-06-04 09:17:08 -07:00
Jim Ladd
7e1814e234 mock has_unpartitioned_events in collection tests
.. just like we do with the main awx tests
2021-06-04 09:17:08 -07:00
Jim Ladd
bdf11aa962 add migrations for Unpartitioned{Job}Event proxy models 2021-06-04 09:17:08 -07:00
Jim Ladd
46807205f8 Move created kwargs to right place 2021-06-04 09:17:08 -07:00
Jim Ladd
d749c172eb Ensure View.model exists before checking type 2021-06-04 09:17:08 -07:00
Jim Ladd
81db8091ea test updates
* when tests create a UnifiedJob and JobEvent,
  the two need to have the same value for job creation time
* some view validation was skipped due to `model` being
  a property in some cases now
2021-06-04 09:17:08 -07:00
Jim Ladd
5c1a33382c update mocks to reflect new migration
* instead of mocking `created_or_epoch` (which no longer exists)
* .. mock `Unified_Job.has_unpartitioned_events`
2021-06-04 09:17:08 -07:00
Jim Ladd
db6f565dca black formatting 2021-06-04 09:17:08 -07:00
Jim Ladd
6b4effc85a bump partition migration to 135 2021-06-04 09:17:08 -07:00
Jim Ladd
74a0c5bac5 Minor rebase fallout
* fix import
* remove dropped url
2021-06-04 09:17:08 -07:00
Jim Ladd
661cf0afb3 short-circuit event_processing_finished for wf jobs
* wf jobs are a wrapper for other jobs
* they do not process their own job events
2021-06-04 09:17:08 -07:00
Ryan Petrello
fbb74a9896 remove code that leaves behind old bigint tables on fresh installs
we don't need this code at all anymore - the bigint migration is long
gone, and anybody upgrading to this version of AWX has already
migrated their data
2021-06-04 09:17:08 -07:00
Ryan Petrello
200901e53b upgrade to partitions without a costly bulk data migration
keep pre-upgrade events in an old table (instead of a partition)

- instead of creating a default partition, keep all events in special
"unpartitioned" tables
- track these tables via distinct proxy=true models
- when generating the queryset for a UnifiedJob's events, look at the
  creation date of the job; if it's before the date of the migration,
  query on the old unpartitioned table, otherwise use the more modern table
  that provides auto-partitioning
2021-06-04 09:17:08 -07:00
Jim Ladd
0eddd5ce7f Enable partition pruning when fetching job's events 2021-06-04 09:17:07 -07:00
Jim Ladd
a7cabec3d0 bump partition migration to 0132 2021-06-04 09:17:07 -07:00
Jim Ladd
b98b3ced1c update tests to reflect new job_event schema 2021-06-04 09:17:07 -07:00
Jim Ladd
8501a45531 lint fixes 2021-06-04 09:17:07 -07:00
Jim Ladd
14b610dabf bump partition migration 2021-06-04 09:17:07 -07:00
Jim Ladd
a1d1e70e43 correct constraint name 2021-06-04 09:17:07 -07:00
Jim Ladd
0fa0a517ac create tmp schema to reference when creating partitioned table
* if we use the actual old job events table
  and make tweaks to its schema
  namely, dropping the pkey constraint,
  then when we go to migrate the old job events
  we will be forcing postgres to do a sequential scan
  on the old table, which effectively causes the migration to hang
2021-06-04 09:17:07 -07:00
Jim Ladd
28f9c0be0b Do not cascade delete job_events
* want to drop job_event _partitions_
  .. instead of having the job events associated with a job
     automatically get cleaned up for us
2021-06-04 09:17:07 -07:00
Jim Ladd
373edbf8c0 Update reference to partition migration 2021-06-04 09:17:07 -07:00
Ryan Petrello
b19bcdd882 remove the global /api/v2/job_events/ endpoint 2021-06-04 09:17:07 -07:00
Ryan Petrello
08b96a0bd7 correct filter events on the migration event horizon
events that existed *prior* to the partition migration will have
`job_created=1970-01-01` auto-applied at migration time; as such,
queries for these events e.g., /api/v2/job/N/job_events/
use 1970-01-01 in related event searche

events created *after* the partition migration (net-new playbook runs
will have `job_created` values that *exactly match* the related
`UnifiedJob.created` field.
2021-06-04 09:17:07 -07:00
Jim Ladd
1e45e2ab9b Rev migration number 2021-06-04 09:17:07 -07:00
Ryan Petrello
2a58605727 some more events view cleanup 2021-06-04 09:17:07 -07:00
Ryan Petrello
c7ab3ea86e move the partition data migration to be a post-upgrade async process
this copies the approach we took with the bigint migration
2021-06-04 09:17:07 -07:00
Jim Ladd
67046513ae Push changes before rebasing 2021-06-04 09:17:07 -07:00
Jim Ladd
f9b439ae82 include job_created field in all job event types 2021-06-04 09:17:07 -07:00
Jim Ladd
80b08d17e3 Continue updating job event views 2021-06-04 09:17:07 -07:00
Jim Ladd
f642c520bd Update fields for job event models to match raw sql operations
* raw sql commands were in migration to partition table
* .. just needed to add FakeAddField entries for the new
     job_created field added to each job event model
* .. and also needed to actually list the new field on the model classes
2021-06-04 09:17:07 -07:00
Jim Ladd
221ddeb915 Fix migration for _all_ job event tables
- each job event table has a different name for the
  fk referencing the unified job id
- create a mapping so that we get the col name correct
  for each table
2021-06-04 09:17:07 -07:00
Jim Ladd
d90d0fb503 fix initial partition creation
* call create_partition correctly (include tblname)
* reference 'awx_epoch'
2021-06-04 09:17:07 -07:00
Jim Ladd
2c529f50af Update querysets for remaining job event views
- search should use job creation date
  so that only the table partition with the relevant job events
  is searched
2021-06-04 09:17:07 -07:00
Jim Ladd
acfa1c4d1d Drop todo / question / conditional
* can safely assume job_created is set
* .. and if it isn't, we want to expose that bug
2021-06-04 09:17:07 -07:00
Jim Ladd
ea2afeec1f Drop todo / answered question 2021-06-04 09:17:07 -07:00
Jim Ladd
a5cfc3036f create_partition needs tblname 2021-06-04 09:17:07 -07:00
Jim Ladd
ec484f81cf Partition *all* job event tables 2021-06-04 09:17:06 -07:00
Jim Ladd
2ffa22e38f Misc doc clean-up 2021-06-04 09:17:06 -07:00
Jim Ladd
8fb313638c get job events based on job creation date 2021-06-04 09:17:06 -07:00
Jim Ladd
0eb1984b22 Only create partitions for regular jobs 2021-06-04 09:17:06 -07:00
Jim Ladd
f259b0a71b Move partition start date to 2000 2021-06-04 09:17:06 -07:00
Jim Ladd
82df3ebddb add option to create partitions that span a single minute
* turned on by default currently for testing
2021-06-04 09:17:06 -07:00
Jim Ladd
c87d7b0d79 fix import 2021-06-04 09:17:06 -07:00
Jim Ladd
612e91263c auto-create partition 2021-06-04 09:17:06 -07:00
Jim Ladd
445042c0f4 Create partition only if it doesn't exist 2021-06-04 09:17:06 -07:00
Jim Ladd
0c289205de Give new primary key constraint unique name, create first live partition 2021-06-04 09:17:06 -07:00
Jim Ladd
ba45592d93 create helper method to create partitions
* create_partition()
2021-06-04 09:17:06 -07:00
Jim Ladd
7e0f2b0f08 first partition is _not_ a special case after all 2021-06-04 09:17:06 -07:00
Jim Ladd
fb30528197 Dynamically create initial partitions
* First partition holds all events up to this very moment
* And second partition starts where first left off and runs
  .. through rest of current hour
* From there, dynamically generated partitions will cover
  one hour at a time
2021-06-04 09:17:06 -07:00
Jim Ladd
48f1910075 Remove temporary catch-all partition 2021-06-04 09:17:06 -07:00
Jim Ladd
0cb2d79889 Only save job_created field on JobEvent for the time being
* Once other job event tables are migrated, remove this
2021-06-04 09:17:06 -07:00
Jim Ladd
1af1a5e9da Convert job_created to string for serialization 2021-06-04 09:17:06 -07:00
Jim Ladd
c0d38e91f5 When saving JobEvents, include job_created
* this is the partition key
* .. used to determine which partition job event rows are sent to
2021-06-04 09:17:06 -07:00
Jim Ladd
2f737f644f Drop primary key index before creating partition table
* Partition tables require unique contstraints to include the
  partition key (uniqueness can only be enforced _inside_
  of a given partition table)
2021-06-04 09:17:06 -07:00
Jim Ladd
0574baf7f7 Create fake partition
* Just to get things working
* Will implement dynamic creation of partitions later
2021-06-04 09:17:06 -07:00
Jim Ladd
f70473dc0b When copying main_jobevent, include all table metadata
* copy the table just like we do in the bigint migration
* without this we lose sequences and very likely other things
  as well
* we want the new table to be identical to the old table,
  so 'including all' makes sense
2021-06-04 09:17:06 -07:00
Jim Ladd
de0b25862b By default, save job_created as null in db
* Want to avoid saving date as empty string
* Should default to null so that it's obvious the field is empty
2021-06-04 09:17:06 -07:00
Jim Ladd
6ff15a928a Register new column created by SQL
* .. using FakeAddField model type
* .. without doing this, Django won't know
     about the field we created using raw SQL
2021-06-04 09:17:06 -07:00
Jim Ladd
d10d1963c1 Rename / remove old main_jobevent table 2021-06-04 09:17:06 -07:00
Jim Ladd
c6acca08d5 first draft of db partitioning 2021-06-04 09:17:06 -07:00
Chris Meyers
9946959599 clarify reference to code to be pasted 2021-06-04 12:10:10 -04:00
Chris Meyers
9ce171d349 Merge pull request #8 from beeankha/doc_edits
Doc Edits
2021-06-04 11:12:47 -04:00
softwarefactory-project-zuul[bot]
12f2975809 Merge pull request #10358 from jakemcdermott/fix-credlink
Make IG credential linkable

SUMMARY
Make the instance group credential detail link to the cred

Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-04 15:12:03 +00:00
softwarefactory-project-zuul[bot]
945125454b Merge pull request #10357 from jakemcdermott/fix-inventory-host-search-config
Add search config for inventory hosts

SUMMARY
Adds search config for inventory hosts.
(includes default icontains, etc.)

Reviewed-by: Kersom <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-04 15:05:25 +00:00
softwarefactory-project-zuul[bot]
ea67c70437 Merge pull request #10257 from mabashian/6073-typeahead-lookup
Adds support for typing values into single select lookups

SUMMARY
link #6073
This adds support for typing values into single select lookups.  Multi-select lookups (credentials on the JT form, instance groups, etc) will remain unchanged.
An input is now rendered next to the lookup button which will allow users to type a value in.
Here's the button (which opens the modal):

Here's the input (which lets users type a value in):

There's a debounce on the input so that we only make a request to check to see if the name is valid after a second of no typing.
The tricky part of this implementation was handling validation on the lookup fields.  If a user types in a string that does not exactly match a value that they can use then we want to show an error indicating that no matching value was found:

but this was tricky because some of these fields are required so the validation functions would need to change a bit.
Since the typed text and the actual underlying value of the lookup are different the validation function would need to have access to both values whenever it runs for this to work.  This meant either storing the typed text up at the form level or pushing the validation down into the lookup(s).  After talking with @keithjgrant we decided to go down the route of pushing the validation down to the lookups.
You can now pass an optional validation function down to the various lookups that will get combined with the typeahead validation via the useField hook.
Here's the whole thing in action:

ISSUE TYPE

Feature Pull Request

COMPONENT NAME

UI

Reviewed-by: Kersom <None>
Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Michael Abashian <None>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-04 15:03:53 +00:00
beeankha
f2f2483708 Doc edits 2021-06-04 11:01:06 -04:00
Alex Corey
8c61a49e01 prevents dashboard counts from reloading with line chart filters change 2021-06-04 10:55:40 -04:00
Jake McDermott
88ff68295b Make IG credential linkable 2021-06-04 10:27:14 -04:00
Jake McDermott
d93f62c030 Add search config for inventory hosts 2021-06-04 09:51:43 -04:00
Chris Meyers
ae5b11a2a9 add docs on debugging job event perf 2021-06-04 09:12:23 -04:00
Rebeccah
baade775ab remove changes to root.py to keep the custom virtualenvs listed in api/config 2021-06-04 09:11:23 -04:00
Rebeccah
bd2da80cea restructure so the -q is actually completely quiet 2021-06-04 09:11:22 -04:00
Rebeccah
550ab82f63 add the conditionals for incorrect paths and helpful info for if a user does that
and remove unused import
2021-06-04 09:11:22 -04:00
Rebeccah
cece7ff741 add a -q flag to make scripting easier and general improvements for readability 2021-06-04 09:11:22 -04:00
Rebeccah
c0b812c47a split unified job templates out into jts and projects because workflows
don't have custom virtualenvs & rename file so the command is shorter

update copypasta and add sanity check
2021-06-04 09:11:22 -04:00
Rebeccah
b256e5b79d adding in a 3rd command that shows the associated templates, orgs, and invs the venv is tied to 2021-06-04 09:11:22 -04:00
Rebeccah
2ed3038a5c fixed what would be a rather embarrassing misspeeeling 2021-06-04 09:11:21 -04:00
Rebeccah
779ca8b260 split the one command into two for clarity and remove unused imports 2021-06-04 09:11:21 -04:00
Shane McDonald
137fedfc9b Rename custom venv export command and add usability tweaks
- Uses a positional argument instead of a named arg
- More helpful output
2021-06-04 09:11:21 -04:00
Shane McDonald
256a47618f Ignore awx venv
- General usability / readibility improvements
2021-06-04 09:11:20 -04:00
Rebeccah
dfaa69be51 add an awx-manage command that gets pip freeze data from custom_venvs and outputs to command line stdout
remove analytics tests for counts of custom venvs, bump collector version, and remove list of custom venvs from API
2021-06-04 09:11:16 -04:00
softwarefactory-project-zuul[bot]
c34fa30ea7 Merge pull request #10342 from mabashian/10338-checkbox-double-select
Fixes bug where checkbox list item was selecting things twice

SUMMARY
Resolves #10338
There was a click event on the row and the underlying checkbox.  I got rid of the underlying click event so now its only handled at the row level.

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-03 21:37:05 +00:00
softwarefactory-project-zuul[bot]
3e5ee9d57a Merge pull request #10322 from jbradberry/show-ee-resolver
Expose the EE resolver to the API

SUMMARY
This change exposes the output of .resolve_execution_environment() for job templates as a new summary field in the API.  Note that this is only exposed for the detail views, not the list views.  Also, there is the caveat for job templates that may be run under workflows that the workflow EE might override the results of this value.
related #10210
ISSUE TYPE

Feature Pull Request

COMPONENT NAME


API

AWX VERSION

Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
Reviewed-by: Chris Meyers <None>
Reviewed-by: Jeff Bradberry <None>
2021-06-03 21:11:33 +00:00
softwarefactory-project-zuul[bot]
c7dd3996df Merge pull request #10351 from AlanCoding/sliced_ee
Skip sliced jobs from the workflow EE logic

Addressing some unanticipated fallout from #10305
Sliced jobs rely on creating a workflow job, but they do not have a workflow_job_template, so in those cases, that was causing a traceback.
2021-06-03 20:10:52,319 ERROR    [a17ebd7f] awx.main.dispatch Worker failed to run task awx.main.tasks.RunJob(*[341], **{}
Traceback (most recent call last):
  File "/awx_devel/awx/main/dispatch/worker/task.py", line 90, in perform_work
    result = self.run_callable(body)
  File "/awx_devel/awx/main/dispatch/worker/task.py", line 65, in run_callable
    return _call(*args, **kwargs)
  File "/awx_devel/awx/main/tasks.py", line 759, in _wrapped
    return f(self, *args, **kwargs)
  File "/awx_devel/awx/main/tasks.py", line 1264, in run
    self.instance = self.update_model(self.instance.pk, execution_environment=self.instance.resolve_execution_environment())
  File "/awx_devel/awx/main/models/mixins.py", line 477, in resolve_execution_environment
    if wf_template.execution_environment is not None:
AttributeError: 'NoneType' object has no attribute 'execution_environment'

that is fixed with this, at least for my one simple test case
This left jobs hanging out in "waiting" status, which is really not good.

Reviewed-by: Jeff Bradberry <None>
2021-06-03 21:02:01 +00:00
softwarefactory-project-zuul[bot]
e342919735 Merge pull request #10323 from wenottingham/look-over-there
Add additional controller directory for collections for inventory update

SUMMARY
This may be present in some scenarios with additional collections for inventory usage.

Reviewed-by: Alan Rominger <arominge@redhat.com>
2021-06-03 20:42:04 +00:00
Jeff Bradberry
d0991bab9e Expose the EE resolver to the job template detail API endpoints 2021-06-03 16:35:50 -04:00
Alan Rominger
efcbea1fc5 Skip sliced jobs from the workflow EE logic 2021-06-03 16:20:47 -04:00
Alex Corey
1537b84ec8 adds more filters to dashboard chart 2021-06-03 15:31:43 -04:00
softwarefactory-project-zuul[bot]
30b7535ca2 Merge pull request #10348 from rooftopcellist/container_groups_error
Fix error msg wording and sdb docs

SUMMARY

Fixes wording in container groups error message
Updates ports for sdb debugging docs

ISSUE TYPE


Bugfix Pull Request

COMPONENT NAME


API

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-03 19:02:34 +00:00
Christian M. Adams
fe02c0b157 Fix error msg wording and sdb docs 2021-06-03 14:24:18 -04:00
mabashian
177901eca6 Adds assertion to ensure that only one chip is shown when a checkbox list item is selected 2021-06-03 14:01:04 -04:00
mabashian
c2c93e7a66 Fix unit test failures 2021-06-03 13:50:26 -04:00
Bill Nottingham
00e60d2698 Add additional controller directory for collections for inventory update 2021-06-03 13:26:23 -04:00
Jake McDermott
ec1408fbd1 Disable cancel button on http 405
When a 405 is received, it means the job is already cancelled. Treat the
request as a success and don't show an error modal.

We disable the button to handle a rare scenario where we receive the 405 long before
the job status is properly updated to "cancelled" over websockets. We want to prevent
more cancel requests when this happens. We're disabling instead of hiding the button
because, assuming the status hasn't changed over sockets, the buttons that usually
replace the cancel button on the toolbar won't be shown yet and we don't want to
needlessly flicker and shift button positions around by rapidly loading and unloading
a different number of buttons onto the bar.
2021-06-03 13:02:03 -04:00
softwarefactory-project-zuul[bot]
23c3e62211 Merge pull request #10345 from sarabrajsingh/bugfix/bump-ansible-runner-version
updated ansible-runner version from 2.0.0a2 -> 2.0.0a4 in requirement…

SUMMARY
version bump (ansible-runner 2.0.0a2 -> 2.0.0a4)
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

API

AWX VERSION

awx: 19.2.0

Reviewed-by: Shane McDonald <me@shanemcd.com>
2021-06-03 16:49:38 +00:00
Sarabraj Singh
383c2bba58 updated ansible-runner version from 2.0.0a2 -> 2.0.0a4 in requirements files 2021-06-03 11:53:57 -04:00
softwarefactory-project-zuul[bot]
8adb53b5a8 Merge pull request #10292 from mabashian/8824-role-modal
Fixes bug where user/team role add modal state is not cleared on close

SUMMARY
link #8824
I modeled these changes after the pattern that existed between ResourceAccessList and AddResourceRole.  The key to fixing this bug is that the component that renders the wizard needs to be unmounted when the wizard closes so that the state, etc get cleared out before the next time the wizard is opened.  In order to achieve that I needed to decouple the add button from the wizard.
The sort of weird part of this pattern (and this exists in the ResourceAccessList as well) is error handling.  We pass the error back and set that to state before rendering the modal which isn't quite as clean as having the request made out at the list level and leveraging our hooks for error handling but I decided to just get in and get out and not worry about trying to refactor too much.
Here it is in action:

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Kersom <None>
2021-06-03 15:52:40 +00:00
softwarefactory-project-zuul[bot]
92401e5328 Merge pull request #10301 from kdelee/unqualified_images
Force fully qualified image names

If we try and pull an unqualified image name, jobs hang on a podman
prompt.
I set the permissions as 644 because thats what worked for me because rootless podman needs to be able to read the file, but maybe there is another way to achieve that

Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
2021-06-03 15:45:24 +00:00
softwarefactory-project-zuul[bot]
d360fb212e Merge pull request #10258 from kdelee/ee_singular_awx_cli
allow singular execution_environment for cli

this makes "execution_environments" or "execution_environment" work
which is helpful
Now these both work:
awx execution_environments create --name foobar --image quay.io/ansible/awx-ee:latest

awx execution_environment create --name foobar1 --image quay.io/ansible/awx-ee:latest

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
Reviewed-by: Jeff Bradberry <None>
2021-06-03 14:11:27 +00:00
mabashian
4c1b0297e7 Fixes bug where checkbox list item was selecting things twice 2021-06-03 09:48:20 -04:00
softwarefactory-project-zuul[bot]
a0b14b994d Merge pull request #8763 from wenottingham/licenses-to-kill
Restore UI license checker

27219d3 removed the license checker for UI dependencies as part of removing the UI. We actually still need it, just pointed at the new UI.
This brings it back, and updates it to do so. It also removes no longer needed license files.
It doesn't pass yet, as I haven't added licenses for the new UI dependencies in this PR. Hi @jakemcdermott.

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-02 23:48:52 +00:00
softwarefactory-project-zuul[bot]
168c022d3e Merge pull request #10329 from keithjgrant/6853-select-all-quirks
Clear list selections on pagination/search/sort

SUMMARY
Updates nearly every list* so that URL param changes (pagination, search, or sort) clear the selection. This prevents the list of selected items in state from including items that may no longer appear on screen — preventing the user from accidentally deleting or otherwise altering an item they may not realize they still have selected.
This also updates the useSelected hook to provide selectAll and clearSelected functions. Any lists that weren't yet already using this hook have been updated to do so.
Addresses #6853 and #7509
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

ADDITIONAL INFORMATION
*Lists that do not include this change are modals where the user is expected to paginate through screens and make several selections along the way (e.g. Multi Credential select modal), and lists that still use PaginatedDataList and are yet to be converted to PaginatedTable
Note: I originally wanted to make the clearSelected prop on PaginatedTable required, so any lists that don't have this fix applied would fail loudly. Unfortunately that wasn't possible, as there were a few lists that should not have this behavior, so I had to leave it as an optional prop.

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-02 23:11:41 +00:00
Shane McDonald
5adfacba64 Merge pull request #10321 from kdelee/management_cmd_ee_creds
Create default EE in seperate awx-managment cmd
2021-06-02 18:37:52 -04:00
Shane McDonald
52eeace20f Register default EEs when booting dev env 2021-06-02 18:19:41 -04:00
Keith J. Grant
21ff1d714d add useSelected tests for new functions 2021-06-02 14:48:53 -07:00
Keith J. Grant
eeca5512be update remaining lists to clear selection on pagination/search/sort 2021-06-02 14:41:20 -07:00
Keith J. Grant
143a4a61b3 clear list selection on navigate (first batch) 2021-06-02 14:41:20 -07:00
softwarefactory-project-zuul[bot]
fef24355ab Merge pull request #9908 from marshmalien/session-work
Add Session context and redirects

SUMMARY
Issues:
#8272 #9197 #8155 #9311

When user is logged out due to inactivity, redirect to the Login Page with a warning alert stating that their session expired.
When a user logs in on one tab, redirect from login page to home on the other tabs.
Clear session state when it expires and/or when a user logs out.
Redirect users to direct link destination after authentication

@AlexSCorey is looking at possibly rolling #9915 (SSO login redirect override URL is not working) into this PR
ISSUE TYPE


Feature Pull Request

COMPONENT NAME


UI

Reviewed-by: Kersom <None>
Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
Reviewed-by: Marliana Lara <marliana.lara@gmail.com>
Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
2021-06-02 21:17:47 +00:00
softwarefactory-project-zuul[bot]
d70dfec6b6 Merge pull request #10215 from keithjgrant/9218-sort-in-modal
fix namespaced url params

SUMMARY
Fixes issues when multiple lists are on the page (generally only occurs now when on a list page with an open modal that contains a second list) — Navigating within the modal list currently wipes out URL parameters for the main list, causing the page to reload, which closes the modal. The fix prevents changes to one set of namespaced URL parameters from wiping out URL parameters from another namespace

Refactors query string utils to consolidate a lot of repeated logic from components into a new util, updateQueryString. Use this function to modify query string parameters while maintaining params for multiple namespaces at the same time.
QS utils that are no longer needed have been deleted: replaceParams and encodeNonDefaultQueryString

Addresses #10181 and #9218
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Keith Grant <keithjgrant@gmail.com>
Reviewed-by: John Mitchell <None>
Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
2021-06-02 21:01:49 +00:00
softwarefactory-project-zuul[bot]
49eccfb19f Merge pull request #10335 from mabashian/10129-multi-choice-survey
Properly validate multiple choice survey questions

SUMMARY
link #10129
In action:

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

UI

Reviewed-by: Kersom <None>
2021-06-02 20:41:20 +00:00
Shane McDonald
223c5bdaf6 Tweaks to register_default_execution_environments command
- The credential will always be updated. I dont think we want to decrypt the password here for comparison
- Preserve newlines in help text
2021-06-02 16:26:58 -04:00
Elijah DeLee
e740cfcb52 revert change to serializer and use get_or_create
still need to fix up the handling of the verify-ssl bool, since
it is not being respected
2021-06-02 16:16:36 -04:00
softwarefactory-project-zuul[bot]
65b03174ea Merge pull request #10304 from akus062381/add-ouia-to-yaml-jason-buttons
Adds ouiaId to YAML and JSON buttons in Variables Detail

small change to add a better locator to these buttons. if we do not do this, our locators for our visual tests are not good and will eventually break tests

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
2021-06-02 19:51:31 +00:00
mabashian
134d84ded9 Adds unique ouiaId to MultiButtonToggle 2021-06-02 14:48:37 -04:00
akus062381
5707d65d0f fix 2021-06-02 14:48:10 -04:00
akus062381
9956538224 yay 2021-06-02 14:48:10 -04:00
Elijah DeLee
7818b2008f Allow modifications of managed_by_tower creds
Sysadmins may need to modify managed_by_tower credentials, the
only known case of which is a default container registry credential
for use by the default execution environments, which are also managed_by_tower
and allow modifications.
2021-06-02 13:05:02 -04:00
Elijah DeLee
043aff6a8c Create default EE in seperate awx-managment cmd
Create EE at a seperate time and also attach a registry credential if
auth information provided

This command can be run multiple times on the same instance and should be
idempotent.
2021-06-02 12:23:01 -04:00
softwarefactory-project-zuul[bot]
7725c6f18f Merge pull request #10305 from jbradberry/resolve-workflow-ee
Include the EE set on a workflow template in the resolver hierarchy

SUMMARY
This step comes immediately after checking the actual job/template for
an explicitly set EE.
Note that now, because of how jobs are spawned off of workflow nodes,
the call to .resolve_execution_environment() no longer happens in
.create_unified_job().  The job instance within .create_unified_job()
doesn't yet have access to the node that it will be attached to,
making it impossible to use this information in the resolver if called
there.
related #9560
ISSUE TYPE


Feature Pull Request
Bugfix Pull Request

COMPONENT NAME

API

AWX VERSION

Reviewed-by: Shane McDonald <me@shanemcd.com>
Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
2021-06-02 16:22:39 +00:00
mabashian
16a3f7c2df Properly validate multiple choice survey questions 2021-06-02 10:38:11 -04:00
Marliana Lara
92f567539f Update .po strings 2021-06-01 14:43:11 -04:00
Marliana Lara
951f6d4636 Redirect user after authenticating through social auth 2021-06-01 13:28:33 -04:00
Marliana Lara
811fa514d2 Remove useMemo from session context 2021-06-01 13:28:33 -04:00
Marliana Lara
a097602d7f Add Session context and redirect on auth 2021-06-01 13:28:29 -04:00
Keith J. Grant
e6cfd726c6 don't reload host if query string changes 2021-05-27 13:22:47 -07:00
Jeff Bradberry
d3cc439fa8 Include the EE set on a workflow template in the resolver hierarchy
This step comes immediately after checking the actual job/template for
an explicitly set EE.

Note that now, because of how jobs are spawned off of workflow nodes,
the call to .resolve_execution_environment() no longer happens in
.create_unified_job().  The job instance within .create_unified_job()
doesn't yet have access to the node that it will be attached to,
making it impossible to use this information in the resolver if called
there.
2021-05-27 15:22:44 -04:00
mabashian
50de068a02 Refactor functions that check typed text in lookups 2021-05-27 11:09:06 -04:00
Elijah DeLee
5d838b8980 Force fully qualified image names
If we try and pull an unqualified image name, jobs hang on a podman
prompt.
2021-05-27 10:59:25 -04:00
mabashian
4ec7ba0107 Adds support for typing values into single select lookups 2021-05-27 10:53:36 -04:00
mabashian
fa7a459e50 Fixes bug where user/team role add modal state is not cleared on close 2021-05-27 10:51:46 -04:00
Elijah DeLee
b74990c480 allow singular execution_environment for cli
this makes "execution_environments" or "execution_environment" work
which is helpful
2021-05-25 11:28:47 -04:00
Bill Nottingham
6d052fdab4 UI licenses 2021-05-21 16:25:55 -04:00
Bill Nottingham
51538b7688 Restore UI license checker removed as part of removing old UI
Remove no longer needed license files.
2021-05-21 00:37:11 -04:00
Keith J. Grant
8ac3cc1542 delete qs utils that are no longer used 2021-05-19 13:49:57 -07:00
Keith J. Grant
908263df50 Rewrite updateQueryString to preserve namespaces
* Refactors ActivityStream to use updateQueryString
2021-05-19 13:23:46 -07:00
Keith J. Grant
7f6e022852 rename replaceNamespacedParams to updateQueryString 2021-05-18 14:15:26 -07:00
Keith J. Grant
d324c12348 add qs test confirming default values are omitted 2021-05-18 12:20:24 -07:00
Keith J. Grant
fd5e22a3f6 fix integer fields in removeParams; maintain page_size/sort 2021-05-18 12:00:20 -07:00
Keith J. Grant
25903431bc refactor JobOutput to use replaceNamespacedParams util 2021-05-17 15:25:16 -07:00
Keith J. Grant
f8374def64 refactor ListHeader to use replaceNamespacedParams 2021-05-17 15:09:37 -07:00
Keith J. Grant
9bbaa6993f refactor param changes to use new util function 2021-05-17 11:49:02 -07:00
AlanCoding
51f4a40cd4 Allow preserving schedules with prevent_teardown 2021-04-19 12:34:14 -04:00
Marcelo Moreira de Mello
fd3475a813 Only update LDAP user when necessary 2021-03-25 11:10:11 -04:00
mcharanrm
412015b7bd tools/scripts/firehose.py: capture all job ids, attach events to all jobs ids and distribute the events 2021-02-19 19:10:34 +05:30
tp48cf
58ce89fc0b improve logging migrate or instance not registered 2020-08-27 09:15:13 +02:00
jamesmarshall24
2394c0cb3d Remove query_parameters from within loop duplicating parameters in URL request 2020-06-05 18:12:10 -07:00
3101 changed files with 301611 additions and 272397 deletions

View File

@@ -1,3 +1,2 @@
awx/ui/node_modules
awx/ui_next/node_modules
Dockerfile

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
workflows/e2e_test.yml @tiagodread @shanemcd @jakemcdermott

View File

@@ -1,41 +0,0 @@
---
name: "\U0001F41B Bug report"
about: Create a report to help us improve
---
<!-- Issues are for **concrete, actionable bugs and feature requests** only - if you're just asking for debugging help or technical support, please use:
- http://webchat.freenode.net/?channels=ansible-awx
- https://groups.google.com/forum/#!forum/awx-project
We have to limit this because of limited volunteer time to respond to issues! -->
##### ISSUE TYPE
- Bug Report
##### SUMMARY
<!-- Briefly describe the problem. -->
##### ENVIRONMENT
* AWX version: X.Y.Z
* AWX install method: openshift, minishift, docker on linux, docker for mac, boot2docker
* Ansible version: X.Y.Z
* Operating System:
* Web Browser:
##### STEPS TO REPRODUCE
<!-- Please describe exactly how to reproduce the problem. -->
##### EXPECTED RESULTS
<!-- What did you expect to happen when running the steps above? -->
##### ACTUAL RESULTS
<!-- What actually happened? -->
##### ADDITIONAL INFORMATION
<!-- Include any links to sosreport, database dumps, screenshots or other
information. -->

135
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,135 @@
---
name: Bug Report
description: Create a report to help us improve
labels:
- bug
body:
- type: markdown
attributes:
value: |
Issues are for **concrete, actionable bugs and feature requests** only. For debugging help or technical support, please use:
- The #ansible-awx channel on irc.libera.chat
- https://groups.google.com/forum/#!forum/awx-project
- type: checkboxes
id: terms
attributes:
label: Please confirm the following
options:
- label: I agree to follow this project's [code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
required: true
- label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
required: true
- label: I understand that AWX is open source software provided for free and that I am not entitled to status updates or other assurances.
required: true
- type: textarea
id: summary
attributes:
label: Summary
description: Briefly describe the problem.
validations:
required: false
- type: input
id: awx-version
attributes:
label: AWX version
description: What version of AWX are you running?
validations:
required: true
- type: dropdown
id: awx-install-method
attributes:
label: Installation method
description: How did you install AWX?
multiple: false
options:
- kubernetes
- minikube
- openshift
- minishift
- docker on linux
- docker for mac
- boot2docker
validations:
required: true
- type: dropdown
id: modified-architecture
attributes:
label: Modifications
description: >-
Have you modified the installation, deployment topology, or container images in any way? If yes, please
explain in the "additional information" field at the bottom of the form.
multiple: false
options:
- "no"
- "yes"
validations:
required: true
- type: input
id: ansible-version
attributes:
label: Ansible version
description: What version of Ansible are you running?
validations:
required: false
- type: input
id: operating-system
attributes:
label: Operating system
description: What operating system are you using?
validations:
required: false
- type: dropdown
id: browsers
attributes:
label: Web browser
description: Which browsers are affected?
multiple: true
options:
- Firefox
- Chrome
- Safari
- Edge
validations:
required: false
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps to reproduce
description: >-
Starting from a new installation of the system, describe exactly how a developer or quality engineer can reproduce the bug
on infrastructure that isn't yours. Include any and all resources created, input values, test users, roles assigned, playbooks used, etc.
validations:
required: true
- type: textarea
id: expected-results
attributes:
label: Expected results
description: What did you expect to happpen when running the steps above?
validations:
required: true
- type: textarea
id: actual-results
attributes:
label: Actual results
description: What actually happened?
validations:
required: true
- type: textarea
id: additional-information
attributes:
label: Additional information
description: Include any relevant log output, links to sosreport, database dumps, screenshots, or other information.
validations:
required: false

View File

@@ -5,7 +5,7 @@ about: Suggest an idea for this project
---
<!-- Issues are for **concrete, actionable bugs and feature requests** only - if you're just asking for debugging help or technical support, please use:
- http://webchat.freenode.net/?channels=ansible-awx
- http://web.libera.chat/?channels=#ansible-awx
- https://groups.google.com/forum/#!forum/awx-project
We have to limit this because of limited volunteer time to respond to issues! -->

173
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,173 @@
---
name: CI
on:
pull_request:
jobs:
api-test:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose-build
- name: Run API Tests
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} /start_tests.sh
api-lint:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose-build
- name: Run API Linters
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} /var/lib/awx/venv/awx/bin/tox -e linters
api-swagger:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} || :
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose-build
- name: Generate API Reference
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} /start_tests.sh swagger
awx-collection:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose-build
- name: Run Collection Tests
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} /start_tests.sh test_collection_all
api-schema:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose-build
- name: Check API Schema
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} /start_tests.sh detect-schema-change
ui-lint:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose-build
- name: Run UI Linters
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} make ui-lint
ui-test:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose-build
- name: Run UI Tests
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }} make ui-test

30
.github/workflows/devel_image.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
---
name: Push Development Image
on:
push:
branches:
- devel
jobs:
push:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make docker-compose-build
- name: Push image
run: |
docker push ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}

100
.github/workflows/e2e_test.yml vendored Normal file
View File

@@ -0,0 +1,100 @@
---
name: E2E Tests
on:
pull_request_target:
types: [labeled]
jobs:
e2e-test:
if: contains(github.event.pull_request.labels.*.name, 'qe:e2e')
runs-on: ubuntu-latest
timeout-minutes: 40
permissions:
packages: write
contents: read
strategy:
matrix:
job: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
steps:
- uses: actions/checkout@v2
- name: Install system deps
run: sudo apt-get install -y gettext
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ github.base_ref }}
- name: Build UI
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make ui-devel
- name: Start AWX
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ github.base_ref }} make docker-compose &> make-docker-compose-output.log &
- name: Pull awx_cypress_base image
run: |
docker pull quay.io/awx/awx_cypress_base:latest
- name: Checkout test project
uses: actions/checkout@v2
with:
repository: ${{ github.repository_owner }}/tower-qa
ssh-key: ${{ secrets.QA_REPO_KEY }}
path: tower-qa
ref: devel
- name: Build cypress
run: |
cd ${{ secrets.E2E_PROJECT }}/ui-tests/awx-pf-tests
docker build -t awx-pf-tests .
- name: Update default AWX password
run: |
while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' -k https://localhost:8043/api/v2/ping/)" != "200" ]]
do
echo "Waiting for AWX..."
sleep 5;
done
echo "AWX is up, updating the password..."
docker exec -i tools_awx_1 sh <<-EOSH
awx-manage update_password --username=admin --password=password
EOSH
- name: Run E2E tests
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
run: |
export COMMIT_INFO_BRANCH=$GITHUB_HEAD_REF
export COMMIT_INFO_AUTHOR=$GITHUB_ACTOR
export COMMIT_INFO_SHA=$GITHUB_SHA
export COMMIT_INFO_REMOTE=$GITHUB_REPOSITORY_OWNER
cd ${{ secrets.E2E_PROJECT }}/ui-tests/awx-pf-tests
AWX_IP=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' tools_awx_1)
printenv > .env
echo "Executing tests:"
docker run \
--network '_sources_default' \
--ipc=host \
--env-file=.env \
-e CYPRESS_baseUrl="https://$AWX_IP:8043" \
-e CYPRESS_AWX_E2E_USERNAME=admin \
-e CYPRESS_AWX_E2E_PASSWORD='password' \
-e COMMAND="npm run cypress-gha" \
-v /dev/shm:/dev/shm \
-v $PWD:/e2e \
-w /e2e \
awx-pf-tests run --project .
- name: Save AWX logs
uses: actions/upload-artifact@v2
with:
name: AWX-logs-${{ matrix.job }}
path: make-docker-compose-output.log

43
.github/workflows/upload_schema.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
---
name: Upload API Schema
on:
push:
branches:
- devel
jobs:
push:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make docker-compose-build
- name: Generate API Schema
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace }}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} /start_tests.sh genschema
- name: Upload API Schema
env:
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
AWS_REGION: 'us-east-1'
run: |
ansible localhost -c local, -m command -a "{{ ansible_python_interpreter + ' -m pip install boto3'}}"
ansible localhost -c local -m aws_s3 \
-a 'src=${{ github.workspace }}/schema.json bucket=awx-public-ci-files object=schema.json mode=put permission=public-read'

17
.gitignore vendored
View File

@@ -28,12 +28,12 @@ awx/ui/build_test
awx/ui/client/languages
awx/ui/templates/ui/index.html
awx/ui/templates/ui/installing.html
awx/ui_next/node_modules/
awx/ui_next/src/locales/*/messages.js
awx/ui_next/coverage/
awx/ui_next/build
awx/ui_next/.env.local
awx/ui_next/instrumented
awx/ui/node_modules/
awx/ui/src/locales/*/messages.js
awx/ui/coverage/
awx/ui/build
awx/ui/.env.local
awx/ui/instrumented
rsyslog.pid
tools/prometheus/data
tools/docker-compose/ansible/awx_dump.sql
@@ -41,6 +41,7 @@ tools/docker-compose/Dockerfile
tools/docker-compose/_build
tools/docker-compose/_sources
tools/docker-compose/overrides/
tools/docker-compose-minikube/_sources
# Tower setup playbook testing
setup/test/roles/postgresql
@@ -62,14 +63,12 @@ __pycache__
/Gruntfile.js
/Brocfile.js
/bower.json
/package.json
/testem.yml
**/coverage
/.istanbul.yml
**/node_modules/**
/tmp
**/npm-debug.log*
**/package-lock.json
# UI build flag files
awx/ui/.deps_built
@@ -153,7 +152,7 @@ use_dev_supervisor.txt
.idea/*
*.unison.tmp
*.#
/awx/ui_next/.ui-built
/awx/ui/.ui-built
/Dockerfile
/_build/
/_build_kube_dev/

View File

@@ -1,5 +1,6 @@
---
ignore: |
.github
.tox
awx/main/tests/data/inventory/plugins/**
# vault files

View File

@@ -1,6 +1,48 @@
# Changelog
This is a list of high-level changes for each release of AWX. A full list of commits can be found at `https://github.com/ansible/awx/releases/tag/<version>`.
# 19.3.0 (August 12, 2021)
- Fixed threading bug that would sometimes cause jobs to randomly fail (https://github.com/ansible/awx/pull/10537)
- Fixed race where app would crash when postgres is not available (https://github.com/ansible/awx/pull/10583)
- Add support for workflow node aliasing via identifier field (https://github.com/ansible/awx/pull/10592)
- Add UI support for management jobs in workflows (https://github.com/ansible/awx/pull/10572)
- Show PAT as part of bulk delete list (https://github.com/ansible/awx/pull/10794)
- Return 404 for ad_hoc_command_events list api. Remove api endtpoint (https://github.com/ansible/awx/pull/10716)
- Fix multiple accessibility violations (https://github.com/ansible/awx/pull/10713)
- Fix ignoring --no-color for awx-manage list_instances command (https://github.com/ansible/awx/pull/10668)
- Fix to handle ask_* parameters correctly when set false (https://github.com/ansible/awx/pull/10108)
- Default source_project to organization for inventory source (https://github.com/ansible/awx/pull/10573)
- Fix headers missing in webhook notification request (https://github.com/ansible/awx/pull/10566)
- Avoid double LDAP updates (https://github.com/ansible/awx/pull/9703)
- introduced a pre-flight check for postgres 12 (https://github.com/ansible/awx/pull/10425)
- Fix Job Settings Page Break on Firefox (https://github.com/ansible/awx/pull/10523)
- bumped django version to 2.2.20 (https://github.com/ansible/awx/pull/10564)
- Add Thycotic SecretServer support (https://github.com/ansible/awx/pull/10632)
# 19.2.2 (June 28, 2021)
- Fixed bug where symlinks pointing to directories were not preserved (https://github.com/ansible/ansible-runner/pull/736)
- Various bugfixes found during testing (https://github.com/ansible/awx/pull/10532)
# 19.2.1 (June 17, 2021)
- There are now 2 default Instance Groups: 'controlplane' and 'default' (https://github.com/ansible/awx/pull/10324)
- Removed deprecated modules: `tower_send`, `tower_receive`, `tower_workflow_template` (https://github.com/ansible/awx/pull/9980)
- Improved UI performance when a large amount of events are being emitted by jobs (https://github.com/ansible/awx/pull/10053)
- Settings UI Revert All button now issues a DELETE instead of PATCHing all fields (https://github.com/ansible/awx/pull/10376)
- Fixed a bug with the schedule date/time picker in Firefox (https://github.com/ansible/awx/pull/10291)
- UI now preselects the system default Galaxy credential when creating a new organization (https://github.com/ansible/awx/pull/10395)
- Added favicon (https://github.com/ansible/awx/pull/10388)
- Removed `not` option from smart inventory host filter search as it's not supported by the API (https://github.com/ansible/awx/pull/10380)
- Added button to allow user to refetch project revision after project sync has finished (https://github.com/ansible/awx/pull/10334)
- Fixed bug where extraneous CONFIG requests were made on logout (https://github.com/ansible/awx/pull/10379)
- Fixed bug where users were unable to cancel inventory syncs (https://github.com/ansible/awx/pull/10346)
- Added missing dashboard graph filters (https://github.com/ansible/awx/pull/10349)
- Added support for typing in to single select lookup form fields (https://github.com/ansible/awx/pull/10257)
- Fixed various bugs related to user sessions (https://github.com/ansible/awx/pull/9908)
- Fixed bug where sorting in modals would close the modal (https://github.com/ansible/awx/pull/10215)
- Added support for Red Hat Insights as an inventory source (https://github.com/ansible/awx/pull/8650)
- Fixed bugs when selecting items in a list then sorting/paginating (https://github.com/ansible/awx/pull/10329)
# 19.2.0 (June 1, 2021)
- Fixed race condition that would sometimes cause jobs to error out at the very end of an otherwise successful run (https://github.com/ansible/receptor/pull/328)

View File

@@ -6,21 +6,21 @@ Have questions about this document or anything not covered here? Come chat with
## Table of contents
* [Things to know prior to submitting code](#things-to-know-prior-to-submitting-code)
* [Setting up your development environment](#setting-up-your-development-environment)
* [Prerequisites](#prerequisites)
* [Docker](#docker)
* [Docker compose](#docker-compose)
* [Frontend Development](#frontend-development)
* [Build and Run the Development Environment](#build-and-run-the-development-environment)
* [Fork and clone the AWX repo](#fork-and-clone-the-awx-repo)
* [Building API Documentation](#building-api-documentation)
* [Accessing the AWX web interface](#accessing-the-awx-web-interface)
* [Purging containers and images](#purging-containers-and-images)
* [What should I work on?](#what-should-i-work-on)
* [Submitting Pull Requests](#submitting-pull-requests)
* [PR Checks run by Zuul](#pr-checks-run-by-zuul)
* [Reporting Issues](#reporting-issues)
- [Things to know prior to submitting code](#things-to-know-prior-to-submitting-code)
- [Setting up your development environment](#setting-up-your-development-environment)
- [Prerequisites](#prerequisites)
- [Docker](#docker)
- [Docker compose](#docker-compose)
- [Frontend Development](#frontend-development)
- [Build and Run the Development Environment](#build-and-run-the-development-environment)
- [Fork and clone the AWX repo](#fork-and-clone-the-awx-repo)
- [Building API Documentation](#building-api-documentation)
- [Accessing the AWX web interface](#accessing-the-awx-web-interface)
- [Purging containers and images](#purging-containers-and-images)
- [What should I work on?](#what-should-i-work-on)
- [Submitting Pull Requests](#submitting-pull-requests)
- [PR Checks run by Zuul](#pr-checks-run-by-zuul)
- [Reporting Issues](#reporting-issues)
## Things to know prior to submitting code
@@ -46,15 +46,15 @@ respectively.
For Linux platforms, refer to the following from Docker:
* **Fedora** - https://docs.docker.com/engine/installation/linux/docker-ce/fedora/
- **Fedora** - https://docs.docker.com/engine/installation/linux/docker-ce/fedora/
* **CentOS** - https://docs.docker.com/engine/installation/linux/docker-ce/centos/
- **CentOS** - https://docs.docker.com/engine/installation/linux/docker-ce/centos/
* **Ubuntu** - https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
- **Ubuntu** - https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
* **Debian** - https://docs.docker.com/engine/installation/linux/docker-ce/debian/
- **Debian** - https://docs.docker.com/engine/installation/linux/docker-ce/debian/
* **Arch** - https://wiki.archlinux.org/index.php/Docker
- **Arch** - https://wiki.archlinux.org/index.php/Docker
#### Docker Compose
@@ -66,7 +66,7 @@ If you're not using Docker for Mac, or Docker for Windows, you may need, or choo
#### Frontend Development
See [the ui development documentation](awx/ui_next/CONTRIBUTING.md).
See [the ui development documentation](awx/ui/CONTRIBUTING.md).
#### Fork and clone the AWX repo
@@ -74,19 +74,19 @@ If you have not done so already, you'll need to fork the AWX repo on GitHub. For
### Build and Run the Development Environment
See the [README.md](./tools/docker-compose/README.md) for docs on how to build the awx_devel image and run the development environment.
See the [README.md](./tools/docker-compose/README.md) for docs on how to build the awx_devel image and run the development environment.
### Building API Documentation
AWX includes support for building [Swagger/OpenAPI
documentation](https://swagger.io). To build the documentation locally, run:
documentation](https://swagger.io). To build the documentation locally, run:
```bash
(container)/awx_devel$ make swagger
```
This will write a file named `swagger.json` that contains the API specification
in OpenAPI format. A variety of online tools are available for translating
in OpenAPI format. A variety of online tools are available for translating
this data into more consumable formats (such as HTML). http://editor.swagger.io
is an example of one such service.
@@ -126,15 +126,15 @@ Fixes and Features for AWX will go through the Github pull request process. Subm
Here are a few things you can do to help the visibility of your change, and increase the likelihood that it will be accepted:
* No issues when running linters/code checkers
* Python: black: `(container)/awx_devel$ make black`
* Javascript: JsHint: `(container)/awx_devel$ make jshint`
* No issues from unit tests
* Python: py.test: `(container)/awx_devel$ make test`
* JavaScript: Jasmine: `(container)/awx_devel$ make ui-test-ci`
* Write tests for new functionality, update/add tests for bug fixes
* Make the smallest change possible
* Write good commit messages. See [How to write a Git commit message](https://chris.beams.io/posts/git-commit/).
- No issues when running linters/code checkers
- Python: black: `(container)/awx_devel$ make black`
- Javascript: `(container)/awx_devel$ make ui-lint`
- No issues from unit tests
- Python: py.test: `(container)/awx_devel$ make test`
- JavaScript: `(container)/awx_devel$ make ui-test`
- Write tests for new functionality, update/add tests for bug fixes
- Make the smallest change possible
- Write good commit messages. See [How to write a Git commit message](https://chris.beams.io/posts/git-commit/).
It's generally a good idea to discuss features with us first by engaging us in the `#ansible-awx` channel on irc.libera.chat, or on the [mailing list](https://groups.google.com/forum/#!forum/awx-project).
@@ -146,21 +146,24 @@ Sometimes it might take us a while to fully review your PR. We try to keep the `
All submitted PRs will have the linter and unit tests run against them via Zuul, and the status reported in the PR.
## PR Checks run by Zuul
Zuul jobs for awx are defined in the [zuul-jobs](https://github.com/ansible/zuul-jobs) repo.
Zuul runs the following checks that must pass:
1) `tox-awx-api-lint`
2) `tox-awx-ui-lint`
3) `tox-awx-api`
4) `tox-awx-ui`
5) `tox-awx-swagger`
1. `tox-awx-api-lint`
2. `tox-awx-ui-lint`
3. `tox-awx-api`
4. `tox-awx-ui`
5. `tox-awx-swagger`
Zuul runs the following checks that are non-voting (can not pass but serve to inform PR reviewers):
1) `tox-awx-detect-schema-change`
This check generates the schema and diffs it against a reference copy of the `devel` version of the schema.
Reviewers should inspect the `job-output.txt.gz` related to the check if their is a failure (grep for `diff -u -b` to find beginning of diff).
If the schema change is expected and makes sense in relation to the changes made by the PR, then you are good to go!
If not, the schema changes should be fixed, but this decision must be enforced by reviewers.
1. `tox-awx-detect-schema-change`
This check generates the schema and diffs it against a reference copy of the `devel` version of the schema.
Reviewers should inspect the `job-output.txt.gz` related to the check if their is a failure (grep for `diff -u -b` to find beginning of diff).
If the schema change is expected and makes sense in relation to the changes made by the PR, then you are good to go!
If not, the schema changes should be fixed, but this decision must be enforced by reviewers.
## Reporting Issues

View File

@@ -4,8 +4,8 @@ recursive-include awx *.mo
recursive-include awx/static *
recursive-include awx/templates *.html
recursive-include awx/api/templates *.md *.html
recursive-include awx/ui_next/build *.html
recursive-include awx/ui_next/build *
recursive-include awx/ui/build *.html
recursive-include awx/ui/build *
recursive-include awx/playbooks *.yml
recursive-include awx/lib/site-packages *
recursive-include awx/plugins *.ps1

View File

@@ -83,7 +83,7 @@ clean-schema:
clean-languages:
rm -f $(I18N_FLAG_FILE)
find . -type f -regex ".*\.mo$$" -delete
find ./awx/locale/ -type f -regex ".*\.mo$" -delete
# Remove temporary build files, compiled Python files.
clean: clean-ui clean-api clean-awxkit clean-dist
@@ -173,7 +173,7 @@ init:
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(MANAGEMENT_COMMAND) provision_instance --hostname=$(COMPOSE_HOST); \
$(MANAGEMENT_COMMAND) register_queue --queuename=tower --instance_percent=100;
$(MANAGEMENT_COMMAND) register_queue --queuename=controlplane --instance_percent=100;
# Refresh development environment after pulling new code.
refresh: clean requirements_dev version_file develop migrate
@@ -288,6 +288,11 @@ swagger: reports
check: black
api-lint:
BLACK_ARGS="--check" make black
flake8 awx
yamllint -s .
awx-link:
[ -d "/awx_devel/awx.egg-info" ] || $(PYTHON) /awx_devel/setup.py egg_info_dev
cp -f /tmp/awx.egg-link /var/lib/awx/venv/awx/lib/python$(PYTHON_VERSION)/site-packages/awx.egg-link
@@ -315,7 +320,7 @@ test_collection:
if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi && \
pip install ansible && \
pip install ansible-core && \
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
@@ -378,45 +383,49 @@ bulk_data:
# UI TASKS
# --------------------------------------
UI_BUILD_FLAG_FILE = awx/ui_next/.ui-built
UI_BUILD_FLAG_FILE = awx/ui/.ui-built
clean-ui:
rm -rf node_modules
rm -rf awx/ui_next/node_modules
rm -rf awx/ui_next/build
rm -rf awx/ui_next/src/locales/_build
rm -rf awx/ui/node_modules
rm -rf awx/ui/build
rm -rf awx/ui/src/locales/_build
rm -rf $(UI_BUILD_FLAG_FILE)
awx/ui_next/node_modules:
NODE_OPTIONS=--max-old-space-size=4096 $(NPM_BIN) --prefix awx/ui_next --loglevel warn ci
awx/ui/node_modules:
NODE_OPTIONS=--max-old-space-size=4096 $(NPM_BIN) --prefix awx/ui --loglevel warn ci
$(UI_BUILD_FLAG_FILE):
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run compile-strings
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run build
$(PYTHON) tools/scripts/compilemessages.py
$(NPM_BIN) --prefix awx/ui --loglevel warn run compile-strings
$(NPM_BIN) --prefix awx/ui --loglevel warn run build
mkdir -p awx/public/static/css
mkdir -p awx/public/static/js
mkdir -p awx/public/static/media
cp -r awx/ui_next/build/static/css/* awx/public/static/css
cp -r awx/ui_next/build/static/js/* awx/public/static/js
cp -r awx/ui_next/build/static/media/* awx/public/static/media
cp -r awx/ui/build/static/css/* awx/public/static/css
cp -r awx/ui/build/static/js/* awx/public/static/js
cp -r awx/ui/build/static/media/* awx/public/static/media
touch $@
ui-release: awx/ui_next/node_modules $(UI_BUILD_FLAG_FILE)
ui-release: awx/ui/node_modules $(UI_BUILD_FLAG_FILE)
ui-devel: awx/ui_next/node_modules
ui-devel: awx/ui/node_modules
@$(MAKE) -B $(UI_BUILD_FLAG_FILE)
ui-devel-instrumented: awx/ui_next/node_modules
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run start-instrumented
ui-devel-instrumented: awx/ui/node_modules
$(NPM_BIN) --prefix awx/ui --loglevel warn run start-instrumented
ui-devel-test: awx/ui_next/node_modules
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run start
ui-devel-test: awx/ui/node_modules
$(NPM_BIN) --prefix awx/ui --loglevel warn run start
ui-zuul-lint-and-test:
$(NPM_BIN) --prefix awx/ui_next install
$(NPM_BIN) run --prefix awx/ui_next lint
$(NPM_BIN) run --prefix awx/ui_next prettier-check
$(NPM_BIN) run --prefix awx/ui_next test -- --coverage --watchAll=false
ui-lint:
$(NPM_BIN) --prefix awx/ui install
$(NPM_BIN) run --prefix awx/ui lint
$(NPM_BIN) run --prefix awx/ui prettier-check
ui-test:
$(NPM_BIN) --prefix awx/ui install
$(NPM_BIN) run --prefix awx/ui test -- --coverage --maxWorkers=4 --watchAll=false
# Build a pip-installable package into dist/ with a timestamped version number.
@@ -462,15 +471,22 @@ awx/projects:
COMPOSE_UP_OPTS ?=
CLUSTER_NODE_COUNT ?= 1
MINIKUBE_CONTAINER_GROUP ?= false
docker-compose-sources: .git/hooks/pre-commit
@if [ $(MINIKUBE_CONTAINER_GROUP) = true ]; then\
ansible-playbook -i tools/docker-compose/inventory tools/docker-compose-minikube/deploy.yml; \
fi;
ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/sources.yml \
-e awx_image=$(DEV_DOCKER_TAG_BASE)/awx_devel \
-e awx_image_tag=$(COMPOSE_TAG) \
-e cluster_node_count=$(CLUSTER_NODE_COUNT)
-e cluster_node_count=$(CLUSTER_NODE_COUNT) \
-e minikube_container_group=$(MINIKUBE_CONTAINER_GROUP)
docker-compose: docker-auth awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_UP_OPTS) up
docker-compose -f tools/docker-compose/_sources/docker-compose.yml up $(COMPOSE_UP_OPTS)
docker-compose-credential-plugins: docker-auth awx/projects docker-compose-sources
echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m"
@@ -493,6 +509,12 @@ detect-schema-change: genschema
docker-compose-clean: awx/projects
docker-compose -f tools/docker-compose/_sources/docker-compose.yml rm -sf
docker-compose-container-group-clean:
@if [ -f "tools/docker-compose-minikube/_sources/minikube" ]; then \
tools/docker-compose-minikube/_sources/minikube delete; \
fi
rm -rf tools/docker-compose-minikube/_sources/
# Base development image build
docker-compose-build:
ansible-playbook tools/ansible/dockerfile.yml -e build_dev=True
@@ -504,7 +526,7 @@ docker-clean:
$(foreach container_id,$(shell docker ps -f name=tools_awx -aq),docker stop $(container_id); docker rm -f $(container_id);)
docker images | grep "awx_devel" | awk '{print $$1 ":" $$2}' | xargs docker rmi
docker-clean-volumes: docker-compose-clean
docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
docker volume rm tools_awx_db
docker-refresh: docker-clean docker-compose
@@ -519,6 +541,9 @@ docker-compose-cluster-elk: docker-auth awx/projects docker-compose-sources
prometheus:
docker run -u0 --net=tools_default --link=`docker ps | egrep -o "tools_awx(_run)?_([^ ]+)?"`:awxweb --volume `pwd`/tools/prometheus:/prometheus --name prometheus -d -p 0.0.0.0:9090:9090 prom/prometheus --web.enable-lifecycle --config.file=/prometheus/prometheus.yml
docker-compose-container-group:
MINIKUBE_CONTAINER_GROUP=true make docker-compose
clean-elk:
docker stop tools_kibana_1
docker stop tools_logstash_1
@@ -551,10 +576,13 @@ awx-kube-dev-build: Dockerfile.kube-dev
# Translation TASKS
# --------------------------------------
# generate UI .pot
# generate UI .pot file, an empty template of strings yet to be translated
pot: $(UI_BUILD_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run extract-strings
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run extract-template
$(NPM_BIN) --prefix awx/ui --loglevel warn run extract-template --clean
# generate UI .po files for each locale (will update translated strings for `en`)
po: $(UI_BUILD_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui --loglevel warn run extract-strings -- --clean
# generate API django .pot .po
LANG = "en-us"

View File

@@ -1,5 +1,5 @@
[![Gated by Zuul](https://zuul-ci.org/gated.svg)](https://ansible.softwarefactory-project.io/zuul/status) [![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-Ansible-yellow.svg)](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) [![Apache v2 License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](https://github.com/ansible/awx/blob/devel/LICENSE.md) [![AWX Mailing List](https://img.shields.io/badge/mailing%20list-AWX-orange.svg)](https://groups.google.com/g/awx-project)
[![IRC Chat](https://img.shields.io/badge/IRC-%23ansible--awx-blueviolet.svg)](irc.libera.chat - #ansible-awx)
[![.github/workflows/ci.yml](https://github.com/ansible/awx/actions/workflows/ci.yml/badge.svg)](https://github.com/ansible/awx/actions/workflows/ci.yml) [![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-Ansible-yellow.svg)](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) [![Apache v2 License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](https://github.com/ansible/awx/blob/devel/LICENSE.md) [![AWX Mailing List](https://img.shields.io/badge/mailing%20list-AWX-orange.svg)](https://groups.google.com/g/awx-project)
[![IRC Chat - #ansible-awx](https://img.shields.io/badge/IRC-%23ansible--awx-blueviolet.svg)](https://libera.chat)
<img src="https://raw.githubusercontent.com/ansible/awx-logos/master/awx/ui/client/assets/logo-login.svg?sanitize=true" width=200 alt="AWX" />
@@ -20,7 +20,7 @@ Contributing
- All code submissions are made through pull requests against the `devel` branch.
- All contributors must use git commit --signoff for any commit to be merged and agree that usage of --signoff constitutes agreement with the terms of [DCO 1.1](./DCO_1_1.md)
- Take care to make sure no merge commits are in the submission, and use `git rebase` vs. `git merge` for this reason.
- If submitting a large code change, it's a good idea to join the `#ansible-awx` channel on webchat.freenode.net and talk about what you would like to do or add first. This not only helps everyone know what's going on, but it also helps save time and effort if the community decides some changes are needed.
- If submitting a large code change, it's a good idea to join the `#ansible-awx` channel on web.libera.chat and talk about what you would like to do or add first. This not only helps everyone know what's going on, but it also helps save time and effort if the community decides some changes are needed.
Reporting Issues
----------------
@@ -37,5 +37,5 @@ Get Involved
We welcome your feedback and ideas. Here's how to reach us with feedback and questions:
- Join the `#ansible-awx` channel on webchat.freenode.net
- Join the `#ansible-awx` channel on irc.libera.chat
- Join the [mailing list](https://groups.google.com/forum/#!forum/awx-project)

View File

@@ -1 +1 @@
19.2.0
19.3.0

View File

@@ -34,6 +34,7 @@ else:
from django.db.backends.base import schema
from django.db.models import indexes
from django.db.backends.utils import names_digest
from django.db import connection
if HAS_DJANGO is True:
@@ -149,6 +150,12 @@ def manage():
from django.conf import settings
from django.core.management import execute_from_command_line
# enforce the postgres version is equal to 12. if not, then terminate program with exit code of 1
if not MODE == 'development':
if (connection.pg_version // 10000) < 12:
sys.stderr.write("Postgres version 12 is required\n")
sys.exit(1)
if len(sys.argv) >= 2 and sys.argv[1] in ('version', '--version'): # pragma: no cover
sys.stdout.write('%s\n' % __version__)
# If running as a user without permission to read settings, display an

View File

@@ -133,7 +133,7 @@ class FieldLookupBackend(BaseFilterBackend):
Filter using field lookups provided via query string parameters.
"""
RESERVED_NAMES = ('page', 'page_size', 'format', 'order', 'order_by', 'search', 'type', 'host_filter', 'count_disabled', 'no_truncate')
RESERVED_NAMES = ('page', 'page_size', 'format', 'order', 'order_by', 'search', 'type', 'host_filter', 'count_disabled', 'no_truncate', 'limit')
SUPPORTED_LOOKUPS = (
'exact',

View File

@@ -39,6 +39,7 @@ from awx.main.models import UnifiedJob, UnifiedJobTemplate, User, Role, Credenti
from awx.main.access import access_registry
from awx.main.utils import camelcase_to_underscore, get_search_fields, getattrd, get_object_or_400, decrypt_field, get_awx_version
from awx.main.utils.db import get_all_field_names
from awx.main.utils.licensing import server_product_name
from awx.main.views import ApiErrorView
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
from awx.api.versioning import URLPathVersioning
@@ -184,9 +185,6 @@ class APIView(views.APIView):
"""
Log warning for 400 requests. Add header with elapsed time.
"""
from awx.main.utils import get_licenser
from awx.main.utils.licensing import OpenLicense
#
# If the URL was rewritten, and we get a 404, we should entirely
# replace the view in the request context with an ApiErrorView()
@@ -219,14 +217,14 @@ class APIView(views.APIView):
if hasattr(self, '__init_request_error__'):
response = self.handle_exception(self.__init_request_error__)
if response.status_code == 401:
response.data['detail'] += ' To establish a login session, visit /api/login/.'
response.data['detail'] += _(' To establish a login session, visit') + ' /api/login/.'
logger.info(status_msg)
else:
logger.warning(status_msg)
response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
time_started = getattr(self, 'time_started', None)
response['X-API-Product-Version'] = get_awx_version()
response['X-API-Product-Name'] = 'AWX' if isinstance(get_licenser(), OpenLicense) else 'Red Hat Ansible Tower'
response['X-API-Product-Name'] = server_product_name()
response['X-API-Node'] = settings.CLUSTER_HOST_ID
if time_started:

View File

@@ -24,7 +24,7 @@ from rest_framework.request import clone_request
from awx.api.fields import ChoiceNullField
from awx.main.fields import JSONField, ImplicitRoleField
from awx.main.models import NotificationTemplate
from awx.main.tasks import AWXReceptorJob
from awx.main.utils.execution_environments import get_default_pod_spec
# Polymorphic
from polymorphic.models import PolymorphicModel
@@ -211,7 +211,7 @@ class Metadata(metadata.SimpleMetadata):
continue
if field == "pod_spec_override":
meta['default'] = AWXReceptorJob().pod_definition
meta['default'] = get_default_pod_spec()
# Add type choices if available from the serializer.
if field == 'type' and hasattr(serializer, 'get_type_choices'):

View File

@@ -1,12 +1,16 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
from collections import OrderedDict
# Django REST Framework
from django.conf import settings
from django.core.paginator import Paginator as DjangoPaginator
from rest_framework import pagination
from rest_framework.response import Response
from rest_framework.utils.urls import replace_query_param
from rest_framework.settings import api_settings
from django.utils.translation import gettext_lazy as _
class DisabledPaginator(DjangoPaginator):
@@ -65,3 +69,65 @@ class Pagination(pagination.PageNumberPagination):
if self.count_disabled:
return Response({'results': data})
return super(Pagination, self).get_paginated_response(data)
class LimitPagination(pagination.BasePagination):
default_limit = api_settings.PAGE_SIZE
limit_query_param = 'limit'
limit_query_description = _('Number of results to return per page.')
max_page_size = settings.MAX_PAGE_SIZE
def paginate_queryset(self, queryset, request, view=None):
self.limit = self.get_limit(request)
self.request = request
return list(queryset[0 : self.limit])
def get_paginated_response(self, data):
return Response(OrderedDict([('results', data)]))
def get_paginated_response_schema(self, schema):
return {
'type': 'object',
'properties': {
'results': schema,
},
}
def get_limit(self, request):
try:
return pagination._positive_int(request.query_params[self.limit_query_param], strict=True)
except (KeyError, ValueError):
pass
return self.default_limit
class UnifiedJobEventPagination(Pagination):
"""
By default, use Pagination for all operations.
If `limit` query parameter specified use LimitPagination
"""
def __init__(self, *args, **kwargs):
self.use_limit_paginator = False
self.limit_pagination = LimitPagination()
return super().__init__(*args, **kwargs)
def paginate_queryset(self, queryset, request, view=None):
if 'limit' in request.query_params:
self.use_limit_paginator = True
if self.use_limit_paginator:
return self.limit_pagination.paginate_queryset(queryset, request, view=view)
return super().paginate_queryset(queryset, request, view=view)
def get_paginated_response(self, data):
if self.use_limit_paginator:
return self.limit_pagination.get_paginated_response(data)
return super().get_paginated_response(data)
def get_paginated_response_schema(self, schema):
if self.use_limit_paginator:
return self.limit_pagination.get_paginated_response_schema(schema)
return super().get_paginated_response_schema(schema)

View File

@@ -4,6 +4,8 @@
# Python
import logging
from django.conf import settings
# Django REST Framework
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
from rest_framework import permissions
@@ -245,7 +247,7 @@ class IsSuperUser(permissions.BasePermission):
class InstanceGroupTowerPermission(ModelAccessPermission):
def has_object_permission(self, request, view, obj):
if request.method == 'DELETE' and obj.name == "tower":
if request.method == 'DELETE' and obj.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
return False
return super(InstanceGroupTowerPermission, self).has_object_permission(request, view, obj)

View File

@@ -144,7 +144,6 @@ SUMMARIZABLE_FK_FIELDS = {
'inventory_sources_with_failures',
'organization_id',
'kind',
'insights_credential_id',
),
'host': DEFAULT_SUMMARY_FIELDS,
'group': DEFAULT_SUMMARY_FIELDS,
@@ -171,7 +170,6 @@ SUMMARIZABLE_FK_FIELDS = {
'role': ('id', 'role_field'),
'notification_template': DEFAULT_SUMMARY_FIELDS,
'instance_group': ('id', 'name', 'is_container_group'),
'insights_credential': DEFAULT_SUMMARY_FIELDS,
'source_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
'target_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
'webhook_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
@@ -724,6 +722,20 @@ class UnifiedJobTemplateSerializer(BaseSerializer):
else:
return super(UnifiedJobTemplateSerializer, self).to_representation(obj)
def get_summary_fields(self, obj):
summary_fields = super().get_summary_fields(obj)
if self.is_detail_view:
resolved_ee = obj.resolve_execution_environment()
if resolved_ee is not None:
summary_fields['resolved_environment'] = {
field: getattr(resolved_ee, field, None)
for field in SUMMARIZABLE_FK_FIELDS['execution_environment']
if getattr(resolved_ee, field, None) is not None
}
return summary_fields
class UnifiedJobSerializer(BaseSerializer):
show_capabilities = ['start', 'delete']
@@ -754,6 +766,7 @@ class UnifiedJobSerializer(BaseSerializer):
'result_traceback',
'event_processing_finished',
'launched_by',
'work_unit_id',
)
extra_kwargs = {
@@ -935,7 +948,6 @@ class UserSerializer(BaseSerializer):
'*',
'-name',
'-description',
'-modified',
'username',
'first_name',
'last_name',
@@ -1396,11 +1408,11 @@ class ProjectOptionsSerializer(BaseSerializer):
class ExecutionEnvironmentSerializer(BaseSerializer):
show_capabilities = ['edit', 'delete', 'copy']
managed_by_tower = serializers.ReadOnlyField()
managed = serializers.ReadOnlyField()
class Meta:
model = ExecutionEnvironment
fields = ('*', 'organization', 'image', 'managed_by_tower', 'credential', 'pull')
fields = ('*', 'organization', 'image', 'managed', 'credential', 'pull')
def get_related(self, obj):
res = super(ExecutionEnvironmentSerializer, self).get_related(obj)
@@ -1646,7 +1658,6 @@ class InventorySerializer(BaseSerializerWithVariables):
'has_inventory_sources',
'total_inventory_sources',
'inventory_sources_with_failures',
'insights_credential',
'pending_deletion',
)
@@ -1671,8 +1682,6 @@ class InventorySerializer(BaseSerializerWithVariables):
copy=self.reverse('api:inventory_copy', kwargs={'pk': obj.pk}),
)
)
if obj.insights_credential:
res['insights_credential'] = self.reverse('api:credential_detail', kwargs={'pk': obj.insights_credential.pk})
if obj.organization:
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
return res
@@ -1740,10 +1749,9 @@ class HostSerializer(BaseSerializerWithVariables):
'has_inventory_sources',
'last_job',
'last_job_host_summary',
'insights_system_id',
'ansible_facts_modified',
)
read_only_fields = ('last_job', 'last_job_host_summary', 'insights_system_id', 'ansible_facts_modified')
read_only_fields = ('last_job', 'last_job_host_summary', 'ansible_facts_modified')
def build_relational_field(self, field_name, relation_info):
field_class, field_kwargs = super(HostSerializer, self).build_relational_field(field_name, relation_info)
@@ -1767,7 +1775,6 @@ class HostSerializer(BaseSerializerWithVariables):
smart_inventories=self.reverse('api:host_smart_inventories_list', kwargs={'pk': obj.pk}),
ad_hoc_commands=self.reverse('api:host_ad_hoc_commands_list', kwargs={'pk': obj.pk}),
ad_hoc_command_events=self.reverse('api:host_ad_hoc_command_events_list', kwargs={'pk': obj.pk}),
insights=self.reverse('api:host_insights', kwargs={'pk': obj.pk}),
ansible_facts=self.reverse('api:host_ansible_facts_detail', kwargs={'pk': obj.pk}),
)
)
@@ -2473,14 +2480,14 @@ class ResourceAccessListElementSerializer(UserSerializer):
class CredentialTypeSerializer(BaseSerializer):
show_capabilities = ['edit', 'delete']
managed_by_tower = serializers.ReadOnlyField()
managed = serializers.ReadOnlyField()
class Meta:
model = CredentialType
fields = ('*', 'kind', 'namespace', 'name', 'managed_by_tower', 'inputs', 'injectors')
fields = ('*', 'kind', 'namespace', 'name', 'managed', 'inputs', 'injectors')
def validate(self, attrs):
if self.instance and self.instance.managed_by_tower:
if self.instance and self.instance.managed:
raise PermissionDenied(detail=_("Modifications not allowed for managed credential types"))
old_inputs = {}
@@ -2512,8 +2519,8 @@ class CredentialTypeSerializer(BaseSerializer):
def to_representation(self, data):
value = super(CredentialTypeSerializer, self).to_representation(data)
# translate labels and help_text for credential fields "managed by Tower"
if value.get('managed_by_tower'):
# translate labels and help_text for credential fields "managed"
if value.get('managed'):
value['name'] = _(value['name'])
for field in value.get('inputs', {}).get('fields', []):
field['label'] = _(field['label'])
@@ -2532,11 +2539,11 @@ class CredentialTypeSerializer(BaseSerializer):
class CredentialSerializer(BaseSerializer):
show_capabilities = ['edit', 'delete', 'copy', 'use']
capabilities_prefetch = ['admin', 'use']
managed_by_tower = serializers.ReadOnlyField()
managed = serializers.ReadOnlyField()
class Meta:
model = Credential
fields = ('*', 'organization', 'credential_type', 'managed_by_tower', 'inputs', 'kind', 'cloud', 'kubernetes')
fields = ('*', 'organization', 'credential_type', 'managed', 'inputs', 'kind', 'cloud', 'kubernetes')
extra_kwargs = {'credential_type': {'label': _('Credential Type')}}
def to_representation(self, data):
@@ -2603,7 +2610,7 @@ class CredentialSerializer(BaseSerializer):
return summary_dict
def validate(self, attrs):
if self.instance and self.instance.managed_by_tower:
if self.instance and self.instance.managed:
raise PermissionDenied(detail=_("Modifications not allowed for managed credentials"))
return super(CredentialSerializer, self).validate(attrs)
@@ -2615,7 +2622,7 @@ class CredentialSerializer(BaseSerializer):
return ret
def validate_organization(self, org):
if self.instance and self.instance.credential_type.kind == 'galaxy' and org is None:
if self.instance and (not self.instance.managed) and self.instance.credential_type.kind == 'galaxy' and org is None:
raise serializers.ValidationError(_("Galaxy credentials must be owned by an Organization."))
return org
@@ -2623,7 +2630,6 @@ class CredentialSerializer(BaseSerializer):
if self.instance and credential_type.pk != self.instance.credential_type.pk:
for related_objects in (
'ad_hoc_commands',
'insights_inventories',
'unifiedjobs',
'unifiedjobtemplates',
'projects',
@@ -3031,7 +3037,7 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
res = super(JobSerializer, self).get_related(obj)
res.update(
dict(
job_events=self.reverse('api:job_job_events_list', kwargs={'pk': obj.pk}),
job_events=self.reverse('api:job_job_events_list', kwargs={'pk': obj.pk}), # TODO: consider adding job_created
job_host_summaries=self.reverse('api:job_job_host_summaries_list', kwargs={'pk': obj.pk}),
activity_stream=self.reverse('api:job_activity_stream_list', kwargs={'pk': obj.pk}),
notifications=self.reverse('api:job_notifications_list', kwargs={'pk': obj.pk}),
@@ -3098,8 +3104,8 @@ class JobDetailSerializer(JobSerializer):
fields = ('*', 'host_status_counts', 'playbook_counts', 'custom_virtualenv')
def get_playbook_counts(self, obj):
task_count = obj.job_events.filter(event='playbook_on_task_start').count()
play_count = obj.job_events.filter(event='playbook_on_play_start').count()
task_count = obj.get_event_queryset().filter(event='playbook_on_task_start').count()
play_count = obj.get_event_queryset().filter(event='playbook_on_play_start').count()
data = {'play_count': play_count, 'task_count': task_count}
@@ -3107,7 +3113,7 @@ class JobDetailSerializer(JobSerializer):
def get_host_status_counts(self, obj):
try:
counts = obj.job_events.only('event_data').get(event='playbook_on_stats').get_host_status_counts()
counts = obj.get_event_queryset().only('event_data').get(event='playbook_on_stats').get_host_status_counts()
except JobEvent.DoesNotExist:
counts = {}
@@ -3414,6 +3420,7 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
'ask_limit_on_launch',
'webhook_service',
'webhook_credential',
'-execution_environment',
)
def get_related(self, obj):
@@ -3440,6 +3447,7 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
survey_spec=self.reverse('api:workflow_job_template_survey_spec', kwargs={'pk': obj.pk}),
copy=self.reverse('api:workflow_job_template_copy', kwargs={'pk': obj.pk}),
)
res.pop('execution_environment', None) # EEs aren't meaningful for workflows
if obj.organization:
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
if obj.webhook_credential_id:
@@ -3491,6 +3499,7 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
'allow_simultaneous',
'job_template',
'is_sliced_job',
'-execution_environment',
'-execution_node',
'-event_processing_finished',
'-controller_node',
@@ -3504,6 +3513,7 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
def get_related(self, obj):
res = super(WorkflowJobSerializer, self).get_related(obj)
res.pop('execution_environment', None) # EEs aren't meaningful for workflows
if obj.workflow_job_template:
res['workflow_job_template'] = self.reverse('api:workflow_job_template_detail', kwargs={'pk': obj.workflow_job_template.pk})
res['notifications'] = self.reverse('api:workflow_job_notifications_list', kwargs={'pk': obj.pk})
@@ -3528,7 +3538,7 @@ class WorkflowJobSerializer(LabelsListMixin, UnifiedJobSerializer):
class WorkflowJobListSerializer(WorkflowJobSerializer, UnifiedJobListSerializer):
class Meta:
fields = ('*', '-execution_node', '-controller_node')
fields = ('*', '-execution_environment', '-execution_node', '-controller_node')
class WorkflowJobCancelSerializer(WorkflowJobSerializer):
@@ -4178,7 +4188,7 @@ class JobLaunchSerializer(BaseSerializer):
elif field_name == 'credentials':
for cred in obj.credentials.all():
cred_dict = dict(id=cred.id, name=cred.name, credential_type=cred.credential_type.pk, passwords_needed=cred.passwords_needed)
if cred.credential_type.managed_by_tower and 'vault_id' in cred.credential_type.defined_fields:
if cred.credential_type.managed and 'vault_id' in cred.credential_type.defined_fields:
cred_dict['vault_id'] = cred.get_input('vault_id', default=None)
defaults_dict.setdefault(field_name, []).append(cred_dict)
else:
@@ -4766,7 +4776,7 @@ class InstanceSerializer(BaseSerializer):
class Meta:
model = Instance
read_only_fields = ('uuid', 'hostname', 'version')
read_only_fields = ('uuid', 'hostname', 'version', 'node_type')
fields = (
"id",
"type",
@@ -4789,6 +4799,7 @@ class InstanceSerializer(BaseSerializer):
"mem_capacity",
"enabled",
"managed_by_policy",
"node_type",
)
def get_related(self, obj):
@@ -4905,8 +4916,12 @@ class InstanceGroupSerializer(BaseSerializer):
return value
def validate_name(self, value):
if self.instance and self.instance.name == 'tower' and value != 'tower':
raise serializers.ValidationError(_('tower instance group name may not be changed.'))
if self.instance and self.instance.name == settings.DEFAULT_EXECUTION_QUEUE_NAME and value != settings.DEFAULT_EXECUTION_QUEUE_NAME:
raise serializers.ValidationError(_('%s instance group name may not be changed.' % settings.DEFAULT_EXECUTION_QUEUE_NAME))
if self.instance and self.instance.name == settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME and value != settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME:
raise serializers.ValidationError(_('%s instance group name may not be changed.' % settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME))
return value
def validate_credential(self, value):
@@ -4973,7 +4988,7 @@ class ActivityStreamSerializer(BaseSerializer):
('notification', ('id', 'status', 'notification_type', 'notification_template_id')),
('o_auth2_access_token', ('id', 'user_id', 'description', 'application_id', 'scope')),
('o_auth2_application', ('id', 'name', 'description')),
('credential_type', ('id', 'name', 'description', 'kind', 'managed_by_tower')),
('credential_type', ('id', 'name', 'description', 'kind', 'managed')),
('ad_hoc_command', ('id', 'name', 'status', 'limit')),
('workflow_approval', ('id', 'name', 'unified_job_id')),
]

View File

@@ -0,0 +1 @@
{% include "api/job_job_events_list.md" %}

View File

@@ -0,0 +1 @@
{% include "api/job_job_events_list.md" %}

View File

@@ -0,0 +1,21 @@
{% include "api/sub_list_api_view.md" %}
{% ifmeth GET %}
## Special limit feature for event list views
Use the `limit` query string parameter to opt out of the pagination keys.
Doing this can improve response times for jobs that produce a large volume
of outputs.
?limit=25
This will set the page size to 25 and the `previous` and `next` keys will be
omitted from the response data. The data structure will look like this.
{
"results": [
...
]
}
{% endifmeth %}

View File

@@ -1,25 +0,0 @@
Make a GET request to retrieve the list of aggregated play data associated with a job
## Filtering
This endpoints supports a limited filtering subset:
?event_id__in=1,2,3
Will show only the given ids.
?event_id__gt=1
Will show ids greater than the given one.
?event_id__lt=3
Will show ids less than the given one.
?failed=true
Will show only failed plays. Alternatively `false` may be used.
?play__icontains=test
Will filter plays matching the substring `test`

View File

@@ -1,27 +0,0 @@
Make a GET request to retrieve the list of aggregated task data associated with the play given by event_id.
`event_id` is a required query parameter and must match the job event id of the parent play in order to receive the list of tasks associated with the play
## Filtering
This endpoints supports a limited filtering subset:
?event_id__in=1,2,3
Will show only the given task ids under the play given by `event_id`.
?event_id__gt=1
Will show ids greater than the given one.
?event_id__lt=3
Will show ids less than the given one.
?failed=true
Will show only failed plays. Alternatively `false` may be used.
?task__icontains=test
Will filter tasks matching the substring `test`

View File

@@ -0,0 +1 @@
{% include "api/job_job_events_list.md" %}

View File

@@ -0,0 +1 @@
{% include "api/job_job_events_list.md" %}

View File

@@ -3,11 +3,10 @@
from django.conf.urls import url
from awx.api.views import AdHocCommandEventList, AdHocCommandEventDetail
from awx.api.views import AdHocCommandEventDetail
urls = [
url(r'^$', AdHocCommandEventList.as_view(), name='ad_hoc_command_event_list'),
url(r'^(?P<pk>[0-9]+)/$', AdHocCommandEventDetail.as_view(), name='ad_hoc_command_event_detail'),
]

View File

@@ -16,7 +16,6 @@ from awx.api.views import (
HostSmartInventoriesList,
HostAdHocCommandsList,
HostAdHocCommandEventsList,
HostInsights,
)
@@ -33,7 +32,6 @@ urls = [
url(r'^(?P<pk>[0-9]+)/smart_inventories/$', HostSmartInventoriesList.as_view(), name='host_smart_inventories_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', HostAdHocCommandsList.as_view(), name='host_ad_hoc_commands_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_command_events/$', HostAdHocCommandEventsList.as_view(), name='host_ad_hoc_command_events_list'),
url(r'^(?P<pk>[0-9]+)/insights/$', HostInsights.as_view(), name='host_insights'),
]
__all__ = ['urls']

View File

@@ -3,14 +3,11 @@
from django.conf.urls import url
from awx.api.views import JobEventList, JobEventDetail, JobEventChildrenList, JobEventHostsList
from awx.api.views import JobEventDetail, JobEventChildrenList
urls = [
url(r'^$', JobEventList.as_view(), name='job_event_list'),
url(r'^(?P<pk>[0-9]+)/$', JobEventDetail.as_view(), name='job_event_detail'),
url(r'^(?P<pk>[0-9]+)/children/$', JobEventChildrenList.as_view(), name='job_event_children_list'),
url(r'^(?P<pk>[0-9]+)/hosts/$', JobEventHostsList.as_view(), name='job_event_hosts_list'),
]
__all__ = ['urls']

View File

@@ -21,7 +21,7 @@ from urllib3.exceptions import ConnectTimeoutError
from django.conf import settings
from django.core.exceptions import FieldError, ObjectDoesNotExist
from django.db.models import Q, Sum
from django.db import IntegrityError, transaction, connection
from django.db import IntegrityError, ProgrammingError, transaction, connection
from django.shortcuts import get_object_or_404
from django.utils.safestring import mark_safe
from django.utils.timezone import now
@@ -90,17 +90,14 @@ from awx.main import models
from awx.main.utils import (
camelcase_to_underscore,
extract_ansible_vars,
get_awx_http_client_headers,
get_object_or_400,
getattrd,
get_pk_from_dict,
schedule_task_manager,
ignore_inventory_computed_fields,
set_environ,
)
from awx.main.utils.encryption import encrypt_value
from awx.main.utils.filters import SmartFilter
from awx.main.utils.insights import filter_insights_api_response
from awx.main.redact import UriCleaner
from awx.api.permissions import (
JobTemplateCallbackPermission,
@@ -172,11 +169,21 @@ from awx.api.views.root import ( # noqa
ApiV2AttachView,
)
from awx.api.views.webhooks import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver # noqa
from awx.api.pagination import UnifiedJobEventPagination
logger = logging.getLogger('awx.api.views')
def unpartitioned_event_horizon(cls):
with connection.cursor() as cursor:
try:
cursor.execute(f'SELECT MAX(id) FROM _unpartitioned_{cls._meta.db_table}')
return cursor.fetchone()[0] or -1
except ProgrammingError:
return 0
def api_exception_handler(exc, context):
"""
Override default API exception handler to catch IntegrityError exceptions.
@@ -685,6 +692,7 @@ class TeamAccessList(ResourceAccessList):
class ExecutionEnvironmentList(ListCreateAPIView):
always_allow_superuser = False
model = models.ExecutionEnvironment
serializer_class = serializers.ExecutionEnvironmentSerializer
swagger_topic = "Execution Environments"
@@ -692,10 +700,26 @@ class ExecutionEnvironmentList(ListCreateAPIView):
class ExecutionEnvironmentDetail(RetrieveUpdateDestroyAPIView):
always_allow_superuser = False
model = models.ExecutionEnvironment
serializer_class = serializers.ExecutionEnvironmentSerializer
swagger_topic = "Execution Environments"
def update(self, request, *args, **kwargs):
instance = self.get_object()
fields_to_check = ['name', 'description', 'organization', 'image', 'credential']
if instance.managed and request.user.can_access(models.ExecutionEnvironment, 'change', instance):
for field in fields_to_check:
if kwargs.get('partial') and field not in request.data:
continue
left = getattr(instance, field, None)
if hasattr(left, 'id'):
left = left.id
right = request.data.get(field)
if left != right:
raise PermissionDenied(_("Only the 'pull' field can be edited for managed execution environments."))
return super().update(request, *args, **kwargs)
class ExecutionEnvironmentJobTemplateList(SubListAPIView):
@@ -878,11 +902,17 @@ class ProjectUpdateEventsList(SubListAPIView):
relationship = 'project_update_events'
name = _('Project Update Events List')
search_fields = ('stdout',)
pagination_class = UnifiedJobEventPagination
def finalize_response(self, request, response, *args, **kwargs):
response['X-UI-Max-Events'] = settings.MAX_UI_JOB_EVENTS
return super(ProjectUpdateEventsList, self).finalize_response(request, response, *args, **kwargs)
def get_queryset(self):
pu = self.get_parent_object()
self.check_parent_access(pu)
return pu.get_event_queryset()
class SystemJobEventsList(SubListAPIView):
@@ -892,11 +922,17 @@ class SystemJobEventsList(SubListAPIView):
relationship = 'system_job_events'
name = _('System Job Events List')
search_fields = ('stdout',)
pagination_class = UnifiedJobEventPagination
def finalize_response(self, request, response, *args, **kwargs):
response['X-UI-Max-Events'] = settings.MAX_UI_JOB_EVENTS
return super(SystemJobEventsList, self).finalize_response(request, response, *args, **kwargs)
def get_queryset(self):
job = self.get_parent_object()
self.check_parent_access(job)
return job.get_event_queryset()
class ProjectUpdateCancel(RetrieveAPIView):
@@ -1274,7 +1310,7 @@ class CredentialTypeDetail(RetrieveUpdateDestroyAPIView):
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.managed_by_tower:
if instance.managed:
raise PermissionDenied(detail=_("Deletion not allowed for managed credential types"))
if instance.credentials.exists():
raise PermissionDenied(detail=_("Credential types that are in use cannot be deleted"))
@@ -1389,7 +1425,7 @@ class CredentialDetail(RetrieveUpdateDestroyAPIView):
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.managed_by_tower:
if instance.managed:
raise PermissionDenied(detail=_("Deletion not allowed for managed credentials"))
return super(CredentialDetail, self).destroy(request, *args, **kwargs)
@@ -1665,106 +1701,6 @@ class GatewayTimeout(APIException):
default_code = 'gateway_timeout'
class HostInsights(GenericAPIView):
model = models.Host
serializer_class = serializers.EmptySerializer
def _call_insights_api(self, url, session, headers):
try:
with set_environ(**settings.AWX_TASK_ENV):
res = session.get(url, headers=headers, timeout=120)
except requests.exceptions.SSLError:
raise BadGateway(_('SSLError while trying to connect to {}').format(url))
except requests.exceptions.Timeout:
raise GatewayTimeout(_('Request to {} timed out.').format(url))
except requests.exceptions.RequestException as e:
raise BadGateway(_('Unknown exception {} while trying to GET {}').format(e, url))
if res.status_code == 401:
raise BadGateway(_('Unauthorized access. Please check your Insights Credential username and password.'))
elif res.status_code != 200:
raise BadGateway(
_('Failed to access the Insights API at URL {}.' ' Server responded with {} status code and message {}').format(
url, res.status_code, res.content
)
)
try:
return res.json()
except ValueError:
raise BadGateway(_('Expected JSON response from Insights at URL {}' ' but instead got {}').format(url, res.content))
def _get_session(self, username, password):
session = requests.Session()
session.auth = requests.auth.HTTPBasicAuth(username, password)
return session
def _get_platform_info(self, host, session, headers):
url = '{}/api/inventory/v1/hosts?insights_id={}'.format(settings.INSIGHTS_URL_BASE, host.insights_system_id)
res = self._call_insights_api(url, session, headers)
try:
res['results'][0]['id']
except (IndexError, KeyError):
raise NotFound(_('Could not translate Insights system ID {}' ' into an Insights platform ID.').format(host.insights_system_id))
return res['results'][0]
def _get_reports(self, platform_id, session, headers):
url = '{}/api/insights/v1/system/{}/reports/'.format(settings.INSIGHTS_URL_BASE, platform_id)
return self._call_insights_api(url, session, headers)
def _get_remediations(self, platform_id, session, headers):
url = '{}/api/remediations/v1/remediations?system={}'.format(settings.INSIGHTS_URL_BASE, platform_id)
remediations = []
# Iterate over all of the pages of content.
while url:
data = self._call_insights_api(url, session, headers)
remediations.extend(data['data'])
url = data['links']['next'] # Will be `None` if this is the last page.
return remediations
def _get_insights(self, host, session, headers):
platform_info = self._get_platform_info(host, session, headers)
platform_id = platform_info['id']
reports = self._get_reports(platform_id, session, headers)
remediations = self._get_remediations(platform_id, session, headers)
return {'insights_content': filter_insights_api_response(platform_info, reports, remediations)}
def get(self, request, *args, **kwargs):
host = self.get_object()
cred = None
if host.insights_system_id is None:
return Response(dict(error=_('This host is not recognized as an Insights host.')), status=status.HTTP_404_NOT_FOUND)
if host.inventory and host.inventory.insights_credential:
cred = host.inventory.insights_credential
else:
return Response(dict(error=_('The Insights Credential for "{}" was not found.').format(host.inventory.name)), status=status.HTTP_404_NOT_FOUND)
username = cred.get_input('username', default='')
password = cred.get_input('password', default='')
session = self._get_session(username, password)
headers = get_awx_http_client_headers()
data = self._get_insights(host, session, headers)
return Response(data, status=status.HTTP_200_OK)
def handle_exception(self, exc):
# Continue supporting the slightly different way we have handled error responses on this view.
response = super().handle_exception(exc)
response.data['error'] = response.data.pop('detail')
return response
class GroupList(ListCreateAPIView):
model = models.Group
@@ -3602,7 +3538,7 @@ class JobRelaunch(RetrieveAPIView):
status=status.HTTP_400_BAD_REQUEST,
)
host_qs = obj.retry_qs(retry_hosts)
if not obj.job_events.filter(event='playbook_on_stats').exists():
if not obj.get_event_queryset().filter(event='playbook_on_stats').exists():
return Response(
{'hosts': _('Cannot retry on {status_value} hosts, playbook stats not available.').format(status_value=retry_hosts)},
status=status.HTTP_400_BAD_REQUEST,
@@ -3729,18 +3665,22 @@ class JobHostSummaryDetail(RetrieveAPIView):
serializer_class = serializers.JobHostSummarySerializer
class JobEventList(NoTruncateMixin, ListAPIView):
model = models.JobEvent
serializer_class = serializers.JobEventSerializer
search_fields = ('stdout',)
class JobEventDetail(RetrieveAPIView):
model = models.JobEvent
serializer_class = serializers.JobEventSerializer
@property
def is_partitioned(self):
if 'pk' not in self.kwargs:
return True
return int(self.kwargs['pk']) > unpartitioned_event_horizon(models.JobEvent)
@property
def model(self):
if self.is_partitioned:
return models.JobEvent
return models.UnpartitionedJobEvent
def get_serializer_context(self):
context = super().get_serializer_context()
context.update(no_truncate=True)
@@ -3749,33 +3689,31 @@ class JobEventDetail(RetrieveAPIView):
class JobEventChildrenList(NoTruncateMixin, SubListAPIView):
model = models.JobEvent
serializer_class = serializers.JobEventSerializer
parent_model = models.JobEvent
relationship = 'children'
name = _('Job Event Children List')
search_fields = ('stdout',)
def get_queryset(self):
parent_event = self.get_parent_object()
self.check_parent_access(parent_event)
qs = self.request.user.get_queryset(self.model).filter(parent_uuid=parent_event.uuid)
return qs
@property
def is_partitioned(self):
if 'pk' not in self.kwargs:
return True
return int(self.kwargs['pk']) > unpartitioned_event_horizon(models.JobEvent)
@property
def model(self):
if self.is_partitioned:
return models.JobEvent
return models.UnpartitionedJobEvent
class JobEventHostsList(HostRelatedSearchMixin, SubListAPIView):
model = models.Host
serializer_class = serializers.HostSerializer
parent_model = models.JobEvent
relationship = 'hosts'
name = _('Job Event Hosts List')
@property
def parent_model(self):
return self.model
def get_queryset(self):
parent_event = self.get_parent_object()
self.check_parent_access(parent_event)
qs = self.request.user.get_queryset(self.model).filter(job_events_as_primary_host=parent_event)
return qs
return parent_event.job.get_event_queryset().filter(parent_uuid=parent_event.uuid)
class BaseJobEventsList(NoTruncateMixin, SubListAPIView):
@@ -3811,12 +3749,12 @@ class GroupJobEventsList(BaseJobEventsList):
class JobJobEventsList(BaseJobEventsList):
parent_model = models.Job
pagination_class = UnifiedJobEventPagination
def get_queryset(self):
job = self.get_parent_object()
self.check_parent_access(job)
qs = job.job_events.select_related('host').order_by('start_line')
return qs.all()
return job.get_event_queryset().select_related('host').order_by('start_line')
class AdHocCommandList(ListCreateAPIView):
@@ -3968,13 +3906,6 @@ class AdHocCommandRelaunch(GenericAPIView):
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
class AdHocCommandEventList(NoTruncateMixin, ListAPIView):
model = models.AdHocCommandEvent
serializer_class = serializers.AdHocCommandEventSerializer
search_fields = ('stdout',)
class AdHocCommandEventDetail(RetrieveAPIView):
model = models.AdHocCommandEvent
@@ -3994,12 +3925,21 @@ class BaseAdHocCommandEventsList(NoTruncateMixin, SubListAPIView):
relationship = 'ad_hoc_command_events'
name = _('Ad Hoc Command Events List')
search_fields = ('stdout',)
pagination_class = UnifiedJobEventPagination
def get_queryset(self):
parent = self.get_parent_object()
self.check_parent_access(parent)
return parent.get_event_queryset()
class HostAdHocCommandEventsList(BaseAdHocCommandEventsList):
parent_model = models.Host
def get_queryset(self):
return super(BaseAdHocCommandEventsList, self).get_queryset()
# class GroupJobEventsList(BaseJobEventsList):
# parent_model = Group

View File

@@ -38,6 +38,9 @@ from awx.api.serializers import (
)
from awx.api.views.mixin import RelatedJobsPreventDeleteMixin, ControlledByScmMixin
from awx.api.pagination import UnifiedJobEventPagination
logger = logging.getLogger('awx.api.views.organization')
@@ -49,6 +52,12 @@ class InventoryUpdateEventsList(SubListAPIView):
relationship = 'inventory_update_events'
name = _('Inventory Update Events List')
search_fields = ('stdout',)
pagination_class = UnifiedJobEventPagination
def get_queryset(self):
iu = self.get_parent_object()
self.check_parent_access(iu)
return iu.get_event_queryset()
def finalize_response(self, request, response, *args, **kwargs):
response['X-UI-Max-Events'] = settings.MAX_UI_JOB_EVENTS

View File

@@ -52,6 +52,11 @@ class UnifiedJobDeletionMixin(object):
else:
# if it has been > 1 minute, events are probably lost
logger.warning('Allowing deletion of {} through the API without all events ' 'processed.'.format(obj.log_format))
# Manually cascade delete events if unpartitioned job
if obj.has_unpartitioned_events:
obj.get_event_queryset().delete()
obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

View File

@@ -30,6 +30,7 @@ from awx.api.versioning import reverse, drf_reverse
from awx.main.constants import PRIVILEGE_ESCALATION_METHODS
from awx.main.models import Project, Organization, Instance, InstanceGroup, JobTemplate
from awx.main.utils import set_environ
from awx.main.utils.licensing import get_licenser
logger = logging.getLogger('awx.api.views.root')
@@ -106,7 +107,6 @@ class ApiVersionRootView(APIView):
data['hosts'] = reverse('api:host_list', request=request)
data['job_templates'] = reverse('api:job_template_list', request=request)
data['jobs'] = reverse('api:job_list', request=request)
data['job_events'] = reverse('api:job_event_list', request=request)
data['ad_hoc_commands'] = reverse('api:ad_hoc_command_list', request=request)
data['system_job_templates'] = reverse('api:system_job_template_list', request=request)
data['system_jobs'] = reverse('api:system_job_list', request=request)
@@ -174,8 +174,6 @@ class ApiV2SubscriptionView(APIView):
self.permission_denied(request) # Raises PermissionDenied exception.
def post(self, request):
from awx.main.utils.common import get_licenser
data = request.data.copy()
if data.get('subscriptions_password') == '$encrypted$':
data['subscriptions_password'] = settings.SUBSCRIPTIONS_PASSWORD
@@ -223,7 +221,6 @@ class ApiV2AttachView(APIView):
user = getattr(settings, 'SUBSCRIPTIONS_USERNAME', None)
pw = getattr(settings, 'SUBSCRIPTIONS_PASSWORD', None)
if pool_id and user and pw:
from awx.main.utils.common import get_licenser
data = request.data.copy()
try:
@@ -265,8 +262,6 @@ class ApiV2ConfigView(APIView):
def get(self, request, format=None):
'''Return various sitewide configuration settings'''
from awx.main.utils.common import get_licenser
license_data = get_licenser().validate()
if not license_data.get('valid_key', False):
@@ -302,7 +297,9 @@ class ApiV2ConfigView(APIView):
):
data.update(
dict(
project_base_dir=settings.PROJECTS_ROOT, project_local_paths=Project.get_local_path_choices(), custom_virtualenvs=get_custom_venv_choices()
project_base_dir=settings.PROJECTS_ROOT,
project_local_paths=Project.get_local_path_choices(),
custom_virtualenvs=get_custom_venv_choices(),
)
)
elif JobTemplate.accessible_objects(request.user, 'admin_role').exists():
@@ -319,8 +316,6 @@ class ApiV2ConfigView(APIView):
logger.info(smart_text(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username))
return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST)
from awx.main.utils.common import get_licenser
license_data = json.loads(data_actual)
if 'license_key' in license_data:
return Response({"error": _('Legacy license submitted. A subscription manifest is now required.')}, status=status.HTTP_400_BAD_REQUEST)

View File

@@ -1,62 +0,0 @@
import base64
import hashlib
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
from cryptography.hazmat.primitives.ciphers.modes import ECB
__all__ = ['get_encryption_key', 'decrypt_field']
def get_encryption_key(field_name, pk=None):
"""
Generate key for encrypted password based on field name,
``settings.SECRET_KEY``, and instance pk (if available).
:param pk: (optional) the primary key of the ``awx.conf.model.Setting``;
can be omitted in situations where you're encrypting a setting
that is not database-persistent (like a read-only setting)
"""
from django.conf import settings
h = hashlib.sha1()
h.update(settings.SECRET_KEY)
if pk is not None:
h.update(str(pk))
h.update(field_name)
return h.digest()[:16]
def decrypt_value(encryption_key, value):
raw_data = value[len('$encrypted$') :]
# If the encrypted string contains a UTF8 marker, discard it
utf8 = raw_data.startswith('UTF8$')
if utf8:
raw_data = raw_data[len('UTF8$') :]
algo, b64data = raw_data.split('$', 1)
if algo != 'AES':
raise ValueError('unsupported algorithm: %s' % algo)
encrypted = base64.b64decode(b64data)
decryptor = Cipher(AES(encryption_key), ECB(), default_backend()).decryptor()
value = decryptor.update(encrypted) + decryptor.finalize()
value = value.rstrip('\x00')
# If the encrypted string contained a UTF8 marker, decode the data
if utf8:
value = value.decode('utf-8')
return value
def decrypt_field(instance, field_name, subfield=None):
"""
Return content of the given instance and field name decrypted.
"""
value = getattr(instance, field_name)
if isinstance(value, dict) and subfield is not None:
value = value[subfield]
if not value or not value.startswith('$encrypted$'):
return value
key = get_encryption_key(field_name, getattr(instance, 'pk', None))
return decrypt_value(key, value)

View File

@@ -23,8 +23,8 @@ import cachetools
# AWX
from awx.main.utils import encrypt_field, decrypt_field
from awx.conf import settings_registry
from awx.conf.fields import PrimaryKeyRelatedField
from awx.conf.models import Setting
from awx.conf.migrations._reencrypt import decrypt_field as old_decrypt_field
# FIXME: Gracefully handle when settings are accessed before the database is
# ready (or during migrations).
@@ -298,13 +298,7 @@ class SettingsWrapper(UserSettingsHolder):
continue
if self.registry.is_setting_encrypted(setting.key):
setting_ids[setting.key] = setting.id
try:
value = decrypt_field(setting, 'value')
except ValueError as e:
# TODO: Remove in Tower 3.3
logger.debug('encountered error decrypting field: %s - attempting fallback to old', e)
value = old_decrypt_field(setting, 'value')
value = decrypt_field(setting, 'value')
else:
value = setting.value
settings_to_cache[setting.key] = get_cache_value(value)
@@ -420,9 +414,9 @@ class SettingsWrapper(UserSettingsHolder):
raise ImproperlyConfigured('Setting "{}" is read only.'.format(name))
try:
data = field.to_representation(value)
data = None if value is None and isinstance(field, PrimaryKeyRelatedField) else field.to_representation(value)
setting_value = field.run_validation(data)
db_value = field.to_representation(setting_value)
db_value = None if setting_value is None and isinstance(field, PrimaryKeyRelatedField) else field.to_representation(setting_value)
except Exception as e:
logger.exception('Unable to assign value "%r" to setting "%s".', value, name, exc_info=True)
raise e

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -45,6 +45,7 @@ from awx.main.models import (
InventoryUpdateEvent,
Job,
JobEvent,
UnpartitionedJobEvent,
JobHostSummary,
JobLaunchConfig,
JobTemplate,
@@ -464,7 +465,7 @@ class BaseAccess(object):
if display_method == 'schedule':
user_capabilities['schedule'] = user_capabilities['start']
continue
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob, CredentialInputSource)):
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob, CredentialInputSource, ExecutionEnvironment)):
user_capabilities['delete'] = user_capabilities['edit']
continue
elif display_method == 'copy' and isinstance(obj, (Group, Host)):
@@ -866,13 +867,11 @@ class InventoryAccess(BaseAccess):
# If no data is specified, just checking for generic add permission?
if not data:
return Organization.accessible_objects(self.user, 'inventory_admin_role').exists()
return self.check_related('organization', Organization, data, role_field='inventory_admin_role') and self.check_related(
'insights_credential', Credential, data, role_field='use_role'
)
return self.check_related('organization', Organization, data, role_field='inventory_admin_role')
@check_superuser
def can_change(self, obj, data):
return self.can_admin(obj, data) and self.check_related('insights_credential', Credential, data, obj=obj, role_field='use_role')
return self.can_admin(obj, data)
@check_superuser
def can_admin(self, obj, data):
@@ -1037,7 +1036,7 @@ class InventorySourceAccess(NotificationAttachMixin, BaseAccess):
def can_add(self, data):
if not data or 'inventory' not in data:
return Organization.accessible_objects(self.user, 'admin_role').exists()
return Inventory.accessible_objects(self.user, 'admin_role').exists()
if not self.check_related('source_project', Project, data, role_field='use_role'):
return False
@@ -1120,7 +1119,7 @@ class CredentialTypeAccess(BaseAccess):
I can create when:
- I'm a superuser:
I can change when:
- I'm a superuser and the type is not "managed by Tower"
- I'm a superuser and the type is not "managed"
"""
model = CredentialType
@@ -1206,7 +1205,7 @@ class CredentialAccess(BaseAccess):
def get_user_capabilities(self, obj, **kwargs):
user_capabilities = super(CredentialAccess, self).get_user_capabilities(obj, **kwargs)
user_capabilities['use'] = self.can_use(obj)
if getattr(obj, 'managed_by_tower', False) is True:
if getattr(obj, 'managed', False) is True:
user_capabilities['edit'] = user_capabilities['delete'] = False
return user_capabilities
@@ -1369,6 +1368,8 @@ class ExecutionEnvironmentAccess(BaseAccess):
return self.check_related('organization', Organization, data, obj=obj, mandatory=True, role_field='execution_environment_admin_role')
def can_delete(self, obj):
if obj.managed:
raise PermissionDenied
return self.can_change(obj, None)
@@ -2352,6 +2353,11 @@ class JobEventAccess(BaseAccess):
return False
class UnpartitionedJobEventAccess(JobEventAccess):
model = UnpartitionedJobEvent
class ProjectUpdateEventAccess(BaseAccess):
"""
I can see project update event records whenever I can access the project update
@@ -2895,3 +2901,4 @@ class WorkflowApprovalTemplateAccess(BaseAccess):
for cls in BaseAccess.__subclasses__():
access_registry[cls.model] = cls
access_registry[UnpartitionedJobEvent] = UnpartitionedJobEventAccess

View File

@@ -6,7 +6,7 @@ import platform
import distro
from django.db import connection
from django.db.models import Count, Max, Min
from django.db.models import Count
from django.conf import settings
from django.contrib.sessions.models import Session
from django.utils.timezone import now, timedelta
@@ -15,7 +15,7 @@ from django.utils.translation import ugettext_lazy as _
from psycopg2.errors import UntranslatableCharacter
from awx.conf.license import get_license
from awx.main.utils import get_awx_version, get_custom_venv_choices, camelcase_to_underscore, datetime_hook
from awx.main.utils import get_awx_version, camelcase_to_underscore, datetime_hook
from awx.main import models
from awx.main.analytics import register
@@ -58,7 +58,10 @@ def four_hour_slicing(key, since, until, last_gather):
horizon = until - timedelta(weeks=4)
last_entries = Setting.objects.filter(key='AUTOMATION_ANALYTICS_LAST_ENTRIES').first()
last_entries = json.loads((last_entries.value if last_entries is not None else '') or '{}', object_hook=datetime_hook)
last_entry = max(last_entries.get(key) or last_gather, horizon)
try:
last_entry = max(last_entries.get(key) or last_gather, horizon)
except TypeError: # last_entries has a stale non-datetime entry for this collector
last_entry = max(last_gather, horizon)
start, end = last_entry, None
while start < until:
@@ -67,7 +70,7 @@ def four_hour_slicing(key, since, until, last_gather):
start = end
def events_slicing(key, since, until, last_gather):
def _identify_lower(key, since, until, last_gather):
from awx.conf.models import Setting
last_entries = Setting.objects.filter(key='AUTOMATION_ANALYTICS_LAST_ENTRIES').first()
@@ -77,16 +80,8 @@ def events_slicing(key, since, until, last_gather):
lower = since or last_gather
if not since and last_entries.get(key):
lower = horizon
pk_values = models.JobEvent.objects.filter(created__gte=lower, created__lte=until).aggregate(Min('pk'), Max('pk'))
previous_pk = pk_values['pk__min'] - 1 if pk_values['pk__min'] is not None else 0
if not since and last_entries.get(key):
previous_pk = max(last_entries[key], previous_pk)
final_pk = pk_values['pk__max'] or 0
step = 100000
for start in range(previous_pk, final_pk + 1, step):
yield (start, min(start + step, final_pk))
return lower, last_entries
@register('config', '1.3', description=_('General platform configuration.'))
@@ -120,7 +115,7 @@ def config(since, **kwargs):
}
@register('counts', '1.0', description=_('Counts of objects such as organizations, inventories, and projects'))
@register('counts', '1.1', description=_('Counts of objects such as organizations, inventories, and projects'))
def counts(since, **kwargs):
counts = {}
for cls in (
@@ -138,9 +133,6 @@ def counts(since, **kwargs):
):
counts[camelcase_to_underscore(cls.__name__)] = cls.objects.count()
venvs = get_custom_venv_choices()
counts['custom_virtualenvs'] = len([v for v in venvs if os.path.basename(v.rstrip('/')) != 'ansible'])
inv_counts = dict(models.Inventory.objects.order_by().values_list('kind').annotate(Count('kind')))
inv_counts['normal'] = inv_counts.get('', 0)
inv_counts.pop('', None)
@@ -183,12 +175,12 @@ def org_counts(since, **kwargs):
def cred_type_counts(since, **kwargs):
counts = {}
for cred_type in models.CredentialType.objects.annotate(num_credentials=Count('credentials', distinct=True)).values(
'name', 'id', 'managed_by_tower', 'num_credentials'
'name', 'id', 'managed', 'num_credentials'
):
counts[cred_type['id']] = {
'name': cred_type['name'],
'credential_count': cred_type['num_credentials'],
'managed_by_tower': cred_type['managed_by_tower'],
'managed': cred_type['managed'],
}
return counts
@@ -335,39 +327,49 @@ def _copy_table(table, query, path):
return file.file_list()
@register('events_table', '1.2', format='csv', description=_('Automation task records'), expensive=events_slicing)
def events_table(since, full_path, until, **kwargs):
def _events_table(since, full_path, until, tbl, where_column, project_job_created=False, **kwargs):
def query(event_data):
return f'''COPY (SELECT main_jobevent.id,
main_jobevent.created,
main_jobevent.modified,
main_jobevent.uuid,
main_jobevent.parent_uuid,
main_jobevent.event,
{event_data}->'task_action' AS task_action,
(CASE WHEN event = 'playbook_on_stats' THEN event_data END) as playbook_on_stats,
main_jobevent.failed,
main_jobevent.changed,
main_jobevent.playbook,
main_jobevent.play,
main_jobevent.task,
main_jobevent.role,
main_jobevent.job_id,
main_jobevent.host_id,
main_jobevent.host_name,
CAST({event_data}->>'start' AS TIMESTAMP WITH TIME ZONE) AS start,
CAST({event_data}->>'end' AS TIMESTAMP WITH TIME ZONE) AS end,
{event_data}->'duration' AS duration,
{event_data}->'res'->'warnings' AS warnings,
{event_data}->'res'->'deprecations' AS deprecations
FROM main_jobevent
WHERE (main_jobevent.id > {since} AND main_jobevent.id <= {until})
ORDER BY main_jobevent.id ASC) TO STDOUT WITH CSV HEADER'''
query = f'''COPY (SELECT {tbl}.id,
{tbl}.created,
{tbl}.modified,
{tbl + '.job_created' if project_job_created else 'NULL'} as job_created,
{tbl}.uuid,
{tbl}.parent_uuid,
{tbl}.event,
task_action,
(CASE WHEN event = 'playbook_on_stats' THEN event_data END) as playbook_on_stats,
{tbl}.failed,
{tbl}.changed,
{tbl}.playbook,
{tbl}.play,
{tbl}.task,
{tbl}.role,
{tbl}.job_id,
{tbl}.host_id,
{tbl}.host_name,
CAST(x.start AS TIMESTAMP WITH TIME ZONE) AS start,
CAST(x.end AS TIMESTAMP WITH TIME ZONE) AS end,
x.duration AS duration,
x.res->'warnings' AS warnings,
x.res->'deprecations' AS deprecations
FROM {tbl}, json_to_record({event_data}) AS x("res" json, "duration" text, "task_action" text, "start" text, "end" text)
WHERE ({tbl}.{where_column} > '{since.isoformat()}' AND {tbl}.{where_column} <= '{until.isoformat()}')) TO STDOUT WITH CSV HEADER'''
return query
try:
return _copy_table(table='events', query=query("main_jobevent.event_data::json"), path=full_path)
return _copy_table(table='events', query=query(f"{tbl}.event_data::json"), path=full_path)
except UntranslatableCharacter:
return _copy_table(table='events', query=query("replace(main_jobevent.event_data::text, '\\u0000', '')::json"), path=full_path)
return _copy_table(table='events', query=query(f"replace({tbl}.event_data::text, '\\u0000', '')::json"), path=full_path)
@register('events_table', '1.3', format='csv', description=_('Automation task records'), expensive=four_hour_slicing)
def events_table_unpartitioned(since, full_path, until, **kwargs):
return _events_table(since, full_path, until, '_unpartitioned_main_jobevent', 'created', **kwargs)
@register('events_table', '1.3', format='csv', description=_('Automation task records'), expensive=four_hour_slicing)
def events_table_partitioned_modified(since, full_path, until, **kwargs):
return _events_table(since, full_path, until, 'main_jobevent', 'modified', project_job_created=True, **kwargs)
@register('unified_jobs_table', '1.2', format='csv', description=_('Data on jobs run'), expensive=four_hour_slicing)

View File

@@ -270,7 +270,8 @@ def gather(dest=None, module=None, subset=None, since=None, until=None, collecti
if not files:
if collection_type != 'dry-run':
with disable_activity_stream():
last_entries[key] = max(last_entries[key], end) if last_entries.get(key) else end
entry = last_entries.get(key)
last_entries[key] = max(entry, end) if entry and type(entry) == type(end) else end
settings.AUTOMATION_ANALYTICS_LAST_ENTRIES = json.dumps(last_entries, cls=DjangoJSONEncoder)
continue
@@ -293,7 +294,8 @@ def gather(dest=None, module=None, subset=None, since=None, until=None, collecti
if slice_succeeded and collection_type != 'dry-run':
with disable_activity_stream():
last_entries[key] = max(last_entries[key], end) if last_entries.get(key) else end
entry = last_entries.get(key)
last_entries[key] = max(entry, end) if entry and type(entry) == type(end) else end
settings.AUTOMATION_ANALYTICS_LAST_ENTRIES = json.dumps(last_entries, cls=DjangoJSONEncoder)
except Exception:
succeeded = False

View File

@@ -39,7 +39,6 @@ def metrics():
],
registry=REGISTRY,
)
CUSTOM_VENVS = Gauge('awx_custom_virtualenvs_total', 'Number of virtualenvs', registry=REGISTRY)
RUNNING_JOBS = Gauge('awx_running_jobs_total', 'Number of running jobs on the system', registry=REGISTRY)
PENDING_JOBS = Gauge('awx_pending_jobs_total', 'Number of pending jobs on the system', registry=REGISTRY)
STATUS = Gauge(
@@ -159,7 +158,6 @@ def metrics():
HOST_COUNT.labels(type='active').set(current_counts['active_host_count'])
SCHEDULE_COUNT.set(current_counts['schedule'])
CUSTOM_VENVS.set(current_counts['custom_virtualenvs'])
USER_SESSIONS.labels(type='all').set(current_counts['active_sessions'])
USER_SESSIONS.labels(type='user').set(current_counts['active_user_sessions'])

View File

@@ -177,6 +177,24 @@ register(
read_only=True,
)
register(
'DEFAULT_CONTROL_PLANE_QUEUE_NAME',
field_class=fields.CharField,
label=_('The instance group where control plane tasks run'),
category=_('System'),
category_slug='system',
read_only=True,
)
register(
'DEFAULT_EXECUTION_QUEUE_NAME',
field_class=fields.CharField,
label=_('The instance group where user jobs run (currently only on non-VM installs)'),
category=_('System'),
category_slug='system',
read_only=True,
)
register(
'DEFAULT_EXECUTION_ENVIRONMENT',
field_class=fields.PrimaryKeyRelatedField,
@@ -344,6 +362,17 @@ register(
category_slug='jobs',
)
register(
'MAX_WEBSOCKET_EVENT_RATE',
field_class=fields.IntegerField,
min_value=0,
default=30,
label=_('Job Event Maximum Websocket Messages Per Second'),
help_text=_('Maximum number of messages to update the UI live job output with per second. Value of 0 means no limit.'),
category=_('Jobs'),
category_slug='jobs',
)
register(
'SCHEDULE_MAX_JOBS',
field_class=fields.IntegerField,
@@ -663,6 +692,15 @@ register(
unit=_('seconds'),
)
register(
'IS_K8S',
field_class=fields.BooleanField,
read_only=True,
category=_('System'),
category_slug='system',
help_text=_('Indicates whether the instance is part of a kubernetes-based deployment.'),
)
def logging_validate(serializer, attrs):
if not serializer.instance or not hasattr(serializer.instance, 'LOG_AGGREGATOR_HOST') or not hasattr(serializer.instance, 'LOG_AGGREGATOR_TYPE'):

View File

@@ -14,7 +14,7 @@ __all__ = [
'STANDARD_INVENTORY_UPDATE_ENV',
]
CLOUD_PROVIDERS = ('azure_rm', 'ec2', 'gce', 'vmware', 'openstack', 'rhv', 'satellite6', 'tower')
CLOUD_PROVIDERS = ('azure_rm', 'ec2', 'gce', 'vmware', 'openstack', 'rhv', 'satellite6', 'controller', 'insights')
PRIVILEGE_ESCALATION_METHODS = [
('sudo', _('Sudo')),
('su', _('Su')),
@@ -41,6 +41,7 @@ STANDARD_INVENTORY_UPDATE_ENV = {
}
CAN_CANCEL = ('new', 'pending', 'waiting', 'running')
ACTIVE_STATES = CAN_CANCEL
MINIMAL_EVENTS = set(['playbook_on_play_start', 'playbook_on_task_start', 'playbook_on_stats', 'EOF'])
CENSOR_VALUE = '************'
ENV_BLOCKLIST = frozenset(
(

View File

@@ -0,0 +1,56 @@
from .plugin import CredentialPlugin
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from thycotic.secrets.vault import SecretsVault
dsv_inputs = {
'fields': [
{
'id': 'tenant',
'label': _('Tenant'),
'help_text': _('The tenant e.g. "ex" when the URL is https://ex.secretservercloud.com'),
'type': 'string',
},
{
'id': 'tld',
'label': _('Top-level Domain (TLD)'),
'help_text': _('The TLD of the tenant e.g. "com" when the URL is https://ex.secretservercloud.com'),
'choices': ['ca', 'com', 'com.au', 'com.sg', 'eu'],
'default': 'com',
},
{'id': 'client_id', 'label': _('Client ID'), 'type': 'string'},
{
'id': 'client_secret',
'label': _('Client Secret'),
'type': 'string',
'secret': True,
},
],
'metadata': [
{
'id': 'path',
'label': _('Secret Path'),
'type': 'string',
'help_text': _('The secret path e.g. /test/secret1'),
},
],
'required': ['tenant', 'client_id', 'client_secret', 'path'],
}
if settings.DEBUG:
dsv_inputs['fields'].append(
{
'id': 'url_template',
'label': _('URL template'),
'type': 'string',
'default': 'https://{}.secretsvaultcloud.{}/v1',
}
)
dsv_plugin = CredentialPlugin(
'Thycotic DevOps Secrets Vault',
dsv_inputs,
lambda **kwargs: SecretsVault(**{k: v for (k, v) in kwargs.items() if k in [field['id'] for field in dsv_inputs['fields']]}).get_secret(kwargs['path']),
)

View File

@@ -63,7 +63,15 @@ base_inputs = {
'id': 'secret_path',
'label': _('Path to Secret'),
'type': 'string',
'help_text': _('The path to the secret stored in the secret backend e.g, /some/secret/'),
'help_text': _(
(
'The path to the secret stored in the secret backend e.g, /some/secret/. It is recommended'
' that you use the secret backend field to identify the storage backend and to use this field'
' for locating a specific secret within that store. However, if you prefer to fully identify'
' both the secret backend and one of its secrets using only this field, join their locations'
' into a single path without any additional separators, e.g, /location/of/backend/some/secret.'
)
),
},
{
'id': 'auth_path',

View File

@@ -0,0 +1,59 @@
from .plugin import CredentialPlugin
from django.utils.translation import ugettext_lazy as _
from thycotic.secrets.server import PasswordGrantAuthorizer, SecretServer, ServerSecret
tss_inputs = {
'fields': [
{
'id': 'server_url',
'label': _('Secret Server URL'),
'help_text': _('The Base URL of Secret Server e.g. https://myserver/SecretServer or https://mytenant.secretservercloud.com'),
'type': 'string',
},
{
'id': 'username',
'label': _('Username'),
'help_text': _('The (Application) user username'),
'type': 'string',
},
{
'id': 'password',
'label': _('Password'),
'help_text': _('The corresponding password'),
'type': 'string',
'secret': True,
},
],
'metadata': [
{
'id': 'secret_id',
'label': _('Secret ID'),
'help_text': _('The integer ID of the secret'),
'type': 'string',
},
{
'id': 'secret_field',
'label': _('Secret Field'),
'help_text': _('The field to extract from the secret'),
'type': 'string',
},
],
'required': ['server_url', 'username', 'password', 'secret_id', 'secret_field'],
}
def tss_backend(**kwargs):
authorizer = PasswordGrantAuthorizer(kwargs['server_url'], kwargs['username'], kwargs['password'])
secret_server = SecretServer(kwargs['server_url'], authorizer)
secret_dict = secret_server.get_secret(kwargs['secret_id'])
secret = ServerSecret(**secret_dict)
return secret.fields[kwargs['secret_field']]
tss_plugin = CredentialPlugin(
'Thycotic Secret Server',
tss_inputs,
tss_backend,
)

View File

@@ -142,7 +142,8 @@ class CallbackBrokerWorker(BaseWorker):
logger.exception('Database Error Saving Job Event')
duration_to_save = time.perf_counter() - duration_to_save
for e in events:
emit_event_detail(e)
if not getattr(e, '_skip_websocket_message', False):
emit_event_detail(e)
self.buff = {}
self.last_flush = time.time()
# only update metrics if we saved events
@@ -207,7 +208,13 @@ class CallbackBrokerWorker(BaseWorker):
GuidMiddleware.set_guid('')
return
skip_websocket_message = body.pop('skip_websocket_message', False)
event = cls.create_from_data(**body)
if skip_websocket_message:
event._skip_websocket_message = True
self.buff.setdefault(cls, []).append(event)
retries = 0

View File

@@ -642,7 +642,7 @@ class CredentialInputField(JSONSchemaField):
# `ssh_key_unlock` requirements are very specific and can't be
# represented without complicated JSON schema
if model_instance.credential_type.managed_by_tower is True and 'ssh_key_unlock' in defined_fields:
if model_instance.credential_type.managed is True and 'ssh_key_unlock' in defined_fields:
# in order to properly test the necessity of `ssh_key_unlock`, we
# need to know the real value of `ssh_key_data`; for a payload like:
@@ -711,7 +711,7 @@ class CredentialTypeInputField(JSONSchemaField):
}
def validate(self, value, model_instance):
if isinstance(value, dict) and 'dependencies' in value and not model_instance.managed_by_tower:
if isinstance(value, dict) and 'dependencies' in value and not model_instance.managed:
raise django_exceptions.ValidationError(
_("'dependencies' is not supported for custom credentials."),
code='invalid',

View File

@@ -4,11 +4,13 @@
# Python
import datetime
import logging
import pytz
import re
# Django
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.db import transaction, connection
from django.utils.timezone import now
# AWX
@@ -18,6 +20,132 @@ from awx.main.signals import disable_activity_stream, disable_computed_fields
from awx.main.utils.deletion import AWXCollector, pre_delete
def unified_job_class_to_event_table_name(job_class):
return f'main_{job_class().event_class.__name__.lower()}'
def partition_table_name(job_class, dt):
suffix = dt.replace(microsecond=0, second=0, minute=0).strftime('%Y%m%d_%H')
event_tbl_name = unified_job_class_to_event_table_name(job_class)
event_tbl_name += f'_{suffix}'
return event_tbl_name
def partition_name_dt(part_name):
"""
part_name examples:
main_jobevent_20210318_09
main_projectupdateevent_20210318_11
main_inventoryupdateevent_20210318_03
"""
if '_unpartitioned' in part_name:
return None
p = re.compile('([a-z]+)_([a-z]+)_([0-9]+)_([0-9][0-9])')
m = p.match(part_name)
if not m:
return m
dt_str = f"{m.group(3)}_{m.group(4)}"
dt = datetime.datetime.strptime(dt_str, '%Y%m%d_%H').replace(tzinfo=pytz.UTC)
return dt
def dt_to_partition_name(tbl_name, dt):
return f"{tbl_name}_{dt.strftime('%Y%m%d_%H')}"
class DeleteMeta:
def __init__(self, logger, job_class, cutoff, dry_run):
self.logger = logger
self.job_class = job_class
self.cutoff = cutoff
self.dry_run = dry_run
self.jobs_qs = None # Set in by find_jobs_to_delete()
self.parts_no_drop = set() # Set in identify_excluded_partitions()
self.parts_to_drop = set() # Set in find_partitions_to_drop()
self.jobs_pk_list = [] # Set in find_jobs_to_delete()
self.jobs_to_delete_count = 0 # Set in find_jobs_to_delete()
self.jobs_no_delete_count = 0 # Set in find_jobs_to_delete()
def find_jobs_to_delete(self):
self.jobs_qs = self.job_class.objects.filter(created__lt=self.cutoff).values_list('pk', 'status', 'created')
for pk, status, created in self.jobs_qs:
if status not in ['pending', 'waiting', 'running']:
self.jobs_to_delete_count += 1
self.jobs_pk_list.append(pk)
self.jobs_no_delete_count = (
self.job_class.objects.filter(created__gte=self.cutoff) | self.job_class.objects.filter(status__in=['pending', 'waiting', 'running'])
).count()
def identify_excluded_partitions(self):
part_drop = {}
for pk, status, created in self.jobs_qs:
part_key = partition_table_name(self.job_class, created)
if status in ['pending', 'waiting', 'running']:
part_drop[part_key] = False
else:
part_drop.setdefault(part_key, True)
# Note that parts_no_drop _may_ contain the names of partitions that don't exist
# This can happen when the cleanup of _unpartitioned_* logic leaves behind jobs with status pending, waiting, running. The find_jobs_to_delete() will
# pick these jobs up.
self.parts_no_drop = set([k for k, v in part_drop.items() if v is False])
def delete_jobs(self):
if not self.dry_run:
self.job_class.objects.filter(pk__in=self.jobs_pk_list).delete()
def find_partitions_to_drop(self):
tbl_name = unified_job_class_to_event_table_name(self.job_class)
with connection.cursor() as cursor:
query = "SELECT inhrelid::regclass::text AS child FROM pg_catalog.pg_inherits"
query += f" WHERE inhparent = 'public.{tbl_name}'::regclass"
query += f" AND TO_TIMESTAMP(LTRIM(inhrelid::regclass::text, '{tbl_name}_'), 'YYYYMMDD_HH24') < '{self.cutoff}'"
query += " ORDER BY inhrelid::regclass::text"
cursor.execute(query)
partitions_from_db = [r[0] for r in cursor.fetchall()]
partitions_dt = [partition_name_dt(p) for p in partitions_from_db if not None]
partitions_dt = [p for p in partitions_dt if not None]
# convert datetime partition back to string partition
partitions_maybe_drop = set([dt_to_partition_name(tbl_name, dt) for dt in partitions_dt])
# Do not drop partition if there is a job that will not be deleted pointing at it
self.parts_to_drop = partitions_maybe_drop - self.parts_no_drop
def drop_partitions(self):
if len(self.parts_to_drop) > 0:
parts_to_drop = list(self.parts_to_drop)
parts_to_drop.sort() # sort it to make reading it easier for humans
parts_to_drop_str = ','.join(parts_to_drop)
if self.dry_run:
self.logger.debug(f"Would drop event partition(s) {parts_to_drop_str}")
else:
self.logger.debug(f"Dropping event partition(s) {parts_to_drop_str}")
if not self.dry_run:
with connection.cursor() as cursor:
cursor.execute(f"DROP TABLE {parts_to_drop_str}")
else:
self.logger.debug("No event partitions to drop")
def delete(self):
self.find_jobs_to_delete()
self.identify_excluded_partitions()
self.find_partitions_to_drop()
self.drop_partitions()
self.delete_jobs()
return (self.jobs_no_delete_count, self.jobs_to_delete_count)
class Command(BaseCommand):
"""
Management command to cleanup old jobs and project updates.
@@ -36,6 +164,43 @@ class Command(BaseCommand):
parser.add_argument('--notifications', dest='only_notifications', action='store_true', default=False, help='Remove notifications')
parser.add_argument('--workflow-jobs', default=False, action='store_true', dest='only_workflow_jobs', help='Remove workflow jobs')
def cleanup(self, job_class):
delete_meta = DeleteMeta(self.logger, job_class, self.cutoff, self.dry_run)
skipped, deleted = delete_meta.delete()
return (delete_meta.jobs_no_delete_count, delete_meta.jobs_to_delete_count)
def cleanup_jobs_partition(self):
return self.cleanup(Job)
def cleanup_ad_hoc_commands_partition(self):
return self.cleanup(AdHocCommand)
def cleanup_project_updates_partition(self):
return self.cleanup(ProjectUpdate)
def cleanup_inventory_updates_partition(self):
return self.cleanup(InventoryUpdate)
def cleanup_management_jobs_partition(self):
return self.cleanup(SystemJob)
def cleanup_workflow_jobs_partition(self):
delete_meta = DeleteMeta(self.logger, WorkflowJob, self.cutoff, self.dry_run)
delete_meta.find_jobs_to_delete()
delete_meta.delete_jobs()
return (delete_meta.jobs_no_delete_count, delete_meta.jobs_to_delete_count)
def _cascade_delete_job_events(self, model, pk_list):
if len(pk_list) > 0:
with connection.cursor() as cursor:
tblname = unified_job_class_to_event_table_name(model)
pk_list_csv = ','.join(map(str, pk_list))
rel_name = model().event_parent_key
cursor.execute(f"DELETE FROM _unpartitioned_{tblname} WHERE {rel_name} IN ({pk_list_csv})")
def cleanup_jobs(self):
skipped, deleted = 0, 0
@@ -45,12 +210,14 @@ class Command(BaseCommand):
# get queryset for available jobs to remove
qs = Job.objects.filter(created__lt=self.cutoff).exclude(status__in=['pending', 'waiting', 'running'])
# get pk list for the first N (batch_size) objects
pk_list = qs[0:batch_size].values_list('pk')
pk_list = qs[0:batch_size].values_list('pk', flat=True)
# You cannot delete queries with sql LIMIT set, so we must
# create a new query from this pk_list
qs_batch = Job.objects.filter(pk__in=pk_list)
just_deleted = 0
if not self.dry_run:
self._cascade_delete_job_events(Job, pk_list)
del_query = pre_delete(qs_batch)
collector = AWXCollector(del_query.db)
collector.collect(del_query)
@@ -71,6 +238,7 @@ class Command(BaseCommand):
def cleanup_ad_hoc_commands(self):
skipped, deleted = 0, 0
ad_hoc_commands = AdHocCommand.objects.filter(created__lt=self.cutoff)
pk_list = []
for ad_hoc_command in ad_hoc_commands.iterator():
ad_hoc_command_display = '"%s" (%d events)' % (str(ad_hoc_command), ad_hoc_command.ad_hoc_command_events.count())
if ad_hoc_command.status in ('pending', 'waiting', 'running'):
@@ -81,15 +249,20 @@ class Command(BaseCommand):
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, ad_hoc_command_display)
if not self.dry_run:
pk_list.append(ad_hoc_command.pk)
ad_hoc_command.delete()
deleted += 1
if not self.dry_run:
self._cascade_delete_job_events(AdHocCommand, pk_list)
skipped += AdHocCommand.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_project_updates(self):
skipped, deleted = 0, 0
project_updates = ProjectUpdate.objects.filter(created__lt=self.cutoff)
pk_list = []
for pu in project_updates.iterator():
pu_display = '"%s" (type %s)' % (str(pu), str(pu.launch_type))
if pu.status in ('pending', 'waiting', 'running'):
@@ -104,15 +277,20 @@ class Command(BaseCommand):
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, pu_display)
if not self.dry_run:
pk_list.append(pu.pk)
pu.delete()
deleted += 1
if not self.dry_run:
self._cascade_delete_job_events(ProjectUpdate, pk_list)
skipped += ProjectUpdate.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_inventory_updates(self):
skipped, deleted = 0, 0
inventory_updates = InventoryUpdate.objects.filter(created__lt=self.cutoff)
pk_list = []
for iu in inventory_updates.iterator():
iu_display = '"%s" (source %s)' % (str(iu), str(iu.source))
if iu.status in ('pending', 'waiting', 'running'):
@@ -127,15 +305,20 @@ class Command(BaseCommand):
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, iu_display)
if not self.dry_run:
pk_list.append(iu.pk)
iu.delete()
deleted += 1
if not self.dry_run:
self._cascade_delete_job_events(InventoryUpdate, pk_list)
skipped += InventoryUpdate.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_management_jobs(self):
skipped, deleted = 0, 0
system_jobs = SystemJob.objects.filter(created__lt=self.cutoff)
pk_list = []
for sj in system_jobs.iterator():
sj_display = '"%s" (type %s)' % (str(sj), str(sj.job_type))
if sj.status in ('pending', 'waiting', 'running'):
@@ -146,9 +329,13 @@ class Command(BaseCommand):
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, sj_display)
if not self.dry_run:
pk_list.append(sj.pk)
sj.delete()
deleted += 1
if not self.dry_run:
self._cascade_delete_job_events(SystemJob, pk_list)
skipped += SystemJob.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
@@ -222,6 +409,13 @@ class Command(BaseCommand):
for m in model_names:
if m in models_to_cleanup:
skipped, deleted = getattr(self, 'cleanup_%s' % m)()
func = getattr(self, 'cleanup_%s_partition' % m, None)
if func:
skipped_partition, deleted_partition = func()
skipped += skipped_partition
deleted += deleted_partition
if self.dry_run:
self.logger.log(99, '%s: %d would be deleted, %d would be skipped.', m.replace('_', ' '), deleted, skipped)
else:

View File

@@ -2,9 +2,8 @@
# All Rights Reserved
from django.core.management.base import BaseCommand
from django.conf import settings
from crum import impersonate
from awx.main.models import User, Organization, Project, Inventory, CredentialType, Credential, Host, JobTemplate, ExecutionEnvironment
from awx.main.models import User, Organization, Project, Inventory, CredentialType, Credential, Host, JobTemplate
from awx.main.signals import disable_computed_fields
@@ -45,7 +44,7 @@ class Command(BaseCommand):
public_galaxy_credential = Credential(
name='Ansible Galaxy',
managed_by_tower=True,
managed=True,
credential_type=CredentialType.objects.get(kind='galaxy'),
inputs={'url': 'https://galaxy.ansible.com/'},
)
@@ -68,13 +67,6 @@ class Command(BaseCommand):
print('Demo Credential, Inventory, and Job Template added.')
changed = True
for ee in reversed(settings.DEFAULT_EXECUTION_ENVIRONMENTS):
_, created = ExecutionEnvironment.objects.update_or_create(name=ee['name'], defaults={'image': ee['image'], 'managed_by_tower': True})
if created:
changed = True
print('Default Execution Environment(s) registered.')
if changed:
print('(changed: True)')
else:

View File

@@ -0,0 +1,59 @@
# Copyright (c) 2021 Ansible, Inc.
# All Rights Reserved
from django.core.management.base import BaseCommand
from awx.main.utils.common import get_custom_venv_choices
from awx.main.models import Organization, InventorySource, JobTemplate, Project
import yaml
class Command(BaseCommand):
"""Returns the pip freeze from the path passed in the argument"""
def add_arguments(self, parser):
parser.add_argument(
'path',
type=str,
nargs=1,
default='',
help='run this with a path to a virtual environment as an argument to see the associated Job Templates, Organizations, Projects, and Inventory Sources.',
)
parser.add_argument('-q', action='store_true', help='run with -q to output only the results of the query.')
def handle(self, *args, **options):
# look organiztions and unified job templates (which include JTs, workflows, and Inventory updates)
super(Command, self).__init__()
results = {}
path = options.get('path')
if path:
all_venvs = get_custom_venv_choices()
if path[0] in all_venvs: # verify this is a valid path
path = path[0]
orgs = [{"name": org.name, "id": org.id} for org in Organization.objects.filter(custom_virtualenv=path)]
jts = [{"name": jt.name, "id": jt.id} for jt in JobTemplate.objects.filter(custom_virtualenv=path)]
proj = [{"name": proj.name, "id": proj.id} for proj in Project.objects.filter(custom_virtualenv=path)]
invsrc = [{"name": inv.name, "id": inv.id} for inv in InventorySource.objects.filter(custom_virtualenv=path)]
results["organizations"] = orgs
results["job_templates"] = jts
results["projects"] = proj
results["inventory_sources"] = invsrc
if not options.get('q'):
msg = [
'# Virtual Environments Associations:',
yaml.dump(results),
'- To list all (now deprecated) custom virtual environments run:',
'awx-manage list_custom_venvs',
'',
'- To export the contents of a (deprecated) virtual environment, ' 'run the following command while supplying the path as an argument:',
'awx-manage export_custom_venv /path/to/venv',
'',
'- Run these commands with `-q` to remove tool tips.',
'',
]
print('\n'.join(msg))
else:
print(yaml.dump(results))
else:
print('\n', '# Incorrect path, verify your path is from the following list:')
print('\n'.join(all_venvs), '\n')

View File

@@ -0,0 +1,48 @@
# Copyright (c) 2021 Ansible, Inc.
# All Rights Reserved
from awx.main.utils.common import get_custom_venv_pip_freeze, get_custom_venv_choices
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""Returns the pip freeze from the path passed in the argument"""
def add_arguments(self, parser):
parser.add_argument(
'path',
type=str,
nargs=1,
default='',
help='run this with a path to a virtual environment as an argument to see the pip freeze data',
)
parser.add_argument('-q', action='store_true', help='run with -q to output only the results of the query.')
def handle(self, *args, **options):
super(Command, self).__init__()
if options.get('path'):
path = options.get('path')
all_venvs = get_custom_venv_choices()
if path[0] in all_venvs:
pip_data = get_custom_venv_pip_freeze(options.get('path')[0])
if pip_data:
if not options.get('q'):
msg = [
'# Virtual environment contents:',
pip_data,
'- To list all (now deprecated) custom virtual environments run:',
'awx-manage list_custom_venvs',
'',
'- To view the connections a (deprecated) virtual environment had in the database, run the following command while supplying the path as an argument:',
'awx-manage custom_venv_associations /path/to/venv',
'',
'- Run these commands with `-q` to remove tool tips.',
'',
]
print('\n'.join(msg))
else:
print(pip_data)
else:
print('\n', '# Incorrect path, verify your path is from the following list:')
print('\n'.join(all_venvs))

View File

@@ -36,20 +36,20 @@ from awx.main.utils.pglock import advisory_lock
logger = logging.getLogger('awx.main.commands.inventory_import')
LICENSE_EXPIRED_MESSAGE = '''\
License expired.
See http://www.ansible.com/renew for license extension information.'''
Subscription expired.
Contact us (https://www.redhat.com/contact) for subscription extension information.'''
LICENSE_NON_EXISTANT_MESSAGE = '''\
No license.
See http://www.ansible.com/renew for license information.'''
No subscription.
Contact us (https://www.redhat.com/contact) for subscription information.'''
LICENSE_MESSAGE = '''\
Number of licensed instances exceeded, would bring available instances to %(new_count)d, system is licensed for %(instance_count)d.
See http://www.ansible.com/renew for license extension information.'''
%(new_count)d instances have been automated, system is subscribed for %(instance_count)d.
Contact us (https://www.redhat.com/contact) for upgrade information.'''
DEMO_LICENSE_MESSAGE = '''\
Demo mode free license count exceeded, would bring available instances to %(new_count)d, demo mode allows %(instance_count)d.
See http://www.ansible.com/renew for licensing information.'''
Demo mode free subscription count exceeded. Current automated instances are %(new_count)d, demo mode allows %(instance_count)d.
Contact us (https://www.redhat.com/contact) for subscription information.'''
def functioning_dir(path):
@@ -66,13 +66,9 @@ class AnsibleInventoryLoader(object):
/usr/bin/ansible/ansible-inventory -i hosts --list
"""
def __init__(self, source, venv_path=None, verbosity=0):
def __init__(self, source, verbosity=0):
self.source = source
self.verbosity = verbosity
if venv_path:
self.venv_path = venv_path
else:
self.venv_path = settings.ANSIBLE_VENV_PATH
def get_base_args(self):
bargs = ['podman', 'run', '--user=root', '--quiet']
@@ -131,7 +127,6 @@ class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--inventory-name', dest='inventory_name', type=str, default=None, metavar='n', help='name of inventory to sync')
parser.add_argument('--inventory-id', dest='inventory_id', type=int, default=None, metavar='i', help='id of inventory to sync')
parser.add_argument('--venv', dest='venv', type=str, default=None, help='absolute path to the AWX custom virtualenv to use')
parser.add_argument('--overwrite', dest='overwrite', action='store_true', default=False, help='overwrite the destination hosts and groups')
parser.add_argument('--overwrite-vars', dest='overwrite_vars', action='store_true', default=False, help='overwrite (rather than merge) variables')
parser.add_argument('--keep-vars', dest='keep_vars', action='store_true', default=False, help='DEPRECATED legacy option, has no effect')
@@ -761,29 +756,22 @@ class Command(BaseCommand):
instance_count = license_info.get('instance_count', 0)
free_instances = license_info.get('free_instances', 0)
time_remaining = license_info.get('time_remaining', 0)
automated_count = license_info.get('automated_instances', 0)
hard_error = license_info.get('trial', False) is True or license_info['instance_count'] == 10
new_count = Host.objects.active_count()
if time_remaining <= 0:
if hard_error:
logger.error(LICENSE_EXPIRED_MESSAGE)
raise PermissionDenied("License has expired!")
raise PermissionDenied("Subscription has expired!")
else:
logger.warning(LICENSE_EXPIRED_MESSAGE)
# special check for tower-type inventory sources
# but only if running the plugin
TOWER_SOURCE_FILES = ['tower.yml', 'tower.yaml']
if self.inventory_source.source == 'tower' and any(f in self.inventory_source.source_path for f in TOWER_SOURCE_FILES):
# only if this is the 2nd call to license check, we cannot compare before running plugin
if hasattr(self, 'all_group'):
self.remote_tower_license_compare(local_license_type)
if free_instances < 0:
d = {
'new_count': new_count,
'new_count': automated_count,
'instance_count': instance_count,
}
if hard_error:
logger.error(LICENSE_MESSAGE % d)
raise PermissionDenied('License count exceeded!')
raise PermissionDenied('Subscription count exceeded!')
else:
logger.warning(LICENSE_MESSAGE % d)
@@ -824,7 +812,6 @@ class Command(BaseCommand):
raise CommandError('--source is required')
verbosity = int(options.get('verbosity', 1))
self.set_logging_level(verbosity)
venv_path = options.get('venv', None)
# Load inventory object based on name or ID.
if inventory_id:
@@ -854,7 +841,7 @@ class Command(BaseCommand):
_eager_fields=dict(job_args=json.dumps(sys.argv), job_env=dict(os.environ.items()), job_cwd=os.getcwd())
)
data = AnsibleInventoryLoader(source=source, venv_path=venv_path, verbosity=verbosity).load()
data = AnsibleInventoryLoader(source=source, verbosity=verbosity).load()
logger.debug('Finished loading from source: %s', source)

View File

@@ -0,0 +1,43 @@
# Copyright (c) 2021 Ansible, Inc.
# All Rights Reserved
import sys
from awx.main.utils.common import get_custom_venv_choices
from django.core.management.base import BaseCommand
from django.conf import settings
class Command(BaseCommand):
"""Returns a list of custom venv paths from the path passed in the argument"""
def add_arguments(self, parser):
parser.add_argument('-q', action='store_true', help='run with -q to output only the results of the query.')
def handle(self, *args, **options):
super(Command, self).__init__()
venvs = get_custom_venv_choices()
if venvs:
if not options.get('q'):
msg = [
'# Discovered Virtual Environments:',
'\n'.join(venvs),
'',
'- To export the contents of a (deprecated) virtual environment, ' 'run the following command while supplying the path as an argument:',
'awx-manage export_custom_venv /path/to/venv',
'',
'- To view the connections a (deprecated) virtual environment had in the database, run the following command while supplying the path as an argument:',
'awx-manage custom_venv_associations /path/to/venv',
'',
'- Run these commands with `-q` to remove tool tips.',
'',
]
print('\n'.join(msg))
else:
print('\n'.join(venvs), '\n')
else:
msg = ["No custom virtual environments detected in:", settings.BASE_VENV_PATH]
for path in settings.CUSTOM_VENV_PATHS:
msg.append(path)
print('\n'.join(msg), file=sys.stderr)

View File

@@ -25,6 +25,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
super(Command, self).__init__()
no_color = options.get("no_color", False)
groups = list(InstanceGroup.objects.all())
ungrouped = Ungrouped()
@@ -44,6 +45,8 @@ class Command(BaseCommand):
color = '\033[91m'
if x.enabled is False:
color = '\033[90m[DISABLED] '
if no_color:
color = ''
fmt = '\t' + color + '{0.hostname} capacity={0.capacity} version={1}'
if x.capacity:
fmt += ' heartbeat="{0.modified:%Y-%m-%d %H:%M:%S}"'

View File

@@ -18,11 +18,12 @@ class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--hostname', dest='hostname', type=str, help='Hostname used during provisioning')
parser.add_argument('--node_type', type=str, default="hybrid", choices=["control", "execution", "hybrid"], help='Instance Node type')
def _register_hostname(self, hostname):
def _register_hostname(self, hostname, node_type):
if not hostname:
return
(changed, instance) = Instance.objects.register(uuid=self.uuid, hostname=hostname)
(changed, instance) = Instance.objects.register(uuid=self.uuid, hostname=hostname, node_type=node_type)
if changed:
print('Successfully registered instance {}'.format(hostname))
else:
@@ -35,6 +36,6 @@ class Command(BaseCommand):
raise CommandError("Specify `--hostname` to use this command.")
self.uuid = settings.SYSTEM_UUID
self.changed = False
self._register_hostname(options.get('hostname'))
self._register_hostname(options.get('hostname'), options.get('node_type'))
if self.changed:
print('(changed: True)')

View File

@@ -0,0 +1,135 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved
import sys
from distutils.util import strtobool
from argparse import RawTextHelpFormatter
from django.core.management.base import BaseCommand
from django.conf import settings
from awx.main.models import CredentialType, Credential, ExecutionEnvironment
class Command(BaseCommand):
"""Create default execution environments, intended for new installs"""
help = """
Creates or updates the execution environments set in settings.DEFAULT_EXECUTION_ENVIRONMENTS if they are not yet created.
Optionally provide authentication details to create or update a container registry credential that will be set on all of these default execution environments.
Note that settings.DEFAULT_EXECUTION_ENVIRONMENTS is and ordered list, the first in the list will be used for project updates.
"""
# Preserves newlines in the help text
def create_parser(self, *args, **kwargs):
parser = super(Command, self).create_parser(*args, **kwargs)
parser.formatter_class = RawTextHelpFormatter
return parser
def add_arguments(self, parser):
parser.add_argument(
"--registry-url",
type=str,
default="",
help="URL for the container registry",
)
parser.add_argument(
"--registry-username",
type=str,
default="",
help="username for the container registry",
)
parser.add_argument(
"--registry-password",
type=str,
default="",
help="Password or token for CLI authentication with the container registry",
)
parser.add_argument(
"--verify-ssl",
type=lambda x: bool(strtobool(str(x))),
default=True,
help="Verify SSL when authenticating with the container registry",
)
def handle(self, *args, **options):
changed = False
registry_cred = None
if options.get("registry_username"):
if not options.get("registry_password"):
sys.stderr.write("Registry password must be provided when providing registry username\n")
sys.exit(1)
if not options.get("registry_url"):
sys.stderr.write("Registry url must be provided when providing registry username\n")
sys.exit(1)
registry_cred_type = CredentialType.objects.filter(kind="registry")
if not registry_cred_type.exists():
sys.stderr.write("No registry credential type found")
sys.exit(1)
inputs = {
"host": options.get("registry_url"),
"password": options.get("registry_password"),
"username": options.get("registry_username"),
"verify_ssl": options.get("verify_ssl"),
}
registry_cred, cred_created = Credential.objects.get_or_create(
name="Default Execution Environment Registry Credential",
managed=True,
credential_type=registry_cred_type[0],
defaults={'inputs': inputs},
)
if cred_created:
changed = True
print("'Default Execution Environment Credential' registered.")
for key, value in inputs.items():
if not registry_cred.inputs.get(key) or registry_cred.get_input(key) != value:
registry_cred.inputs[key] = value
changed = True
if changed:
registry_cred.save()
print("'Default Execution Environment Credential' updated.")
# Create default globally available Execution Environments
for ee in reversed(settings.GLOBAL_JOB_EXECUTION_ENVIRONMENTS):
_this_ee, ee_created = ExecutionEnvironment.objects.get_or_create(name=ee["name"], defaults={'image': ee["image"], 'credential': registry_cred})
if ee_created:
changed = True
print(f"'{ee['name']}' Default Execution Environment registered.")
else:
if _this_ee.image != ee["image"]:
_this_ee.image = ee["image"]
changed = True
if _this_ee.credential != registry_cred:
_this_ee.credential = registry_cred
changed = True
if changed:
_this_ee.save()
print(f"'{ee['name']}' Default Execution Environment updated.")
# Create the control plane execution environment that is used for project updates and system jobs
ee = settings.CONTROL_PLANE_EXECUTION_ENVIRONMENT
_this_ee, cp_created = ExecutionEnvironment.objects.get_or_create(
name="Control Plane Execution Environment", defaults={'image': ee, 'managed': True, 'credential': registry_cred}
)
if cp_created:
changed = True
print("Control Plane Execution Environment registered.")
else:
if _this_ee.image != ee:
_this_ee.image = ee
changed = True
if _this_ee.credential != registry_cred:
_this_ee.credential = registry_cred
changed = True
if changed:
_this_ee.save()
if changed:
print("(changed: True)")
else:
print("(changed: False)")

View File

@@ -97,27 +97,29 @@ class Command(BaseCommand):
executor = MigrationExecutor(connection)
migrating = bool(executor.migration_plan(executor.loader.graph.leaf_nodes()))
registered = False
if not migrating:
try:
Instance.objects.me()
registered = True
except RuntimeError:
pass
# In containerized deployments, migrations happen in the task container,
# and the services running there don't start until migrations are
# finished.
# *This* service runs in the web container, and it's possible that it can
# start _before_ migrations are finished, thus causing issues with the ORM
# queries it makes (specifically, conf.settings queries).
# This block is meant to serve as a sort of bail-out for the situation
# where migrations aren't yet finished (similar to the migration
# detection middleware that the uwsgi processes have) or when instance
# registration isn't done yet
if migrating:
logger.info('AWX is currently migrating, retry in 10s...')
time.sleep(10)
return
if migrating or not registered:
# In containerized deployments, migrations happen in the task container,
# and the services running there don't start until migrations are
# finished.
# *This* service runs in the web container, and it's possible that it can
# start _before_ migrations are finished, thus causing issues with the ORM
# queries it makes (specifically, conf.settings queries).
# This block is meant to serve as a sort of bail-out for the situation
# where migrations aren't yet finished (similar to the migration
# detection middleware that the uwsgi processes have) or when instance
# registration isn't done yet
logger.error('AWX is currently installing/upgrading. Trying again in 5s...')
try:
me = Instance.objects.me()
logger.info('Active instance with hostname {} is registered.'.format(me.hostname))
except RuntimeError as e:
# the CLUSTER_HOST_ID in the task, and web instance must match and
# ensure network connectivity between the task and web instance
logger.info('Unable to return currently active instance: {}, retry in 5s...'.format(e))
time.sleep(5)
return

View File

@@ -11,11 +11,16 @@ from django.conf import settings
from awx.main.utils.filters import SmartFilter
from awx.main.utils.pglock import advisory_lock
___all__ = ['HostManager', 'InstanceManager', 'InstanceGroupManager']
___all__ = ['HostManager', 'InstanceManager', 'InstanceGroupManager', 'DeferJobCreatedManager']
logger = logging.getLogger('awx.main.managers')
class DeferJobCreatedManager(models.Manager):
def get_queryset(self):
return super(DeferJobCreatedManager, self).get_queryset().defer('job_created')
class HostManager(models.Manager):
"""Custom manager class for Hosts model."""
@@ -28,7 +33,7 @@ class HostManager(models.Manager):
- Only consider results that are unique
- Return the count of this query
"""
return self.order_by().exclude(inventory_sources__source='tower').values('name').distinct().count()
return self.order_by().exclude(inventory_sources__source='controller').values('name').distinct().count()
def org_active_count(self, org_id):
"""Return count of active, unique hosts used by an organization.
@@ -40,7 +45,7 @@ class HostManager(models.Manager):
- Only consider results that are unique
- Return the count of this query
"""
return self.order_by().exclude(inventory_sources__source='tower').filter(inventory__organization=org_id).values('name').distinct().count()
return self.order_by().exclude(inventory_sources__source='controller').filter(inventory__organization=org_id).values('name').distinct().count()
def get_queryset(self):
"""When the parent instance of the host query set has a `kind=smart` and a `host_filter`
@@ -106,11 +111,13 @@ class InstanceManager(models.Manager):
return node[0]
raise RuntimeError("No instance found with the current cluster host id")
def register(self, uuid=None, hostname=None, ip_address=None):
def register(self, uuid=None, hostname=None, ip_address=None, node_type=None):
if not uuid:
uuid = settings.SYSTEM_UUID
if not hostname:
hostname = settings.CLUSTER_HOST_ID
if not node_type:
node_type = "hybrid"
with advisory_lock('instance_registration_%s' % hostname):
if settings.AWX_AUTO_DEPROVISION_INSTANCES:
# detect any instances with the same IP address.
@@ -126,13 +133,19 @@ class InstanceManager(models.Manager):
instance = self.filter(hostname=hostname)
if instance.exists():
instance = instance.get()
update_fields = []
if instance.ip_address != ip_address:
instance.ip_address = ip_address
instance.save(update_fields=['ip_address'])
update_fields.append('ip_address')
if instance.node_type != node_type:
instance.node_type = node_type
update_fields.append('node_type')
if update_fields:
instance.save(update_fields=update_fields)
return (True, instance)
else:
return (False, instance)
instance = self.create(uuid=uuid, hostname=hostname, ip_address=ip_address, capacity=0)
instance = self.create(uuid=uuid, hostname=hostname, ip_address=ip_address, capacity=0, node_type=node_type)
return (True, instance)
def get_or_register(self):
@@ -141,8 +154,8 @@ class InstanceManager(models.Manager):
pod_ip = os.environ.get('MY_POD_IP')
registered = self.register(ip_address=pod_ip)
is_container_group = settings.IS_K8S
RegisterQueue('tower', 100, 0, [], is_container_group).register()
RegisterQueue(settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME, 100, 0, [], is_container_group=False).register()
RegisterQueue(settings.DEFAULT_EXECUTION_QUEUE_NAME, 100, 0, [], is_container_group=True).register()
return registered
else:
return (False, self.me())
@@ -151,10 +164,6 @@ class InstanceManager(models.Manager):
"""Return count of active Tower nodes for licensing."""
return self.all().count()
def my_role(self):
# NOTE: TODO: Likely to repurpose this once standalone ramparts are a thing
return "tower"
class InstanceGroupManager(models.Manager):
"""A custom manager class for the Instance model.

View File

@@ -46,7 +46,7 @@ class TimingMiddleware(threading.local, MiddlewareMixin):
response['X-API-Total-Time'] = '%0.3fs' % total_time
if settings.AWX_REQUEST_PROFILE:
response['X-API-Profile-File'] = self.prof.stop()
perf_logger.info(
perf_logger.debug(
f'request: {request}, response_time: {response["X-API-Total-Time"]}',
extra=dict(python_objects=dict(request=request, response=response, X_API_TOTAL_TIME=response["X-API-Total-Time"])),
)
@@ -197,4 +197,4 @@ class MigrationRanCheckMiddleware(MiddlewareMixin):
executor = MigrationExecutor(connection)
plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
if bool(plan) and getattr(resolve(request.path), 'url_name', '') != 'migrations_notran':
return redirect(reverse("ui_next:migrations_notran"))
return redirect(reverse("ui:migrations_notran"))

View File

@@ -5,10 +5,6 @@ from __future__ import unicode_literals
# Django
from django.db import migrations
# AWX
from awx.main.migrations import _migration_utils as migration_utils
from awx.main.migrations._reencrypt import blank_old_start_args
class Migration(migrations.Migration):
@@ -17,6 +13,8 @@ class Migration(migrations.Migration):
]
operations = [
migrations.RunPython(migration_utils.set_current_apps_for_migrations, migrations.RunPython.noop),
migrations.RunPython(blank_old_start_args, migrations.RunPython.noop),
# This list is intentionally empty.
# Tower 3.3 included several data migrations that are no longer
# necessary (this list is now empty because Tower 3.3 is past EOL and
# cannot be directly upgraded to modern versions)
]

View File

@@ -10,7 +10,7 @@ from awx.main.utils.common import set_current_apps
def migrate_to_static_inputs(apps, schema_editor):
set_current_apps(apps)
CredentialType.setup_tower_managed_defaults()
CredentialType.setup_tower_managed_defaults(apps)
class Migration(migrations.Migration):

View File

@@ -14,7 +14,7 @@ from awx.main.utils.common import set_current_apps
def setup_tower_managed_defaults(apps, schema_editor):
set_current_apps(apps)
CredentialType.setup_tower_managed_defaults()
CredentialType.setup_tower_managed_defaults(apps)
class Migration(migrations.Migration):

View File

@@ -8,7 +8,7 @@ from awx.main.utils.common import set_current_apps
def setup_tower_managed_defaults(apps, schema_editor):
set_current_apps(apps)
CredentialType.setup_tower_managed_defaults()
CredentialType.setup_tower_managed_defaults(apps)
class Migration(migrations.Migration):

View File

@@ -9,7 +9,7 @@ from awx.main.utils.common import set_current_apps
def create_new_credential_types(apps, schema_editor):
set_current_apps(apps)
CredentialType.setup_tower_managed_defaults()
CredentialType.setup_tower_managed_defaults(apps)
class Migration(migrations.Migration):

View File

@@ -5,7 +5,7 @@ from awx.main.models import CredentialType
def update_cyberark_aim_name(apps, schema_editor):
CredentialType.setup_tower_managed_defaults()
CredentialType.setup_tower_managed_defaults(apps)
aim_types = apps.get_model('main', 'CredentialType').objects.filter(namespace='aim').order_by('id')
if aim_types.count() == 2:

View File

@@ -10,15 +10,6 @@ def migrate_event_data(apps, schema_editor):
# that have a bigint primary key (because the old usage of an integer
# numeric isn't enough, as its range is about 2.1B, see:
# https://www.postgresql.org/docs/9.1/datatype-numeric.html)
# unfortunately, we can't do this with a simple ALTER TABLE, because
# for tables with hundreds of millions or billions of rows, the ALTER TABLE
# can take *hours* on modest hardware.
#
# the approach in this migration means that post-migration, event data will
# *not* immediately show up, but will be repopulated over time progressively
# the trade-off here is not having to wait hours for the full data migration
# before you can start and run AWX again (including new playbook runs)
for tblname in ('main_jobevent', 'main_inventoryupdateevent', 'main_projectupdateevent', 'main_adhoccommandevent', 'main_systemjobevent'):
with connection.cursor() as cursor:
# rename the current event table
@@ -35,30 +26,7 @@ def migrate_event_data(apps, schema_editor):
cursor.execute(f'CREATE SEQUENCE "{tblname}_id_seq";')
cursor.execute(f'ALTER TABLE "{tblname}" ALTER COLUMN "id" ' f"SET DEFAULT nextval('{tblname}_id_seq');")
cursor.execute(f"SELECT setval('{tblname}_id_seq', (SELECT MAX(id) FROM _old_{tblname}), true);")
# replace the BTREE index on main_jobevent.job_id with
# a BRIN index to drastically improve per-UJ lookup performance
# see: https://info.crunchydata.com/blog/postgresql-brin-indexes-big-data-performance-with-minimal-storage
if tblname == 'main_jobevent':
cursor.execute("SELECT indexname FROM pg_indexes WHERE tablename='main_jobevent' AND indexdef LIKE '%USING btree (job_id)';")
old_index = cursor.fetchone()[0]
cursor.execute(f'DROP INDEX {old_index}')
cursor.execute('CREATE INDEX main_jobevent_job_id_brin_idx ON main_jobevent USING brin (job_id);')
# remove all of the indexes and constraints from the old table
# (they just slow down the data migration)
cursor.execute(f"SELECT indexname, indexdef FROM pg_indexes WHERE tablename='_old_{tblname}' AND indexname != '{tblname}_pkey';")
indexes = cursor.fetchall()
cursor.execute(
f"SELECT conname, contype, pg_catalog.pg_get_constraintdef(r.oid, true) as condef FROM pg_catalog.pg_constraint r WHERE r.conrelid = '_old_{tblname}'::regclass AND conname != '{tblname}_pkey';"
)
constraints = cursor.fetchall()
for indexname, indexdef in indexes:
cursor.execute(f'DROP INDEX IF EXISTS {indexname}')
for conname, contype, condef in constraints:
cursor.execute(f'ALTER TABLE _old_{tblname} DROP CONSTRAINT IF EXISTS {conname}')
cursor.execute(f'DROP TABLE _old_{tblname};')
class FakeAlterField(migrations.AlterField):

View File

@@ -6,7 +6,7 @@ from awx.main.utils.common import set_current_apps
def setup_tower_managed_defaults(apps, schema_editor):
set_current_apps(apps)
CredentialType.setup_tower_managed_defaults()
CredentialType.setup_tower_managed_defaults(apps)
class Migration(migrations.Migration):

View File

@@ -1,15 +1,30 @@
# Generated by Django 2.2.16 on 2021-04-21 15:02
from django.db import migrations, models
from django.db import migrations, models, transaction
def remove_iso_instances(apps, schema_editor):
Instance = apps.get_model('main', 'Instance')
with transaction.atomic():
Instance.objects.filter(rampart_groups__controller__isnull=False).delete()
def remove_iso_groups(apps, schema_editor):
InstanceGroup = apps.get_model('main', 'InstanceGroup')
with transaction.atomic():
InstanceGroup.objects.filter(controller__isnull=False).delete()
class Migration(migrations.Migration):
atomic = False
dependencies = [
('main', '0138_custom_inventory_scripts_removal'),
]
operations = [
migrations.RunPython(remove_iso_instances),
migrations.RunPython(remove_iso_groups),
migrations.RemoveField(
model_name='instance',
name='last_isolated_check',

View File

@@ -0,0 +1,268 @@
from django.db import migrations, models, connection
def migrate_event_data(apps, schema_editor):
# see: https://github.com/ansible/awx/issues/9039
#
# the goal of this function is -- for each job event table -- to:
# - create a parent partition table
# - .. with a single partition
# - .. that includes all existing job events
#
# the new main_jobevent_parent table should have a new
# denormalized column, job_created, this is used as a
# basis for partitioning job event rows
#
# The initial partion will be a unique case. After
# the migration is completed, awx should create
# new partitions on an hourly basis, as needed.
# All events for a given job should be placed in
# a partition based on the job's _created time_.
for tblname in ('main_jobevent', 'main_inventoryupdateevent', 'main_projectupdateevent', 'main_adhoccommandevent', 'main_systemjobevent'):
with connection.cursor() as cursor:
# mark existing table as _unpartitioned_*
# we will drop this table after its data
# has been moved over
cursor.execute(f'ALTER TABLE {tblname} RENAME TO _unpartitioned_{tblname}')
# create a copy of the table that we will use as a reference for schema
# otherwise, the schema changes we would make on the old jobevents table
# (namely, dropping the primary key constraint) would cause the migration
# to suffer a serious performance degradation
cursor.execute(f'CREATE TABLE tmp_{tblname} ' f'(LIKE _unpartitioned_{tblname} INCLUDING ALL)')
# drop primary key constraint; in a partioned table
# constraints must include the partition key itself
# TODO: do more generic search for pkey constraints
# instead of hardcoding this one that applies to main_jobevent
cursor.execute(f'ALTER TABLE tmp_{tblname} DROP CONSTRAINT tmp_{tblname}_pkey')
# create parent table
cursor.execute(
f'CREATE TABLE {tblname} '
f'(LIKE tmp_{tblname} INCLUDING ALL, job_created TIMESTAMP WITH TIME ZONE NOT NULL) '
f'PARTITION BY RANGE(job_created);'
)
cursor.execute(f'DROP TABLE tmp_{tblname}')
# recreate primary key constraint
cursor.execute(f'ALTER TABLE ONLY {tblname} ' f'ADD CONSTRAINT {tblname}_pkey_new PRIMARY KEY (id, job_created);')
with connection.cursor() as cursor:
"""
Big int migration introduced the brin index main_jobevent_job_id_brin_idx index. For upgardes, we drop the index, new installs do nothing.
I have seen the second index in my dev environment. I can not find where in the code it was created. Drop it just in case
"""
cursor.execute('DROP INDEX IF EXISTS main_jobevent_job_id_brin_idx')
cursor.execute('DROP INDEX IF EXISTS main_jobevent_job_id_idx')
class FakeAddField(migrations.AddField):
def database_forwards(self, *args):
# this is intentionally left blank, because we're
# going to accomplish the migration with some custom raw SQL
pass
class Migration(migrations.Migration):
dependencies = [
('main', '0143_hostmetric'),
]
operations = [
migrations.RunPython(migrate_event_data),
FakeAddField(
model_name='jobevent',
name='job_created',
field=models.DateTimeField(null=True, editable=False),
),
FakeAddField(
model_name='inventoryupdateevent',
name='job_created',
field=models.DateTimeField(null=True, editable=False),
),
FakeAddField(
model_name='projectupdateevent',
name='job_created',
field=models.DateTimeField(null=True, editable=False),
),
FakeAddField(
model_name='adhoccommandevent',
name='job_created',
field=models.DateTimeField(null=True, editable=False),
),
FakeAddField(
model_name='systemjobevent',
name='job_created',
field=models.DateTimeField(null=True, editable=False),
),
migrations.CreateModel(
name='UnpartitionedAdHocCommandEvent',
fields=[],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('main.adhoccommandevent',),
),
migrations.CreateModel(
name='UnpartitionedInventoryUpdateEvent',
fields=[],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('main.inventoryupdateevent',),
),
migrations.CreateModel(
name='UnpartitionedJobEvent',
fields=[],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('main.jobevent',),
),
migrations.CreateModel(
name='UnpartitionedProjectUpdateEvent',
fields=[],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('main.projectupdateevent',),
),
migrations.CreateModel(
name='UnpartitionedSystemJobEvent',
fields=[],
options={
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('main.systemjobevent',),
),
migrations.AlterField(
model_name='adhoccommandevent',
name='ad_hoc_command',
field=models.ForeignKey(
db_index=False, editable=False, on_delete=models.deletion.DO_NOTHING, related_name='ad_hoc_command_events', to='main.AdHocCommand'
),
),
migrations.AlterField(
model_name='adhoccommandevent',
name='created',
field=models.DateTimeField(default=None, editable=False, null=True),
),
migrations.AlterField(
model_name='adhoccommandevent',
name='modified',
field=models.DateTimeField(db_index=True, default=None, editable=False),
),
migrations.AlterField(
model_name='inventoryupdateevent',
name='created',
field=models.DateTimeField(default=None, editable=False, null=True),
),
migrations.AlterField(
model_name='inventoryupdateevent',
name='inventory_update',
field=models.ForeignKey(
db_index=False, editable=False, on_delete=models.deletion.DO_NOTHING, related_name='inventory_update_events', to='main.InventoryUpdate'
),
),
migrations.AlterField(
model_name='inventoryupdateevent',
name='modified',
field=models.DateTimeField(db_index=True, default=None, editable=False),
),
migrations.AlterField(
model_name='jobevent',
name='created',
field=models.DateTimeField(default=None, editable=False, null=True),
),
migrations.AlterField(
model_name='jobevent',
name='job',
field=models.ForeignKey(db_index=False, editable=False, null=True, on_delete=models.deletion.DO_NOTHING, related_name='job_events', to='main.Job'),
),
migrations.AlterField(
model_name='jobevent',
name='modified',
field=models.DateTimeField(db_index=True, default=None, editable=False),
),
migrations.AlterField(
model_name='projectupdateevent',
name='created',
field=models.DateTimeField(default=None, editable=False, null=True),
),
migrations.AlterField(
model_name='projectupdateevent',
name='modified',
field=models.DateTimeField(db_index=True, default=None, editable=False),
),
migrations.AlterField(
model_name='projectupdateevent',
name='project_update',
field=models.ForeignKey(
db_index=False, editable=False, on_delete=models.deletion.DO_NOTHING, related_name='project_update_events', to='main.ProjectUpdate'
),
),
migrations.AlterField(
model_name='systemjobevent',
name='created',
field=models.DateTimeField(default=None, editable=False, null=True),
),
migrations.AlterField(
model_name='systemjobevent',
name='modified',
field=models.DateTimeField(db_index=True, default=None, editable=False),
),
migrations.AlterField(
model_name='systemjobevent',
name='system_job',
field=models.ForeignKey(
db_index=False, editable=False, on_delete=models.deletion.DO_NOTHING, related_name='system_job_events', to='main.SystemJob'
),
),
migrations.AlterIndexTogether(
name='adhoccommandevent',
index_together={
('ad_hoc_command', 'job_created', 'event'),
('ad_hoc_command', 'job_created', 'counter'),
('ad_hoc_command', 'job_created', 'uuid'),
},
),
migrations.AlterIndexTogether(
name='inventoryupdateevent',
index_together={('inventory_update', 'job_created', 'counter'), ('inventory_update', 'job_created', 'uuid')},
),
migrations.AlterIndexTogether(
name='jobevent',
index_together={
('job', 'job_created', 'counter'),
('job', 'job_created', 'uuid'),
('job', 'job_created', 'event'),
('job', 'job_created', 'parent_uuid'),
},
),
migrations.AlterIndexTogether(
name='projectupdateevent',
index_together={
('project_update', 'job_created', 'uuid'),
('project_update', 'job_created', 'event'),
('project_update', 'job_created', 'counter'),
},
),
migrations.AlterIndexTogether(
name='systemjobevent',
index_together={('system_job', 'job_created', 'uuid'), ('system_job', 'job_created', 'counter')},
),
]

View File

@@ -0,0 +1,21 @@
# Generated by Django 2.2.16 on 2021-06-07 19:36
from django.db import migrations
def forwards(apps, schema_editor):
ExecutionEnvironment = apps.get_model('main', 'ExecutionEnvironment')
for row in ExecutionEnvironment.objects.filter(managed_by_tower=True):
row.managed_by_tower = False
row.save(update_fields=['managed_by_tower'])
class Migration(migrations.Migration):
dependencies = [
('main', '0144_event_partitions'),
]
operations = [
migrations.RunPython(forwards),
]

View File

@@ -0,0 +1,59 @@
# Generated by Django 2.2.16 on 2021-06-08 18:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0145_deregister_managed_ee_objs'),
]
operations = [
migrations.RemoveField(
model_name='host',
name='insights_system_id',
),
migrations.AlterField(
model_name='inventorysource',
name='source',
field=models.CharField(
choices=[
('file', 'File, Directory or Script'),
('scm', 'Sourced from a Project'),
('ec2', 'Amazon EC2'),
('gce', 'Google Compute Engine'),
('azure_rm', 'Microsoft Azure Resource Manager'),
('vmware', 'VMware vCenter'),
('satellite6', 'Red Hat Satellite 6'),
('openstack', 'OpenStack'),
('rhv', 'Red Hat Virtualization'),
('tower', 'Ansible Tower'),
('insights', 'Red Hat Insights'),
],
default=None,
max_length=32,
),
),
migrations.AlterField(
model_name='inventoryupdate',
name='source',
field=models.CharField(
choices=[
('file', 'File, Directory or Script'),
('scm', 'Sourced from a Project'),
('ec2', 'Amazon EC2'),
('gce', 'Google Compute Engine'),
('azure_rm', 'Microsoft Azure Resource Manager'),
('vmware', 'VMware vCenter'),
('satellite6', 'Red Hat Satellite 6'),
('openstack', 'OpenStack'),
('rhv', 'Red Hat Virtualization'),
('tower', 'Ansible Tower'),
('insights', 'Red Hat Insights'),
],
default=None,
max_length=32,
),
),
]

View File

@@ -0,0 +1,24 @@
# Generated by Django 2.2.16 on 2021-06-15 02:49
import awx.main.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0146_add_insights_inventory'),
]
operations = [
migrations.AlterField(
model_name='executionenvironment',
name='image',
field=models.CharField(
help_text='The full image location, including the container registry, image name, and version tag.',
max_length=1024,
validators=[awx.main.validators.validate_container_image_name],
verbose_name='image location',
),
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 2.2.16 on 2021-06-11 04:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0147_validate_ee_image_field'),
]
operations = [
migrations.AddField(
model_name='unifiedjob',
name='work_unit_id',
field=models.CharField(
blank=True, default=None, editable=False, help_text='The Receptor work unit ID associated with this job.', max_length=255, null=True
),
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 2.2.16 on 2021-06-16 21:00
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('main', '0148_unifiedjob_receptor_unit_id'),
]
operations = [
migrations.RemoveField(
model_name='inventory',
name='insights_credential',
),
]

View File

@@ -0,0 +1,113 @@
# Generated by Django 2.2.16 on 2021-06-17 13:12
import logging
from django.db import migrations, models
from awx.main.models.credential import ManagedCredentialType, CredentialType as ModernCredentialType
logger = logging.getLogger(__name__)
def forwards(apps, schema_editor):
InventoryUpdate = apps.get_model('main', 'InventoryUpdate')
InventorySource = apps.get_model('main', 'InventorySource')
r = InventoryUpdate.objects.filter(source='tower').update(source='controller')
if r:
logger.warn(f'Renamed {r} tower inventory updates to controller')
InventorySource.objects.filter(source='tower').update(source='controller')
if r:
logger.warn(f'Renamed {r} tower inventory sources to controller')
CredentialType = apps.get_model('main', 'CredentialType')
tower_type = CredentialType.objects.filter(managed_by_tower=True, namespace='tower').first()
if tower_type is not None:
controller_type = CredentialType.objects.filter(managed_by_tower=True, namespace='controller', kind='cloud').first()
if controller_type:
# this gets created by prior migrations in upgrade scenarios
controller_type.delete()
registry_type = ManagedCredentialType.registry.get('controller')
if not registry_type:
raise RuntimeError('Excpected to find controller credential, this may need to be edited in the future!')
logger.warn('Renaming the Ansible Tower credential type for existing install')
tower_type.name = registry_type.name # sensitive to translations
tower_type.namespace = 'controller' # if not done, will error setup_tower_managed_defaults
tower_type.save(update_fields=['name', 'namespace'])
ModernCredentialType.setup_tower_managed_defaults(apps)
def backwards(apps, schema_editor):
InventoryUpdate = apps.get_model('main', 'InventoryUpdate')
InventorySource = apps.get_model('main', 'InventorySource')
r = InventoryUpdate.objects.filter(source='controller').update(source='tower')
if r:
logger.warn(f'Renamed {r} controller inventory updates to tower')
r = InventorySource.objects.filter(source='controller').update(source='tower')
if r:
logger.warn(f'Renamed {r} controller inventory sources to tower')
CredentialType = apps.get_model('main', 'CredentialType')
tower_type = CredentialType.objects.filter(managed_by_tower=True, namespace='controller', kind='cloud').first()
if tower_type is not None and not CredentialType.objects.filter(managed_by_tower=True, namespace='tower').exists():
logger.info('Renaming the controller credential type back')
tower_type.namespace = 'tower'
tower_type.name = 'Ansible Tower'
tower_type.save(update_fields=['namespace', 'name'])
class Migration(migrations.Migration):
dependencies = [
('main', '0149_remove_inventory_insights_credential'),
]
operations = [
migrations.RunPython(migrations.RunPython.noop, backwards),
migrations.AlterField(
model_name='inventorysource',
name='source',
field=models.CharField(
choices=[
('file', 'File, Directory or Script'),
('scm', 'Sourced from a Project'),
('ec2', 'Amazon EC2'),
('gce', 'Google Compute Engine'),
('azure_rm', 'Microsoft Azure Resource Manager'),
('vmware', 'VMware vCenter'),
('satellite6', 'Red Hat Satellite 6'),
('openstack', 'OpenStack'),
('rhv', 'Red Hat Virtualization'),
('controller', 'Red Hat Ansible Automation Platform'),
('insights', 'Red Hat Insights'),
],
default=None,
max_length=32,
),
),
migrations.AlterField(
model_name='inventoryupdate',
name='source',
field=models.CharField(
choices=[
('file', 'File, Directory or Script'),
('scm', 'Sourced from a Project'),
('ec2', 'Amazon EC2'),
('gce', 'Google Compute Engine'),
('azure_rm', 'Microsoft Azure Resource Manager'),
('vmware', 'VMware vCenter'),
('satellite6', 'Red Hat Satellite 6'),
('openstack', 'OpenStack'),
('rhv', 'Red Hat Virtualization'),
('controller', 'Red Hat Ansible Automation Platform'),
('insights', 'Red Hat Insights'),
],
default=None,
max_length=32,
),
),
migrations.RunPython(forwards, migrations.RunPython.noop),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 2.2.16 on 2021-06-17 18:32
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('main', '0150_rename_inv_sources_inv_updates'),
]
operations = [
migrations.RenameField(
model_name='credential',
old_name='managed_by_tower',
new_name='managed',
),
migrations.RenameField(
model_name='credentialtype',
old_name='managed_by_tower',
new_name='managed',
),
migrations.RenameField(
model_name='executionenvironment',
old_name='managed_by_tower',
new_name='managed',
),
]

View File

@@ -0,0 +1,22 @@
# Generated by Django 2.2.20 on 2021-07-26 19:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0151_rename_managed_by_tower'),
]
operations = [
migrations.AddField(
model_name='instance',
name='node_type',
field=models.CharField(
choices=[('control', 'Control plane node'), ('execution', 'Execution plane node'), ('hybrid', 'Controller and execution')],
default='hybrid',
max_length=16,
),
),
]

View File

@@ -19,7 +19,7 @@ def migrate_galaxy_settings(apps, schema_editor):
# nothing to migrate
return
set_current_apps(apps)
ModernCredentialType.setup_tower_managed_defaults()
ModernCredentialType.setup_tower_managed_defaults(apps)
CredentialType = apps.get_model('main', 'CredentialType')
Credential = apps.get_model('main', 'Credential')
Setting = apps.get_model('conf', 'Setting')
@@ -34,10 +34,21 @@ def migrate_galaxy_settings(apps, schema_editor):
if public_galaxy_setting and public_galaxy_setting.value is False:
# ...UNLESS this behavior was explicitly disabled via this setting
public_galaxy_enabled = False
public_galaxy_credential = Credential(
created=now(), modified=now(), name='Ansible Galaxy', managed_by_tower=True, credential_type=galaxy_type, inputs={'url': 'https://galaxy.ansible.com/'}
)
try:
# Needed for old migrations
public_galaxy_credential = Credential(
created=now(),
modified=now(),
name='Ansible Galaxy',
managed_by_tower=True,
credential_type=galaxy_type,
inputs={'url': 'https://galaxy.ansible.com/'},
)
except:
# Needed for new migrations, tests
public_galaxy_credential = Credential(
created=now(), modified=now(), name='Ansible Galaxy', managed=True, credential_type=galaxy_type, inputs={'url': 'https://galaxy.ansible.com/'}
)
public_galaxy_credential.save()
for org in Organization.objects.all():

View File

@@ -1,26 +0,0 @@
import logging
from awx.conf.migrations._reencrypt import (
decrypt_field,
)
logger = logging.getLogger('awx.main.migrations')
__all__ = []
def blank_old_start_args(apps, schema_editor):
UnifiedJob = apps.get_model('main', 'UnifiedJob')
for uj in UnifiedJob.objects.defer('result_stdout_text').exclude(start_args='').iterator():
if uj.status in ['running', 'pending', 'new', 'waiting']:
continue
try:
args_dict = decrypt_field(uj, 'start_args')
except ValueError:
args_dict = None
if args_dict == {}:
continue
if uj.start_args:
logger.debug('Blanking job args for %s', uj.pk)
uj.start_args = ''
uj.save()

View File

@@ -3,7 +3,6 @@
# Django
from django.conf import settings # noqa
from django.db import connection
from django.db.models.signals import pre_delete # noqa
# AWX
@@ -36,6 +35,11 @@ from awx.main.models.events import ( # noqa
JobEvent,
ProjectUpdateEvent,
SystemJobEvent,
UnpartitionedAdHocCommandEvent,
UnpartitionedInventoryUpdateEvent,
UnpartitionedJobEvent,
UnpartitionedProjectUpdateEvent,
UnpartitionedSystemJobEvent,
)
from awx.main.models.ad_hoc_commands import AdHocCommand # noqa
from awx.main.models.schedules import Schedule # noqa
@@ -92,27 +96,6 @@ User.add_to_class('can_access_with_errors', check_user_access_with_errors)
User.add_to_class('accessible_objects', user_accessible_objects)
def enforce_bigint_pk_migration():
#
# NOTE: this function is not actually in use anymore,
# but has been intentionally kept for historical purposes,
# and to serve as an illustration if we ever need to perform
# bulk modification/migration of event data in the future.
#
# see: https://github.com/ansible/awx/issues/6010
# look at all the event tables and verify that they have been fully migrated
# from the *old* int primary key table to the replacement bigint table
# if not, attempt to migrate them in the background
#
for tblname in ('main_jobevent', 'main_inventoryupdateevent', 'main_projectupdateevent', 'main_adhoccommandevent', 'main_systemjobevent'):
with connection.cursor() as cursor:
cursor.execute('SELECT 1 FROM information_schema.tables WHERE table_name=%s', (f'_old_{tblname}',))
if bool(cursor.rowcount):
from awx.main.tasks import migrate_legacy_event_data
migrate_legacy_event_data.apply_async([tblname])
def cleanup_created_modified_by(sender, **kwargs):
# work around a bug in django-polymorphic that doesn't properly
# handle cascades for reverse foreign keys on the polymorphic base model

View File

@@ -15,7 +15,7 @@ from django.core.exceptions import ValidationError
# AWX
from awx.api.versioning import reverse
from awx.main.models.base import prevent_search, AD_HOC_JOB_TYPE_CHOICES, VERBOSITY_CHOICES, VarsDictProperty
from awx.main.models.events import AdHocCommandEvent
from awx.main.models.events import AdHocCommandEvent, UnpartitionedAdHocCommandEvent
from awx.main.models.unified_jobs import UnifiedJob
from awx.main.models.notifications import JobNotificationMixin, NotificationTemplate
@@ -127,6 +127,8 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
@property
def event_class(self):
if self.has_unpartitioned_events:
return UnpartitionedAdHocCommandEvent
return AdHocCommandEvent
@property
@@ -215,9 +217,6 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
self.name = Truncator(u': '.join(filter(None, (self.module_name, self.module_args)))).chars(512)
if 'name' not in update_fields:
update_fields.append('name')
if not self.execution_environment_id:
self.execution_environment = self.resolve_execution_environment()
update_fields.append('execution_environment')
super(AdHocCommand, self).save(*args, **kwargs)
@property

View File

@@ -19,6 +19,7 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop
from django.core.exceptions import ValidationError
from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.timezone import now
# AWX
from awx.api.versioning import reverse
@@ -92,7 +93,7 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
on_delete=models.CASCADE,
help_text=_('Specify the type of credential you want to create. Refer ' 'to the documentation for details on each type.'),
)
managed_by_tower = models.BooleanField(default=False, editable=False)
managed = models.BooleanField(default=False, editable=False)
organization = models.ForeignKey(
'Organization',
null=True,
@@ -341,7 +342,7 @@ class CredentialType(CommonModelNameNotUnique):
)
kind = models.CharField(max_length=32, choices=KIND_CHOICES)
managed_by_tower = models.BooleanField(default=False, editable=False)
managed = models.BooleanField(default=False, editable=False)
namespace = models.CharField(max_length=1024, null=True, default=None, editable=False)
inputs = CredentialTypeInputField(
blank=True, default=dict, help_text=_('Enter inputs using either JSON or YAML syntax. ' 'Refer to the documentation for example syntax.')
@@ -355,7 +356,7 @@ class CredentialType(CommonModelNameNotUnique):
@classmethod
def from_db(cls, db, field_names, values):
instance = super(CredentialType, cls).from_db(db, field_names, values)
if instance.managed_by_tower and instance.namespace:
if instance.managed and instance.namespace:
native = ManagedCredentialType.registry[instance.namespace]
instance.inputs = native.inputs
instance.injectors = native.injectors
@@ -395,9 +396,13 @@ class CredentialType(CommonModelNameNotUnique):
return dict((k, functools.partial(v.create)) for k, v in ManagedCredentialType.registry.items())
@classmethod
def setup_tower_managed_defaults(cls):
def setup_tower_managed_defaults(cls, apps=None):
if apps is not None:
ct_class = apps.get_model('main', 'CredentialType')
else:
ct_class = CredentialType
for default in ManagedCredentialType.registry.values():
existing = CredentialType.objects.filter(name=default.name, kind=default.kind).first()
existing = ct_class.objects.filter(name=default.name, kind=default.kind).first()
if existing is not None:
existing.namespace = default.namespace
existing.inputs = {}
@@ -405,7 +410,11 @@ class CredentialType(CommonModelNameNotUnique):
existing.save()
continue
logger.debug(_("adding %s credential type" % default.name))
created = default.create()
params = default.get_creation_params()
if 'managed' not in [f.name for f in ct_class._meta.get_fields()]:
params['managed_by_tower'] = params.pop('managed')
params['created'] = params['modified'] = now() # CreatedModifiedModel service
created = ct_class(**params)
created.inputs = created.injectors = {}
created.save()
@@ -439,7 +448,7 @@ class CredentialType(CommonModelNameNotUnique):
files)
"""
if not self.injectors:
if self.managed_by_tower and credential.credential_type.namespace in dir(builtin_injectors):
if self.managed and credential.credential_type.namespace in dir(builtin_injectors):
injected_env = {}
getattr(builtin_injectors, credential.credential_type.namespace)(credential, injected_env, private_data_dir)
env.update(injected_env)
@@ -556,16 +565,19 @@ class ManagedCredentialType(SimpleNamespace):
)
ManagedCredentialType.registry[namespace] = self
def create(self):
return CredentialType(
def get_creation_params(self):
return dict(
namespace=self.namespace,
kind=self.kind,
name=self.name,
managed_by_tower=True,
managed=True,
inputs=self.inputs,
injectors=self.injectors,
)
def create(self):
return CredentialType(**self.get_creation_params())
ManagedCredentialType(
namespace='ssh',
@@ -606,7 +618,7 @@ ManagedCredentialType(
namespace='scm',
kind='scm',
name=ugettext_noop('Source Control'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{'id': 'username', 'label': ugettext_noop('Username'), 'type': 'string'},
@@ -621,7 +633,7 @@ ManagedCredentialType(
namespace='vault',
kind='vault',
name=ugettext_noop('Vault'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{'id': 'vault_password', 'label': ugettext_noop('Vault Password'), 'type': 'string', 'secret': True, 'ask_at_runtime': True},
@@ -647,7 +659,7 @@ ManagedCredentialType(
namespace='net',
kind='net',
name=ugettext_noop('Network'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{'id': 'username', 'label': ugettext_noop('Username'), 'type': 'string'},
@@ -687,7 +699,7 @@ ManagedCredentialType(
namespace='aws',
kind='cloud',
name=ugettext_noop('Amazon Web Services'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{'id': 'username', 'label': ugettext_noop('Access Key'), 'type': 'string'},
@@ -718,7 +730,7 @@ ManagedCredentialType(
namespace='openstack',
kind='cloud',
name=ugettext_noop('OpenStack'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{'id': 'username', 'label': ugettext_noop('Username'), 'type': 'string'},
@@ -776,7 +788,7 @@ ManagedCredentialType(
namespace='vmware',
kind='cloud',
name=ugettext_noop('VMware vCenter'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{
@@ -801,7 +813,7 @@ ManagedCredentialType(
namespace='satellite6',
kind='cloud',
name=ugettext_noop('Red Hat Satellite 6'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{
@@ -826,7 +838,7 @@ ManagedCredentialType(
namespace='gce',
kind='cloud',
name=ugettext_noop('Google Compute Engine'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{
@@ -864,7 +876,7 @@ ManagedCredentialType(
namespace='azure_rm',
kind='cloud',
name=ugettext_noop('Microsoft Azure Resource Manager'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{
@@ -903,7 +915,7 @@ ManagedCredentialType(
namespace='github_token',
kind='token',
name=ugettext_noop('GitHub Personal Access Token'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{
@@ -922,7 +934,7 @@ ManagedCredentialType(
namespace='gitlab_token',
kind='token',
name=ugettext_noop('GitLab Personal Access Token'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{
@@ -941,7 +953,7 @@ ManagedCredentialType(
namespace='insights',
kind='insights',
name=ugettext_noop('Insights'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{'id': 'username', 'label': ugettext_noop('Username'), 'type': 'string'},
@@ -954,6 +966,10 @@ ManagedCredentialType(
"scm_username": "{{username}}",
"scm_password": "{{password}}",
},
'env': {
'INSIGHTS_USER': '{{username}}',
'INSIGHTS_PASSWORD': '{{password}}',
},
},
)
@@ -961,7 +977,7 @@ ManagedCredentialType(
namespace='rhv',
kind='cloud',
name=ugettext_noop('Red Hat Virtualization'),
managed_by_tower=True,
managed=True,
inputs={
'fields': [
{'id': 'host', 'label': ugettext_noop('Host (Authentication URL)'), 'type': 'string', 'help_text': ugettext_noop('The host to authenticate with.')},
@@ -1002,23 +1018,25 @@ ManagedCredentialType(
)
ManagedCredentialType(
namespace='tower',
namespace='controller',
kind='cloud',
name=ugettext_noop('Ansible Tower'),
managed_by_tower=True,
name=ugettext_noop('Red Hat Ansible Automation Platform'),
managed=True,
inputs={
'fields': [
{
'id': 'host',
'label': ugettext_noop('Ansible Tower Hostname'),
'label': ugettext_noop('Red Hat Ansible Automation Platform'),
'type': 'string',
'help_text': ugettext_noop('The Ansible Tower base URL to authenticate with.'),
'help_text': ugettext_noop('Red Hat Ansible Automation Platform base URL to authenticate with.'),
},
{
'id': 'username',
'label': ugettext_noop('Username'),
'type': 'string',
'help_text': ugettext_noop('The Ansible Tower user to authenticate as.' 'This should not be set if an OAuth token is being used.'),
'help_text': ugettext_noop(
'Red Hat Ansible Automation Platform username id to authenticate as.' 'This should not be set if an OAuth token is being used.'
),
},
{
'id': 'password',
@@ -1044,6 +1062,11 @@ ManagedCredentialType(
'TOWER_PASSWORD': '{{password}}',
'TOWER_VERIFY_SSL': '{{verify_ssl}}',
'TOWER_OAUTH_TOKEN': '{{oauth_token}}',
'CONTROLLER_HOST': '{{host}}',
'CONTROLLER_USERNAME': '{{username}}',
'CONTROLLER_PASSWORD': '{{password}}',
'CONTROLLER_VERIFY_SSL': '{{verify_ssl}}',
'CONTROLLER_OAUTH_TOKEN': '{{oauth_token}}',
}
},
)
@@ -1095,6 +1118,7 @@ ManagedCredentialType(
'label': ugettext_noop('Authentication URL'),
'type': 'string',
'help_text': ugettext_noop('Authentication endpoint for the container registry.'),
'default': 'quay.io',
},
{
'id': 'username',

View File

@@ -15,7 +15,9 @@ from django.utils.encoding import force_text
from awx.api.versioning import reverse
from awx.main import consumers
from awx.main.managers import DeferJobCreatedManager
from awx.main.fields import JSONField
from awx.main.constants import MINIMAL_EVENTS
from awx.main.models.base import CreatedModifiedModel
from awx.main.utils import ignore_inventory_computed_fields, camelcase_to_underscore
@@ -56,9 +58,6 @@ def create_host_status_counts(event_data):
return dict(host_status_counts)
MINIMAL_EVENTS = set(['playbook_on_play_start', 'playbook_on_task_start', 'playbook_on_stats', 'EOF'])
def emit_event_detail(event):
if settings.UI_LIVE_UPDATES_ENABLED is False and event.event not in MINIMAL_EVENTS:
return
@@ -271,6 +270,10 @@ class BasePlaybookEvent(CreatedModifiedModel):
null=True,
default=None,
editable=False,
)
modified = models.DateTimeField(
default=None,
editable=False,
db_index=True,
)
@@ -365,14 +368,24 @@ class BasePlaybookEvent(CreatedModifiedModel):
# find parent links and progagate changed=T and failed=T
changed = (
job.job_events.filter(changed=True).exclude(parent_uuid=None).only('parent_uuid').values_list('parent_uuid', flat=True).distinct()
job.get_event_queryset()
.filter(changed=True)
.exclude(parent_uuid=None)
.only('parent_uuid')
.values_list('parent_uuid', flat=True)
.distinct()
) # noqa
failed = (
job.job_events.filter(failed=True).exclude(parent_uuid=None).only('parent_uuid').values_list('parent_uuid', flat=True).distinct()
job.get_event_queryset()
.filter(failed=True)
.exclude(parent_uuid=None)
.only('parent_uuid')
.values_list('parent_uuid', flat=True)
.distinct()
) # noqa
JobEvent.objects.filter(job_id=self.job_id, uuid__in=changed).update(changed=True)
JobEvent.objects.filter(job_id=self.job_id, uuid__in=failed).update(failed=True)
job.get_event_queryset().filter(uuid__in=changed).update(changed=True)
job.get_event_queryset().filter(uuid__in=failed).update(failed=True)
# send success/failure notifications when we've finished handling the playbook_on_stats event
from awx.main.tasks import handle_success_and_failure_notifications # circular import
@@ -423,6 +436,16 @@ class BasePlaybookEvent(CreatedModifiedModel):
except (KeyError, ValueError):
kwargs.pop('created', None)
# same as above, for job_created
# TODO: if this approach, identical to above, works, can convert to for loop
try:
if not isinstance(kwargs['job_created'], datetime.datetime):
kwargs['job_created'] = parse_datetime(kwargs['job_created'])
if not kwargs['job_created'].tzinfo:
kwargs['job_created'] = kwargs['job_created'].replace(tzinfo=utc)
except (KeyError, ValueError):
kwargs.pop('job_created', None)
host_map = kwargs.pop('host_map', {})
sanitize_event_keys(kwargs, cls.VALID_KEYS)
@@ -430,6 +453,11 @@ class BasePlaybookEvent(CreatedModifiedModel):
event = cls(**kwargs)
if workflow_job_id:
setattr(event, 'workflow_job_id', workflow_job_id)
# shouldn't job_created _always_ be present?
# if it's not, how could we save the event to the db?
job_created = kwargs.pop('job_created', None)
if job_created:
setattr(event, 'job_created', job_created)
setattr(event, 'host_map', host_map)
event._update_from_event_data()
return event
@@ -444,25 +472,28 @@ class JobEvent(BasePlaybookEvent):
An event/message logged from the callback when running a job.
"""
VALID_KEYS = BasePlaybookEvent.VALID_KEYS + ['job_id', 'workflow_job_id']
VALID_KEYS = BasePlaybookEvent.VALID_KEYS + ['job_id', 'workflow_job_id', 'job_created']
objects = DeferJobCreatedManager()
class Meta:
app_label = 'main'
ordering = ('pk',)
index_together = [
('job', 'event'),
('job', 'uuid'),
('job', 'start_line'),
('job', 'end_line'),
('job', 'parent_uuid'),
('job', 'job_created', 'event'),
('job', 'job_created', 'uuid'),
('job', 'job_created', 'parent_uuid'),
('job', 'job_created', 'counter'),
]
id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
job = models.ForeignKey(
'Job',
related_name='job_events',
on_delete=models.CASCADE,
null=True,
on_delete=models.DO_NOTHING,
editable=False,
db_index=False,
)
host = models.ForeignKey(
'Host',
@@ -482,6 +513,7 @@ class JobEvent(BasePlaybookEvent):
default='',
editable=False,
)
job_created = models.DateTimeField(null=True, editable=False)
def get_absolute_url(self, request=None):
return reverse('api:job_event_detail', kwargs={'pk': self.pk}, request=request)
@@ -518,7 +550,7 @@ class JobEvent(BasePlaybookEvent):
summaries = dict()
updated_hosts_list = list()
for host in hostnames:
updated_hosts_list.append(host)
updated_hosts_list.append(host.lower())
host_id = self.host_map.get(host, None)
if host_id not in existing_host_ids:
host_id = None
@@ -561,33 +593,52 @@ class JobEvent(BasePlaybookEvent):
return self.job.verbosity
class UnpartitionedJobEvent(JobEvent):
class Meta:
proxy = True
UnpartitionedJobEvent._meta.db_table = '_unpartitioned_' + JobEvent._meta.db_table # noqa
class ProjectUpdateEvent(BasePlaybookEvent):
VALID_KEYS = BasePlaybookEvent.VALID_KEYS + ['project_update_id', 'workflow_job_id']
VALID_KEYS = BasePlaybookEvent.VALID_KEYS + ['project_update_id', 'workflow_job_id', 'job_created']
objects = DeferJobCreatedManager()
class Meta:
app_label = 'main'
ordering = ('pk',)
index_together = [
('project_update', 'event'),
('project_update', 'uuid'),
('project_update', 'start_line'),
('project_update', 'end_line'),
('project_update', 'job_created', 'event'),
('project_update', 'job_created', 'uuid'),
('project_update', 'job_created', 'counter'),
]
id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
project_update = models.ForeignKey(
'ProjectUpdate',
related_name='project_update_events',
on_delete=models.CASCADE,
on_delete=models.DO_NOTHING,
editable=False,
db_index=False,
)
job_created = models.DateTimeField(null=True, editable=False)
@property
def host_name(self):
return 'localhost'
class UnpartitionedProjectUpdateEvent(ProjectUpdateEvent):
class Meta:
proxy = True
UnpartitionedProjectUpdateEvent._meta.db_table = '_unpartitioned_' + ProjectUpdateEvent._meta.db_table # noqa
class BaseCommandEvent(CreatedModifiedModel):
"""
An event/message logged from a command for each host.
@@ -627,6 +678,16 @@ class BaseCommandEvent(CreatedModifiedModel):
default=0,
editable=False,
)
created = models.DateTimeField(
null=True,
default=None,
editable=False,
)
modified = models.DateTimeField(
default=None,
editable=False,
db_index=True,
)
def __str__(self):
return u'%s @ %s' % (self.get_event_display(), self.created.isoformat())
@@ -681,16 +742,17 @@ class BaseCommandEvent(CreatedModifiedModel):
class AdHocCommandEvent(BaseCommandEvent):
VALID_KEYS = BaseCommandEvent.VALID_KEYS + ['ad_hoc_command_id', 'event', 'host_name', 'host_id', 'workflow_job_id']
VALID_KEYS = BaseCommandEvent.VALID_KEYS + ['ad_hoc_command_id', 'event', 'host_name', 'host_id', 'workflow_job_id', 'job_created']
objects = DeferJobCreatedManager()
class Meta:
app_label = 'main'
ordering = ('-pk',)
index_together = [
('ad_hoc_command', 'event'),
('ad_hoc_command', 'uuid'),
('ad_hoc_command', 'start_line'),
('ad_hoc_command', 'end_line'),
('ad_hoc_command', 'job_created', 'event'),
('ad_hoc_command', 'job_created', 'uuid'),
('ad_hoc_command', 'job_created', 'counter'),
]
EVENT_TYPES = [
@@ -737,8 +799,9 @@ class AdHocCommandEvent(BaseCommandEvent):
ad_hoc_command = models.ForeignKey(
'AdHocCommand',
related_name='ad_hoc_command_events',
on_delete=models.CASCADE,
on_delete=models.DO_NOTHING,
editable=False,
db_index=False,
)
host = models.ForeignKey(
'Host',
@@ -753,6 +816,7 @@ class AdHocCommandEvent(BaseCommandEvent):
default='',
editable=False,
)
job_created = models.DateTimeField(null=True, editable=False)
def get_absolute_url(self, request=None):
return reverse('api:ad_hoc_command_event_detail', kwargs={'pk': self.pk}, request=request)
@@ -768,26 +832,37 @@ class AdHocCommandEvent(BaseCommandEvent):
analytics_logger.info('Event data saved.', extra=dict(python_objects=dict(job_event=self)))
class UnpartitionedAdHocCommandEvent(AdHocCommandEvent):
class Meta:
proxy = True
UnpartitionedAdHocCommandEvent._meta.db_table = '_unpartitioned_' + AdHocCommandEvent._meta.db_table # noqa
class InventoryUpdateEvent(BaseCommandEvent):
VALID_KEYS = BaseCommandEvent.VALID_KEYS + ['inventory_update_id', 'workflow_job_id']
VALID_KEYS = BaseCommandEvent.VALID_KEYS + ['inventory_update_id', 'workflow_job_id', 'job_created']
objects = DeferJobCreatedManager()
class Meta:
app_label = 'main'
ordering = ('-pk',)
index_together = [
('inventory_update', 'uuid'),
('inventory_update', 'start_line'),
('inventory_update', 'end_line'),
('inventory_update', 'job_created', 'uuid'),
('inventory_update', 'job_created', 'counter'),
]
id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
inventory_update = models.ForeignKey(
'InventoryUpdate',
related_name='inventory_update_events',
on_delete=models.CASCADE,
on_delete=models.DO_NOTHING,
editable=False,
db_index=False,
)
job_created = models.DateTimeField(null=True, editable=False)
@property
def event(self):
@@ -802,26 +877,37 @@ class InventoryUpdateEvent(BaseCommandEvent):
return False
class UnpartitionedInventoryUpdateEvent(InventoryUpdateEvent):
class Meta:
proxy = True
UnpartitionedInventoryUpdateEvent._meta.db_table = '_unpartitioned_' + InventoryUpdateEvent._meta.db_table # noqa
class SystemJobEvent(BaseCommandEvent):
VALID_KEYS = BaseCommandEvent.VALID_KEYS + ['system_job_id']
VALID_KEYS = BaseCommandEvent.VALID_KEYS + ['system_job_id', 'job_created']
objects = DeferJobCreatedManager()
class Meta:
app_label = 'main'
ordering = ('-pk',)
index_together = [
('system_job', 'uuid'),
('system_job', 'start_line'),
('system_job', 'end_line'),
('system_job', 'job_created', 'uuid'),
('system_job', 'job_created', 'counter'),
]
id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
system_job = models.ForeignKey(
'SystemJob',
related_name='system_job_events',
on_delete=models.CASCADE,
on_delete=models.DO_NOTHING,
editable=False,
db_index=False,
)
job_created = models.DateTimeField(null=True, editable=False)
@property
def event(self):
@@ -834,3 +920,11 @@ class SystemJobEvent(BaseCommandEvent):
@property
def changed(self):
return False
class UnpartitionedSystemJobEvent(SystemJobEvent):
class Meta:
proxy = True
UnpartitionedSystemJobEvent._meta.db_table = '_unpartitioned_' + SystemJobEvent._meta.db_table # noqa

View File

@@ -3,6 +3,7 @@ from django.utils.translation import ugettext_lazy as _
from awx.api.versioning import reverse
from awx.main.models.base import CommonModel
from awx.main.validators import validate_container_image_name
__all__ = ['ExecutionEnvironment']
@@ -31,8 +32,9 @@ class ExecutionEnvironment(CommonModel):
max_length=1024,
verbose_name=_('image location'),
help_text=_("The full image location, including the container registry, image name, and version tag."),
validators=[validate_container_image_name],
)
managed_by_tower = models.BooleanField(default=False, editable=False)
managed = models.BooleanField(default=False, editable=False)
credential = models.ForeignKey(
'Credential',
related_name='%(class)ss',

View File

@@ -86,6 +86,8 @@ class Instance(HasPolicyEditsMixin, BaseModel):
default=0,
editable=False,
)
NODE_TYPE_CHOICES = [("control", "Control plane node"), ("execution", "Execution plane node"), ("hybrid", "Controller and execution")]
node_type = models.CharField(default='hybrid', choices=NODE_TYPE_CHOICES, max_length=16)
class Meta:
app_label = 'main'
@@ -130,12 +132,6 @@ class Instance(HasPolicyEditsMixin, BaseModel):
return self.modified < ref_time - timedelta(seconds=grace_period)
def refresh_capacity(self):
if settings.IS_K8S:
self.capacity = self.cpu = self.memory = self.cpu_capacity = self.mem_capacity = 0 # noqa
self.version = awx_application_version
self.save(update_fields=['capacity', 'version', 'modified', 'cpu', 'memory', 'cpu_capacity', 'mem_capacity'])
return
cpu = get_cpu_capacity()
mem = get_mem_capacity()
if self.enabled:

View File

@@ -35,7 +35,7 @@ from awx.main.fields import (
)
from awx.main.managers import HostManager
from awx.main.models.base import BaseModel, CommonModelNameNotUnique, VarsDictProperty, CLOUD_INVENTORY_SOURCES, prevent_search, accepts_json
from awx.main.models.events import InventoryUpdateEvent
from awx.main.models.events import InventoryUpdateEvent, UnpartitionedInventoryUpdateEvent
from awx.main.models.unified_jobs import UnifiedJob, UnifiedJobTemplate
from awx.main.models.mixins import (
ResourceMixin,
@@ -51,6 +51,7 @@ from awx.main.models.credential.injectors import _openstack_data
from awx.main.utils import _inventory_updates
from awx.main.utils.safe_yaml import sanitize_jinja
from awx.main.utils.execution_environments import to_container_path
from awx.main.utils.licensing import server_product_name
__all__ = ['Inventory', 'Host', 'Group', 'InventorySource', 'InventoryUpdate', 'SmartInventoryMembership']
@@ -164,15 +165,6 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
'admin_role',
]
)
insights_credential = models.ForeignKey(
'Credential',
related_name='insights_inventories',
help_text=_('Credentials to be used by hosts belonging to this inventory when accessing Red Hat Insights API.'),
on_delete=models.SET_NULL,
blank=True,
null=True,
default=None,
)
pending_deletion = models.BooleanField(
default=False,
editable=False,
@@ -314,7 +306,12 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
for host in hosts:
data['_meta']['hostvars'][host.name] = host.variables_dict
if towervars:
tower_dict = dict(remote_tower_enabled=str(host.enabled).lower(), remote_tower_id=host.id)
tower_dict = dict(
remote_tower_enabled=str(host.enabled).lower(),
remote_tower_id=host.id,
remote_host_enabled=str(host.enabled).lower(),
remote_host_id=host.id,
)
data['_meta']['hostvars'][host.name].update(tower_dict)
return data
@@ -367,13 +364,6 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
group_pks = self.groups.values_list('pk', flat=True)
return self.groups.exclude(parents__pk__in=group_pks).distinct()
def clean_insights_credential(self):
if self.kind == 'smart' and self.insights_credential:
raise ValidationError(_("Assignment not allowed for Smart Inventory"))
if self.insights_credential and self.insights_credential.credential_type.kind != 'insights':
raise ValidationError(_("Credential kind must be 'insights'."))
return self.insights_credential
@transaction.atomic
def schedule_deletion(self, user_id=None):
from awx.main.tasks import delete_inventory
@@ -503,13 +493,6 @@ class Host(CommonModelNameNotUnique, RelatedJobsMixin):
null=True,
help_text=_('The date and time ansible_facts was last modified.'),
)
insights_system_id = models.TextField(
blank=True,
default=None,
null=True,
db_index=True,
help_text=_('Red Hat Insights host unique identifier.'),
)
objects = HostManager()
@@ -827,7 +810,8 @@ class InventorySourceOptions(BaseModel):
('satellite6', _('Red Hat Satellite 6')),
('openstack', _('OpenStack')),
('rhv', _('Red Hat Virtualization')),
('tower', _('Ansible Tower')),
('controller', _('Red Hat Ansible Automation Platform')),
('insights', _('Red Hat Insights')),
]
# From the options of the Django management base command
@@ -1230,6 +1214,10 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin,
def is_container_group_task(self):
return bool(self.instance_group and self.instance_group.is_container_group)
@property
def can_run_containerized(self):
return True
def _get_parent_field_name(self):
return 'inventory_source'
@@ -1265,6 +1253,8 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin,
@property
def event_class(self):
if self.has_unpartitioned_events:
return UnpartitionedInventoryUpdateEvent
return InventoryUpdateEvent
@property
@@ -1306,16 +1296,6 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions, JobNotificationMixin,
return self.global_instance_groups
return selected_groups
@property
def ansible_virtualenv_path(self):
if self.inventory_source and self.inventory_source.custom_virtualenv:
return self.inventory_source.custom_virtualenv
if self.inventory_source and self.inventory_source.source_project:
project = self.inventory_source.source_project
if project and project.custom_virtualenv:
return project.custom_virtualenv
return settings.ANSIBLE_VENV_PATH
def cancel(self, job_explanation=None, is_chain=False):
res = super(InventoryUpdate, self).cancel(job_explanation=job_explanation, is_chain=is_chain)
if res:
@@ -1350,6 +1330,7 @@ class PluginFileInjector(object):
namespace = None
collection = None
collection_migration = '2.9' # Starting with this version, we use collections
use_fqcn = False # plugin: name versus plugin: namespace.collection.name
# TODO: delete this method and update unit tests
@classmethod
@@ -1376,7 +1357,12 @@ class PluginFileInjector(object):
Note that a plugin value of '' should still be overridden.
'''
if self.plugin_name is not None:
source_vars['plugin'] = self.plugin_name
if hasattr(self, 'downstream_namespace') and server_product_name() != 'AWX':
source_vars['plugin'] = f'{self.downstream_namespace}.{self.downstream_collection}.{self.plugin_name}'
elif self.use_fqcn:
source_vars['plugin'] = f'{self.namespace}.{self.collection}.{self.plugin_name}'
else:
source_vars['plugin'] = self.plugin_name
return source_vars
def build_env(self, inventory_update, env, private_data_dir, private_data_files):
@@ -1387,7 +1373,7 @@ class PluginFileInjector(object):
return env
def _get_shared_env(self, inventory_update, private_data_dir, private_data_files):
"""By default, we will apply the standard managed_by_tower injectors"""
"""By default, we will apply the standard managed injectors"""
injected_env = {}
credential = inventory_update.get_cloud_credential()
# some sources may have no credential, specifically ec2
@@ -1406,7 +1392,7 @@ class PluginFileInjector(object):
args = []
credential.credential_type.inject_credential(credential, injected_env, safe_env, args, private_data_dir)
# NOTE: safe_env is handled externally to injector class by build_safe_env static method
# that means that managed_by_tower injectors must only inject detectable env keys
# that means that managed injectors must only inject detectable env keys
# enforcement of this is accomplished by tests
return injected_env
@@ -1524,12 +1510,17 @@ class rhv(PluginFileInjector):
initial_version = '2.9'
namespace = 'ovirt'
collection = 'ovirt'
downstream_namespace = 'redhat'
downstream_collection = 'rhv'
class satellite6(PluginFileInjector):
plugin_name = 'foreman'
namespace = 'theforeman'
collection = 'foreman'
downstream_namespace = 'redhat'
downstream_collection = 'satellite'
use_fqcn = True
def get_plugin_env(self, inventory_update, private_data_dir, private_data_files):
# this assumes that this is merged
@@ -1542,18 +1533,24 @@ class satellite6(PluginFileInjector):
ret['FOREMAN_PASSWORD'] = credential.get_input('password', default='')
return ret
def inventory_as_dict(self, inventory_update, private_data_dir):
ret = super(satellite6, self).inventory_as_dict(inventory_update, private_data_dir)
# this inventory plugin requires the fully qualified inventory plugin name
ret['plugin'] = f'{self.namespace}.{self.collection}.{self.plugin_name}'
return ret
class tower(PluginFileInjector):
plugin_name = 'tower'
class controller(PluginFileInjector):
plugin_name = 'tower' # TODO: relying on routing for now, update after EEs pick up revised collection
base_injector = 'template'
namespace = 'awx'
collection = 'awx'
downstream_namespace = 'ansible'
downstream_collection = 'controller'
class insights(PluginFileInjector):
plugin_name = 'insights'
base_injector = 'template'
namespace = 'redhatinsights'
collection = 'insights'
downstream_namespace = 'redhat'
downstream_collection = 'insights'
use_fqcn = True
for cls in PluginFileInjector.__subclasses__():

View File

@@ -37,7 +37,7 @@ from awx.main.models.base import (
VERBOSITY_CHOICES,
VarsDictProperty,
)
from awx.main.models.events import JobEvent, SystemJobEvent
from awx.main.models.events import JobEvent, UnpartitionedJobEvent, UnpartitionedSystemJobEvent, SystemJobEvent
from awx.main.models.unified_jobs import UnifiedJobTemplate, UnifiedJob
from awx.main.models.notifications import (
NotificationTemplate,
@@ -600,20 +600,10 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
def get_ui_url(self):
return urljoin(settings.TOWER_URL_BASE, "/#/jobs/playbook/{}".format(self.pk))
@property
def ansible_virtualenv_path(self):
# the order here enforces precedence (it matters)
for virtualenv in (
self.job_template.custom_virtualenv if self.job_template else None,
self.project.custom_virtualenv,
self.organization.custom_virtualenv if self.organization else None,
):
if virtualenv:
return virtualenv
return settings.ANSIBLE_VENV_PATH
@property
def event_class(self):
if self.has_unpartitioned_events:
return UnpartitionedJobEvent
return JobEvent
def copy_unified_job(self, **new_prompts):
@@ -855,23 +845,6 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
continue
host.ansible_facts = ansible_facts
host.ansible_facts_modified = now()
ansible_local = ansible_facts.get('ansible_local', {}).get('insights', {})
ansible_facts = ansible_facts.get('insights', {})
ansible_local_system_id = ansible_local.get('system_id', None) if isinstance(ansible_local, dict) else None
ansible_facts_system_id = ansible_facts.get('system_id', None) if isinstance(ansible_facts, dict) else None
if ansible_local_system_id:
print("Setting local {}".format(ansible_local_system_id))
logger.debug(
"Insights system_id {} found for host <{}, {}> in"
" ansible local facts".format(ansible_local_system_id, host.inventory.id, host.name)
)
host.insights_system_id = ansible_local_system_id
elif ansible_facts_system_id:
logger.debug(
"Insights system_id {} found for host <{}, {}> in"
" insights facts".format(ansible_local_system_id, host.inventory.id, host.name)
)
host.insights_system_id = ansible_facts_system_id
host.save()
system_tracking_logger.info(
'New fact for inventory {} host {}'.format(smart_str(host.inventory.name), smart_str(host.name)),
@@ -1259,17 +1232,21 @@ class SystemJob(UnifiedJob, SystemJobOptions, JobNotificationMixin):
@property
def event_class(self):
if self.has_unpartitioned_events:
return UnpartitionedSystemJobEvent
return SystemJobEvent
@property
def can_run_on_control_plane(self):
return True
@property
def task_impact(self):
if settings.IS_K8S:
return 0
return 5
@property
def preferred_instance_groups(self):
return self.global_instance_groups
return self.control_plane_instance_group
'''
JobNotificationMixin

View File

@@ -464,15 +464,18 @@ class ExecutionEnvironmentMixin(models.Model):
def resolve_execution_environment(self):
"""
Return the execution environment that should be used when creating a new job.
Return the execution environment that should be used when executing a job.
"""
if self.execution_environment is not None:
return self.execution_environment
template = getattr(self, 'unified_job_template', None)
if template is not None and template.execution_environment is not None:
return template.execution_environment
if getattr(self, 'project_id', None) and self.project.default_environment is not None:
return self.project.default_environment
if getattr(self, 'organization', None) and self.organization.default_environment is not None:
if getattr(self, 'organization_id', None) and self.organization.default_environment is not None:
return self.organization.default_environment
if getattr(self, 'inventory', None) and self.inventory.organization is not None:
if getattr(self, 'inventory_id', None) and self.inventory.organization is not None:
if self.inventory.organization.default_environment is not None:
return self.inventory.organization.default_environment

View File

@@ -117,7 +117,7 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin, CustomVi
def create_default_galaxy_credential(self):
from awx.main.models import Credential
public_galaxy_credential = Credential.objects.filter(managed_by_tower=True, name='Ansible Galaxy').first()
public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first()
if public_galaxy_credential not in self.galaxy_credentials.all():
self.galaxy_credentials.add(public_galaxy_credential)

Some files were not shown because too many files have changed in this diff Show More