Compare commits

...

813 Commits

Author SHA1 Message Date
Ryan Petrello
3e03c726cb Merge pull request #9133 from ryanpetrello/more-changelog-bits
Change the 17.0.0 date and make room for a bit more to land.
2021-01-22 01:11:39 -05:00
softwarefactory-project-zuul[bot]
a2c2588383 Merge pull request #9083 from jlmitch5/actStream
Update Breadcrumbs/Add Activity Stream UI

Reviewed-by: John Hill <johill@redhat.com>
             https://github.com/unlikelyzero
2021-01-21 23:45:23 +00:00
Ryan Petrello
67066a3fa5 Change the 17.0.0 date and make room for a bit more to land. 2021-01-21 17:12:25 -05:00
softwarefactory-project-zuul[bot]
bd76d1a75f Merge pull request #9050 from ryanpetrello/bump-17-0-0
Bump version to 17.0.0

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-21 21:01:21 +00:00
Ryan Petrello
c77ca928cc Bump version to 17.0.0 2021-01-21 15:31:46 -05:00
John Mitchell
7d495713ee updated aria label for activity stream type select 2021-01-21 15:31:08 -05:00
softwarefactory-project-zuul[bot]
b78fee1f01 Merge pull request #9011 from AlexSCorey/PreLingUI2
Updates files to pre lingUI upgrade work

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-21 20:30:18 +00:00
John Mitchell
00e837c17c update grouping of activity stream type select and remove inv scripts 2021-01-21 10:01:49 -05:00
John Mitchell
06ff178f9e update activity stream file structure to be consistent with other routes and aid in testing 2021-01-21 10:01:49 -05:00
John Mitchell
f07818f04a check if breadcrumbs should update by name (which changes), not ID 2021-01-21 10:01:49 -05:00
John Mitchell
7a3002f218 fix routes with breadcrumb issues:
team roles title crumb missing
various inventory crums missing
make it so inventories and templates don't get rid of data needed to generate the crumb config
2021-01-21 10:01:49 -05:00
John Mitchell
a0ded889f9 add min height to title to keep page redrwaw from flashing 2021-01-21 10:01:49 -05:00
John Mitchell
8d46e78606 fix lint issue with urlParam name 2021-01-21 10:01:49 -05:00
John Mitchell
6b53ea51fc fix spacing issues with activity stream description builder 2021-01-21 10:01:49 -05:00
John Mitchell
ce28968a11 reset page to 1 after activity stream type changes 2021-01-21 10:01:49 -05:00
John Mitchell
c793b3a9c8 fix issues from rebase fallout 2021-01-21 10:01:49 -05:00
John Mitchell
77cd875a9c add initiated by sort on activity stream 2021-01-21 10:01:49 -05:00
John Mitchell
fd708456df fix workflow event activity steam linking 2021-01-21 10:01:49 -05:00
John Mitchell
2f7a7b453f add workflow node based events to be shown when templates is selected in activity streram 2021-01-21 10:01:49 -05:00
John Mitchell
cec5a77762 add username-based search to activity stream 2021-01-21 10:01:49 -05:00
John Mitchell
7c57a8e5d0 add activity stream ui 2021-01-21 10:01:49 -05:00
John Mitchell
87a2039ded don't strip out non-namespaced params when encoding url search params 2021-01-21 10:01:49 -05:00
John Mitchell
90edb3b551 update Breadcrumb component to ScreenHeader:
- show last breadcrum item as Title on new line
- add activity stream type (to display activity stream icon link in header)
2021-01-21 10:01:49 -05:00
softwarefactory-project-zuul[bot]
f37471c858 Merge pull request #8782 from marshmalien/setting-radius-tacacs-edit-forms
Add RADIUS and TACACS+ setting forms

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-20 22:55:51 +00:00
softwarefactory-project-zuul[bot]
41a855fa6a Merge pull request #9121 from shanemcd/devel
Dont fail image builds because of debuginfo repo problems

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-20 21:12:37 +00:00
Shane McDonald
54e1a802c5 Dont fail imagee builds because of debuginfo repo problems 2021-01-20 15:34:38 -05:00
softwarefactory-project-zuul[bot]
8a7c714613 Merge pull request #9028 from mabashian/7015-prompt-cred-passwords-v2
Add support for credential password prompting on job launch

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-20 19:32:48 +00:00
Alex Corey
0a88d42645 Updates files to pre lingUI upgrade work 2021-01-20 13:31:03 -05:00
softwarefactory-project-zuul[bot]
93160fa4fd Merge pull request #9113 from rooftopcellist/fix-pg12-upgrades
Fix bind-mount problem with pg12 upgrades

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-19 22:04:23 +00:00
mabashian
f738f52c5c Remove credential password mapping in favor of using keys that the api accepts 2021-01-19 16:56:23 -05:00
Christian M. Adams
ac925a03b5 Fix bind-mount problem with pg12 upgrades 2021-01-19 16:34:24 -05:00
mabashian
90caea2273 Separate vault password from id with vertical separator 2021-01-19 13:49:01 -05:00
softwarefactory-project-zuul[bot]
a06366ccc9 Merge pull request #9106 from cl1ent/patch-1
fixed default location for docker_compose_dir variable

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-19 17:49:05 +00:00
softwarefactory-project-zuul[bot]
f4fb13492b Merge pull request #9111 from shanemcd/no-default-password
Do not set default admin_password

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2021-01-19 17:04:29 +00:00
mabashian
7f78018386 Fix job relaunch where credentials are needed 2021-01-19 11:34:19 -05:00
Shane McDonald
aabb55810b Do not set default admin_password 2021-01-19 11:32:06 -05:00
mabashian
fb62e0ec2c Revert changes to isValid 2021-01-19 09:59:18 -05:00
mabashian
448e49ae43 Add support for password prompting on job launch 2021-01-19 09:59:18 -05:00
cl1ent
9d53bab050 fixed default location for docker_compose_dir variable 2021-01-19 13:17:24 +01:00
softwarefactory-project-zuul[bot]
3a467067f3 Merge pull request #9086 from ryanpetrello/more-callback-tinkering
further optimize callback receiver buffering for certain situations

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-18 19:13:23 +00:00
softwarefactory-project-zuul[bot]
3f759d8ddb Merge pull request #8896 from mabashian/7700-smart-inv-button
Adds smart inventory button on host list

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-18 18:54:52 +00:00
softwarefactory-project-zuul[bot]
5959bfc4ae Merge pull request #9089 from sean-m-sullivan/survey_update
Survey update to workflows

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
             https://github.com/beeankha
2021-01-18 17:22:43 +00:00
softwarefactory-project-zuul[bot]
7ffbc7ed1e Merge pull request #9078 from rooftopcellist/pg12-upgrade-migrations
Fix Local Docker partial migration and unavailable superuser issues

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-18 15:51:25 +00:00
sean-m-sullivan
74d1859552 add alias 2021-01-18 09:12:30 -06:00
Sean Sullivan
e4cb50921e Merge pull request #27 from ansible/devel
Rebase
2021-01-16 22:51:21 -06:00
softwarefactory-project-zuul[bot]
d1e5dc1eae Merge pull request #9099 from rooftopcellist/rm_launch_configmap
Remove launch script config mapping for k8s and ocp

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-15 21:46:18 +00:00
mabashian
6a7f7a0256 Move smart inventory button out to it's own component to properly handle kebabification 2021-01-15 14:50:41 -05:00
mabashian
bb2248cb24 Adds tooltip around host filter lookup when an organization is not selected 2021-01-15 14:14:34 -05:00
mabashian
fa6de04e79 Remove object import as its not used 2021-01-15 14:14:34 -05:00
mabashian
87604749b7 Adds smart inventory button on host list 2021-01-15 14:14:34 -05:00
softwarefactory-project-zuul[bot]
684998cd51 Merge pull request #8580 from ryanpetrello/fork-race
forcibly close DB and cache socket connection post-fork

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-15 19:00:43 +00:00
softwarefactory-project-zuul[bot]
2d4a3bc943 Merge pull request #8802 from AlexSCorey/4212-LoadingState
Adds Spinner to Loading state

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-15 13:23:14 +00:00
sean-m-sullivan
73c46030bc update completeness 2021-01-14 16:19:39 -06:00
Ryan Petrello
b744c4ebb7 further optimize callback receiver buffering for certain situations
see: https://github.com/ansible/awx/issues/9085
2021-01-14 17:17:12 -05:00
sean-m-sullivan
328435d435 update to survey option on workflow module. 2021-01-14 15:37:59 -06:00
Marliana Lara
62eae017cf Add tacacs category setting edit form 2021-01-14 14:23:12 -05:00
Marliana Lara
dcb1773918 Add radius category setting edit form 2021-01-14 14:23:06 -05:00
Christian M. Adams
a1514a3b26 Remove launch scrip config mapping for k8s and ocp
* Related to https://github.com/ansible/awx/pull/8968
2021-01-14 13:48:33 -05:00
Christian M. Adams
88a0d98447 Run migrations via a task, not in the container
* Issue: https://github.com/ansible/awx/issues/9077
  * Fixes problem with migrations not completing
2021-01-14 09:50:26 -05:00
softwarefactory-project-zuul[bot]
d88ed19edf Merge pull request #8781 from marshmalien/setting-ldap-edit-forms
Add all LDAP (Default, 1-5) setting forms

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-14 12:49:25 +00:00
Alex Corey
47c1dc8171 Adds spinner to loadiing and updating states 2021-01-13 18:15:05 -05:00
Marliana Lara
28733beee8 Show placeholder for codemirror inputs and expand width of "DN" ldap fields 2021-01-13 18:02:40 -05:00
Marliana Lara
c90a459837 Fix bug where revert all reverted all ldap categories 2021-01-13 17:58:00 -05:00
Marliana Lara
ba8cf1aaf2 Add all LDAP (Default-5) setting forms 2021-01-13 17:57:55 -05:00
Christian M. Adams
57c3b9ab17 Run PG upgrade tasks in container because of permissions
* update pg references
2021-01-13 17:27:03 -05:00
Ryan Petrello
b24a1746ae Remove old logo 2021-01-13 13:55:45 -05:00
softwarefactory-project-zuul[bot]
2f16b361f7 Merge pull request #8656 from nixocio/ui_issue_8194
Fix Inventory/Project rbac broken on JT form

Reviewed-by: Kersom
             https://github.com/nixocio
2021-01-13 18:23:35 +00:00
softwarefactory-project-zuul[bot]
5bb59246af Merge pull request #8761 from marshmalien/setting-github-edit-forms
Add all github category setting edit forms

Reviewed-by: John Hill <johill@redhat.com>
             https://github.com/unlikelyzero
2021-01-13 15:23:34 +00:00
Alex Corey
766b2f774d convert PaginatedDataList to function 2021-01-13 10:13:15 -05:00
nixocio
b8369defd6 Fix Inventory/Project rbac broken on JT form
Fix Inventory/Project rbac broken on JT form.

Also, update ProjectLookup to filter using `role_level: 'use_role'` as
per old UI implementation.

Also, update InventoryLookup to filter using `role_level: 'use_role'` as
per old UI implementation.

See: https://github.com/ansible/awx/issues/8194
2021-01-13 09:23:12 -05:00
softwarefactory-project-zuul[bot]
7daa1fe786 Merge pull request #8860 from CUB-OIT-PE/jinja-chain-undefined
Enabled jinja2.ChainableUndefined for custom webhook notifications

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2021-01-12 20:35:46 +00:00
softwarefactory-project-zuul[bot]
74daa49e6f Merge pull request #9063 from ryanpetrello/activity-stream-analytics-gather
don't record AUTOMATION_ANALYTICS_LAST_GATHER updates

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-12 19:17:45 +00:00
softwarefactory-project-zuul[bot]
c7b51176a4 Merge pull request #9046 from jbradberry/export-inventory-source-inventories
Do not drop inventories marked as has_inventory_sources

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-12 18:58:11 +00:00
softwarefactory-project-zuul[bot]
b50e72ab20 Merge pull request #8776 from nixocio/ui_issue_7708
Show access tab when credential does not belong to an organization

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-12 18:46:27 +00:00
Ryan Petrello
b3d4b57ae9 don't record AUTOMATION_ANALYTICS_LAST_GATHER updates
this is noisy in the activity stream
2021-01-12 11:21:11 -05:00
Marliana Lara
1c2605be8e Add ouiaId props to button and alert components 2021-01-11 16:38:32 -05:00
Marliana Lara
7662a67a65 Add all github category setting edit forms 2021-01-11 16:37:28 -05:00
willhaines
e2cb6a8caf Merge pull request #1 from jladdjr/jladd_jinja-chain-undefined
minor dep changes for jinja2.ChainableUndefined fix
2021-01-11 13:03:12 -07:00
Jim Ladd
60dee83481 revert jinja2 dep changes for ansible venv 2021-01-11 11:48:39 -08:00
Will Haines
d59e172f53 Pinned Jinja2 to ensure ChainableUndefined is present
Signed-off-by: Will Haines <william.haines@colorado.edu>
2021-01-11 11:56:04 -07:00
softwarefactory-project-zuul[bot]
b22aa3e99e Merge pull request #9054 from Spredzy/downgrade_cryptography
Pin cryptography to pre 3 release

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-11 16:13:25 +00:00
Yanis Guenane
7275db8d66 Pin cryptography to pre 3 release 2021-01-11 14:36:56 +01:00
softwarefactory-project-zuul[bot]
938725c86c Merge pull request #8943 from rooftopcellist/pg12
Upgrade PostgreSQL from 10 to 12

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2021-01-08 21:44:40 +00:00
Jeff Bradberry
a3723db357 Do not drop inventories marked as has_inventory_sources 2021-01-08 14:32:33 -05:00
nixocio
682b06be5a Show access tab when credential does not belong to an organization
Credential access tab should be shown when cred doesn't belong to an organization.

Also, update unit-tests to reflect change.

See: https://github.com/ansible/awx/issues/7708
2021-01-08 14:30:08 -05:00
softwarefactory-project-zuul[bot]
aa87a99441 Merge pull request #9044 from kdelee/awx_silent_delete_conflict
silent_delete also needs to handle Confict

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-08 16:25:54 +00:00
Elijah DeLee
a157a3598f silent_delete also needs to handle Confict 2021-01-08 10:55:55 -05:00
Christian M. Adams
36466b9694 Upgrade PostgreSQL from 10 to 12 2021-01-08 10:54:00 -05:00
softwarefactory-project-zuul[bot]
1dec79b62d Merge pull request #8880 from vguillard/issue_5080_openstack_region_field_missing
Related #5080 openstack region field missing

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-08 14:39:03 +00:00
Will Haines
9ec958f839 Added test for Chainable Undefined Behavior
Signed-off-by: Will Haines <william.haines@colorado.edu>
2021-01-07 23:25:19 -07:00
softwarefactory-project-zuul[bot]
98b25f619e Merge pull request #9040 from kdelee/new_teardown_error
When deleting a job sometimes we get this error

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-07 22:38:29 +00:00
Elijah DeLee
908291dd3c When deleting a job sometimes we get this error
For the silent delete method, we should let this one slide
because it is an expected error that may occur if there are still
events processing.
2021-01-07 15:37:57 -05:00
softwarefactory-project-zuul[bot]
764511f33f Merge pull request #8738 from AlexSCorey/8532-VaultIdsOnCredChips
Adds vault IDs to Vault credential chips

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-07 19:49:13 +00:00
softwarefactory-project-zuul[bot]
b0c3c2b16a Merge pull request #8654 from mabashian/8530-data-list-toolbar-ids
Swap underscores for hyphens in qs namespace strings

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-07 19:12:44 +00:00
mabashian
dcd79cdb98 Swap underscores for hyphens in qs namespace strings 2021-01-07 13:19:05 -05:00
softwarefactory-project-zuul[bot]
e1fb6542c3 Merge pull request #9002 from nixocio/ui_update_dep
Update dependencies

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-07 16:43:51 +00:00
Alex Corey
9cc3579189 Adds vault IDs to Vault credential chips 2021-01-07 11:39:57 -05:00
softwarefactory-project-zuul[bot]
c8594edc0b Merge pull request #9009 from chrismeyersfsu/purge_devel_settings
consolidate settings and delete dead settings

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-07 15:56:11 +00:00
nixocio
a1b0fa252a Update dependencies
Update dependencies
2021-01-07 09:06:43 -05:00
softwarefactory-project-zuul[bot]
e640bde42c Merge pull request #9003 from AlexSCorey/8847-fix
Adds sync button to project details page

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-06 22:39:26 +00:00
Alex Corey
d1fcb96ee2 Adds sync button to project details page 2021-01-06 15:47:11 -05:00
softwarefactory-project-zuul[bot]
b6f032bf88 Merge pull request #8762 from marshmalien/setting-google-oauth2-edit-form
Add Google OAuth 2.0 setting edit form

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-06 19:48:11 +00:00
softwarefactory-project-zuul[bot]
8e104417a6 Merge pull request #9008 from jbradberry/autobahn-cve
Update autobahn to address CVE-2020-35678

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-06 18:14:22 +00:00
softwarefactory-project-zuul[bot]
148e4ef10c Merge pull request #9017 from rh-dluong/fix-timeout-description
Changed task to job in job timeout description, fixes #9016

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-06 15:31:19 +00:00
dluong
3e8eb7f23e Changed task to job in job timeout description, fixes #9016 2021-01-06 09:52:48 -05:00
Jeff Bradberry
0eff06318f Update autobahn to address CVE-2020-35678 2021-01-05 13:44:05 -05:00
Chris Meyers
ad621a7da2 consolidate settings and delete dead settings 2021-01-05 13:02:25 -05:00
softwarefactory-project-zuul[bot]
96a7fe0035 Merge pull request #9005 from AlanCoding/assert_workflow_failure
Make workflow_job.assert_successful() give specifics

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-05 17:28:28 +00:00
softwarefactory-project-zuul[bot]
545119fb56 Merge pull request #9006 from ryanpetrello/pin-pip-tools-updater
pin pip-tools for now

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-05 16:15:11 +00:00
Ryan Petrello
f40ee7ca15 pin pip-tools for now
a new version of pip-tools changed the format of dependency annotations
in generated requirements.txt files

we should probably change to the new format at some point, but maybe
*after* we merge a few of our long-running branches that touch these
files (otherwise, managing conflicts could be pretty hellish)
2021-01-05 10:45:40 -05:00
softwarefactory-project-zuul[bot]
c6e61395f5 Merge pull request #9001 from chrismeyersfsu/fix-iso_manager_log
specify isolated_manager.log path

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-05 15:41:06 +00:00
Alan Rominger
d3c51ce75d Minor organization clarity for workflow failure summary 2021-01-05 10:33:35 -05:00
Alan Rominger
9a16e9f787 Condense logic for handling null job 2021-01-05 10:26:38 -05:00
Alan Rominger
d79b96b6cc Make workflow_job.assert_successful() give specifics 2021-01-05 10:15:32 -05:00
softwarefactory-project-zuul[bot]
b667162496 Merge pull request #8892 from AlexSCorey/8603-fix
Adds searchable keys and related keys to Credentials list

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-05 15:14:43 +00:00
softwarefactory-project-zuul[bot]
72cab99cd7 Merge pull request #9000 from nixocio/ui_fix_contrib_docs
Small docs update

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-05 14:56:09 +00:00
Chris Meyers
474252dbff specify isolated_manager.log path
* By default, log files are created in the dir relative to the awx
source. For production, explicitly specify the log file path
2021-01-05 09:22:56 -05:00
nixocio
45e9bdcf86 Small docs update
Small docs update. Fix broken link, and update node version used.

See: https://github.com/ansible/awx/pull/8766/files
2021-01-05 09:16:44 -05:00
softwarefactory-project-zuul[bot]
f52b23f298 Merge pull request #8658 from mabashian/5683-created-modified-details
Move jt/wfjt created/modified details to the end right before the full width details

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-04 22:49:40 +00:00
mabashian
0b3d9b026d Adds created/modified details to several areas 2021-01-04 16:17:46 -05:00
Alex Corey
1dbadca78e Adds searchable keys and related keys 2021-01-04 15:35:54 -05:00
softwarefactory-project-zuul[bot]
13861dee85 Merge pull request #8836 from chrismeyersfsu/sustaining-improve_iso_logging_devel
Sustaining improve iso logging devel

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-04 20:18:24 +00:00
mabashian
4ea757c91a Move jt/wfjt created/modified details to the end right before the full width details 2021-01-04 15:04:34 -05:00
softwarefactory-project-zuul[bot]
7e74f823f4 Merge pull request #8996 from robled/license_module_docs_fix
Fixed link to Content Hub in Tower module documentation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2021-01-04 16:54:15 +00:00
David Roble
e611a67be7 Fixed link to Content Hub in Tower module documentation
Signed-off-by: David Roble <droble@redhat.com>
2021-01-04 11:21:30 -05:00
softwarefactory-project-zuul[bot]
a98dfc978e Merge pull request #8980 from shanemcd/simplify-image-build
Simplify image build

Reviewed-by: Alan Rominger <arominge@redhat.com>
             https://github.com/AlanCoding
2021-01-04 15:47:58 +00:00
Shane McDonald
642e6f792c Remove unnecessary conditional from image build task 2020-12-29 19:14:16 -05:00
Shane McDonald
b857fb5074 Remove use_container_for_build from inventory 2020-12-29 19:14:05 -05:00
Shane McDonald
6f9862c72e Sweeping replace of old dev venv paths 2020-12-26 21:29:22 -05:00
Shane McDonald
1033c4d251 Explicitly run image_build and image_push on localhost 2020-12-26 13:16:42 -05:00
Shane McDonald
ab6430e50d Dramatically simplify image_build role
This does a few things:

- Removes need for awx_sdist_builder image
- Reorders Dockerfile steps to optimize image cache between prod and dev builds
- Unifies VENV_BASE and COLLECTION_BASE in prod and dev builds
2020-12-26 13:16:42 -05:00
Shane McDonald
8ceb505977 Add standalone target for rendering official Dockerfile
With the next commit it will be possible to run:

```
$ make Dockerfile
$ docker build .
```
2020-12-26 13:16:40 -05:00
Sean Sullivan
d9ca825935 Merge pull request #23 from ansible/devel
Rebase
2020-12-24 21:08:13 -05:00
softwarefactory-project-zuul[bot]
cb5c16918c Merge pull request #8928 from mabashian/8207-cancel-button-disable
Disable cancel button on jobs list when one or more selected jobs is not running

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-23 01:27:47 +00:00
softwarefactory-project-zuul[bot]
2a353a809b Merge pull request #8959 from jakemcdermott/fix-8884
Default to lang in catalog when browser preference unavailable

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-22 23:09:27 +00:00
softwarefactory-project-zuul[bot]
0b364b2918 Merge pull request #8972 from shanemcd/sorry-jake
Restore old behavior of ui-devel

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-22 22:58:17 +00:00
Shane McDonald
4219089166 Restore old behavior of ui-devel 2020-12-22 17:20:20 -05:00
Jake McDermott
8db88e979e Default to lang in catalog when browser preference unavailable
When strings aren't available for the browser's preferred locale,
default to one with strings to avoid displaying raw javascript
variables.
2020-12-22 15:36:33 -05:00
softwarefactory-project-zuul[bot]
3077cb9802 Merge pull request #8963 from marshmalien/8962-fix-output-navigation
Fix navigation bug in job output 

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-22 20:16:01 +00:00
softwarefactory-project-zuul[bot]
70f7bd957d Merge pull request #8968 from shanemcd/refactor-image-build
Refactor official image build process

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-22 20:04:27 +00:00
Shane McDonald
f951aa24bf More sane way of building the official AWX image 2020-12-22 14:27:47 -05:00
Shane McDonald
225c3d6a39 Speed up subsequent invocations of ui-devel / ui-release 2020-12-22 14:27:45 -05:00
mabashian
8f8c4e6b7b Wrap permissions v. running tooltip contents so that they appear on different lines 2020-12-22 13:08:56 -05:00
mabashian
e4c708f458 Disable cancel button when one or more selected jobs is not running. Separate messaging for jobs that you don't have permission to cancel v. jobs that cannot be canceled because they aren't running. 2020-12-22 13:08:56 -05:00
softwarefactory-project-zuul[bot]
983d377a93 Merge pull request #8657 from mabashian/7816-user-role-empty-name
Display 'System' for user role resource name when summary_fields.resource_name not present

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-22 17:17:32 +00:00
softwarefactory-project-zuul[bot]
efcc1bf262 Merge pull request #8967 from shanemcd/less-config
Remove launch scripts from configmaps

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-22 14:50:51 +00:00
Shane McDonald
106d90aeb3 Remove launch scripts from configmaps
The duplication of these scripts has been bothering me for a while. They dont
get enough usage to justify their existence.
2020-12-22 09:12:03 -05:00
Marliana Lara
b695f583dd Fix job output loading state 2020-12-21 15:19:26 -05:00
softwarefactory-project-zuul[bot]
6d577feeba Merge pull request #8951 from robled/license_module_docs_fix
Added module prefix to awx license module example documentation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-18 21:13:08 +00:00
softwarefactory-project-zuul[bot]
f8edb6b4f6 Merge pull request #8912 from Saurabh-Thakre/patch-1
Update consumers.py

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-18 19:35:15 +00:00
softwarefactory-project-zuul[bot]
66b9a65a14 Merge pull request #8667 from mabashian/7522-survey-q-breadcrumb
Fix issue with broken survey question edit breadcrumb by altering the url scheme

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-18 18:55:39 +00:00
softwarefactory-project-zuul[bot]
5632f72bb1 Merge pull request #8729 from keithjgrant/6189-list-tables
Create PaginatedTable component

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-18 17:44:43 +00:00
mabashian
4d448510b4 Fixes bug where navigating from one survey question form directly to another wasn't reloading the form. 2020-12-18 12:19:14 -05:00
mabashian
f44faf4e61 Fix issue with broken survey question edit breadcrumb by altering the url scheme 2020-12-18 12:19:14 -05:00
David Roble
3bd976bda9 Added module prefix to awx license module example documentation
Signed-off-by: David Roble <droble@redhat.com>
2020-12-18 11:58:27 -05:00
Jake McDermott
c8d471466c Resolve most console errors in tests 2020-12-18 11:34:39 -05:00
Jake McDermott
fa1ef87f20 Use location hook in routed tabs
Fix a unit test that is failing due to history.location
not updating as expected when a routed tab is selected.
2020-12-18 11:01:22 -05:00
Jake McDermott
f09120a973 Replace chip key with non-array index
Address a lint error (rule: react/no-array-index-key) by using
chip.key prop val instead of an array index for the component key.
2020-12-18 11:01:19 -05:00
Jake McDermott
6223a78ff4 Address errors from type system 2020-12-18 11:01:16 -05:00
Jake McDermott
d05ffd24f4 Regenerate lockfile 2020-12-18 11:01:10 -05:00
Keith Grant
ee1ed2aaa7 handle null values on inventories pending deletion
Co-authored-by: Jake McDermott <yo@jakemcdermott.me>
2020-12-17 11:29:45 -08:00
Keith Grant
a9d7fea86f flush out tests for PaginatedTable and related components 2020-12-17 11:29:45 -08:00
Keith Grant
204af9ec91 update tests for PaginatedTable lists 2020-12-17 11:29:45 -08:00
Keith Grant
9da636e294 table header cleanup; fix inventory status labels 2020-12-17 11:29:45 -08:00
Keith Grant
6a47899dbb simplify ActionsTd interface; add ActionItem component 2020-12-17 11:29:45 -08:00
Keith Grant
a8159273eb convert InventoryList to use PaginatedTable 2020-12-17 11:29:45 -08:00
Keith Grant
1816280a15 convert PaginatedTable to function component 2020-12-17 11:29:45 -08:00
Keith Grant
b9d3beaa7f add HeaderRow component with table sorting 2020-12-17 11:29:45 -08:00
Keith Grant
cfc4c3a1a7 add patternfly tables; add PaginatedTable 2020-12-17 11:29:45 -08:00
softwarefactory-project-zuul[bot]
e08e88d940 Merge pull request #8939 from mabashian/8937-org-tabs-requests
Wrap breadcrumb function in useCallback to prevent infinite requests on org tabs

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-17 15:49:56 +00:00
softwarefactory-project-zuul[bot]
1937c0cc08 Merge pull request #8938 from jakemcdermott/fix-8936
Don't build job redirect until data available

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-17 15:24:40 +00:00
Jake McDermott
19f855717d Don't build redirect until data available 2020-12-17 09:45:44 -05:00
mabashian
82f6799c34 Wrap breadcrumb function in useCallback to prevent infinite requests on org tabs 2020-12-17 09:19:44 -05:00
Jake McDermott
d35732c4b7 Add missing slash to routing key 2020-12-17 09:15:10 -05:00
softwarefactory-project-zuul[bot]
793764283d Merge pull request #8683 from jakemcdermott/fix-8605
Avoid prop reference error when saving cred

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 22:27:25 +00:00
softwarefactory-project-zuul[bot]
fc8d2300af Merge pull request #8866 from jakemcdermott/fix-ldap-group-param-500
Fix 500 on unhandled group param type

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 22:02:46 +00:00
softwarefactory-project-zuul[bot]
846d2a0cbd Merge pull request #8908 from wenottingham/instance-karma
Flip the instance ID var for AWS to `instance_id`

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 22:00:03 +00:00
softwarefactory-project-zuul[bot]
7706ef415a Merge pull request #8706 from AlexSCorey/PreLinguiUpgrade
Pre-lingui upgrade 

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
             https://github.com/jakemcdermott
2020-12-16 21:46:31 +00:00
Jake McDermott
b2341408b9 Fix 500 on unhandled group param type 2020-12-16 16:06:29 -05:00
softwarefactory-project-zuul[bot]
a5e54c3858 Merge pull request #8780 from mabashian/7879-notif-copy-search
Add support for notification template copy and advanced search

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 20:39:52 +00:00
softwarefactory-project-zuul[bot]
7c96677510 Merge pull request #8922 from fosterseth/fix_move_deletion_to_utils
Move deletion.py to utils

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 20:02:08 +00:00
mabashian
3d03c473d6 Change Type to Notification type since this endpoint has both type and notification_type attributes. 2020-12-16 14:55:19 -05:00
Jake McDermott
5cb580be7a Refactor top-level template routes
* Fix repeated api calls from useEffect hook by wrapping the breadcrumb
setter with useCallback

* Rework the top-level routes to remove some old patterns and bring it more
into alignment with how it's done on the projects screen
2020-12-16 13:46:59 -05:00
softwarefactory-project-zuul[bot]
6900ded80b Merge pull request #8399 from AlexSCorey/5913-WFNODEPOL
Add WF Node Promptability

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 17:36:40 +00:00
Seth Foster
81dd54504e move custom deletion tool for cleanup jobs to utils 2020-12-16 11:14:33 -05:00
softwarefactory-project-zuul[bot]
1c0ac75782 Merge pull request #8920 from jakemcdermott/fix-lockfile
Generate package lock file with recent dependency updates

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 15:50:30 +00:00
Alex Corey
d82f68c88e moves some files to hooks in preparation for lingUI upgrade 2020-12-16 10:34:45 -05:00
mabashian
a345675a97 Cleanup handling of extra_vars in workflow node prompting 2020-12-16 09:46:00 -05:00
mabashian
d95373f2b7 Fixes bug where page would crash on preview step if extra vars was malformed 2020-12-16 09:46:00 -05:00
mabashian
6abc981a5e Wrap the sparkline down to the next line instead of overflowing 2020-12-16 09:46:00 -05:00
mabashian
0ac38ef5fc Fix run step title 2020-12-16 09:46:00 -05:00
mabashian
ca1e597a4d Adds blanket error handling to visualizer save process 2020-12-16 09:46:00 -05:00
mabashian
7a3382dd76 Fix initial multiplechoice survey question value when no default present. 2020-12-16 09:46:00 -05:00
mabashian
b7c729c96f Adds ID's to prompt wizard steps 2020-12-16 09:46:00 -05:00
mabashian
1be1fad610 Fixes display of multi-select survey question fields 2020-12-16 09:46:00 -05:00
Alex Corey
307c9eafb3 addresses missing name property and fixes tests 2020-12-16 09:46:00 -05:00
Alex Corey
7d5b198ce6 resloves outstanding issues 2020-12-16 09:46:00 -05:00
Alex Corey
72c6ff095f adds tests 2020-12-16 09:46:00 -05:00
Alex Corey
60751dfa16 adds edit functionality 2020-12-16 09:46:00 -05:00
Alex Corey
2545f14a93 refactoring for adding modal 2020-12-16 09:46:00 -05:00
Alex Corey
20231041e6 Adds Node Modal Promptability
Adds steps for NodeType, RunType, Inventory, Credentials, updates Reducers, adds API calls, adds Add functionality to Visualizer;

Adds other prompt step

Adds SurveyStep

refactors add node functionality
2020-12-16 09:45:59 -05:00
mabashian
a0afe0bdb7 Fix disabled prop on notification button 2020-12-16 09:20:30 -05:00
mabashian
e9a51c0bcc Fix casing on quick search labels 2020-12-16 09:20:12 -05:00
Jake McDermott
1321895e83 Generate package lock file with recent dependency updates 2020-12-16 09:17:49 -05:00
mabashian
d58b4807d9 Disable copy button while copy request is outstanding 2020-12-16 08:52:38 -05:00
Saurabh Thakre
dae1f8dc7f Update consumers.py
Caught a syntax issue at line number 78, modified the syntax to return correct value of nonce_diff.
2020-12-16 09:45:53 +05:30
softwarefactory-project-zuul[bot]
33c3a6d89b Merge pull request #8888 from jakemcdermott/fix-8856
Make display type unique for different job types and consistent between job list and details

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-16 02:07:20 +00:00
softwarefactory-project-zuul[bot]
a756b4400a Merge pull request #8867 from nixocio/ui_schedules
Wrap functions in useCallback to avoid extra requests

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 22:52:28 +00:00
softwarefactory-project-zuul[bot]
3f35ea66fb Merge pull request #8909 from mabashian/fix-test-warning
Fix console being thrown in Dashboard test

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 22:46:15 +00:00
nixocio
4958a428ec Wrap functions in useCallback to avoid extra requests
Wrap functions in useCallback to avoid extra requests.
2020-12-15 17:14:36 -05:00
mabashian
ad20d6c93f Configure advanced search on notification templates list 2020-12-15 17:09:35 -05:00
mabashian
77da8c6994 Adds copy button to notification templates list rows 2020-12-15 17:09:35 -05:00
mabashian
a2d5d9e320 Display 'System' for user role resource name when summary_fields.resource_name not present 2020-12-15 17:07:49 -05:00
Jake McDermott
4033e0f218 Align display types for job list and details 2020-12-15 17:05:38 -05:00
Jake McDermott
1a4eab6f25 Use type field as key for job display type 2020-12-15 17:05:31 -05:00
Jake McDermott
7f89eb324a Fix key for adhoc command display type 2020-12-15 17:05:22 -05:00
mabashian
70b90dbb24 Fix console being thrown in Dashboard test 2020-12-15 17:01:55 -05:00
Bill Nottingham
a1934823ba Flip the instance ID var for AWS to instance_id
This is always returned by the plugin, ec2_id was what the old script returned.
2020-12-15 16:56:08 -05:00
softwarefactory-project-zuul[bot]
de0967a587 Merge pull request #8250 from jakemcdermott/session-timeout
Add session timeout support

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 20:56:34 +00:00
softwarefactory-project-zuul[bot]
3ae6ea9cdc Merge pull request #8877 from jakemcdermott/ws-proto
Support ws or wss proto

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 19:40:17 +00:00
softwarefactory-project-zuul[bot]
44df90686a Merge pull request #8887 from jakemcdermott/fix-8878
Use credential_type for multicred distinction

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 19:40:13 +00:00
softwarefactory-project-zuul[bot]
50d3b69629 Merge pull request #8899 from marshmalien/patternfly-upgrade
Upgrade PatternFly dependencies

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 19:36:49 +00:00
softwarefactory-project-zuul[bot]
bbcf12b4fc Merge pull request #8891 from AlexSCorey/8817-fix
Fix misnamed webhook field

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 18:50:24 +00:00
softwarefactory-project-zuul[bot]
f66485ff12 Merge pull request #8886 from jakemcdermott/make-readme-updates
More readme and makefile updates

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
             https://github.com/jakemcdermott
2020-12-15 17:05:36 +00:00
softwarefactory-project-zuul[bot]
a98fe1955a Merge pull request #8900 from ansible/jakemcdermott-patch-instructions
Update wording of getting started section

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-15 16:46:16 +00:00
Alex Corey
d31851820a Fixes mis labeled HHTP field 2020-12-15 11:31:28 -05:00
Jake McDermott
3398452197 Update wording of getting started section 2020-12-14 19:22:13 -05:00
Jake McDermott
487bf50544 Don't display a negative time
If the remaining session time dips below 0 imediately before auto-
logout, ceil the display value to 0 to avoid showing negative
seconds left.
2020-12-14 17:05:47 -05:00
Jake McDermott
997200dd19 Unchunkify session warning string 2020-12-14 17:05:39 -05:00
Jake McDermott
aa048049ea Add logout button, remove close button 2020-12-14 17:05:36 -05:00
Jake McDermott
d7949e3db9 Clamp timeout to maximum allowed by js 2020-12-14 17:05:32 -05:00
Jake McDermott
838a3822a5 Debounce storage calls on http intercept 2020-12-14 17:05:28 -05:00
Jake McDermott
5ccee4aea2 Add session timeout support
Intercept all http(s) responses and store expiration time from headers
in local storage. Drive expiration timers in app container across all
tabs with browser storage events and accompanying react hooks
integration. Show a warning with logout countdown and continue button
when session is nearly expired.
2020-12-14 17:05:18 -05:00
Marliana Lara
ae38c11211 Upgrade PatternFly dependencies 2020-12-14 16:44:25 -05:00
softwarefactory-project-zuul[bot]
3b2ff25f3c Merge pull request #8803 from marshmalien/8699-wf-notifications-approval-toggle
Show WFJT notification list approval toggle 

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-14 19:57:34 +00:00
softwarefactory-project-zuul[bot]
4c36183343 Merge pull request #7255 from unlikelyzero/instrumented
Add cypress black box code cov instrumentation to ui_next 

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-14 16:42:06 +00:00
Jake McDermott
d88ba5873b Use credential_type for multicred distinction 2020-12-14 10:11:42 -05:00
Jake McDermott
8b32b61072 More readme and makefile updates
* Set log levels for build commands
* Add locale build dirs to cleanup commands
* Move container dev environment build section closer to top of readme
2020-12-14 08:53:03 -05:00
VGU
14f2803ea7 Add 'Region Name' label for openstack credential 2020-12-13 20:20:47 +01:00
VGU
8153d60a5f Rollback to origin file 2020-12-13 20:15:12 +01:00
VGU
e35f1afd57 Fix lint 2020-12-13 19:05:29 +01:00
VGU
bfb00aecbe Add project_region_name input 2020-12-13 18:57:13 +01:00
VGU
06fa2a9e26 Add test_openstack_client_config_generation_with_project_region_name test 2020-12-13 18:56:20 +01:00
Jake McDermott
2cd9a05329 Support ws or wss proto 2020-12-11 19:22:37 -05:00
softwarefactory-project-zuul[bot]
058cfc55a6 Merge pull request #8875 from ansible/jakemcdermott-add-make-to-readme
Add make target info to readme

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-11 22:33:40 +00:00
Jake McDermott
4be9008821 Add make target info to readme 2020-12-11 16:33:36 -05:00
softwarefactory-project-zuul[bot]
e5436a0147 Merge pull request #8833 from AlanCoding/is_superuser
Sync the is_superuser flag when the members relationship changes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-11 20:42:40 +00:00
John Hill
6e4c3b9a51 New Instrumented script, package, and ignored files 2020-12-11 16:20:19 -03:00
softwarefactory-project-zuul[bot]
13cadbc779 Merge pull request #8868 from jakemcdermott/deps-autofix-12-11
Autofix problematic dependency

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-11 17:40:07 +00:00
Jake McDermott
9687c09108 Autofix problematic dependency 2020-12-11 12:06:47 -05:00
softwarefactory-project-zuul[bot]
4376365931 Merge pull request #8841 from nixocio/ui_a11y
Upgrade jsx-a11y plugin

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-11 16:49:59 +00:00
softwarefactory-project-zuul[bot]
6c59111e6c Merge pull request #8862 from ansible/jakemcdermott-update-readme
Update readme requirements

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-11 16:12:18 +00:00
softwarefactory-project-zuul[bot]
d72f8eaf2c Merge pull request #8684 from mabashian/8666-app-token-modal
Show modals with app/token info after creation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-11 13:52:26 +00:00
Jake McDermott
a0ce1350ec Update readme requirements 2020-12-10 22:17:34 -05:00
Will Haines
fc2a2e538f Enabled jinja2.ChainableUndefined for custom webhook notifications
Signed-off-by: Will Haines <william.haines@colorado.edu>
2020-12-10 18:06:59 -07:00
nixocio
ff78156945 Upgrade jsx-a11y plugin
Upgrade jsx-a11y plugin. Also enable strict rules.

See: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y

See: https://github.com/ansible/awx/issues/8443
2020-12-10 16:18:08 -05:00
Chris Meyers
32ad6cdea6 enable iso logger
* The namespace for isolated logging was not enabled. Add a handler and
logger so that it's enabled. This is particularly useful when the
logging level is switched to DEBUG
2020-12-10 15:22:14 -05:00
Chris Meyers
566913fcec log time it took to run check_isolated.yml
* Knowing how long check_isolated.yml ran can be helpful in debuging the
isolated execution path. Especially if you suspect the connection speed
or reliability of the control node -> execution node
2020-12-10 15:05:27 -05:00
Chris Meyers
d39d4d9a9e add job id to iso management playbook output
* It's hard/impossible to know what job a check_isolated.yml playbook
runs for by just looking at the logs.
* Forward the job id for which an iso management playbook is running for
and output that job id so it can be found in the logs.
2020-12-10 15:05:20 -05:00
Chris Meyers
daeba1a898 output timing data for isolated playbook runs
* We batch logging isolated management playbook output. This results in
the timestamp of the log being useless when trying to determine when
each task in the playbook ran.
* To fix this, we enable timestamp logging at the playbook level via
ansible `profile_tasks` callback plugin.
2020-12-10 15:04:55 -05:00
Alan Rominger
da3e521566 Fix the reverse association and edge cases 2020-12-10 14:36:53 -05:00
Alan Rominger
d27afe9691 Small tweaks to logic to make is_superuser change take effect 2020-12-10 13:59:46 -05:00
softwarefactory-project-zuul[bot]
9bf721665d Merge pull request #8723 from ryanpetrello/bump-16
Bump version to 16.0.0

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-10 17:39:28 +00:00
Rebeccah
ee111be261 move away from signals towards the origin of the POST to see if I can impact the data sent within the POST so that it can impact the User model, this may not work because the POST is related only to the Roles model 2020-12-10 12:26:31 -05:00
Rebeccah
b3f15a1e61 added function in signals to corroborate the RBAC to the database, prior it was only corroborating from the DB to RBAC and we need both ways 2020-12-10 12:26:31 -05:00
Ryan Petrello
5f6a383ebe Bump version to 16.0.0 2020-12-10 12:12:51 -05:00
softwarefactory-project-zuul[bot]
871b862731 Merge pull request #8799 from jakemcdermott/fix-8355-part0
Place some initial files for migration view

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-10 16:31:28 +00:00
softwarefactory-project-zuul[bot]
851f7b4c7e Merge pull request #8812 from gamuniz/change_galaxy_token_logger_warning
log galaxy token message as warning

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-10 16:22:13 +00:00
softwarefactory-project-zuul[bot]
c78a50b44d Merge pull request #8728 from mabashian/social-auth
Adds support for GitHub, Azure AD, Google and SAML auth to the UI

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-10 16:13:56 +00:00
Jake McDermott
704029459f Place some initial files for migration view
This restores some of the original files and routes from the migration
view of the classic ui with the eventual goal of fully reintegrating this
system with the new ui.

See: b39db745d4
2020-12-10 11:00:43 -05:00
Gabe Muniz
b78cacb4d8 log galaxy token message as warning 2020-12-10 10:36:02 -05:00
softwarefactory-project-zuul[bot]
4c5757b3bd Merge pull request #8754 from ryanpetrello/strict-csp
Introduce a strict Content-Security-Policy

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-10 15:32:53 +00:00
Jake McDermott
ca2f67e0a9 FFox ESR 78 Compatibility 2020-12-10 09:39:25 -05:00
Marliana Lara
ccd39a60db Show workflow template notification list approval toggle 2020-12-09 15:25:26 -05:00
mabashian
889eb2331c Adds support for GitHub, Azure AD, Google and SAML auth to the UI 2020-12-08 17:28:03 -05:00
softwarefactory-project-zuul[bot]
8e46166313 Merge pull request #8790 from rooftopcellist/quantity_not_exported
Aggregate quantity per sub allocation, not exported

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-08 21:52:49 +00:00
Christian M. Adams
b81f082a18 Aggregate quantity per sub allocation, not exported
* The exported field shows total quantity exported to a manifest for a given sub.  We want to sum the quantities of each sub allocation in a manifest instead.
2020-12-08 16:23:43 -05:00
nixocio
51b18aa012 Fix JobEvent tests
Fix JobEvent tests
2020-12-08 14:49:26 -05:00
mabashian
86d289c375 Adds dataCy id's to app/token details 2020-12-08 14:26:36 -05:00
softwarefactory-project-zuul[bot]
5e51dd2ff7 Merge pull request #8787 from shanemcd/remove-fsgroup-hack
Remove fsgroup hack

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-08 19:20:26 +00:00
mabashian
f2c86cc962 Fix tests after delete button cleanup 2020-12-08 14:12:57 -05:00
mabashian
97837a05e6 Add messaging that certain fields are only available in success modal 2020-12-08 13:54:58 -05:00
mabashian
1a270bfc8b Removes token edit button from details. Removes unnecessary request/props that were used to determine whether a user could delete a token. 2020-12-08 13:38:55 -05:00
Jake McDermott
15704e55e1 Move INLINE_RUNTIME_CHUNK flag to scripts definition
We _always_ want INLINE_RUNTIME_CHUNK to be false when building the ui,
even if someone happens to unexpectedly make a production build without
using the top-level make targets for some reason.
2020-12-08 13:26:10 -05:00
Jake McDermott
b3266f6c62 Avoid prop reference error in test 2020-12-08 13:26:07 -05:00
Jake McDermott
c120b731a4 Add global mock for webpack csp var 2020-12-08 13:26:05 -05:00
Jake McDermott
ab61675c2d Add system for strict-csp stdout html generation 2020-12-08 13:26:02 -05:00
Jake McDermott
548ebd5999 Add w3c-compliant reporting for CSP violations 2020-12-08 13:25:59 -05:00
Jake McDermott
12077627e4 Integrate CSP config with frontend framework 2020-12-08 13:25:56 -05:00
Ryan Petrello
3d5f28f790 Introduce a strict Content-Security-Policy 2020-12-08 13:25:46 -05:00
mabashian
f7a51fe658 Change Name strings to Application name in user token search/sort dropdowns 2020-12-08 13:15:48 -05:00
mabashian
920eda9999 Show token/refresh token/expires in modal after successful token add 2020-12-08 13:15:48 -05:00
mabashian
957ab9bf7c Show client id/secret in modal after successful application add 2020-12-08 13:15:48 -05:00
Shane McDonald
8788c904c8 Revert: Force containers in k8s to run under root group
This reverts most of:
423df6618d

Since https://github.com/sclorg/redis-container/pull/62 is now shipped downstream
2020-12-08 13:06:00 -05:00
Shane McDonald
e85a32d463 Fix typo in deployment template 2020-12-08 13:00:14 -05:00
Jake McDermott
05ae6df80b Avoid prop reference error when saving cred 2020-12-08 10:36:06 -05:00
softwarefactory-project-zuul[bot]
be08e0ce69 Merge pull request #8766 from Spredzy/bump_to_nodejs14
NodeJS: Bump to actively maintained LTS 14.15.1

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-08 15:30:26 +00:00
softwarefactory-project-zuul[bot]
3aba1e9db5 Merge pull request #8614 from jctanner/COLLECTION_PLAYBOOK_STATS
analytics: include modified column and full event_data for playbook_on_stats

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-08 13:08:41 +00:00
softwarefactory-project-zuul[bot]
4992fed5a3 Merge pull request #8770 from rooftopcellist/sat_include_port
Read in and use the Sat port if applicable for Subscriptions

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-07 21:41:41 +00:00
Marliana Lara
8d6a6198dc Add Google OAuth 2.0 setting edit form 2020-12-07 15:33:00 -05:00
Christian M. Adams
aa7514a993 Read in and use the Sat port if applicable for Subscriptions 2020-12-07 13:59:58 -05:00
softwarefactory-project-zuul[bot]
ea8ebe8a9f Merge pull request #8619 from mabashian/login-functional
Convert Login.jsx to functional component

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-07 17:57:03 +00:00
mabashian
7ff82db691 Fix login after source variables change 2020-12-07 12:26:39 -05:00
mabashian
8a8bfc5176 Convert Login.jsx to functional component in preparation for social auth integration 2020-12-07 12:26:39 -05:00
Yanis Guenane
14685b9157 NodeJS: Bump to actively maintained LTS 14.15.1 2020-12-07 18:14:35 +01:00
softwarefactory-project-zuul[bot]
87e564026e Merge pull request #8775 from rooftopcellist/powertools
Fix image build - powertools repo ref changed

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-07 16:53:39 +00:00
Christian M. Adams
8795d860d6 Fix image build - powertools repo ref changed 2020-12-07 11:08:00 -05:00
softwarefactory-project-zuul[bot]
d14fa93ce9 Merge pull request #8758 from hjkatz/patch-7
Use literal quotation marks for Kubernetes annotations instead of quo…

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 20:03:33 +00:00
softwarefactory-project-zuul[bot]
e7090a6f8a Merge pull request #8757 from hjkatz/patch-6
Add kubernetes_pod_annotations to management-pod.yml.j2

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 19:38:17 +00:00
Harrison Katz
b6b87aea76 Use literal quotation marks for Kubernetes annotations instead of quote filter 2020-12-04 14:34:08 -05:00
softwarefactory-project-zuul[bot]
e6d1810844 Merge pull request #8756 from hjkatz/patch-5
Fix typo for kubernetes_service_account_annotations variable

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 19:33:49 +00:00
Harrison Katz
720e8055f8 Add kubernetes_pod_annotations to management-pod.yml.j2 2020-12-04 14:08:55 -05:00
Harrison Katz
182ff3464e Fix typo for kubernetes_service_account_annotations variable 2020-12-04 14:02:51 -05:00
softwarefactory-project-zuul[bot]
973c9d313e Merge pull request #8751 from hjkatz/patch-4
Separate Kubernetes Ingress TLS spec from backend spec

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 17:03:26 +00:00
softwarefactory-project-zuul[bot]
a89a683eb4 Merge pull request #8733 from balonik/no-preload-data
make preload data optional again

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 15:59:12 +00:00
softwarefactory-project-zuul[bot]
52646362c3 Merge pull request #8747 from hjkatz/patch-3
Add Kubernetes Service support for annotations

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 15:53:39 +00:00
softwarefactory-project-zuul[bot]
8a433f30e4 Merge pull request #8746 from hjkatz/patch-2
Add quotes to kubernetes annotations

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 15:53:35 +00:00
softwarefactory-project-zuul[bot]
496eea9647 Merge pull request #8743 from hjkatz/patch-1
Remove duplicate spec key from Ingress for kubernetes template

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 15:53:30 +00:00
Harrison Katz
6ab3d5301c Separate Kubernetes Ingress TLS spec from backend spec 2020-12-04 10:50:49 -05:00
softwarefactory-project-zuul[bot]
d93d0f00ee Merge pull request #8721 from rooftopcellist/remove_available_instance
Remove redundant available_instances field

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 15:45:29 +00:00
softwarefactory-project-zuul[bot]
4cc947d65d Merge pull request #8722 from jakemcdermott/fix-8695
Handle prompted inventory without value on schedules

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-04 14:33:58 +00:00
Harrison Katz
8b4b54d2c4 Add Kubernetes Service support for annotations 2020-12-03 18:36:02 -05:00
Harrison Katz
701deb2268 Add quotes to kubernetes annotations 2020-12-03 18:28:50 -05:00
Harrison Katz
85adc4a0ab Remove duplicate spec key from Ingress for kubernetes template 2020-12-03 18:18:18 -05:00
softwarefactory-project-zuul[bot]
9fc5579a50 Merge pull request #8737 from nixocio/ui_fix_select_translation
Add string to translation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-03 17:05:36 +00:00
softwarefactory-project-zuul[bot]
7faf9c6267 Merge pull request #8624 from nixocio/ui_issue_8620
Hide instance group for Inventory Details if the data is not available

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-03 13:24:05 +00:00
nixocio
8cb9341d8f Add string to translation
Add string to translation.
2020-12-02 16:42:15 -05:00
softwarefactory-project-zuul[bot]
8e024c234c Merge pull request #8732 from AlanCoding/save_the_hg
Change to manual instead of deleting hg projects

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-02 15:56:37 +00:00
JAKUBIS Peter H50R8VA
a5f676c3e1 make preload data optional again
Signed-off-by: JAKUBIS Peter H50R8VA <peter.jakubis@erstegroup.com>
2020-12-02 16:17:25 +01:00
Alan Rominger
99f3825826 Change to manual instead of deleting hg projects 2020-12-02 09:08:18 -05:00
softwarefactory-project-zuul[bot]
29926ba5d9 Merge pull request #8727 from AlanCoding/mercury_drops
Remove mercurial support

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-01 22:11:42 +00:00
Alan Rominger
db9fbf1493 Add log for the case that hg projects were deleted 2020-12-01 15:53:55 -05:00
Alan Rominger
590d64f40e Remove hg updates and projects in migration 2020-12-01 15:38:40 -05:00
Alan Rominger
64fa18cafe Run the UI prettier tool for CI fix 2020-12-01 14:49:49 -05:00
Alan Rominger
634df240ed Attempt to fix UI test with hg,svn replacement 2020-12-01 14:25:11 -05:00
Alan Rominger
44e6e9344b Remove mercurial support 2020-12-01 14:06:34 -05:00
nixocio
4b5b95a0f8 Hide instance group for Inventory Details if the data is not available
Hide instance group for Inventory Details if the data is not available.
This is the the same approach used in other details screens.

See: https://github.com/ansible/awx/issues/8620
2020-12-01 13:10:24 -05:00
softwarefactory-project-zuul[bot]
f5e1f2ed14 Merge pull request #8710 from wenottingham/herein-lies-the-extent-of-my-radius-knowledge
Remove old radius library from requirements

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-01 18:07:35 +00:00
softwarefactory-project-zuul[bot]
c232289323 Merge pull request #8534 from tapled/update-helm-chart-location
Updated Helm Chart Location

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-01 17:07:46 +00:00
Jake McDermott
db8c56caf4 Handle prompted inventory without value on schedules 2020-12-01 11:53:19 -05:00
Christian M. Adams
8e66172ed4 Remove redundant available_instances field 2020-12-01 11:20:21 -05:00
softwarefactory-project-zuul[bot]
62be4defa2 Merge pull request #8719 from ryanpetrello/tzid-support
correct a note about TZID support

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-01 14:58:28 +00:00
softwarefactory-project-zuul[bot]
cb590be095 Merge pull request #8718 from chrismeyersfsu/fix-inv_migration
add missing imports

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-01 14:49:07 +00:00
Ryan Petrello
72c3339719 correct a note about TZID support 2020-12-01 09:10:03 -05:00
softwarefactory-project-zuul[bot]
7ca35634a7 Merge pull request #8633 from marshmalien/refactor-project-functional
Fix notification list toolbar filter keys and convert Project/* to functional components

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-12-01 13:52:22 +00:00
Chris Meyers
4ab4f2f8f9 add missing imports 2020-12-01 08:40:18 -05:00
Marliana Lara
3e64e8225a Add ouiaIds to Select component 2020-11-30 16:13:35 -05:00
softwarefactory-project-zuul[bot]
b65d9ede81 Merge pull request #8323 from AlanCoding/prepare_your_containers
Refactor to hook in programmatic use of inventory import saving-to-DB code

Reviewed-by: Jim Ladd
             https://github.com/jladdjr
2020-11-30 20:41:58 +00:00
Bill Nottingham
12edbdab11 Remove old radius library from requirements
If it's not required by django-radius, we probably don't need it.
2020-11-30 15:12:52 -05:00
softwarefactory-project-zuul[bot]
fcdb38469b Merge pull request #8700 from jerosa/patch-1
Add Git-LFS to build image

Reviewed-by: Bill Nottingham
             https://github.com/wenottingham
2020-11-30 19:40:06 +00:00
Alan Rominger
900127fde7 Fix bug in inventory update canceling 2020-11-30 14:39:02 -05:00
softwarefactory-project-zuul[bot]
ffb2198eab Merge pull request #8594 from nixocio/ui_issue_8276
Mark organization as a required field for Galaxy crendentials

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-30 18:44:56 +00:00
softwarefactory-project-zuul[bot]
503a753241 Merge pull request #8672 from wenottingham/if-you-are-sneakerneting-does-it-become-a-pedifest
Allow combining multiple subscriptions if they are in a manifest.

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-30 18:30:11 +00:00
Alan Rominger
7734def856 Fix inventory log timestamp, organize logging code
The fixes and issue where the timestaps in the stdout for
inventory updates gave the time since the start of the dispatcher
instead of the time since the start of the update.

This commit also moves the handler into the utils module where
other custom AWX handlers live, instead of tasks.py
this is to keep tasks.py relatively clean, as best as possible
2020-11-30 11:36:16 -05:00
Alan Rominger
d6e84b54c9 Some fixes for line numbering, and fixes for license error handling (#8)
* Change handling of error cases to global post_run_hook
* handle license errors correctly again
* Fix some issues with line ordering from the custom logger thing
* Remove debug log statement
* Use PermissionDenied for license errors
* More elegant handling of line initialization

Update tests to new exception type

Catch all save errors, fix timing offset bug

Fix license error handling inside import command
2020-11-30 11:35:33 -05:00
Alan Rominger
ec93af4ba8 Not all license errors are caught, do not assume they are 2020-11-30 11:35:32 -05:00
Jim Ladd
197d50bc44 patch test_inventory_update_injected_content
* proot now enabled at task-level
  since tasks are no longer calling
  awx-manage (which would set up its own proot)
* dropping proot env var since it's not
  relevant to the test
2020-11-30 11:35:32 -05:00
Jim Ladd
5ad60a3ed4 use inventory_id to get advisory_lock 2020-11-30 11:35:32 -05:00
Jim Ladd
38638b4a6b add note to remove private_dir when proot removed 2020-11-30 11:35:32 -05:00
Jim Ladd
232801e0ba cache end_line for RunInventoryUpdate jobs 2020-11-30 11:35:32 -05:00
Jim Ladd
d55f36eb90 add clarifying comment
* noting that the inv update task only uses the
  inventory update management command to
  save the inv to the database
  (it doesn't do the work of fetching hosts / groups)
2020-11-30 11:35:31 -05:00
Jim Ladd
277c47ba4e add TODO reminders to remove proot / venv code
* won't be needed once we move to container-based
  execution
2020-11-30 11:35:31 -05:00
Jim Ladd
12cbc9756b inventory updates should use custom venv 2020-11-30 11:35:31 -05:00
Jim Ladd
72df8723f6 lint 2020-11-30 11:35:31 -05:00
Jim Ladd
a8710bf2f1 restore proot for inventory updates
- in the past, inv. update jobs called `awx-manage inventory_update`
  which took care of setting up process isolation
- at this point, though, inv. update jobs call runner / ansible-inventory
  directly, so we need another way to put process isolation in place
- thankfully, there was already support for providing process isolation
  for other types of jobs (namely JT Jobs, Project Updates and Ad Hoc
  commands)
- so, we do what those other jobs do and override the stub for should_use_proot
  (which by default returns false) so that it keys off of the
  `AWX_PROOT_ENABLED` setting
2020-11-30 11:35:31 -05:00
Jim Ladd
4bdc488fe7 restore proot code
* add TODOs to note where proot-related code
  can be removed in the future
  (after moving to container-based execution)
2020-11-30 11:35:31 -05:00
Jim Ladd
9633714c49 create lock for perform_update
* perform_update can be called from either awx-manage
  or the RunInventoryUpdate task
* need to make sure that the inventory updates
  that happen with perform_update are atomic
2020-11-30 11:35:31 -05:00
Shane McDonald
66bdcee854 Address rebase fallout 2020-11-30 11:35:31 -05:00
Shane McDonald
e61f79c8c3 Fix tests 2020-11-30 11:35:30 -05:00
Alan Rominger
96fc38d182 Swap in-memory logger to write stdout in post_save_hook
This commit makes the needed changes to inventory update
post_save_hook logic so that the historic log lines that
inventory updates write will be written to stdout,
but this hack bypasses the ansible-runner verbose event
logic and dispatches verbose events directly.

Fix the venv application with the ansible-inventory system
(note: much of this is undone in a later commit)

Deal with some minor test updates for
the ansible-inventory interface changes
2020-11-30 11:32:26 -05:00
Alan Rominger
ae9ae14e5a Migrate inventory CLI options to programatic interface
POC, successfully importing with this commit

Attempt to surface saving related errors as a part of that
2020-11-30 11:31:38 -05:00
Alan Rominger
39fa70c58b Start on refactor to hook in inventory programatic use 2020-11-30 11:28:49 -05:00
nixocio
4f132e302f Mark organization as a required field for Galaxy crendentials
Mark organization as a required field for Galaxy credential type.

See: https://github.com/ansible/awx/issues/8276
2020-11-30 11:27:06 -05:00
softwarefactory-project-zuul[bot]
a45f586599 Merge pull request #8655 from mabashian/8606-adhoc-detail-cred
Display machine credential in job details when present

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-30 14:09:28 +00:00
softwarefactory-project-zuul[bot]
170e64070b Merge pull request #8659 from mabashian/7989-group-action-buttons
Hide edit/delete buttons on group details view for users that don't have permissions

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-30 13:37:35 +00:00
jerosa
7e0d2aabbd Add Git-LFS to build image 2020-11-28 14:13:59 +01:00
softwarefactory-project-zuul[bot]
ff3f5fd529 Merge pull request #8628 from nixocio/ui_issue_7681
Hide sync icon for smart inventory rows in Inventory List

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-27 21:21:30 +00:00
Bill Nottingham
52db0bf0c0 Allow combining multiple subscriptions if they are in a manifest.
The rules:
- subs must be of same SKU type (all MCTxxxx, all SERxxxx, etc)
- when combining, we take the earliest end date
2020-11-25 17:03:12 -05:00
softwarefactory-project-zuul[bot]
1e66a977c7 Merge pull request #8375 from mabashian/workflow-approvals
Adds workflow approval list and details

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-25 21:09:04 +00:00
softwarefactory-project-zuul[bot]
1b233aa8cc Merge pull request #8682 from jakemcdermott/fix-8669
Only display inventory file for scm sources

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-25 17:01:55 +00:00
Jake McDermott
294b9c8910 Only display inventory file for scm sources 2020-11-25 11:02:07 -05:00
softwarefactory-project-zuul[bot]
6f43784c47 Merge pull request #8671 from AlanCoding/weird_fail
Avoid copies made from failed updates

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-25 15:58:51 +00:00
softwarefactory-project-zuul[bot]
9921887ce8 Merge pull request #8679 from AlanCoding/text_soup
Apply more rigor to asserting text in stdout

Reviewed-by: awxbot
             https://github.com/awxbot
2020-11-25 15:49:29 +00:00
Alan Rominger
501cf297df Apply more rigor to asserting text in stdout 2020-11-25 10:04:48 -05:00
Sean Sullivan
318274c70f Merge pull request #22 from ansible/devel
Rebase
2020-11-25 09:36:11 -05:00
softwarefactory-project-zuul[bot]
169f55c908 Merge pull request #8668 from jakemcdermott/zuul-updates-ship-ui-next
Remove *-next make targets

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-24 21:24:19 +00:00
Jake McDermott
c0d8474ac6 Undo staged locale changes after devel build 2020-11-24 15:39:54 -05:00
Alan Rominger
44949b73cf Avoid copies made from failed updates 2020-11-24 15:33:44 -05:00
softwarefactory-project-zuul[bot]
b55c5f7de2 Merge pull request #8612 from fosterseth/fix-8501_delete_workflow_app_temp_500
Allow deletion of workflow approval template

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-24 19:07:10 +00:00
Jake McDermott
ef27ebfed8 Remove *-next make targets 2020-11-24 13:58:19 -05:00
Seth Foster
a66eca82c2 can delete approval node 2020-11-24 12:27:42 -05:00
softwarefactory-project-zuul[bot]
7248e2c6d0 Merge pull request #8607 from ansible/ship-ui-next
Ship the new ui

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-24 16:48:21 +00:00
mabashian
24f3499bd9 Hide edit/delete buttons on group details view for users that don't have permissions 2020-11-23 16:20:24 -05:00
softwarefactory-project-zuul[bot]
a50034be3c Merge pull request #8651 from wenottingham/not-any-more
Clean up some old sourve var settings in unit tests

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-23 20:34:52 +00:00
softwarefactory-project-zuul[bot]
470db2bc91 Merge pull request #8588 from nixocio/ui_async
Update usage of useDeleteItems

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-23 20:27:53 +00:00
Jake McDermott
02021fe2c9 Source variables provided at build time 2020-11-23 15:14:55 -05:00
softwarefactory-project-zuul[bot]
4882ca0481 Merge pull request #8643 from AlexSCorey/8642-InventoryonWFJTForm
Inventory Lookup on WFJT Form should not be required

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-23 18:57:22 +00:00
Jake McDermott
526a4c303f Include awx logos for official installs 2020-11-23 13:52:25 -05:00
softwarefactory-project-zuul[bot]
bb5f494fbd Merge pull request #8626 from nixocio/ui_minor_strings_update
Add minor update to strings

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-23 18:24:21 +00:00
Jake McDermott
c81bc60a33 Source default login logo from static files 2020-11-23 13:22:45 -05:00
Jake McDermott
a28c44e509 Source header logo from static files 2020-11-23 13:22:38 -05:00
Jake McDermott
27219d34eb Remove vestigal django stuff for old ui 2020-11-23 13:22:34 -05:00
Jake McDermott
f49e4a646f Remove legacy make targets 2020-11-23 13:22:30 -05:00
Jake McDermott
b699864f00 remove classic ui 2020-11-23 13:22:25 -05:00
Jake McDermott
abaeec40ae Ship the new ui with awx installation and builds 2020-11-23 13:22:12 -05:00
mabashian
f81f6cf114 Remove fullWidth prop from machine credential detail field as it's not needed 2020-11-23 11:45:59 -05:00
mabashian
81bccc1c7f Display machine credential in job details when present 2020-11-23 11:41:07 -05:00
nixocio
e23b47b997 Add minor update to strings
Add minor update to strings. And adjust the usage of `toTitleCase` to
dynamic strings.
2020-11-23 09:29:20 -05:00
nixocio
faec21ed08 Update usage of useDeleteItems
* Update usage of useDeleteItems.
* Remove async when not necessary
* Update return of promises
2020-11-23 09:15:23 -05:00
softwarefactory-project-zuul[bot]
1deb4ff5e4 Merge pull request #8472 from marshmalien/setting-misc-system-forms
Add setting "system" category forms and tests

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-20 22:49:55 +00:00
Bill Nottingham
13788c4568 Clean up some old sourve var settings in unit tests
Also if you want to use assert, use assert.
2020-11-20 16:32:47 -05:00
softwarefactory-project-zuul[bot]
69b818ff83 Merge pull request #8587 from nixocio/ui_issue_8548
Add updates related to smart inventories

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-20 15:19:48 +00:00
nixocio
a8400e4b7c Add updates related to smart inventories
Add updates related to smart inventories.

* Add popover for `Smart host filter`.
* Add popover for `Instance Groups` on Smart Inventory screen.
* Rename `Host filter` to `Smart host filter` per mockup.
* Add inventory as part of dynamic host filter.

See: https://github.com/ansible/awx/issues/8581
Also: https://github.com/ansible/awx/issues/8548
2020-11-19 17:17:23 -05:00
nixocio
9141e789aa Hide sync icon for smart inventory rows in Inventory List
Hide sync icon for smart inventory rows in Inventory List

See: https://github.com/ansible/awx/issues/7681
2020-11-19 17:12:02 -05:00
Alex Corey
60ccdfa4e6 removes asterisk from wfjt form inventory field 2020-11-19 14:33:55 -05:00
Marliana Lara
0d7f7df043 Update failed project sync error message 2020-11-19 14:32:42 -05:00
softwarefactory-project-zuul[bot]
b6a55e53d5 Merge pull request #8622 from mabashian/nav-expanded
Fix nav console error

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-19 17:39:25 +00:00
Marliana Lara
1a33f7ce1a Fix notification template type search query key 2020-11-18 16:00:02 -05:00
softwarefactory-project-zuul[bot]
f22fa9c5b0 Merge pull request #8617 from AlanCoding/valid_groups
Avoid invalid group characters in default inventory script factory

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-18 20:26:28 +00:00
James Tanner
3e7554974a set a column name so it doesnt end up as "case" 2020-11-18 12:12:29 -05:00
mabashian
d3928a0c0f Get rid of onExpand but keep isExpanded on side nav 2020-11-18 11:34:54 -05:00
James Tanner
153a1ecd39 bump minor 2020-11-18 11:30:48 -05:00
James Tanner
d6f9c5a0b6 get the modified column too 2020-11-18 11:28:22 -05:00
Marliana Lara
2f47bacb4f Convert project/* components into functional components 2020-11-18 10:54:38 -05:00
Alan Rominger
91eff51390 Avoid invalid group characters in default inventory script factory 2020-11-18 10:16:08 -05:00
James Tanner
9cf294f3d7 implement ryanp suggestion 2020-11-18 09:57:22 -05:00
softwarefactory-project-zuul[bot]
691b4512b5 Merge pull request #8615 from jakemcdermott/fix-navbar
Fix the navbar

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-18 00:41:30 +00:00
Jake McDermott
471e22a4e2 Start with nav expanded 2020-11-17 18:54:11 -05:00
James Tanner
a1c2d458de get a csv of playbook_on_stats event data 2020-11-17 17:48:13 -05:00
mabashian
ef1da5d5de Wrap status label in a div so that it doesn't vertically stretch with it's parent. 2020-11-17 17:05:49 -05:00
Marliana Lara
865f348167 Add descriptive helper text when log aggregator toggle is disabled 2020-11-17 11:01:34 -05:00
Marliana Lara
30f5fbb07a Use ouiaId instead of data-cy id in RevertButton 2020-11-17 11:01:34 -05:00
Marliana Lara
d57fee7b63 Do not render setting field if config is empty 2020-11-17 11:01:34 -05:00
Marliana Lara
79930347f9 Fix number input validation bug 2020-11-17 11:01:33 -05:00
Marliana Lara
e0feda780b Add setting system category forms and tests
* Add activity stream, logging, and misc system forms
 * Hookup logging test alert
 * Hookup revert buttons
 * Add useModal helper hook
 * Swap VariablesDetail for CodeDetail within setting detail views
 * Update SettingDetail import path in setting detail views
2020-11-17 11:01:30 -05:00
mabashian
76c39e38c0 Update snapshot after adding cannotDelete prop to ToolbarDeleteButton 2020-11-17 09:18:59 -05:00
mabashian
8cd4d06903 Hide the delete button on workflow approval details when job is pending 2020-11-17 08:42:35 -05:00
mabashian
8c263f17ab Adds data-cy attributes to the fields in the workflow approval details 2020-11-17 08:42:35 -05:00
mabashian
a4e4f0aa98 Show 'Deleted' when the source workflow job is deleted in workflow approvals list/details 2020-11-17 08:42:35 -05:00
mabashian
ebf9bf429c Add description to the list of default search keys on workflow approvals list 2020-11-17 08:42:35 -05:00
mabashian
30e461c18e Fix basic name filtering on workflow approvals list 2020-11-17 08:42:35 -05:00
mabashian
b8b3424c1f Prevent users from attempting to delete pending approvals 2020-11-17 08:42:35 -05:00
mabashian
929be1652a Move all mock workflow approvals out to data.workflowApprovals.json 2020-11-17 08:42:35 -05:00
mabashian
2be5ae3b2d Remove old TODO 2020-11-17 08:42:35 -05:00
mabashian
aba14bfb8c Combine approve/deny modals into one modal 2020-11-17 08:42:35 -05:00
mabashian
a9c3484387 Move approval action buttons from rows to to level list actions. UX updates to the display of the status. 2020-11-17 08:42:35 -05:00
mabashian
ee7f73623f Adds /#/workflow_approvals list and details and allows users to approve or deny workflow approvals from these interfaces 2020-11-17 08:42:35 -05:00
softwarefactory-project-zuul[bot]
b338da40c5 Merge pull request #8482 from jakemcdermott/fix-8465
Fix inconsistent screen title bars

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-16 21:14:25 +00:00
softwarefactory-project-zuul[bot]
00fb955544 Merge pull request #8563 from AlexSCorey/8535-UpgradePF
Updates PF dependency

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-16 18:16:17 +00:00
softwarefactory-project-zuul[bot]
74711a55bb Merge pull request #8552 from DeloitteHux/ng-helm-install
Add helm installation (#8551)

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-16 17:47:31 +00:00
Jake McDermott
d30dd97c96 Fix inconsistent screen title bars 2020-11-16 11:39:04 -05:00
softwarefactory-project-zuul[bot]
10664d1931 Merge pull request #8582 from wenottingham/collect-again
Revert portions of 40a10dcc5f

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-13 22:54:23 +00:00
Bill Nottingham
7b04fa114e Revert portions of 40a10dcc5f
Keep some of the collectors, while removing ones we calculate
in other ways.
2020-11-13 14:50:04 -05:00
softwarefactory-project-zuul[bot]
0d843899e1 Merge pull request #8519 from nixocio/ui_issue_8098
Remove groups/hosts when deleting inventory sources

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-13 18:37:07 +00:00
Alex Corey
54e1991ff4 Update PF Dependency and associated components and tests 2020-11-13 10:11:05 -05:00
Ryan Petrello
adfd8ed26b forcibly close DB and cache socket connection post-fork
we've seen evidence of a race condition on fork for awx.conf.Setting
access; in the past, we've attempted to solve this by explicitly closing
connections pre-fork, but we've seen evidence that this isn't always
good enough

this patch is an attempt to close connections post-fork so that sockets
aren't inherited post fork, leading to bizarre race conditions in
setting access
2020-11-12 15:13:16 -05:00
softwarefactory-project-zuul[bot]
76fd63ba5f Merge pull request #8463 from nixocio/ui_issue_7130
Add feature to associate teams to users

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-12 18:21:25 +00:00
nixocio
07edf505e7 Add feature to associate teams to users
Add feature to associate teams to users. For the time being when
associating Users to a team, the User will be associated with `member_role` only. And when `diassociating` the User from a team all related roles - member, read, and admin will be removed.

Also, fix a bug related to search not being cleared after closing/cancel
the `AssociateModal`.
2020-11-12 10:06:33 -05:00
softwarefactory-project-zuul[bot]
1078bf76ad Merge pull request #8575 from ryanpetrello/yet-more-downstream-bits
more downstream changes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-11 19:27:28 +00:00
softwarefactory-project-zuul[bot]
cb4fcb9d80 Merge pull request #8566 from AlexSCorey/8539-SurveyRequiredFields
Adds asterisk to required survey questions in preview modal

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-11 18:58:30 +00:00
Ryan Petrello
32e149c76e Merge branch 'downstream' into devel 2020-11-11 13:30:28 -05:00
Ryan Petrello
4d8176e6af Merge remote-tracking branch 'downstream' into downstream 2020-11-11 13:30:21 -05:00
Ryan Petrello
ddd109059f Merge pull request #4682 from wenottingham/subs-corner-cases
Use the exported count in the manifest for the node count, if present.
2020-11-11 13:13:01 -05:00
softwarefactory-project-zuul[bot]
4d480cb95f Merge pull request #8413 from sean-m-sullivan/role_list
Tower_role Improvements, Approvals and use of Lists

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-11 17:37:21 +00:00
softwarefactory-project-zuul[bot]
69c3acfb39 Merge pull request #8570 from ryanpetrello/analytics-cleanup
removed unused analytics metrics

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-11-11 17:26:27 +00:00
Bill Nottingham
a092406543 Use the exported count in the manifest for the node count, if present. 2020-11-11 12:20:32 -05:00
Christian Adams
a65008f762 Merge pull request #4680 from ansible/i18n_release_3.8.0_translations
(More) UI translation strings for release_3.8.0 branch
2020-11-11 12:07:35 -05:00
ansible-translation-bot
2a44a72024 UI translation strings for release_3.8.0 branch 2020-11-11 15:42:54 +00:00
Ryan Petrello
40a10dcc5f removed unused analytics metrics 2020-11-11 09:56:20 -05:00
ansible-translation-bot
d25d5762e0 UI translation strings for release_3.8.0 branch 2020-11-11 14:12:48 +00:00
softwarefactory-project-zuul[bot]
073e518c16 Merge pull request #8503 from AlexSCorey/8237-FixKebabifiedToolbarBtns
Fixes toolbar buttons in Advanced Search mode

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-11 13:25:15 +00:00
Ryan Petrello
454c8e66e0 Merge pull request #4678 from beeankha/delete_cloudforms_from_collections
Remove Cloudforms as a credential type from collections
2020-11-10 17:12:16 -05:00
softwarefactory-project-zuul[bot]
cd5553a1dc Merge pull request #8567 from ryanpetrello/busted-cf-migration
avoid breaking upgrades from certain AWX versions

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-10 21:18:13 +00:00
Christian Adams
e4d9cd4000 Merge pull request #4676 from ansible/i18n_release_3.8.0_translations
UI translation strings for release_3.8.0 branch
2020-11-10 16:07:22 -05:00
beeankha
400c55faaa Remove Cloudforms as a credential type from collections 2020-11-10 15:49:55 -05:00
Ryan Petrello
fabd2eec63 avoid breaking upgrades from certain AWX versions
the prior version of this migration was rewritten, so we should
run the function again to really make sure that cleanup happens
2020-11-10 15:18:49 -05:00
Alex Corey
619fabc3a1 adds asterisk to required survey questions in preview modal 2020-11-10 11:47:30 -05:00
sean-m-sullivan
4e4f1d3cce update comment 2020-11-10 10:04:05 -06:00
sean-m-sullivan
e2e3d30b49 update comment 2020-11-10 09:16:08 -06:00
Christian Adams
ff78cade3a Merge pull request #4677 from rooftopcellist/fix_hover_help
Fix hover-over help text for subscriptions
2020-11-10 09:56:08 -05:00
Christian M. Adams
97381f6810 Fix hover-over help text for subscriptions 2020-11-10 09:32:16 -05:00
sean-m-sullivan
999086968c Merge branch 'role_list' of github.com:sean-m-sullivan/awx into role_list 2020-11-10 08:17:09 -06:00
sean-m-sullivan
ab4abf4e3b update comment 2020-11-10 08:17:01 -06:00
Sean Sullivan
0fd0f0c1bd Merge pull request #21 from ansible/devel
Rebase
2020-11-10 08:13:52 -06:00
softwarefactory-project-zuul[bot]
d16055806b Merge pull request #8520 from AlexSCorey/7636-WFJTSurveyNotEnabled
Toggles WFJT survey on and off

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-10 12:25:57 +00:00
ansible-translation-bot
e09ac530d5 UI translation strings for release_3.8.0 branch 2020-11-09 16:27:11 +00:00
ansible-translation-bot
1923926422 UI translation strings for release_3.8.0 branch 2020-11-09 15:09:59 +00:00
softwarefactory-project-zuul[bot]
7d3bf36227 Merge pull request #8559 from ryanpetrello/yet-anooooooother-downstream-merge
Merge in some downstream bug fixes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-06 19:29:18 +00:00
Ryan Petrello
d653c05da8 Merge branch 'downstream' into devel 2020-11-06 13:22:26 -05:00
softwarefactory-project-zuul[bot]
862a6835fe Merge pull request #8545 from nixocio/ui_issue_4968
Mark `Host Config Key` as a required field

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-06 17:23:16 +00:00
Ryan Petrello
33f3ad17cb Merge pull request #4671 from ryanpetrello/cloudforms-minus-minus
entirely remove CloudForms inventory sources instead of converting
2020-11-06 11:30:23 -05:00
Ryan Petrello
52d9fbce73 update cloudforms-specific tests 2020-11-06 10:39:14 -05:00
softwarefactory-project-zuul[bot]
0933a94ae7 Merge pull request #8528 from AlexSCorey/7673-AddOrgToInventoryList
Adds Organization to Inventory List item

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-06 14:09:58 +00:00
Ryan Petrello
0b701b3b24 entirely remove CloudForms inventory sources instead of converting 2020-11-06 01:02:55 -05:00
Nicolas G
b4a45e4cf4 Add helm installation (#8551)
Update to address https://github.com/ansible/awx/issues/8551
Install `helm` binaries along with `kubectl`
2020-11-05 17:49:04 -05:00
softwarefactory-project-zuul[bot]
0567a2a3bf Merge pull request #8540 from marshmalien/8461-notification-detail-link
Fix notification list to notification list item detail link

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-05 22:23:47 +00:00
Alex Corey
e372f4f8f6 Adds list item label 2020-11-05 16:54:48 -05:00
softwarefactory-project-zuul[bot]
dccddfffe6 Merge pull request #8483 from AlexSCorey/8261-AddRelatedGroups
Supports Associating Related Inventory Group

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-05 21:08:21 +00:00
softwarefactory-project-zuul[bot]
948e4c13d2 Merge pull request #8549 from jakemcdermott/remove-cf-form
Delete cloudforms

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-05 19:43:49 +00:00
softwarefactory-project-zuul[bot]
13f2b3f632 Merge pull request #8531 from AlexSCorey/8196-PrivilegeEscalation
Fixes broken select

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-05 19:06:15 +00:00
Alex Corey
944c32da24 resolve cyclical group association 2020-11-05 13:41:43 -05:00
Ryan Petrello
b8f1fa1a13 Merge pull request #4666 from ryanpetrello/dont-test-me
update a janky old test
2020-11-05 13:36:24 -05:00
Jake McDermott
10ab12c99a Delete cloudforms 2020-11-05 12:40:03 -05:00
Ryan Petrello
662ee6fa36 update a janky old test
UJT list views don't work this way anymore after
a929e82060
2020-11-05 12:29:06 -05:00
Alex Corey
314fdd6066 add identifier 2020-11-05 11:44:33 -05:00
softwarefactory-project-zuul[bot]
94352c9a72 Merge pull request #8446 from nixocio/ui_issue_4950
Hide max hosts field on org form

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-05 16:03:07 +00:00
nixocio
4268f1aeeb Mark Host Config Key as a required field
Mark `Host Config Key` as a required field

See:https://github.com/ansible/awx/issues/4968
2020-11-05 09:52:33 -05:00
softwarefactory-project-zuul[bot]
31c85dd89f Merge pull request #8510 from keithjgrant/7952-host-filter-lookup-fix
Host filter lookup fix

Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
             https://github.com/tiagodread
2020-11-05 13:38:11 +00:00
Ryan Petrello
e9f1f8c6fe Merge pull request #4670 from wenottingham/pendoh-no
Put everyone in the 'anonymous' pendo bucket regardless of setting
2020-11-05 08:36:13 -05:00
Keith Grant
8d87d9e6e7 mark Clear filters button for translation 2020-11-04 15:36:40 -08:00
nixocio
d324baf1b0 Hide max hosts field on org form
Hide max hosts field on org form.

Also, simplify the usage of context API to read the value of me
parameter.

Hide max hosts field on org form.

See: https://github.com/ansible/awx/issues/4950
2020-11-04 17:23:22 -05:00
Marliana Lara
52c8033a08 Fix notification list item detail pathname link 2020-11-04 15:31:00 -05:00
Bill Nottingham
28a70ced56 Put everyone in the 'anonymous' pendo bucket regardless of setting
We no longer have the key detailed accounts are indexed on.
2020-11-04 15:18:12 -05:00
softwarefactory-project-zuul[bot]
bf6064db21 Merge pull request #8508 from marshmalien/8493-enable-all-inv-src-vars
Add Source Vars to all inventory source types

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-04 18:48:09 +00:00
Ryan Petrello
e406e4298b Merge pull request #4660 from beeankha/fix_import_export_failures
Change import/export Collections Module to Detect Errors vs Warnings
2020-11-04 09:59:25 -05:00
Johannes Gross
591a3e7a60 Updated Helm Chart Location
Signed-off-by: Johannes Gross <jgross@bright-skies.de>
2020-11-04 13:16:05 +01:00
softwarefactory-project-zuul[bot]
370440f63d Merge pull request #8526 from mabashian/convert-WorkflowJobTemplatejsx-functional
Convert WorkflowJobTemplate.jsx to functional component

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-04 01:14:45 +00:00
Marliana Lara
330625b565 Enable source vars for all inventory types 2020-11-03 17:55:00 -05:00
nixocio
5de34a9c0b Remove groups/hosts when deleting inventory sources
Remove related resources groups/hosts when deleting inventory sources.

The current UI deletes `groups` and `hosts` once the inventory source is
deleted. Add this behavior to the new UI.

See: https://github.com/ansible/awx/issues/8098
2020-11-03 16:51:37 -05:00
Ryan Petrello
35eda3a9a7 Merge pull request #4664 from ryanpetrello/pin-collections-requirements
pin known working collections in 3.8.0
2020-11-03 15:23:29 -05:00
Ryan Petrello
ac4b38bc30 Merge remote-tracking branch 'downstream/release_3.8.0' into devel 2020-11-03 15:11:50 -05:00
mabashian
3052e2077d Import WorkflowJobTemplateEdit from the correct place 2020-11-03 14:29:11 -05:00
Ryan Petrello
439302b38e pin known working collections in 3.8.0 2020-11-03 14:26:31 -05:00
Alex Corey
22029b9d7c fixes broken select 2020-11-03 14:09:13 -05:00
softwarefactory-project-zuul[bot]
114bcd0349 Merge pull request #8487 from epfl-si/feature/I-want-my-own-metadata
[feature] Keep pod_spec_override-provided pod labels

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-11-03 17:38:57 +00:00
softwarefactory-project-zuul[bot]
6f8725c680 Merge pull request #8529 from ryanpetrello/old-pending-notifications
allow deleting NotificationTemplates w/ old pending notifications

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-03 16:37:38 +00:00
Ryan Petrello
4a75ae9869 allow deleting NotificationTemplates w/ old pending notifications
see: https://github.com/ansible/awx/issues/8525
2020-11-03 11:09:30 -05:00
Alex Corey
68b399fdef Adds Organization to Inventory List item 2020-11-03 10:49:53 -05:00
mabashian
514cba6467 Convert WorkflowJobTemplate to functional component 2020-11-03 10:14:30 -05:00
beeankha
7dfa957619 Change import/export logging detection to detect errors vs warnings 2020-11-02 16:24:51 -05:00
Chris Meyers
cd9838d579 Merge pull request #4661 from ansible/fix-flake8_3.8.0
fix flake8
2020-11-02 15:48:07 -05:00
Chris Meyers
d8ca3ba894 fix flake8 2020-11-02 15:45:16 -05:00
Alex Corey
8ff2c5b576 Supports Associating Related Inventory Group
This also adds support for creating a new inventory group and
associating it at the same time.
2020-11-02 14:59:54 -05:00
Keith Grant
8df6dc0ca0 fix SmartInventoryForm chips 2020-11-02 11:24:01 -08:00
Alex Corey
a1fa21d5a9 toggles WFJT survey on and off 2020-11-02 14:23:04 -05:00
softwarefactory-project-zuul[bot]
df54a1edb5 Merge pull request #8516 from wenottingham/no-version-file
Don't write a tower_version file in awx

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-02 18:52:22 +00:00
Jake McDermott
cc89608d2c Merge pull request #4659 from jakemcdermott/fix-4658
Disable edit mode cred form unless edit capability is true
2020-11-02 13:26:05 -05:00
Jake McDermott
da7896dbc4 Disable edit mode cred form unless edit capability is true 2020-11-02 13:20:44 -05:00
Bill Nottingham
7a9eff7e65 Don't write a tower_version file in awx 2020-11-02 12:54:51 -05:00
softwarefactory-project-zuul[bot]
48ecd2400c Merge pull request #8491 from nixocio/ui_issue_8467
Remove activity from inventory details page

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-02 15:39:54 +00:00
nixocio
78ce54bc4a Remove activity from inventory details page
Remove activity from inventory details page

This information is already present on the `Complete jobs` tab.

See: https://github.com/ansible/awx/issues/8467
2020-11-02 10:09:09 -05:00
softwarefactory-project-zuul[bot]
1a4f2f43b7 Merge pull request #8492 from nixocio/ui_issue_7706
Remove Type from ScheduleList Sort

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-11-02 14:54:20 +00:00
Alex Corey
15ad6a0180 Fixes toolbar buttons in Advanced Search mode 2020-11-02 09:54:15 -05:00
nixocio
7cb3cf4e37 Remove Type from ScheduleList Sort
Remove Type from ScheduleList Sort, and make `name` as default sort.

See: https://github.com/ansible/awx/issues/7706
2020-11-02 09:18:41 -05:00
Keith Grant
c58c7e285c use Promise.all to make requests in parallel 2020-10-30 14:48:02 -07:00
Keith Grant
adc68b672d add advanced search keys to host filter lookup 2020-10-30 14:45:05 -07:00
softwarefactory-project-zuul[bot]
17b5b531bf Merge pull request #8506 from ryanpetrello/yet-another-downstream-merge
merge in some downstream changes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-30 21:15:20 +00:00
softwarefactory-project-zuul[bot]
52ffcc9f7c Merge pull request #8496 from jainnikhil30/fix_tower_inventory_empty__child_group
Add empty child group to inventory groups before adding it to the parent group

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-30 21:02:11 +00:00
Ryan Petrello
3ce9a778f8 fix busted webhook notifications
whoops, I broke it
2020-10-30 16:40:02 -04:00
Christian M. Adams
3e9a98170e Update tool tip for RH username & password settings 2020-10-30 16:40:02 -04:00
Jake McDermott
5ce9e5b03d Use SUBSCRIPTION_* variables in config route 2020-10-30 16:40:02 -04:00
Ryan Petrello
94b6b31185 fix a minor bug in the way we report certain license upload errors 2020-10-30 16:40:02 -04:00
Christian M. Adams
b031e1f05e Properly record the license type when sub is a trial 2020-10-30 16:40:02 -04:00
Elyézer Rezende
aae0b29008 Separate page object for config/attach endpoint 2020-10-30 16:40:02 -04:00
Christian M. Adams
422c7308fd Update compliance wording in UI on license page 2020-10-30 16:40:01 -04:00
Ryan Petrello
23f1cea29b correct manifest argument spec for the tower_license module 2020-10-30 16:40:01 -04:00
Christian M. Adams
633dc60d49 Simplify link to fit UI column 2020-10-30 16:40:01 -04:00
Bill Nottingham
b9960abea6 Add a help popover that points to the docs 2020-10-30 16:40:01 -04:00
Bill Nottingham
2388758f8a Update the license wording and UX 2020-10-30 16:40:01 -04:00
Christian M. Adams
b05c34a969 Valid key always set correctly, compliant field set correctly 2020-10-30 16:40:01 -04:00
Christian M. Adams
bfca3d9910 Update get subscriptions button name in UI 2020-10-30 16:40:01 -04:00
Ryan Petrello
f9511ed7da fix a typo in the tower_license module documentation 2020-10-30 16:40:01 -04:00
mabashian
2e93d9f022 Fix failing license test after rhCreds was changed to subscriptionCreds 2020-10-30 16:40:00 -04:00
Ryan Petrello
478111e7df cut down on queries necessary to generate the X-API-Product-Name header 2020-10-30 16:40:00 -04:00
Christian M. Adams
dd459e23e2 Add migration to prefill rh username and password for subscriptions 2020-10-30 16:40:00 -04:00
Ryan Petrello
e50c2c2867 warn about legacy license usage in the licensing UI 2020-10-30 16:40:00 -04:00
Ryan Petrello
7f9784c443 clarify that the manifest file is a .zip file 2020-10-30 16:40:00 -04:00
Ryan Petrello
1294efdeb9 consolidate a few license code function calls 2020-10-30 16:40:00 -04:00
Christian M. Adams
be4e4ff47c Clean up unnecessary comments 2020-10-30 16:40:00 -04:00
Bill Nottingham
309396f199 flake8 2020-10-30 16:39:59 -04:00
Bill Nottingham
393e1b75e9 Return more user-friendly errors for assorted manifest failures 2020-10-30 16:39:59 -04:00
Ryan Petrello
c139a998b8 simplify how awx "open" licensing works 2020-10-30 16:39:59 -04:00
Ryan Petrello
e591f1f002 update the tower_license module to properly upload manifests 2020-10-30 16:39:59 -04:00
Christian M. Adams
67000f0ce9 Remove license_key check & fix docker-compose make command 2020-10-30 16:39:59 -04:00
Ryan Petrello
0ddf47740c fix incorrect detection of license on inventory updates 2020-10-30 16:39:59 -04:00
Christian M. Adams
05de875ace Fix flake8 2020-10-30 16:39:59 -04:00
Christian M. Adams
d8b7791375 Revert subman install and setfacl 2020-10-30 16:39:59 -04:00
Christian M. Adams
b609e4ee84 remove outdated license references 2020-10-30 16:39:58 -04:00
Christian M. Adams
0a23bb6e36 Install subman and set ACL for rhsm.conf for dev 2020-10-30 16:39:58 -04:00
Ryan Petrello
74c7883b3b cleanup more old licensing cruft 2020-10-30 16:39:58 -04:00
Ryan Petrello
0a36959ef1 clarify some Sat6 verbiage in the license screen 2020-10-30 16:39:58 -04:00
Ryan Petrello
2ae429b4ac remove unnneeded licenses 2020-10-30 16:39:58 -04:00
Ryan Petrello
13f2e90a82 change rhsm candlepin crt location 2020-10-30 16:39:58 -04:00
Ryan Petrello
74ad1f36ac remove some entitlements config we no longer need 2020-10-30 16:39:58 -04:00
Christian M. Adams
cb86193459 Fallback to RH Candlepin Verify setting for OCP 2020-10-30 16:39:57 -04:00
Ryan Petrello
86d0ee590f clarify messaging and behavior when subscription-manager isn't installed 2020-10-30 16:39:57 -04:00
Christian M. Adams
10242cd6c4 Add error handling for missing rhsm.conf 2020-10-30 16:39:57 -04:00
Ryan Petrello
3bb930c769 cleanup up some unused code/comments, and simplify the license migration 2020-10-30 16:39:57 -04:00
Ryan Petrello
ef43d85271 remove Organization label from RHSM/Sat6 license form 2020-10-30 16:39:57 -04:00
Ryan Petrello
927b055e65 change license uploading to parse RHSM manifests
Co-authored-by: Christian Adams <chadams@redhat.com>
2020-10-30 16:39:57 -04:00
Ryan Petrello
4445d096f5 reimplement licensing to work with RHSM and entitlement uploads
Co-authored-by: Christian Adams <chadams@redhat.com>
2020-10-30 16:39:57 -04:00
Bill Nottingham
48934e8544 Enable source vars for all inventory types
Update plugin popover to point to the plugin docs.
2020-10-30 16:39:57 -04:00
Jeff Bradberry
cb570a2ba1 Fix the 'absent' state in tower_instance_group 2020-10-30 16:39:56 -04:00
Jeff Bradberry
607bc07887 Rework the export of full dependent objects
and include hosts and groups in the export.
2020-10-30 16:39:56 -04:00
Ryan Petrello
df874966a6 fix a display bug in webhook notifications with unicode characters
see: https://github.com/ansible/awx/issues/7400
2020-10-30 16:39:56 -04:00
Caleb Boylan
b5c2a6ad65 fix lookup plugin fqcn issue 2020-10-30 16:39:54 -04:00
softwarefactory-project-zuul[bot]
e38d082394 Merge pull request #8509 from ryanpetrello/daylight-wastings-time
Abolish Daylight Savings Time

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-30 20:39:31 +00:00
Ryan Petrello
b9bce03f71 fix a test related to proximity to the DST boundary
technically speaking, this test could still fail on the Saturday before
DST boundaries

...but I don't care
2020-10-30 16:10:07 -04:00
Ryan Petrello
024d148b7f Merge pull request #4648 from rebeccahhh/non_admin_jt_copy
Allow user to copy job templates as permissions intended
2020-10-30 15:46:58 -04:00
Ryan Petrello
8775afc5ea Merge pull request #4656 from ryanpetrello/ryan-broke-webhooks
fix busted webhook notifications
2020-10-30 13:09:46 -04:00
Ryan Petrello
2f738415b8 fix busted webhook notifications
whoops, I broke it
2020-10-30 13:05:37 -04:00
Ryan Petrello
57cd474beb Merge pull request #4634 from ryanpetrello/licensing-rhsm-changes-380
reimplement licensing to work with RHSM and entitlement uploads
2020-10-30 13:03:08 -04:00
softwarefactory-project-zuul[bot]
9b00421ec3 Merge pull request #8468 from nixocio/ui_issue_8453
Fix username as a required field

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-30 15:27:13 +00:00
Nikhil Jain
23a852bdab add the empty child group to groups before adding it to the parent group 2020-10-30 14:23:57 +05:30
softwarefactory-project-zuul[bot]
52d178bbe4 Merge pull request #8489 from sean-m-sullivan/workflow_node_logic
Update Logic for workflow node creation/deletion

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-29 18:36:40 +00:00
sean-m-sullivan
5703aa8af5 pep8 fixing 2020-10-29 11:50:29 -05:00
Christian M. Adams
a4e76db672 Update tool tip for RH username & password settings 2020-10-29 12:15:24 -04:00
Jake McDermott
31275122a1 Merge pull request #4653 from wenottingham/taking-inventory-of-ourselves
Enable source vars for all inventory types
2020-10-29 11:06:39 -04:00
sean-m-sullivan
beb329c31e update logic for node creation 2020-10-29 09:52:13 -05:00
Dominique Quatravaux
deb56bf4f8 [fix] Now with doctest that actually passes 2020-10-29 14:03:19 +01:00
Dominique Quatravaux
87b97530ff [fix] flake8 2020-10-29 13:35:24 +01:00
Dominique Quatravaux
3335ea953e [feature] Keep pod_spec_override-provided pod labels
- Write a deepmerge() implementation, keeping only the test suite of
https://stackoverflow.com/a/20666342/435004

- Use it to deep-merge pod['metadata'] with user input,
instead of replacing fields in it
2020-10-29 13:35:24 +01:00
Bill Nottingham
0fbc02864e Enable source vars for all inventory types
Update plugin popover to point to the plugin docs.
2020-10-28 19:58:14 -04:00
Jake McDermott
94eec401c3 Use SUBSCRIPTION_* variables in config route 2020-10-28 19:03:38 -04:00
Keith Grant
fa07889f39 switch host filter lookup to use icontains searches for name/group 2020-10-28 15:41:03 -07:00
softwarefactory-project-zuul[bot]
82a42d1db7 Merge pull request #8476 from jlmitch5/fixSearchLabelBug
fix issue where adding a search tag could cause an error

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-28 21:05:53 +00:00
softwarefactory-project-zuul[bot]
a672022a6a Merge pull request #8479 from jlmitch5/fixUserDetailLink
fix malformed user details link in toolbar

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-28 18:44:52 +00:00
Ryan Petrello
a75874a5d0 Merge pull request #4650 from jbradberry/tower-instance-group-absent
Fix a typo in checking the 'absent' state for the tower_instance_group module
2020-10-28 14:38:01 -04:00
Jeff Bradberry
ff7fe2acdf Fix the 'absent' state in tower_instance_group 2020-10-28 14:27:03 -04:00
Ryan Petrello
98d2e1a898 Merge pull request #4622 from jbradberry/import-export-groups-hosts
Rework the export of full dependent objects
2020-10-28 13:55:12 -04:00
John Mitchell
9517bf01ce fix malformed user details link in toolbar 2020-10-28 13:52:59 -04:00
Jeff Bradberry
b8b1e3d760 Rework the export of full dependent objects
and include hosts and groups in the export.
2020-10-28 13:43:14 -04:00
Ryan Petrello
e5c0889361 Merge pull request #4649 from ryanpetrello/webhook-unicode-bug
fix a display bug in webhook notifications with unicode characters
2020-10-28 13:08:15 -04:00
Ryan Petrello
41d3b164ea fix a display bug in webhook notifications with unicode characters
see: https://github.com/ansible/awx/issues/7400
2020-10-28 13:03:34 -04:00
John Mitchell
3a512f39ae fix issue where adding a search tag could cause an error 2020-10-28 11:36:05 -04:00
nixocio
40e821d0d8 Fix username as a required field
Fix username as a required field. `UserForm` is used for adding and
editing an user. When adding an user, the initial user value is a `{}`
update logic to cover this case.

Also, add unit-tests to cover this particular case.

See: https://github.com/ansible/awx/issues/8453
2020-10-28 10:11:38 -04:00
Ryan Petrello
ee06df97a4 fix a minor bug in the way we report certain license upload errors 2020-10-28 09:58:39 -04:00
softwarefactory-project-zuul[bot]
0d3c9ebc2b Merge pull request #8471 from ryanpetrello/whoops-scm
fix a minor bug introduced in Project save validation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-27 20:13:53 +00:00
Christian M. Adams
6d412fd8e7 Properly record the license type when sub is a trial 2020-10-27 16:05:43 -04:00
Ryan Petrello
e0af178968 fix a minor bug introduced in Project save validation 2020-10-27 15:42:36 -04:00
softwarefactory-project-zuul[bot]
720d705df3 Merge pull request #8466 from jlmitch5/dashboardInvSyncFailureFix
update inventory sync failure count to look at correct data

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-27 19:31:01 +00:00
softwarefactory-project-zuul[bot]
e35b0d1441 Merge pull request #8430 from AlexSCorey/8361-MergeAddDropDown
Merges 2 tool bar add buttons that use dropdowns

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-27 19:22:28 +00:00
Elyézer Rezende
ddcbb1f9c2 Separate page object for config/attach endpoint 2020-10-27 15:13:13 -04:00
Alex Corey
2e90cd8d31 fixes failing tests and template list dropdown 2020-10-27 14:54:47 -04:00
Alex Corey
a2ca2729ba Merges 2 tool bar add buttons that use dropdowns 2020-10-27 14:37:23 -04:00
softwarefactory-project-zuul[bot]
51600986c9 Merge pull request #8462 from jakegatsby/devel
cast create_preload_data to boolean with `create_preload_data | bool` in launch_awx_task.sh.j2

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-10-27 15:32:21 +00:00
Christian M. Adams
0a839430e7 Update compliance wording in UI on license page 2020-10-27 10:51:11 -04:00
John Mitchell
abaefd0319 update inventory sync failure count to look at correct data 2020-10-27 10:44:00 -04:00
softwarefactory-project-zuul[bot]
5a67aa7fff Merge pull request #8447 from thedoubl3j/local_path_mod
related #7665 added 400 if user attempts an edit to local_path in a SCM project

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-27 13:30:28 +00:00
Ryan Petrello
22e68fe973 correct manifest argument spec for the tower_license module 2020-10-27 09:09:39 -04:00
softwarefactory-project-zuul[bot]
4db5447db8 Merge pull request #8394 from chrismeyersfsu/enhancement-profiling_code
centralize reusable profiling code

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-27 12:57:02 +00:00
Chris Meyers
eb47c8dbc6 centralize reusable profiling code 2020-10-27 08:21:41 -04:00
Jake Jackson
abd0eb53bf fix tests 2020-10-27 00:39:51 -04:00
Jake Jackson
dbc4b677f6 related #7665 added 400 if user attempts an edit to local_path in a SCM project and test case 2020-10-26 22:47:37 -04:00
Christian M. Adams
f83e4cf092 Simplify link to fit UI column 2020-10-26 22:17:20 -04:00
Bill Nottingham
bb38940638 Add a help popover that points to the docs 2020-10-26 20:04:18 -04:00
Bill Nottingham
a72a688506 Update the license wording and UX 2020-10-26 18:35:16 -04:00
Christian M. Adams
1f5df7e39c Valid key always set correctly, compliant field set correctly 2020-10-26 16:25:25 -04:00
odroid
8a325d40e4 create_preload_data | bool in launch_awx_task.sh.j2 2020-10-26 15:22:29 -04:00
Caleb Boylan
581a0b67f0 Merge pull request #4645 from squidboylan/fix_collections_tests
fix lookup plugin fqcn issue
2020-10-26 11:37:31 -07:00
softwarefactory-project-zuul[bot]
a71261d5fd Merge pull request #8419 from keithjgrant/8331-number-survey-fields
Fix integer/float errors in survey

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-26 18:14:44 +00:00
Caleb Boylan
98f572a50e fix lookup plugin fqcn issue 2020-10-26 10:02:11 -07:00
Christian M. Adams
44633c2ba7 Update get subscriptions button name in UI 2020-10-26 12:16:53 -04:00
softwarefactory-project-zuul[bot]
53dede734f Merge pull request #8345 from donald-picard-kr/update-tower-job-wait-for-workflow
add support for wait of project_updates jobs, inventory_update, and w…

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-26 15:47:27 +00:00
softwarefactory-project-zuul[bot]
95a4cc7b76 Merge pull request #8457 from ryanpetrello/downstream-sync
merge in some downstream bug fixes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-26 14:46:23 +00:00
softwarefactory-project-zuul[bot]
db3e79e240 Merge pull request #8449 from lennart/local_docker_labels
allow labelling docker web container

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-26 14:30:31 +00:00
Ryan Petrello
b7f1393c33 fix a typo in the tower_license module documentation 2020-10-26 10:18:58 -04:00
mabashian
3c1cc7fcef Fix failing license test after rhCreds was changed to subscriptionCreds 2020-10-26 10:14:16 -04:00
Ryan Petrello
6097066cd8 Merge branch 'downstream' into devel 2020-10-26 09:32:00 -04:00
Ryan Petrello
048e35850a cut down on queries necessary to generate the X-API-Product-Name header 2020-10-26 09:19:46 -04:00
Chris Meyers
d2ceb39d73 Merge pull request #4616 from chrismeyersfsu/fix-same_jt_abuse
Fix same jt abuse
2020-10-26 09:13:08 -04:00
Lennart Melzer
2991ddfc52 allow labelling docker web container 2020-10-25 14:34:48 +01:00
Keith Grant
a8bb3519c5 fix multiselect survey question on launch 2020-10-23 14:37:32 -07:00
Christian M. Adams
98b2ac77c8 Add migration to prefill rh username and password for subscriptions 2020-10-23 17:01:14 -04:00
softwarefactory-project-zuul[bot]
d550487bc8 Merge pull request #8433 from Malizor/devel
Expose the SCM Branch name in the playbook environment

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-23 17:40:07 +00:00
Ryan Petrello
942d7ccfc6 warn about legacy license usage in the licensing UI 2020-10-23 11:42:35 -04:00
softwarefactory-project-zuul[bot]
02fa85206f Merge pull request #8441 from nixocio/ui_issue_7595
Rename users and access tabs

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-23 15:39:49 +00:00
Ryan Petrello
b36afa3c3e clarify that the manifest file is a .zip file 2020-10-23 11:08:50 -04:00
Ryan Petrello
3fe9d1c096 consolidate a few license code function calls 2020-10-23 11:05:08 -04:00
Christian M. Adams
8a9f75c291 Clean up unnecessary comments 2020-10-23 11:00:08 -04:00
Bill Nottingham
bfb8e384a8 flake8 2020-10-23 10:58:29 -04:00
Bill Nottingham
9bc17db45d Return more user-friendly errors for assorted manifest failures 2020-10-23 10:57:43 -04:00
Ryan Petrello
7c63a6592e simplify how awx "open" licensing works 2020-10-23 10:56:19 -04:00
Ryan Petrello
1f0b1923d7 update the tower_license module to properly upload manifests 2020-10-23 10:30:51 -04:00
Chris Meyers
6e8996f59f Merge pull request #4626 from chrismeyersfsu/enhancement-graph_jobs_3_8_0
terminal graph of job status changes
2020-10-23 10:22:04 -04:00
Chris Meyers
79d7c6d9b3 make optimization code work with container groups
* Task manager fit_ optimization code caused problems with container
group code.
* Note that we don't actually get the benefit of the optimization for
container groups. We just make it so that the code doesn't blow up. It
will take another pass to apply optimizations to the container group
task manager path.
2020-10-23 10:17:30 -04:00
Chris Meyers
ce052922c6 terminal graph of job status changes
* Visualize how jobs go from pending, waiting, running over time
2020-10-23 10:15:32 -04:00
softwarefactory-project-zuul[bot]
20e2472329 Merge pull request #8442 from beeankha/revert_to_satellite6
Revert "Kind" Choice from 'satellite' to 'satellite6'

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-23 13:54:11 +00:00
beeankha
26ebf47c71 Revert choice from 'satellite' to 'satellite6' 2020-10-22 18:03:09 -04:00
softwarefactory-project-zuul[bot]
f54116afbb Merge pull request #8431 from wenottingham/pg-ate-ten
Move to rhel8 PG10 container for persistent PG

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-22 21:38:51 +00:00
Bill Nottingham
f1d2d79f00 Move to rhel8 PG10 container for persistent PG
Merge in updated liveness checks from upstream template
2020-10-22 17:08:16 -04:00
Christian M. Adams
25ace77048 Remove license_key check & fix docker-compose make command 2020-10-22 16:49:13 -04:00
Ryan Petrello
91f72672a1 fix incorrect detection of license on inventory updates 2020-10-22 16:07:28 -04:00
Christian M. Adams
44e9ba1117 Fix flake8 2020-10-22 15:47:54 -04:00
Christian M. Adams
a5b644c23c Revert subman install and setfacl 2020-10-22 15:40:05 -04:00
softwarefactory-project-zuul[bot]
3ff1d77c03 Merge pull request #8438 from beeankha/add_cred_kind_options
Update Doc String for tower_credential Module "Kind" Choices

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-22 19:09:16 +00:00
Christian M. Adams
784c924d88 remove outdated license references 2020-10-22 14:59:48 -04:00
softwarefactory-project-zuul[bot]
466dff96e9 Merge pull request #8402 from jlmitch5/dashboardAug20
add ui_next dashboard

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-22 18:45:11 +00:00
Christian M. Adams
fbde4797f8 Install subman and set ACL for rhsm.conf for dev 2020-10-22 14:39:31 -04:00
Ryan Petrello
2df924ae78 cleanup more old licensing cruft 2020-10-22 14:37:26 -04:00
Ryan Petrello
be5ff0a088 clarify some Sat6 verbiage in the license screen 2020-10-22 14:32:03 -04:00
Ryan Petrello
d8514851bf remove unnneeded licenses 2020-10-22 14:29:34 -04:00
Ryan Petrello
849079316a change rhsm candlepin crt location 2020-10-22 14:08:19 -04:00
Ryan Petrello
f266325fb0 remove some entitlements config we no longer need 2020-10-22 13:46:36 -04:00
nixocio
dcc3422484 Rename users and access tabs
Rename users and access tabs

See: https://github.com/ansible/awx/issues/7595
2020-10-22 13:42:41 -04:00
Christian M. Adams
f812d2e318 Fallback to RH Candlepin Verify setting for OCP 2020-10-22 13:33:41 -04:00
Ryan Petrello
0c63e6a624 clarify messaging and behavior when subscription-manager isn't installed 2020-10-22 13:20:55 -04:00
softwarefactory-project-zuul[bot]
a532421eef Merge pull request #8436 from jbradberry/profile-sql-message
Improve handling of 0 and negative thresholds in the profile_sql command

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-22 17:04:40 +00:00
Christian M. Adams
23f365786c Add error handling for missing rhsm.conf 2020-10-22 12:29:29 -04:00
softwarefactory-project-zuul[bot]
8206874158 Merge pull request #8434 from nicolas-g/patch-1
Add support for Kubernetes Pod annotations

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-22 16:07:09 +00:00
Chris Meyers
7baf681b55 Merge pull request #4623 from chrismeyersfsu/enhancement-db_application_name_3_8_0
fill in postgres application_name on connection
2020-10-22 12:04:41 -04:00
Ryan Petrello
fcf56b4ba6 cleanup up some unused code/comments, and simplify the license migration 2020-10-22 11:56:47 -04:00
Ryan Petrello
afc028147a remove Organization label from RHSM/Sat6 license form 2020-10-22 11:56:47 -04:00
Ryan Petrello
a7c7ac714f change license uploading to parse RHSM manifests
Co-authored-by: Christian Adams <chadams@redhat.com>
2020-10-22 11:56:41 -04:00
beeankha
4b625f0f13 Update credential 'kind' choices 🔑 2020-10-22 11:54:42 -04:00
Jeff Bradberry
d6e39376c8 Improve handling of 0 and negative thresholds in the profile_sql command
- output a profiling disabled message when appropriate
- specify that we are doing SQL profiling in the enabled case
- treat negative thresholds the same as zero, disabling profiling
2020-10-22 11:27:21 -04:00
Ryan Petrello
ffab48c77f reimplement licensing to work with RHSM and entitlement uploads
Co-authored-by: Christian Adams <chadams@redhat.com>
2020-10-22 11:10:28 -04:00
Donald Picard
8f66cfa2c0 related #8344 add support for wait of project_updates jobs, inventory_update, and workflow_job.
Signed-off-by: Donald Picard <donald.picard@sogeti.com>
2020-10-22 09:05:02 -04:00
Nicolas G
a50e32d4ea Add support for Kubernetes Pod annotations
Variable `kubernetes_pod_annotations` will add annotations to Kubernetes pods
2020-10-21 19:59:11 -04:00
Nicolas Delvaux
a58e37e31f Expose {awx,tower}_job_scm_branch variables in the environment
related #8429
2020-10-22 00:09:18 +02:00
Nicolas Delvaux
51aed19b29 Expose {awx,tower}_project_scm_branch variables in the environment 2020-10-21 23:54:48 +02:00
Tiago Góes
e30569cc1b Change the id from / to - 2020-10-21 18:26:19 -03:00
softwarefactory-project-zuul[bot]
81a79c30cb Merge pull request #7976 from bbayszczak/missing_creds_type_to_tower_credentials_module
add missing creds types to tower_credential module

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-21 19:03:41 +00:00
John Mitchell
2c0de9ce3d update render dashboard default unit t est 2020-10-21 12:52:38 -04:00
softwarefactory-project-zuul[bot]
3b3dfb6dbe Merge pull request #8424 from ansible/deps-autofix-10-21
Autofix dependencies

Reviewed-by: John Hill <johill@redhat.com>
             https://github.com/unlikelyzero
2020-10-21 16:33:42 +00:00
Bianca Henderson
143831ffd0 Add required whitespace 2020-10-21 12:21:30 -04:00
softwarefactory-project-zuul[bot]
6bd573cf07 Merge pull request #8263 from AlexSCorey/8238-AddRelatedGroups
8238 add related groups

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-21 15:42:55 +00:00
softwarefactory-project-zuul[bot]
447bc4b4da Merge pull request #8364 from sean-m-sullivan/workflow_approval
Workflow approval

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
             https://github.com/beeankha
2020-10-21 15:08:01 +00:00
softwarefactory-project-zuul[bot]
7c038c9329 Merge pull request #8348 from nesanton/feature/8347
Rename inventory_source param to name in tower_inventory_source_update

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-21 14:53:27 +00:00
Ryan Petrello
a26d20cbf2 Merge pull request #4631 from ryanpetrello/galaxy-creds-cli
allow the CLI to associate Galaxy credentials to Organizations
2020-10-21 10:40:55 -04:00
John Mitchell
52deb7fd86 update dashboard and graph code to aid in automated testing 2020-10-21 10:32:37 -04:00
Ryan Petrello
c373d5307f allow the CLI to associate Galaxy credentials to Organizations
$ awx organizations associate Default --galaxy_credential "Ansible Galaxy"
2020-10-21 09:39:33 -04:00
Jake McDermott
1ab0e318f9 Fix vulnerable dependencies 2020-10-21 08:57:41 -04:00
softwarefactory-project-zuul[bot]
062ce5f735 Merge pull request #7281 from mabashian/7127-cred-input-details
Updates credential details to support plugin and prompt fields

Reviewed-by: John Hill <johill@redhat.com>
             https://github.com/unlikelyzero
2020-10-21 00:32:26 +00:00
Keith Grant
9b5e59f045 add number validator support for negative numbers, large numbers 2020-10-20 15:44:17 -07:00
Alex Corey
8cb8cfe3d5 fixes search and sort 2020-10-20 17:53:54 -04:00
John Mitchell
5f4d6daf1b update dashboard to 3 tab single pane 2020-10-20 17:33:37 -04:00
Alex Corey
bebaf2d97e Uses existing kebabified workflow for run command 2020-10-20 17:07:01 -04:00
Alex Corey
ef85a321bc brings all lists in line with exsiting Ad Hoc workflow 2020-10-20 17:05:51 -04:00
Alex Corey
b919d4885c reformats long string, removes unneeded key 2020-10-20 17:05:51 -04:00
Alex Corey
f604065246 Refactors to show add button properly in Advanced Search mode 2020-10-20 17:05:51 -04:00
Alex Corey
9620da287c Adds Related Groups List 2020-10-20 17:05:51 -04:00
sean-m-sullivan
1ca46893bb update 2020-10-20 15:55:15 -05:00
softwarefactory-project-zuul[bot]
717861fb46 Merge pull request #8339 from keithjgrant/7515-form-error-polish
Refactor FormSubmitError for easier testing, better error display

Reviewed-by: John Hill <johill@redhat.com>
             https://github.com/unlikelyzero
2020-10-20 20:52:09 +00:00
John Mitchell
8839fb9af3 remove unused comment from template lists 2020-10-20 16:42:28 -04:00
John Mitchell
a3c5f50bbf add dashboard (including counts, line chart and portal mode style lists) to ui_next 2020-10-20 16:42:28 -04:00
John Mitchell
5ea98ab02a add copy of template list for dashboard use, moving around shared ws hook to util 2020-10-20 16:42:28 -04:00
John Mitchell
782e8d5875 add two_weeks filter to dashbaord job graph api view 2020-10-20 16:42:28 -04:00
Jake McDermott
36abc9b123 Merge pull request #4630 from jakemcdermott/current-date
[3.8] Use current year in about modal
2020-10-20 15:31:31 -04:00
Anton Nesterov
130f6300c5 Fix missing alias in argument_spec and add tests for it 2020-10-20 21:15:28 +02:00
Jake McDermott
7bc7cb00ac Use current year in about modal 2020-10-20 15:13:58 -04:00
softwarefactory-project-zuul[bot]
f3ac57e3b6 Merge pull request #8346 from marshmalien/popover-component
Merge FieldTooltip and DetailPopover into single Popover component

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-20 18:55:02 +00:00
Keith Grant
a9c01e891f remove console log
Co-authored-by: Jake McDermott <yo@jakemcdermott.me>
2020-10-20 11:18:40 -07:00
Keith Grant
acd8a8dd3c fix integer/float errors in survey 2020-10-20 10:47:26 -07:00
Jake McDermott
f85548abeb Merge pull request #4628 from mabashian/4310-license-string
Replace SETTINGS > SYSTEM with SETTINGS &gt; SYSTEM to get around issue with translating this string
2020-10-20 12:34:19 -04:00
softwarefactory-project-zuul[bot]
44776189de Merge pull request #8162 from nixocio/ui_instance_groups_update_labels
Update labels to display isolated and controller instance groups

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-20 16:11:55 +00:00
Rebeccah
a929e82060 replacing capabilities prefetch definition with empty braces and removing the dunder. Explanation: Originally _capabilities_prefetch was populated with: ['admin', 'execute', {'copy': ['jobtemplate.project.use', 'jobtemplate.inventory.use', 'organization.workflow_admin']}]
This was problematic because it was overwriting the original values that had been defined in the other serializers. Additionally, there are no other dunders for other capabilities prefetch
this was likely added because UnifiedJobTemplateSerializer does not have it's own capabilities, but rather derives them from JTSerializer and WFJTSeralizer, but it worked better without the dunder once I removed the data that was overwriting the data from the WFJT and JT serializers.
2020-10-20 11:58:53 -04:00
Marliana Lara
5d0b001764 Fix prop type errors in unit tests 2020-10-20 11:57:32 -04:00
Marliana Lara
f369f8535d Add default aria label to Popover component 2020-10-20 11:55:04 -04:00
Marliana Lara
35ba74d265 Merge FieldTooltip and DetailPopover into single Popover component 2020-10-20 11:55:00 -04:00
nixocio
c8b9cbe0d5 Update labels to display isolated and controller instance groups
Update labels to display isolated and controller instance groups.

See: https://github.com/ansible/awx/issues/8244
Also: https://github.com/ansible/awx/issues/7467
2020-10-20 11:39:17 -04:00
softwarefactory-project-zuul[bot]
677fb594e8 Merge pull request #8281 from mabashian/7835-galaxy-cred-org-2
Add Galaxy Credentials field to organizations form

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-20 15:37:08 +00:00
softwarefactory-project-zuul[bot]
439e872a05 Merge pull request #8404 from mabashian/fix-test-consoles
Fix issues with prop types that were causing errors to be logged during tests

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-20 15:33:53 +00:00
mabashian
d27c482e5e Pass actual error to ContentError so it can be displayed 2020-10-20 11:16:38 -04:00
mabashian
34e85dea8b Check for existence of data.next before checking it 2020-10-20 11:16:38 -04:00
mabashian
6df173ce1d Update return structure of readInputSources to match what the edit component is expecting. This also required me to make corresponding updates to the detail component so that it matched. 2020-10-20 11:16:38 -04:00
mabashian
e6a1ad0127 Ran prettier 2020-10-20 11:16:38 -04:00
mabashian
c3c7e120c8 Removes use of Trans tag in favor of t/i18n 2020-10-20 11:16:38 -04:00
mabashian
81822dfd1c Adds an upper limit on recursive calls set statically in the method at 5. 2020-10-20 11:16:38 -04:00
mabashian
a71a9057a2 Wraps GET requests in useRequest in order to handle unmounting more gracefully if the requests are still pending. 2020-10-20 11:16:38 -04:00
mabashian
a1d1a1078b Adds logic to recursively fetch input sources in the model method. This way we don't have to duplicate this logic every place that calls the method. 2020-10-20 11:16:38 -04:00
mabashian
e7cd9bbb98 Display fields that have plugins configured. 2020-10-20 11:16:38 -04:00
mabashian
908e583c69 Display prompt on launch passwords properly 2020-10-20 11:16:38 -04:00
mabashian
19ae4eadfb Add galaxy credentials field to organizations form 2020-10-20 11:03:27 -04:00
mabashian
485cee56bc Fix issues with prop types that were causing errors to be logged during tests 2020-10-20 10:59:39 -04:00
softwarefactory-project-zuul[bot]
9e4a236c64 Merge pull request #8417 from nicolas-g/patch-1
Add Kubernetes Deployment support for annotations

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-10-20 14:53:44 +00:00
Sean Sullivan
3a34a079aa Merge pull request #18 from ansible/devel
rebase to ansible/awx
2020-10-20 09:41:56 -05:00
sean-m-sullivan
03c7504d2b fix existing item error 2020-10-20 09:40:45 -05:00
mabashian
7a9b55c21b Replace SETTINGS > SYSTEM with SETTINGS &gt; SYSTEM to get around issue with translating this string 2020-10-20 10:31:30 -04:00
Chris Meyers
84cb7be079 fill in postgres application_name on connection
* Tried to fill in application_name in awx/__init__.py but I think that
is too late
* Fill in database application_name with enough information to easily
trace the connection from postgres back to the node and pid that
initiated the connection.
* Set application_name in django settings so that application_name is
set _before_ the first postgres connection is established.
2020-10-20 08:32:09 -04:00
Sean Sullivan
dc26580466 Update to response code
set response code for current versions of tower/awx
2020-10-19 19:46:49 -05:00
sean-m-sullivan
1636f0cb25 linting 2020-10-19 17:35:18 -05:00
Sean Sullivan
f6a1707684 Merge pull request #17 from ansible/devel
Rebase
2020-10-19 15:56:04 -05:00
sean-m-sullivan
fe55dca661 make workflow approval creation return an HTTP 201, not 200 OK 2020-10-19 15:55:49 -05:00
sean-m-sullivan
a8159c0391 revert check 2020-10-19 15:35:36 -05:00
Nicolas G
23c386223c Add Kubernetes Deployment support for annotations
Annotations are only supported for ingress and service accounts
This PR will allow you now to specify annotations for Kubernetes Deployment
 resources by defining `kubernetes_deployment_annotations` var list
2020-10-19 16:33:54 -04:00
sean-m-sullivan
5959809fed make workflow approval creation return an HTTP 201, not 200 OK 2020-10-19 15:19:01 -05:00
sean-m-sullivan
e416b55b1a update to fix missing options and fix pep8 2020-10-19 15:15:33 -05:00
sean-m-sullivan
91ef686fe0 update to incorporate requested changes, change approve to 201 response. 2020-10-19 15:11:19 -05:00
sean-m-sullivan
862cd974ff linting 2020-10-19 12:12:08 -05:00
Chris Meyers
11cc6362b5 reduce per-job database query count
* Do not query the database for the set of Instance that belong to the
group for which we are trying to fit a job on, for each job.
* Instead, cache the set of instances per-instance group.
2020-10-19 11:01:11 -04:00
Chris Meyers
bdabe36029 reduce parent->child lock contention
* We update the parent unified job template to point at new jobs
created. We also update a similar foreign key when the job finishes
running. This causes lock contention when the job template is
allow_simultaneous and there are a lot of jobs from that job template
running in parallel. I've seen as bad as 5 minutes waiting for the lock
when a job finishes.
* This change moves the parent->child update to OUTSIDE of the
transaction if the job is allow_simultaneous (inherited from the parent
unified job). We sacrafice a bit of correctness for performance. The
logic is, if you are launching 1,000 parallel jobs do you really care
that the job template contains a pointer to the last one you launched?
Probably not. If you do, you can always query jobs related to the job
template sorted by created time.
2020-10-19 11:01:05 -04:00
Anton Nesterov
2e237661f8 Add the inventory_source as alias. 2020-10-17 17:33:53 +02:00
Anton Nesterov
8a09731a52 Rename inventory_source param to name
* fixes #8347
* Rename inventory_source to name in the tower_inventory_source_update
* Allow to specify both name or id for `name` and `inventory` params
2020-10-17 17:33:53 +02:00
sean-m-sullivan
4151361420 linting 2020-10-17 01:13:50 -05:00
sean-m-sullivan
c0e1ac266c add tests 2020-10-17 01:00:14 -05:00
Sean Sullivan
6c1f688bf1 Merge pull request #16 from sean-m-sullivan/approval_role
update to approval role
2020-10-17 00:10:00 -05:00
sean-m-sullivan
0393d537de rewrite to use lists 2020-10-17 00:08:39 -05:00
sean-m-sullivan
82bb8033ec update to approval role 2020-10-16 13:27:28 -05:00
Sean Sullivan
106b19a05d Merge pull request #13 from ansible/devel
Rebase
2020-10-16 12:15:47 -05:00
sean-m-sullivan
7ca2f33112 update test 2020-10-16 11:22:12 -05:00
sean-m-sullivan
ad1937b394 update test 2020-10-16 11:16:15 -05:00
sean-m-sullivan
0fee6d8b86 update test 2020-10-16 10:52:56 -05:00
sean-m-sullivan
237727dd62 update pytest 2020-10-13 20:56:50 -05:00
sean-m-sullivan
d9184e02f5 update pytest 2020-10-13 20:40:35 -05:00
sean-m-sullivan
3b903a7459 fix typo 2020-10-13 18:41:52 -05:00
sean-m-sullivan
c72c335b0c fix pep8 issues 2020-10-13 18:27:27 -05:00
sean-m-sullivan
51eb4e6d6b update to auto_exit, add tests, add mutual exclusive parameters 2020-10-13 18:17:22 -05:00
sean-m-sullivan
e16a910062 updated workflow task name 2020-10-13 14:24:56 -05:00
sean-m-sullivan
6b27ee6a3c updated workflow name 2020-10-13 14:24:22 -05:00
sean-m-sullivan
226046dd16 update 2020-10-12 12:03:37 -05:00
sean-m-sullivan
c205ee81f0 update delete 2020-10-12 00:17:18 -05:00
sean-m-sullivan
c57ec1ea79 update delete 2020-10-10 13:25:09 -05:00
sean-m-sullivan
c3045f6a29 update delete 2020-10-10 13:02:58 -05:00
sean-m-sullivan
7ffa70422a remove typo changes 2020-10-10 11:57:34 -05:00
sean-m-sullivan
5655f766f0 linting 2020-10-10 11:56:00 -05:00
sean-m-sullivan
a2c8e3d87e clean up and tests added 2020-10-10 11:53:50 -05:00
sean-m-sullivan
9bcb5ef0c9 intial update for workflow approval nodes 2020-10-10 04:06:49 -05:00
Sean Sullivan
501c91f035 Merge pull request #12 from ansible/devel
rebase
2020-10-09 23:25:32 -05:00
Keith Grant
2133b83db4 fix handling of nested API form errors 2020-10-08 09:14:51 -07:00
Keith Grant
f5e4147502 add comment to tests 2020-10-07 08:30:11 -07:00
Keith Grant
52f37242fc clean up & unit test form error handling 2020-10-06 14:48:23 -07:00
Benoit Bayszczak
d49a61b63e add missing creds types to tower_credential module
Add the following native credentials types to the tower_credential module
 - 'satellite': 'Red Hat Satellite 6' # renaming of satellite6
 - 'aim': 'CyberArk AIM Central Credential Provider Lookup'
 - 'conjur': 'CyberArk Conjur Secret Lookup'
 - 'hashivault_kv': 'HashiCorp Vault Secret Lookup'
 - 'hashivault_ssh': 'HashiCorp Vault Signed SSH'
 - 'azure_kv': 'Microsoft Azure Key Vault'
 - 'kubernetes_bearer_token': 'OpenShift or Kubernetes API Bearer Token'
 - 'github_token': 'GitHub Personal Access Token'
 - 'gitlab_token': 'GitLab Personal Access Token'
2020-08-25 17:24:17 +02:00
2048 changed files with 35454 additions and 199741 deletions

View File

@@ -1,2 +1 @@
.git
awx/ui/node_modules

6
.gitignore vendored
View File

@@ -33,9 +33,8 @@ awx/ui_next/src/locales/
awx/ui_next/coverage/
awx/ui_next/build
awx/ui_next/.env.local
awx/ui_next/instrumented
rsyslog.pid
/tower-license
/tower-license/**
tools/prometheus/data
tools/docker-compose/Dockerfile
@@ -147,3 +146,6 @@ use_dev_supervisor.txt
.idea/*
*.unison.tmp
*.#
/tools/docker-compose/overrides/
/awx/ui_next/.ui-built
/Dockerfile

View File

@@ -2,6 +2,46 @@
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>`.
# 17.0.0 (January 22, 2021)
- AWX now requires PostgreSQL 12 by default: https://github.com/ansible/awx/pull/8943
**Note:** users who encounter permissions errors at upgrade time should `chown -R ~/.awx/pgdocker` to ensure it's owned by the user running the install playbook
- Added support for region name for OpenStack inventory: https://github.com/ansible/awx/issues/5080
- Added the ability to chain undefined attributes in custom notification templates: https://github.com/ansible/awx/issues/8677
- Dramatically simplified the `image_build` role: https://github.com/ansible/awx/pull/8980
- Fixed a bug which can cause schema migrations to fail at install time: https://github.com/ansible/awx/issues/9077
- Fixed a bug which caused the `is_superuser` user property to be out of date in certain circumstances: https://github.com/ansible/awx/pull/8833
- Fixed a bug which sometimes results in race conditions on setting access: https://github.com/ansible/awx/pull/8580
- Fixed a bug which sometimes causes an unexpected delay in stdout for some playbooks: https://github.com/ansible/awx/issues/9085
- (UI) Added support for credential password prompting on job launch: https://github.com/ansible/awx/pull/9028
- (UI) Added the ability to configure LDAP settings in the UI: https://github.com/ansible/awx/issues/8291
- (UI) Added a sync button to the Project detail view: https://github.com/ansible/awx/issues/8847
- (UI) Added a form for configuring Google Outh 2.0 settings: https://github.com/ansible/awx/pull/8762
- (UI) Added searchable keys and related keys to the Credentials list: https://github.com/ansible/awx/issues/8603
- (UI) Added support for advanced search and copying to Notification Templates: https://github.com/ansible/awx/issues/7879
- (UI) Added support for prompting on workflow nodes: https://github.com/ansible/awx/issues/5913
- (UI) Added support for session timeouts: https://github.com/ansible/awx/pull/8250
- (UI) Fixed a bug that broke websocket streaming for the insecure ws:// protocol: https://github.com/ansible/awx/pull/8877
- (UI) Fixed a bug in the user interface when a translation for the browser's preferred locale isn't available: https://github.com/ansible/awx/issues/8884
- (UI) Fixed bug where navigating from one survey question form directly to another wasn't reloading the form: https://github.com/ansible/awx/issues/7522
- (UI) Fixed a bug which can cause an uncaught error while launching a Job Template: https://github.com/ansible/awx/issues/8936
- Updated autobahn to address CVE-2020-35678
## 16.0.0 (December 10, 2020)
- AWX now ships with a reimagined user interface. **Please read this before upgrading:** https://groups.google.com/g/awx-project/c/KuT5Ao92HWo
- Removed support for syncing inventory from Red Hat CloudForms - https://github.com/ansible/awx/commit/0b701b3b2
- Removed support for Mercurial-based project updates - https://github.com/ansible/awx/issues/7932
- Upgraded NodeJS to actively maintained LTS 14.15.1 - https://github.com/ansible/awx/pull/8766
- Added Git-LFS to the default image build - https://github.com/ansible/awx/pull/8700
- Added the ability to specify `metadata.labels` in the podspec for container groups - https://github.com/ansible/awx/issues/8486
- Added support for Kubernetes pod annotations - https://github.com/ansible/awx/pull/8434
- Added the ability to label the web container in local Docker installs - https://github.com/ansible/awx/pull/8449
- Added additional metadata (as an extra var) to playbook runs to report the SCM branch name - https://github.com/ansible/awx/pull/8433
- Fixed a bug that caused k8s installations to fail due to an incorrect Helm repo - https://github.com/ansible/awx/issues/8715
- Fixed a bug that prevented certain Workflow Approval resources from being deleted - https://github.com/ansible/awx/pull/8612
- Fixed a bug that prevented the deletion of inventories stuck in "pending deletion" state - https://github.com/ansible/awx/issues/8525
- Fixed a display bug in webhook notifications with certain unicode characters - https://github.com/ansible/awx/issues/7400
- Improved support for exporting dependent objects (Inventory Hosts and Groups) in the `awx export` CLI tool - https://github.com/ansible/awx/commit/607bc0788
## 15.0.1 (October 20, 2020)
- Added several optimizations to improve performance for a variety of high-load simultaneous job launch use cases https://github.com/ansible/awx/pull/8403
- Added the ability to source roles and collections from requirements.yaml files (not just requirements.yml) - https://github.com/ansible/awx/issues/4540
@@ -88,7 +128,7 @@ This is a list of high-level changes for each release of AWX. A full list of com
- Fixed a bug that caused rsyslogd's configuration file to have world-readable file permissions, potentially leaking secrets (CVE-2020-10782)
## 12.0.0 (Jun 9, 2020)
- Removed memcached as a dependency of AWX (https://github.com/ansible/awx/pull/7240)
- Removed memcached as a dependency of AWX (https://github.com/ansible/awx/pull/7240)
- Moved to a single container image build instead of separate awx_web and awx_task images. The container image is just `awx` (https://github.com/ansible/awx/pull/7228)
- Official AWX container image builds now use a two-stage container build process that notably reduces the size of our published images (https://github.com/ansible/awx/pull/7017)
- Removed support for HipChat notifications ([EoL announcement](https://www.atlassian.com/partnerships/slack/faq#faq-98b17ca3-247f-423b-9a78-70a91681eff0)); all previously-created HipChat notification templates will be deleted due to this removal.

View File

@@ -85,7 +85,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/README.md).
See [the ui development documentation](awx/ui_next/CONTRIBUTING.md).
### Build the environment
@@ -158,7 +158,7 @@ $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44251b476f98 gcr.io/ansible-tower-engineering/awx_devel:devel "/entrypoint.sh /bin…" 27 seconds ago Up 23 seconds 0.0.0.0:6899->6899/tcp, 0.0.0.0:7899-7999->7899-7999/tcp, 0.0.0.0:8013->8013/tcp, 0.0.0.0:8043->8043/tcp, 0.0.0.0:8080->8080/tcp, 22/tcp, 0.0.0.0:8888->8888/tcp tools_awx_run_9e820694d57e
40de380e3c2e redis:latest "docker-entrypoint.s…" 28 seconds ago Up 26 seconds
b66a506d3007 postgres:10 "docker-entrypoint.s…" 28 seconds ago Up 26 seconds 0.0.0.0:5432->5432/tcp tools_postgres_1
b66a506d3007 postgres:12 "docker-entrypoint.s…" 28 seconds ago Up 26 seconds 0.0.0.0:5432->5432/tcp tools_postgres_1
```
**NOTE**

View File

@@ -60,7 +60,7 @@ Please note that deploying from `HEAD` (or the latest commit) is **not** stable,
For more on how to clone the repo, view [git clone help](https://git-scm.com/docs/git-clone).
Once you have a local copy, run commands within the root of the project tree.
Once you have a local copy, run the commands in the following sections from the root of the project tree.
### AWX branding
@@ -83,7 +83,7 @@ Before you can run a deployment, you'll need the following installed in your loc
- [GNU Make](https://www.gnu.org/software/make/)
- [Git](https://git-scm.com/) Requires Version 1.8.4+
- Python 3.6+
- [Node 10.x LTS version](https://nodejs.org/en/download/)
- [Node 14.x LTS version](https://nodejs.org/en/download/)
+ This is only required if you're [building your own container images](#official-vs-building-images) with `use_container_for_build=false`
- [NPM 6.x LTS](https://docs.npmjs.com/)
+ This is only required if you're [building your own container images](#official-vs-building-images) with `use_container_for_build=false`
@@ -497,7 +497,7 @@ Before starting the install process, review the [inventory](./installer/inventor
*docker_compose_dir*
> When using docker-compose, the `docker-compose.yml` file will be created there (default `/tmp/awxcompose`).
> When using docker-compose, the `docker-compose.yml` file will be created there (default `~/.awx/awxcompose`).
*custom_venv_dir*

View File

@@ -4,8 +4,6 @@ recursive-include awx *.mo
recursive-include awx/static *
recursive-include awx/templates *.html
recursive-include awx/api/templates *.md *.html
recursive-include awx/ui/templates *.html
recursive-include awx/ui/static *
recursive-include awx/ui_next/build *.html
recursive-include awx/ui_next/build *
recursive-include awx/playbooks *.yml

164
Makefile
View File

@@ -19,7 +19,8 @@ PYCURL_SSL_LIBRARY ?= openssl
COMPOSE_TAG ?= $(GIT_BRANCH)
COMPOSE_HOST ?= $(shell hostname)
VENV_BASE ?= /venv
VENV_BASE ?= /var/lib/awx/venv/
COLLECTION_BASE ?= /var/lib/awx/vendor/awx_ansible_collections
SCL_PREFIX ?=
CELERY_SCHEDULE_FILE ?= /var/lib/awx/beat.db
@@ -56,11 +57,6 @@ WHEEL_COMMAND ?= bdist_wheel
SDIST_TAR_FILE ?= $(SDIST_TAR_NAME).tar.gz
WHEEL_FILE ?= $(WHEEL_NAME)-py2-none-any.whl
# UI flag files
UI_DEPS_FLAG_FILE = awx/ui/.deps_built
UI_RELEASE_DEPS_FLAG_FILE = awx/ui/.release_deps_built
UI_RELEASE_FLAG_FILE = awx/ui/.release_built
I18N_FLAG_FILE = .i18n_built
.PHONY: awx-link clean clean-tmp clean-venv requirements requirements_dev \
@@ -70,22 +66,6 @@ I18N_FLAG_FILE = .i18n_built
ui-docker-machine ui-docker ui-release ui-devel \
ui-test ui-deps ui-test-ci VERSION
# remove ui build artifacts
clean-ui: clean-languages
rm -rf awx/ui/static/
rm -rf awx/ui/node_modules/
rm -rf awx/ui/test/unit/reports/
rm -rf awx/ui/test/spec/reports/
rm -rf awx/ui/test/e2e/reports/
rm -rf awx/ui/client/languages/
rm -rf awx/ui_next/node_modules/
rm -rf node_modules
rm -rf awx/ui_next/coverage/
rm -rf awx/ui_next/build/locales/_build/
rm -f $(UI_DEPS_FLAG_FILE)
rm -f $(UI_RELEASE_DEPS_FLAG_FILE)
rm -f $(UI_RELEASE_FLAG_FILE)
clean-tmp:
rm -rf tmp/
@@ -291,7 +271,7 @@ uwsgi: collectstatic
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
uwsgi -b 32768 --socket 127.0.0.1:8050 --module=awx.wsgi:application --home=/venv/awx --chdir=/awx_devel/ --vacuum --processes=5 --harakiri=120 --master --no-orphans --py-autoreload 1 --max-requests=1000 --stats /tmp/stats.socket --lazy-apps --logformat "%(addr) %(method) %(uri) - %(proto) %(status)" --hook-accepting1="exec:supervisorctl restart tower-processes:awx-dispatcher tower-processes:awx-receiver"
uwsgi -b 32768 --socket 127.0.0.1:8050 --module=awx.wsgi:application --home=/var/lib/awx/venv/awx --chdir=/awx_devel/ --vacuum --processes=5 --harakiri=120 --master --no-orphans --py-autoreload 1 --max-requests=1000 --stats /tmp/stats.socket --lazy-apps --logformat "%(addr) %(method) %(uri) - %(proto) %(status)" --hook-accepting1="exec:supervisorctl restart tower-processes:awx-dispatcher tower-processes:awx-receiver"
daphne:
@if [ "$(VENV_BASE)" ]; then \
@@ -361,7 +341,7 @@ check: flake8 pep8 # pyflakes pylint
awx-link:
[ -d "/awx_devel/awx.egg-info" ] || python3 /awx_devel/setup.py egg_info_dev
cp -f /tmp/awx.egg-link /venv/awx/lib/python$(PYTHON_VERSION)/site-packages/awx.egg-link
cp -f /tmp/awx.egg-link /var/lib/awx/venv/awx/lib/python$(PYTHON_VERSION)/site-packages/awx.egg-link
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
@@ -480,130 +460,47 @@ else
@echo No PO files
endif
# generate UI .pot
pot: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run pot
# generate django .pot .po
LANG = "en-us"
messages:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(PYTHON) manage.py makemessages -l $(LANG) --keep-pot
# generate l10n .json .mo
languages: $(I18N_FLAG_FILE)
$(I18N_FLAG_FILE): $(UI_RELEASE_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run languages
$(PYTHON) tools/scripts/compilemessages.py
touch $(I18N_FLAG_FILE)
# End l10n TASKS
# --------------------------------------
# UI RELEASE TASKS
# --------------------------------------
ui-release: $(UI_RELEASE_FLAG_FILE)
$(UI_RELEASE_FLAG_FILE): $(I18N_FLAG_FILE) $(UI_RELEASE_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run build-release
touch $(UI_RELEASE_FLAG_FILE)
$(UI_RELEASE_DEPS_FLAG_FILE):
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 $(NPM_BIN) --unsafe-perm --prefix awx/ui ci --no-save awx/ui
touch $(UI_RELEASE_DEPS_FLAG_FILE)
# END UI RELEASE TASKS
# --------------------------------------
# UI TASKS
# --------------------------------------
ui-deps: $(UI_DEPS_FLAG_FILE)
$(UI_DEPS_FLAG_FILE):
@if [ -f ${UI_RELEASE_DEPS_FLAG_FILE} ]; then \
rm -rf awx/ui/node_modules; \
rm -f ${UI_RELEASE_DEPS_FLAG_FILE}; \
fi; \
$(NPM_BIN) --unsafe-perm --prefix awx/ui ci --no-save awx/ui
touch $(UI_DEPS_FLAG_FILE)
UI_BUILD_FLAG_FILE = awx/ui_next/.ui-built
ui-docker-machine: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run ui-docker-machine -- $(MAKEFLAGS)
# Native docker. Builds UI and raises BrowserSync & filesystem polling.
ui-docker: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run ui-docker -- $(MAKEFLAGS)
# Builds UI with development UI without raising browser-sync or filesystem polling.
ui-devel: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run build-devel -- $(MAKEFLAGS)
ui-test: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run test
ui-lint: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) run --prefix awx/ui jshint
$(NPM_BIN) run --prefix awx/ui lint
# A standard go-to target for API developers to use building the frontend
ui: clean-ui ui-devel
ui-test-ci: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run test:ci
$(NPM_BIN) --prefix awx/ui run unit
jshint: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) run --prefix awx/ui jshint
$(NPM_BIN) run --prefix awx/ui lint
ui-zuul-lint-and-test:
CHROMIUM_BIN=$(CHROMIUM_BIN) ./awx/ui/build/zuul_download_chromium.sh
CHROMIUM_BIN=$(CHROMIUM_BIN) PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 $(NPM_BIN) --unsafe-perm --prefix awx/ui ci --no-save awx/ui
CHROMIUM_BIN=$(CHROMIUM_BIN) $(NPM_BIN) run --prefix awx/ui jshint
CHROMIUM_BIN=$(CHROMIUM_BIN) $(NPM_BIN) run --prefix awx/ui lint
CHROME_BIN=$(CHROMIUM_BIN) $(NPM_BIN) --prefix awx/ui run test:ci
CHROME_BIN=$(CHROMIUM_BIN) $(NPM_BIN) --prefix awx/ui run unit
# END UI TASKS
# --------------------------------------
# UI NEXT TASKS
# --------------------------------------
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 $(UI_BUILD_FLAG_FILE)
git checkout awx/ui_next/src/locales
awx/ui_next/node_modules:
$(NPM_BIN) --prefix awx/ui_next install
$(NPM_BIN) --prefix awx/ui_next --loglevel warn --ignore-scripts install
ui-release-next:
mkdir -p awx/ui_next/build/static
touch awx/ui_next/build/static/.placeholder
ui-devel-next: awx/ui_next/node_modules
$(NPM_BIN) --prefix awx/ui_next run extract-strings
$(NPM_BIN) --prefix awx/ui_next run compile-strings
$(NPM_BIN) --prefix awx/ui_next run build
$(UI_BUILD_FLAG_FILE):
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run extract-strings
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run compile-strings
$(NPM_BIN) --prefix awx/ui_next --loglevel warn run build
git checkout awx/ui_next/src/locales
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
touch $@
clean-ui-next:
rm -rf node_modules
rm -rf awx/ui_next/node_modules
rm -rf awx/ui_next/build
ui-release: awx/ui_next/node_modules $(UI_BUILD_FLAG_FILE)
ui-next-zuul-lint-and-test:
ui-devel: awx/ui_next/node_modules
@$(MAKE) -B $(UI_BUILD_FLAG_FILE)
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
# END UI NEXT TASKS
# --------------------------------------
# Build a pip-installable package into dist/ with a timestamped version number.
dev_build:
@@ -613,10 +510,10 @@ dev_build:
release_build:
$(PYTHON) setup.py release_build
dist/$(SDIST_TAR_FILE): ui-release ui-release-next VERSION
dist/$(SDIST_TAR_FILE): ui-release VERSION
$(PYTHON) setup.py $(SDIST_COMMAND)
dist/$(WHEEL_FILE): ui-release ui-release-next
dist/$(WHEEL_FILE): ui-release
$(PYTHON) setup.py $(WHEEL_COMMAND)
sdist: dist/$(SDIST_TAR_FILE)
@@ -650,9 +547,11 @@ awx/projects:
docker-compose-isolated: awx/projects
CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml -f tools/docker-isolated-override.yml up
COMPOSE_UP_OPTS ?=
# Docker Compose Development environment
docker-compose: docker-auth awx/projects
CURRENT_UID=$(shell id -u) OS="$(shell docker info | grep 'Operating System')" TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml up --no-recreate awx
CURRENT_UID=$(shell id -u) OS="$(shell docker info | grep 'Operating System')" TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml $(COMPOSE_UP_OPTS) up --no-recreate awx
docker-compose-cluster: docker-auth awx/projects
CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose-cluster.yml up
@@ -720,7 +619,10 @@ clean-elk:
docker rm tools_kibana_1
psql-container:
docker run -it --net tools_default --rm postgres:10 sh -c 'exec psql -h "postgres" -p "5432" -U postgres'
docker run -it --net tools_default --rm postgres:12 sh -c 'exec psql -h "postgres" -p "5432" -U postgres'
VERSION:
@echo "awx: $(VERSION)"
Dockerfile: installer/roles/image_build/templates/Dockerfile.j2
ansible localhost -m template -a "src=installer/roles/image_build/templates/Dockerfile.j2 dest=Dockerfile"

View File

@@ -1,7 +1,5 @@
[![Gated by Zuul](https://zuul-ci.org/gated.svg)](https://ansible.softwarefactory-project.io/zuul/status)
<img src="https://raw.githubusercontent.com/ansible/awx-logos/master/awx/ui/client/assets/logo-login.svg?sanitize=true" width=200 alt="AWX" />
AWX provides a web-based user interface, REST API, and task engine built on top of [Ansible](https://github.com/ansible/ansible). It is the upstream project for [Tower](https://www.ansible.com/tower), a commercial derivative of AWX.
To install AWX, please view the [Install guide](./INSTALL.md).

View File

@@ -1 +1 @@
15.0.1
17.0.0

View File

@@ -47,8 +47,6 @@ from awx.main.utils import (
get_object_or_400,
decrypt_field,
get_awx_version,
get_licenser,
StubLicense
)
from awx.main.utils.db import get_all_field_names
from awx.main.views import ApiErrorView
@@ -189,7 +187,8 @@ 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()
@@ -225,7 +224,8 @@ class APIView(views.APIView):
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(), StubLicense) else 'Red Hat Ansible Tower'
response['X-API-Product-Name'] = 'AWX' if isinstance(get_licenser(), OpenLicense) else 'Red Hat Ansible Tower'
response['X-API-Node'] = settings.CLUSTER_HOST_ID
if time_started:
time_elapsed = time.time() - self.time_started

View File

@@ -453,7 +453,7 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
if 'capability_map' not in self.context:
if hasattr(self, 'polymorphic_base'):
model = self.polymorphic_base.Meta.model
prefetch_list = self.polymorphic_base._capabilities_prefetch
prefetch_list = self.polymorphic_base.capabilities_prefetch
else:
model = self.Meta.model
prefetch_list = self.capabilities_prefetch
@@ -640,12 +640,9 @@ class EmptySerializer(serializers.Serializer):
class UnifiedJobTemplateSerializer(BaseSerializer):
# As a base serializer, the capabilities prefetch is not used directly
_capabilities_prefetch = [
'admin', 'execute',
{'copy': ['jobtemplate.project.use', 'jobtemplate.inventory.use',
'organization.workflow_admin']}
]
# As a base serializer, the capabilities prefetch is not used directly,
# instead they are derived from the Workflow Job Template Serializer and the Job Template Serializer, respectively.
capabilities_prefetch = []
class Meta:
model = UnifiedJobTemplate
@@ -695,7 +692,7 @@ class UnifiedJobTemplateSerializer(BaseSerializer):
serializer.polymorphic_base = self
# capabilities prefetch is only valid for these models
if isinstance(obj, (JobTemplate, WorkflowJobTemplate)):
serializer.capabilities_prefetch = self._capabilities_prefetch
serializer.capabilities_prefetch = serializer_class.capabilities_prefetch
else:
serializer.capabilities_prefetch = None
return serializer.to_representation(obj)
@@ -1333,6 +1330,8 @@ class ProjectOptionsSerializer(BaseSerializer):
scm_type = attrs.get('scm_type', u'') or u''
if self.instance and not scm_type:
valid_local_paths.append(self.instance.local_path)
if self.instance and scm_type and "local_path" in attrs and self.instance.local_path != attrs['local_path']:
errors['local_path'] = _(f'Cannot change local_path for {scm_type}-based projects')
if scm_type:
attrs.pop('local_path', None)
if 'local_path' in attrs and attrs['local_path'] not in valid_local_paths:
@@ -1749,7 +1748,7 @@ class HostSerializer(BaseSerializerWithVariables):
attrs['variables'] = json.dumps(vars_dict)
if Group.objects.filter(name=name, inventory=inventory).exists():
raise serializers.ValidationError(_('A Group with that name already exists.'))
return super(HostSerializer, self).validate(attrs)
def to_representation(self, obj):
@@ -3946,12 +3945,12 @@ class ProjectUpdateEventSerializer(JobEventSerializer):
return UriCleaner.remove_sensitive(obj.stdout)
def get_event_data(self, obj):
# the project update playbook uses the git, hg, or svn modules
# the project update playbook uses the git or svn modules
# to clone repositories, and those modules are prone to printing
# raw SCM URLs in their stdout (which *could* contain passwords)
# attempt to detect and filter HTTP basic auth passwords in the stdout
# of these types of events
if obj.event_data.get('task_action') in ('git', 'hg', 'svn'):
if obj.event_data.get('task_action') in ('git', 'svn'):
try:
return json.loads(
UriCleaner.remove_sensitive(

View File

@@ -4,7 +4,6 @@ The following lists the expected format and details of our rrules:
* DTSTART is expected to be in UTC
* INTERVAL is required
* SECONDLY is not supported
* TZID is not supported
* RRULE must precede the rule statements
* BYDAY is supported but not BYDAY with a numerical prefix
* BYYEARDAY and BYWEEKNO are not supported

View File

@@ -8,7 +8,7 @@ The `period` of the data can be adjusted with:
?period=month
Where `month` can be replaced with `week`, or `day`. `month` is the default.
Where `month` can be replaced with `week`, `two_weeks`, or `day`. `month` is the default.
The type of job can be filtered with:

View File

@@ -15,6 +15,7 @@ from awx.api.views import (
ApiV2PingView,
ApiV2ConfigView,
ApiV2SubscriptionView,
ApiV2AttachView,
AuthView,
UserMeList,
DashboardView,
@@ -94,6 +95,7 @@ v2_urls = [
url(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'),
url(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'),
url(r'^config/subscriptions/$', ApiV2SubscriptionView.as_view(), name='api_v2_subscription_view'),
url(r'^config/attach/$', ApiV2AttachView.as_view(), name='api_v2_attach_view'),
url(r'^auth/$', AuthView.as_view()),
url(r'^me/$', UserMeList.as_view(), name='user_me_list'),
url(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),

View File

@@ -153,6 +153,7 @@ from awx.api.views.root import ( # noqa
ApiV2PingView,
ApiV2ConfigView,
ApiV2SubscriptionView,
ApiV2AttachView,
)
from awx.api.views.webhooks import ( # noqa
WebhookKeyView,
@@ -241,8 +242,6 @@ class DashboardView(APIView):
git_failed_projects = git_projects.filter(last_job_failed=True)
svn_projects = user_projects.filter(scm_type='svn')
svn_failed_projects = svn_projects.filter(last_job_failed=True)
hg_projects = user_projects.filter(scm_type='hg')
hg_failed_projects = hg_projects.filter(last_job_failed=True)
archive_projects = user_projects.filter(scm_type='archive')
archive_failed_projects = archive_projects.filter(last_job_failed=True)
data['scm_types'] = {}
@@ -256,11 +255,6 @@ class DashboardView(APIView):
'failures_url': reverse('api:project_list', request=request) + "?scm_type=svn&last_job_failed=True",
'total': svn_projects.count(),
'failed': svn_failed_projects.count()}
data['scm_types']['hg'] = {'url': reverse('api:project_list', request=request) + "?scm_type=hg",
'label': 'Mercurial',
'failures_url': reverse('api:project_list', request=request) + "?scm_type=hg&last_job_failed=True",
'total': hg_projects.count(),
'failed': hg_failed_projects.count()}
data['scm_types']['archive'] = {'url': reverse('api:project_list', request=request) + "?scm_type=archive",
'label': 'Remote Archive',
'failures_url': reverse('api:project_list', request=request) + "?scm_type=archive&last_job_failed=True",
@@ -316,6 +310,9 @@ class DashboardJobsGraphView(APIView):
if period == 'month':
end_date = start_date - dateutil.relativedelta.relativedelta(months=1)
interval = 'days'
elif period == 'two_weeks':
end_date = start_date - dateutil.relativedelta.relativedelta(weeks=2)
interval = 'days'
elif period == 'week':
end_date = start_date - dateutil.relativedelta.relativedelta(weeks=1)
interval = 'days'
@@ -4253,7 +4250,9 @@ class NotificationTemplateDetail(RetrieveUpdateDestroyAPIView):
obj = self.get_object()
if not request.user.can_access(self.model, 'delete', obj):
return Response(status=status.HTTP_404_NOT_FOUND)
if obj.notifications.filter(status='pending').exists():
hours_old = now() - dateutil.relativedelta.relativedelta(hours=8)
if obj.notifications.filter(status='pending', created__gt=hours_old).exists():
return Response({"error": _("Delete not allowed while there are pending notifications")},
status=status.HTTP_405_METHOD_NOT_ALLOWED)
return super(NotificationTemplateDetail, self).delete(request, *args, **kwargs)

View File

@@ -1,9 +1,10 @@
# Copyright (c) 2018 Ansible, Inc.
# All Rights Reserved.
import base64
import json
import logging
import operator
import json
from collections import OrderedDict
from django.conf import settings
@@ -29,8 +30,8 @@ from awx.main.utils import (
get_custom_venv_choices,
to_python_boolean,
)
from awx.main.utils.licensing import validate_entitlement_manifest
from awx.api.versioning import reverse, drf_reverse
from awx.conf.license import get_license
from awx.main.constants import PRIVILEGE_ESCALATION_METHODS
from awx.main.models import (
Project,
@@ -178,7 +179,7 @@ class ApiV2PingView(APIView):
class ApiV2SubscriptionView(APIView):
permission_classes = (IsAuthenticated,)
name = _('Configuration')
name = _('Subscriptions')
swagger_topic = 'System Configuration'
def check_permissions(self, request):
@@ -189,18 +190,18 @@ class ApiV2SubscriptionView(APIView):
def post(self, request):
from awx.main.utils.common import get_licenser
data = request.data.copy()
if data.get('rh_password') == '$encrypted$':
data['rh_password'] = settings.REDHAT_PASSWORD
if data.get('subscriptions_password') == '$encrypted$':
data['subscriptions_password'] = settings.SUBSCRIPTIONS_PASSWORD
try:
user, pw = data.get('rh_username'), data.get('rh_password')
user, pw = data.get('subscriptions_username'), data.get('subscriptions_password')
with set_environ(**settings.AWX_TASK_ENV):
validated = get_licenser().validate_rh(user, pw)
if user:
settings.REDHAT_USERNAME = data['rh_username']
settings.SUBSCRIPTIONS_USERNAME = data['subscriptions_username']
if pw:
settings.REDHAT_PASSWORD = data['rh_password']
settings.SUBSCRIPTIONS_PASSWORD = data['subscriptions_password']
except Exception as exc:
msg = _("Invalid License")
msg = _("Invalid Subscription")
if (
isinstance(exc, requests.exceptions.HTTPError) and
getattr(getattr(exc, 'response', None), 'status_code', None) == 401
@@ -213,13 +214,63 @@ class ApiV2SubscriptionView(APIView):
elif isinstance(exc, (ValueError, OSError)) and exc.args:
msg = exc.args[0]
else:
logger.exception(smart_text(u"Invalid license submitted."),
logger.exception(smart_text(u"Invalid subscription submitted."),
extra=dict(actor=request.user.username))
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
return Response(validated)
class ApiV2AttachView(APIView):
permission_classes = (IsAuthenticated,)
name = _('Attach Subscription')
swagger_topic = 'System Configuration'
def check_permissions(self, request):
super(ApiV2AttachView, self).check_permissions(request)
if not request.user.is_superuser and request.method.lower() not in {'options', 'head'}:
self.permission_denied(request) # Raises PermissionDenied exception.
def post(self, request):
data = request.data.copy()
pool_id = data.get('pool_id', None)
if not pool_id:
return Response({"error": _("No subscription pool ID provided.")}, status=status.HTTP_400_BAD_REQUEST)
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:
with set_environ(**settings.AWX_TASK_ENV):
validated = get_licenser().validate_rh(user, pw)
except Exception as exc:
msg = _("Invalid Subscription")
if (
isinstance(exc, requests.exceptions.HTTPError) and
getattr(getattr(exc, 'response', None), 'status_code', None) == 401
):
msg = _("The provided credentials are invalid (HTTP 401).")
elif isinstance(exc, requests.exceptions.ProxyError):
msg = _("Unable to connect to proxy server.")
elif isinstance(exc, requests.exceptions.ConnectionError):
msg = _("Could not connect to subscription service.")
elif isinstance(exc, (ValueError, OSError)) and exc.args:
msg = exc.args[0]
else:
logger.exception(smart_text(u"Invalid subscription submitted."),
extra=dict(actor=request.user.username))
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
for sub in validated:
if sub['pool_id'] == pool_id:
sub['valid_key'] = True
settings.LICENSE = sub
return Response(sub)
return Response({"error": _("Error processing subscription metadata.")}, status=status.HTTP_400_BAD_REQUEST)
class ApiV2ConfigView(APIView):
permission_classes = (IsAuthenticated,)
@@ -234,15 +285,11 @@ class ApiV2ConfigView(APIView):
def get(self, request, format=None):
'''Return various sitewide configuration settings'''
if request.user.is_superuser or request.user.is_system_auditor:
license_data = get_license(show_key=True)
else:
license_data = get_license(show_key=False)
from awx.main.utils.common import get_licenser
license_data = get_licenser().validate()
if not license_data.get('valid_key', False):
license_data = {}
if license_data and 'features' in license_data and 'activity_streams' in license_data['features']:
# FIXME: Make the final setting value dependent on the feature?
license_data['features']['activity_streams'] &= settings.ACTIVITY_STREAM_ENABLED
pendo_state = settings.PENDO_TRACKING_STATE if settings.PENDO_TRACKING_STATE in ('off', 'anonymous', 'detailed') else 'off'
@@ -281,9 +328,10 @@ class ApiV2ConfigView(APIView):
return Response(data)
def post(self, request):
if not isinstance(request.data, dict):
return Response({"error": _("Invalid license data")}, status=status.HTTP_400_BAD_REQUEST)
return Response({"error": _("Invalid subscription data")}, status=status.HTTP_400_BAD_REQUEST)
if "eula_accepted" not in request.data:
return Response({"error": _("Missing 'eula_accepted' property")}, status=status.HTTP_400_BAD_REQUEST)
try:
@@ -300,25 +348,47 @@ 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)
try:
from awx.main.utils.common import get_licenser
license_data = json.loads(data_actual)
license_data_validated = get_licenser(**license_data).validate()
except Exception:
logger.warning(smart_text(u"Invalid license submitted."),
extra=dict(actor=request.user.username))
return Response({"error": _("Invalid License")}, 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)
if 'manifest' in license_data:
try:
json_actual = json.loads(base64.b64decode(license_data['manifest']))
if 'license_key' in json_actual:
return Response(
{"error": _('Legacy license submitted. A subscription manifest is now required.')},
status=status.HTTP_400_BAD_REQUEST
)
except Exception:
pass
try:
license_data = validate_entitlement_manifest(license_data['manifest'])
except ValueError as e:
return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)
except Exception:
logger.exception('Invalid manifest submitted. {}')
return Response({"error": _('Invalid manifest submitted.')}, status=status.HTTP_400_BAD_REQUEST)
try:
license_data_validated = get_licenser().license_from_manifest(license_data)
except Exception:
logger.warning(smart_text(u"Invalid subscription submitted."),
extra=dict(actor=request.user.username))
return Response({"error": _("Invalid License")}, status=status.HTTP_400_BAD_REQUEST)
else:
license_data_validated = get_licenser().validate()
# If the license is valid, write it to the database.
if license_data_validated['valid_key']:
settings.LICENSE = license_data
if not settings_registry.is_setting_read_only('TOWER_URL_BASE'):
settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host())
return Response(license_data_validated)
logger.warning(smart_text(u"Invalid license submitted."),
logger.warning(smart_text(u"Invalid subscription submitted."),
extra=dict(actor=request.user.username))
return Response({"error": _("Invalid license")}, status=status.HTTP_400_BAD_REQUEST)
return Response({"error": _("Invalid subscription")}, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request):
try:

View File

@@ -25,10 +25,12 @@ if MODE == 'production':
try:
fd = open("/var/lib/awx/.tower_version", "r")
if fd.read().strip() != tower_version:
raise Exception()
except Exception:
raise ValueError()
except FileNotFoundError:
pass
except ValueError as e:
logger.error("Missing or incorrect metadata for Tower version. Ensure Tower was installed using the setup playbook.")
raise Exception("Missing or incorrect metadata for Tower version. Ensure Tower was installed using the setup playbook.")
raise Exception("Missing or incorrect metadata for Tower version. Ensure Tower was installed using the setup playbook.") from e
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "awx.settings")

View File

@@ -1,18 +1,14 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved.
__all__ = ['get_license']
def _get_validated_license_data():
from awx.main.utils.common import get_licenser
from awx.main.utils import get_licenser
return get_licenser().validate()
def get_license(show_key=False):
def get_license():
"""Return a dictionary representing the active license on this Tower instance."""
license_data = _get_validated_license_data()
if not show_key:
license_data.pop('license_key', None)
return license_data
return _get_validated_license_data()

View File

@@ -0,0 +1,26 @@
# Generated by Django 2.2.11 on 2020-08-04 15:19
import logging
from django.db import migrations
from awx.conf.migrations._subscriptions import clear_old_license, prefill_rh_credentials
logger = logging.getLogger('awx.conf.migrations')
def _noop(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('conf', '0007_v380_rename_more_settings'),
]
operations = [
migrations.RunPython(clear_old_license, _noop),
migrations.RunPython(prefill_rh_credentials, _noop)
]

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
import logging
from django.utils.timezone import now
from awx.main.utils.encryption import decrypt_field, encrypt_field
logger = logging.getLogger('awx.conf.settings')
__all__ = ['clear_old_license', 'prefill_rh_credentials']
def clear_old_license(apps, schema_editor):
Setting = apps.get_model('conf', 'Setting')
Setting.objects.filter(key='LICENSE').delete()
def _migrate_setting(apps, old_key, new_key, encrypted=False):
Setting = apps.get_model('conf', 'Setting')
if not Setting.objects.filter(key=old_key).exists():
return
new_setting = Setting.objects.create(key=new_key,
created=now(),
modified=now()
)
if encrypted:
new_setting.value = decrypt_field(Setting.objects.filter(key=old_key).first(), 'value')
new_setting.value = encrypt_field(new_setting, 'value')
else:
new_setting.value = getattr(Setting.objects.filter(key=old_key).first(), 'value')
new_setting.save()
def prefill_rh_credentials(apps, schema_editor):
_migrate_setting(apps, 'REDHAT_USERNAME', 'SUBSCRIPTIONS_USERNAME', encrypted=False)
_migrate_setting(apps, 'REDHAT_PASSWORD', 'SUBSCRIPTIONS_PASSWORD', encrypted=True)

View File

@@ -78,14 +78,6 @@ class Setting(CreatedModifiedModel):
def get_cache_id_key(self, key):
return '{}_ID'.format(key)
def display_value(self):
if self.key == 'LICENSE' and 'license_key' in self.value:
# don't log the license key in activity stream
value = self.value.copy()
value['license_key'] = '********'
return value
return self.value
import awx.conf.signals # noqa

View File

@@ -4,6 +4,7 @@ import logging
import sys
import threading
import time
import os
# Django
from django.conf import LazySettings
@@ -247,6 +248,7 @@ class SettingsWrapper(UserSettingsHolder):
# These values have to be stored via self.__dict__ in this way to get
# around the magic __setattr__ method on this class (which is used to
# store API-assigned settings in the database).
self.__dict__['__forks__'] = {}
self.__dict__['default_settings'] = default_settings
self.__dict__['_awx_conf_settings'] = self
self.__dict__['_awx_conf_preload_expires'] = None
@@ -255,6 +257,26 @@ class SettingsWrapper(UserSettingsHolder):
self.__dict__['cache'] = EncryptedCacheProxy(cache, registry)
self.__dict__['registry'] = registry
# record the current pid so we compare it post-fork for
# processes like the dispatcher and callback receiver
self.__dict__['pid'] = os.getpid()
def __clean_on_fork__(self):
pid = os.getpid()
# if the current pid does *not* match the value on self, it means
# that value was copied on fork, and we're now in a *forked* process;
# the *first* time we enter this code path (on setting access),
# forcibly close DB/cache sockets and set a marker so we don't run
# this code again _in this process_
#
if pid != self.__dict__['pid'] and pid not in self.__dict__['__forks__']:
self.__dict__['__forks__'][pid] = True
# It's important to close these post-fork, because we
# don't want the forked processes to inherit the open sockets
# for the DB and cache connections (that way lies race conditions)
connection.close()
django_cache.close()
@cached_property
def all_supported_settings(self):
return self.registry.get_registered_settings()
@@ -330,6 +352,7 @@ class SettingsWrapper(UserSettingsHolder):
self.cache.set_many(settings_to_cache, timeout=SETTING_CACHE_TIMEOUT)
def _get_local(self, name, validate=True):
self.__clean_on_fork__()
self._preload_cache()
cache_key = Setting.get_cache_key(name)
try:

View File

@@ -3354,6 +3354,15 @@ msgid ""
"common scenarios."
msgstr ""
#: awx/main/models/credential/__init__.py:824
msgid "Region Name"
msgstr ""
#: awx/main/models/credential/__init__.py:826
msgid ""
"For some cloud providers, like OVH, region must be specified."
msgstr ""
#: awx/main/models/credential/__init__.py:824
#: awx/main/models/credential/__init__.py:1131
#: awx/main/models/credential/__init__.py:1166

View File

@@ -3354,6 +3354,15 @@ msgid ""
"common scenarios."
msgstr ""
#: awx/main/models/credential/__init__.py:824
msgid "Region Name"
msgstr ""
#: awx/main/models/credential/__init__.py:826
msgid ""
"For some cloud providers, like OVH, region must be specified."
msgstr ""
#: awx/main/models/credential/__init__.py:824
#: awx/main/models/credential/__init__.py:1131
#: awx/main/models/credential/__init__.py:1166

View File

@@ -3294,6 +3294,16 @@ msgid ""
"common scenarios."
msgstr "Les domaines OpenStack définissent les limites administratives. Ils sont nécessaires uniquement pour les URL dauthentification Keystone v3. Voir la documentation Ansible Tower pour les scénarios courants."
#: awx/main/models/credential/__init__.py:824
msgid "Region Name"
msgstr "Nom de la region"
#: awx/main/models/credential/__init__.py:826
msgid ""
"For some cloud providers, like OVH, region must be specified."
msgstr ""
"Chez certains fournisseurs, comme OVH, vous devez spécifier le nom de la région"
#: awx/main/models/credential/__init__.py:812
#: awx/main/models/credential/__init__.py:1110
#: awx/main/models/credential/__init__.py:1144

View File

@@ -333,14 +333,14 @@ class BaseAccess(object):
report_violation(_("License has expired."))
free_instances = validation_info.get('free_instances', 0)
available_instances = validation_info.get('available_instances', 0)
instance_count = validation_info.get('instance_count', 0)
if add_host_name:
host_exists = Host.objects.filter(name=add_host_name).exists()
if not host_exists and free_instances == 0:
report_violation(_("License count of %s instances has been reached.") % available_instances)
report_violation(_("License count of %s instances has been reached.") % instance_count)
elif not host_exists and free_instances < 0:
report_violation(_("License count of %s instances has been exceeded.") % available_instances)
report_violation(_("License count of %s instances has been exceeded.") % instance_count)
elif not add_host_name and free_instances < 0:
report_violation(_("Host count exceeds available instances."))

View File

@@ -33,9 +33,9 @@ data _since_ the last report date - i.e., new data in the last 24 hours)
'''
@register('config', '1.1', description=_('General platform configuration.'))
@register('config', '1.2', description=_('General platform configuration.'))
def config(since, **kwargs):
license_info = get_license(show_key=False)
license_info = get_license()
install_type = 'traditional'
if os.environ.get('container') == 'oci':
install_type = 'openshift'
@@ -194,7 +194,6 @@ def instance_info(since, include_hostnames=False, **kwargs):
return info
@register('job_counts', '1.0', description=_('Counts of jobs by status'))
def job_counts(since, **kwargs):
counts = {}
counts['total_jobs'] = models.UnifiedJob.objects.exclude(launch_type='sync').count()
@@ -204,7 +203,6 @@ def job_counts(since, **kwargs):
return counts
@register('job_instance_counts', '1.0', description=_('Counts of jobs by execution node'))
def job_instance_counts(since, **kwargs):
counts = {}
job_types = models.UnifiedJob.objects.exclude(launch_type='sync').values_list(
@@ -282,14 +280,16 @@ def _copy_table(table, query, path):
return file.file_list()
@register('events_table', '1.1', format='csv', description=_('Automation task records'), expensive=True)
@register('events_table', '1.2', format='csv', description=_('Automation task records'), expensive=True)
def events_table(since, full_path, until, **kwargs):
events_query = '''COPY (SELECT main_jobevent.id,
main_jobevent.created,
main_jobevent.modified,
main_jobevent.uuid,
main_jobevent.parent_uuid,
main_jobevent.event,
main_jobevent.event_data::json->'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,

View File

@@ -24,7 +24,7 @@ logger = logging.getLogger('awx.main.analytics')
def _valid_license():
try:
if get_license(show_key=False).get('license_type', 'UNLICENSED') == 'open':
if get_license().get('license_type', 'UNLICENSED') == 'open':
return False
access_registry[Job](None).check_license()
except PermissionDenied:
@@ -68,7 +68,7 @@ def register(key, version, description=None, format='json', expensive=False):
@register('projects_by_scm_type', 1)
def projects_by_scm_type():
return {'git': 5, 'svn': 1, 'hg': 0}
return {'git': 5, 'svn': 1}
"""
def decorate(f):
@@ -102,7 +102,7 @@ def gather(dest=None, module=None, subset = None, since = None, until = now(), c
last_run = since or settings.AUTOMATION_ANALYTICS_LAST_GATHER or (now() - timedelta(weeks=4))
logger.debug("Last analytics run was: {}".format(settings.AUTOMATION_ANALYTICS_LAST_GATHER))
if _valid_license() is False:
logger.exception("Invalid License provided, or No License Provided")
return None

View File

@@ -12,7 +12,7 @@ from prometheus_client import (
from awx.conf.license import get_license
from awx.main.utils import (get_awx_version, get_ansible_version)
from awx.main.analytics.collectors import (
counts,
counts,
instance_info,
job_instance_counts,
job_counts,
@@ -54,7 +54,7 @@ LICENSE_INSTANCE_FREE = Gauge('awx_license_instance_free', 'Number of remaining
def metrics():
license_info = get_license(show_key=False)
license_info = get_license()
SYSTEM_INFO.info({
'install_uuid': settings.INSTALL_UUID,
'insights_analytics': str(settings.INSIGHTS_TRACKING_STATE),
@@ -68,7 +68,7 @@ def metrics():
'external_logger_type': getattr(settings, 'LOG_AGGREGATOR_TYPE', 'None')
})
LICENSE_INSTANCE_TOTAL.set(str(license_info.get('available_instances', 0)))
LICENSE_INSTANCE_TOTAL.set(str(license_info.get('instance_count', 0)))
LICENSE_INSTANCE_FREE.set(str(license_info.get('free_instances', 0)))
current_counts = counts(None)

View File

@@ -1,7 +1,5 @@
# Python
import json
import logging
import os
# Django
from django.utils.translation import ugettext_lazy as _
@@ -13,6 +11,7 @@ from rest_framework.fields import FloatField
# Tower
from awx.conf import fields, register, register_validate
logger = logging.getLogger('awx.main.conf')
register(
@@ -92,22 +91,10 @@ register(
)
def _load_default_license_from_file():
try:
license_file = os.environ.get('AWX_LICENSE_FILE', '/etc/tower/license')
if os.path.exists(license_file):
license_data = json.load(open(license_file))
logger.debug('Read license data from "%s".', license_file)
return license_data
except Exception:
logger.warning('Could not read license from "%s".', license_file, exc_info=True)
return {}
register(
'LICENSE',
field_class=fields.DictField,
default=_load_default_license_from_file,
default=lambda: {},
label=_('License'),
help_text=_('The license controls which features and functionality are '
'enabled. Use /api/v2/config/ to update or change '
@@ -124,7 +111,7 @@ register(
encrypted=False,
read_only=False,
label=_('Red Hat customer username'),
help_text=_('This username is used to retrieve license information and to send Automation Analytics'), # noqa
help_text=_('This username is used to send data to Automation Analytics'),
category=_('System'),
category_slug='system',
)
@@ -137,7 +124,33 @@ register(
encrypted=True,
read_only=False,
label=_('Red Hat customer password'),
help_text=_('This password is used to retrieve license information and to send Automation Analytics'), # noqa
help_text=_('This password is used to send data to Automation Analytics'),
category=_('System'),
category_slug='system',
)
register(
'SUBSCRIPTIONS_USERNAME',
field_class=fields.CharField,
default='',
allow_blank=True,
encrypted=False,
read_only=False,
label=_('Red Hat or Satellite username'),
help_text=_('This username is used to retrieve subscription and content information'), # noqa
category=_('System'),
category_slug='system',
)
register(
'SUBSCRIPTIONS_PASSWORD',
field_class=fields.CharField,
default='',
allow_blank=True,
encrypted=True,
read_only=False,
label=_('Red Hat or Satellite password'),
help_text=_('This password is used to retrieve subscription and content information'), # noqa
category=_('System'),
category_slug='system',
)

View File

@@ -75,7 +75,7 @@ class WebsocketSecretAuthHelper:
nonce_diff = now - nonce_parsed
if abs(nonce_diff) > nonce_tolerance:
logger.warn(f"Potential replay attack or machine(s) time out of sync by {nonce_diff} seconds.")
raise ValueError("Potential replay attack or machine(s) time out of sync by {nonce_diff} seconds.")
raise ValueError(f"Potential replay attack or machine(s) time out of sync by {nonce_diff} seconds.")
return True

View File

@@ -1,10 +1,7 @@
import cProfile
import json
import logging
import os
import pstats
import signal
import tempfile
import time
import traceback
@@ -23,6 +20,7 @@ from awx.main.models import (JobEvent, AdHocCommandEvent, ProjectUpdateEvent,
Job)
from awx.main.tasks import handle_success_and_failure_notifications
from awx.main.models.events import emit_event_detail
from awx.main.utils.profiling import AWXProfiler
from .base import BaseWorker
@@ -40,6 +38,7 @@ class CallbackBrokerWorker(BaseWorker):
MAX_RETRIES = 2
last_stats = time.time()
last_flush = time.time()
total = 0
last_event = ''
prof = None
@@ -48,12 +47,13 @@ class CallbackBrokerWorker(BaseWorker):
self.buff = {}
self.pid = os.getpid()
self.redis = redis.Redis.from_url(settings.BROKER_URL)
self.prof = AWXProfiler("CallbackBrokerWorker")
for key in self.redis.keys('awx_callback_receiver_statistics_*'):
self.redis.delete(key)
def read(self, queue):
try:
res = self.redis.blpop(settings.CALLBACK_QUEUE, timeout=settings.JOB_EVENT_BUFFER_SECONDS)
res = self.redis.blpop(settings.CALLBACK_QUEUE, timeout=1)
if res is None:
return {'event': 'FLUSH'}
self.total += 1
@@ -87,19 +87,12 @@ class CallbackBrokerWorker(BaseWorker):
)
def toggle_profiling(self, *args):
if self.prof:
self.prof.disable()
filename = f'callback-{self.pid}.pstats'
filepath = os.path.join(tempfile.gettempdir(), filename)
with open(filepath, 'w') as f:
pstats.Stats(self.prof, stream=f).sort_stats('cumulative').print_stats()
pstats.Stats(self.prof).dump_stats(filepath + '.raw')
self.prof = False
logger.error(f'profiling is disabled, wrote {filepath}')
else:
self.prof = cProfile.Profile()
self.prof.enable()
if not self.prof.is_started():
self.prof.start()
logger.error('profiling is enabled')
else:
filepath = self.prof.stop()
logger.error(f'profiling is disabled, wrote {filepath}')
def work_loop(self, *args, **kw):
if settings.AWX_CALLBACK_PROFILE:
@@ -110,6 +103,7 @@ class CallbackBrokerWorker(BaseWorker):
now = tz_now()
if (
force or
(time.time() - self.last_flush) > settings.JOB_EVENT_BUFFER_SECONDS or
any([len(events) >= 1000 for events in self.buff.values()])
):
for cls, events in self.buff.items():
@@ -132,6 +126,7 @@ class CallbackBrokerWorker(BaseWorker):
for e in events:
emit_event_detail(e)
self.buff = {}
self.last_flush = time.time()
def perform_work(self, body):
try:

View File

@@ -30,3 +30,10 @@ class _AwxTaskError():
AwxTaskError = _AwxTaskError()
class PostRunError(Exception):
def __init__(self, msg, status='failed', tb=''):
self.status = status
self.tb = tb
super(PostRunError, self).__init__(msg)

View File

@@ -7,6 +7,7 @@ import tempfile
import time
import logging
import yaml
import datetime
from django.conf import settings
import ansible_runner
@@ -123,6 +124,7 @@ class IsolatedManager(object):
dir=private_data_dir
)
params = self.runner_params.copy()
params.get('envvars', dict())['ANSIBLE_CALLBACK_WHITELIST'] = 'profile_tasks'
params['playbook'] = playbook
params['private_data_dir'] = iso_dir
if idle_timeout:
@@ -149,7 +151,6 @@ class IsolatedManager(object):
# don't rsync source control metadata (it can be huge!)
'- /project/.git',
'- /project/.svn',
'- /project/.hg',
# don't rsync job events that are in the process of being written
'- /artifacts/job_events/*-partial.json.tmp',
# don't rsync the ssh_key FIFO
@@ -169,7 +170,8 @@ class IsolatedManager(object):
extravars = {
'src': self.private_data_dir,
'dest': settings.AWX_PROOT_BASE_PATH,
'ident': self.ident
'ident': self.ident,
'job_id': self.instance.id,
}
if playbook:
extravars['playbook'] = playbook
@@ -205,7 +207,10 @@ class IsolatedManager(object):
:param interval: an interval (in seconds) to wait between status polls
"""
interval = interval if interval is not None else settings.AWX_ISOLATED_CHECK_INTERVAL
extravars = {'src': self.private_data_dir}
extravars = {
'src': self.private_data_dir,
'job_id': self.instance.id
}
status = 'failed'
rc = None
last_check = time.time()
@@ -221,9 +226,13 @@ class IsolatedManager(object):
logger.warning('Isolated job {} was manually canceled.'.format(self.instance.id))
logger.debug('Checking on isolated job {} with `check_isolated.yml`.'.format(self.instance.id))
time_start = datetime.datetime.now()
runner_obj = self.run_management_playbook('check_isolated.yml',
self.private_data_dir,
extravars=extravars)
time_end = datetime.datetime.now()
time_diff = time_end - time_start
logger.debug('Finished checking on isolated job {} with `check_isolated.yml` took {} seconds.'.format(self.instance.id, time_diff.total_seconds()))
status, rc = runner_obj.status, runner_obj.rc
if self.check_callback is not None and not self.captured_command_artifact:

View File

@@ -18,7 +18,5 @@ class Command(BaseCommand):
super(Command, self).__init__()
license = get_licenser().validate()
if options.get('data'):
if license.get('license_key', '') != 'UNLICENSED':
license['license_key'] = '********'
return json.dumps(license)
return license.get('license_type', 'none')

View File

@@ -8,5 +8,7 @@ class Command(MakeMigrations):
def execute(self, *args, **options):
settings = connections['default'].settings_dict.copy()
settings['ENGINE'] = 'sqlite3'
if 'application_name' in settings['OPTIONS']:
del settings['OPTIONS']['application_name']
connections['default'] = DatabaseWrapper(settings)
return MakeMigrations().execute(*args, **options)

View File

@@ -21,7 +21,7 @@ from awx.main.signals import (
disable_computed_fields
)
from awx.main.management.commands.deletion import AWXCollector, pre_delete
from awx.main.utils.deletion import AWXCollector, pre_delete
class Command(BaseCommand):

View File

@@ -0,0 +1,117 @@
# Python
import asciichartpy as chart
import collections
import time
import sys
# Django
from django.db.models import Count
from django.core.management.base import BaseCommand
# AWX
from awx.main.models import (
Job,
Instance
)
DEFAULT_WIDTH = 100
DEFAULT_HEIGHT = 30
def chart_color_lookup(color_str):
return getattr(chart, color_str)
def clear_screen():
print(chr(27) + "[2J")
class JobStatus():
def __init__(self, status, color, width):
self.status = status
self.color = color
self.color_code = chart_color_lookup(color)
self.x = collections.deque(maxlen=width)
self.y = collections.deque(maxlen=width)
def tick(self, x, y):
self.x.append(x)
self.y.append(y)
class JobStatusController:
RESET = chart_color_lookup('reset')
def __init__(self, width):
self.plots = [
JobStatus('pending', 'red', width),
JobStatus('waiting', 'blue', width),
JobStatus('running', 'green', width)
]
self.ts_start = int(time.time())
def tick(self):
ts = int(time.time()) - self.ts_start
q = Job.objects.filter(status__in=['pending','waiting','running']).values_list('status').order_by().annotate(Count('status'))
status_count = dict(pending=0, waiting=0, running=0)
for status, count in q:
status_count[status] = count
for p in self.plots:
p.tick(ts, status_count[p.status])
def series(self):
return [list(p.y) for p in self.plots]
def generate_status(self):
line = ""
lines = []
for p in self.plots:
lines.append(f'{p.color_code}{p.status} {p.y[-1]}{self.RESET}')
line += ", ".join(lines) + '\n'
width = 5
time_running = int(time.time()) - self.ts_start
instances = Instance.objects.all().order_by('hostname')
line += "Capacity: " + ", ".join([f"{instance.capacity:{width}}" for instance in instances]) + '\n'
line += "Remaining: " + ", ".join([f"{instance.remaining_capacity:{width}}" for instance in instances]) + '\n'
line += f"Seconds running: {time_running}" + '\n'
return line
class Command(BaseCommand):
help = "Plot pending, waiting, running jobs over time on the terminal"
def add_arguments(self, parser):
parser.add_argument('--refresh', dest='refresh', type=float, default=1.0,
help='Time between refreshes of the graph and data in seconds (defaults to 1.0)')
parser.add_argument('--width', dest='width', type=int, default=DEFAULT_WIDTH,
help=f'Width of the graph (defaults to {DEFAULT_WIDTH})')
parser.add_argument('--height', dest='height', type=int, default=DEFAULT_HEIGHT,
help=f'Height of the graph (defaults to {DEFAULT_HEIGHT})')
def handle(self, *args, **options):
refresh_seconds = options['refresh']
width = options['width']
height = options['height']
jctl = JobStatusController(width)
conf = {
'colors': [chart_color_lookup(p.color) for p in jctl.plots],
'height': height,
}
while True:
jctl.tick()
draw = chart.plot(jctl.series(), conf)
status_line = jctl.generate_status()
clear_screen()
print(draw)
sys.stdout.write(status_line)
time.sleep(refresh_seconds)

View File

@@ -19,6 +19,9 @@ from django.core.management.base import BaseCommand, CommandError
from django.db import connection, transaction
from django.utils.encoding import smart_text
# DRF error class to distinguish license exceptions
from rest_framework.exceptions import PermissionDenied
# AWX inventory imports
from awx.main.models.inventory import (
Inventory,
@@ -31,11 +34,12 @@ from awx.main.utils.safe_yaml import sanitize_jinja
# other AWX imports
from awx.main.models.rbac import batch_role_ancestor_rebuilding
# TODO: remove proot utils once we move to running inv. updates in containers
from awx.main.utils import (
ignore_inventory_computed_fields,
check_proot_installed,
wrap_args_with_proot,
build_proot_temp_dir,
ignore_inventory_computed_fields,
get_licenser
)
from awx.main.signals import disable_activity_stream
@@ -53,11 +57,11 @@ No license.
See http://www.ansible.com/renew for license information.'''
LICENSE_MESSAGE = '''\
Number of licensed instances exceeded, would bring available instances to %(new_count)d, system is licensed for %(available_instances)d.
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.'''
DEMO_LICENSE_MESSAGE = '''\
Demo mode free license count exceeded, would bring available instances to %(new_count)d, demo mode allows %(available_instances)d.
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.'''
@@ -75,13 +79,11 @@ class AnsibleInventoryLoader(object):
/usr/bin/ansible/ansible-inventory -i hosts --list
'''
def __init__(self, source, is_custom=False, venv_path=None, verbosity=0):
def __init__(self, source, venv_path=None, verbosity=0):
self.source = source
self.source_dir = functioning_dir(self.source)
self.is_custom = is_custom
self.tmp_private_dir = None
self.method = 'ansible-inventory'
self.verbosity = verbosity
# TODO: remove once proot has been removed
self.tmp_private_dir = None
if venv_path:
self.venv_path = venv_path
else:
@@ -131,38 +133,34 @@ class AnsibleInventoryLoader(object):
# NOTE: why do we add "python" to the start of these args?
# the script that runs ansible-inventory specifies a python interpreter
# that makes no sense in light of the fact that we put all the dependencies
# inside of /venv/ansible, so we override the specified interpreter
# inside of /var/lib/awx/venv/ansible, so we override the specified interpreter
# https://github.com/ansible/ansible/issues/50714
bargs = ['python', ansible_inventory_path, '-i', self.source]
bargs.extend(['--playbook-dir', self.source_dir])
bargs.extend(['--playbook-dir', functioning_dir(self.source)])
if self.verbosity:
# INFO: -vvv, DEBUG: -vvvvv, for inventory, any more than 3 makes little difference
bargs.append('-{}'.format('v' * min(5, self.verbosity * 2 + 1)))
logger.debug('Using base command: {}'.format(' '.join(bargs)))
return bargs
# TODO: Remove this once we move to running ansible-inventory in containers
# and don't need proot for process isolation anymore
def get_proot_args(self, cmd, env):
cwd = os.getcwd()
if not check_proot_installed():
raise RuntimeError("proot is not installed but is configured for use")
kwargs = {}
if self.is_custom:
# use source's tmp dir for proot, task manager will delete folder
logger.debug("Using provided directory '{}' for isolation.".format(self.source_dir))
kwargs['proot_temp_dir'] = self.source_dir
cwd = self.source_dir
else:
# we cannot safely store tmp data in source dir or trust script contents
if env['AWX_PRIVATE_DATA_DIR']:
# If this is non-blank, file credentials are being used and we need access
private_data_dir = functioning_dir(env['AWX_PRIVATE_DATA_DIR'])
logger.debug("Using private credential data in '{}'.".format(private_data_dir))
kwargs['private_data_dir'] = private_data_dir
self.tmp_private_dir = build_proot_temp_dir()
logger.debug("Using fresh temporary directory '{}' for isolation.".format(self.tmp_private_dir))
kwargs['proot_temp_dir'] = self.tmp_private_dir
kwargs['proot_show_paths'] = [functioning_dir(self.source), settings.AWX_ANSIBLE_COLLECTIONS_PATHS]
# we cannot safely store tmp data in source dir or trust script contents
if env['AWX_PRIVATE_DATA_DIR']:
# If this is non-blank, file credentials are being used and we need access
private_data_dir = functioning_dir(env['AWX_PRIVATE_DATA_DIR'])
logger.debug("Using private credential data in '{}'.".format(private_data_dir))
kwargs['private_data_dir'] = private_data_dir
self.tmp_private_dir = build_proot_temp_dir()
logger.debug("Using fresh temporary directory '{}' for isolation.".format(self.tmp_private_dir))
kwargs['proot_temp_dir'] = self.tmp_private_dir
kwargs['proot_show_paths'] = [functioning_dir(self.source), settings.AWX_ANSIBLE_COLLECTIONS_PATHS]
logger.debug("Running from `{}` working directory.".format(cwd))
if self.venv_path != settings.ANSIBLE_VENV_PATH:
@@ -170,12 +168,14 @@ class AnsibleInventoryLoader(object):
return wrap_args_with_proot(cmd, cwd, **kwargs)
def command_to_json(self, cmd):
data = {}
stdout, stderr = '', ''
env = self.build_env()
if ((self.is_custom or 'AWX_PRIVATE_DATA_DIR' in env) and
# TODO: remove proot args once inv. updates run in containers
if (('AWX_PRIVATE_DATA_DIR' in env) and
getattr(settings, 'AWX_PROOT_ENABLED', False)):
cmd = self.get_proot_args(cmd, env)
@@ -184,11 +184,13 @@ class AnsibleInventoryLoader(object):
stdout = smart_text(stdout)
stderr = smart_text(stderr)
# TODO: can be removed when proot is removed
if self.tmp_private_dir:
shutil.rmtree(self.tmp_private_dir, True)
if proc.returncode != 0:
raise RuntimeError('%s failed (rc=%d) with stdout:\n%s\nstderr:\n%s' % (
self.method, proc.returncode, stdout, stderr))
'ansible-inventory', proc.returncode, stdout, stderr))
for line in stderr.splitlines():
logger.error(line)
@@ -231,9 +233,9 @@ class Command(BaseCommand):
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='use database variables if set')
help='DEPRECATED legacy option, has no effect')
parser.add_argument('--custom', dest='custom', action='store_true', default=False,
help='this is a custom inventory script')
help='DEPRECATED indicates a custom inventory script, no longer used')
parser.add_argument('--source', dest='source', type=str, default=None,
metavar='s', help='inventory directory, file, or script to load')
parser.add_argument('--enabled-var', dest='enabled_var', type=str,
@@ -259,10 +261,10 @@ class Command(BaseCommand):
'specifies the unique, immutable instance ID, may be '
'specified as "foo.bar" to traverse nested dicts.')
def set_logging_level(self):
def set_logging_level(self, verbosity):
log_levels = dict(enumerate([logging.WARNING, logging.INFO,
logging.DEBUG, 0]))
logger.setLevel(log_levels.get(self.verbosity, 0))
logger.setLevel(log_levels.get(verbosity, 0))
def _get_instance_id(self, variables, default=''):
'''
@@ -322,7 +324,8 @@ class Command(BaseCommand):
else:
raise NotImplementedError('Value of enabled {} not understood.'.format(enabled))
def get_source_absolute_path(self, source):
@staticmethod
def get_source_absolute_path(source):
if not os.path.exists(source):
raise IOError('Source does not exist: %s' % source)
source = os.path.join(os.getcwd(), os.path.dirname(source),
@@ -330,61 +333,6 @@ class Command(BaseCommand):
source = os.path.normpath(os.path.abspath(source))
return source
def load_inventory_from_database(self):
'''
Load inventory and related objects from the database.
'''
# Load inventory object based on name or ID.
if self.inventory_id:
q = dict(id=self.inventory_id)
else:
q = dict(name=self.inventory_name)
try:
self.inventory = Inventory.objects.get(**q)
except Inventory.DoesNotExist:
raise CommandError('Inventory with %s = %s cannot be found' % list(q.items())[0])
except Inventory.MultipleObjectsReturned:
raise CommandError('Inventory with %s = %s returned multiple results' % list(q.items())[0])
logger.info('Updating inventory %d: %s' % (self.inventory.pk,
self.inventory.name))
# Load inventory source if specified via environment variable (when
# inventory_import is called from an InventoryUpdate task).
inventory_source_id = os.getenv('INVENTORY_SOURCE_ID', None)
inventory_update_id = os.getenv('INVENTORY_UPDATE_ID', None)
if inventory_source_id:
try:
self.inventory_source = InventorySource.objects.get(pk=inventory_source_id,
inventory=self.inventory)
except InventorySource.DoesNotExist:
raise CommandError('Inventory source with id=%s not found' %
inventory_source_id)
try:
self.inventory_update = InventoryUpdate.objects.get(pk=inventory_update_id)
except InventoryUpdate.DoesNotExist:
raise CommandError('Inventory update with id=%s not found' %
inventory_update_id)
# Otherwise, create a new inventory source to capture this invocation
# via command line.
else:
with ignore_inventory_computed_fields():
self.inventory_source, created = InventorySource.objects.get_or_create(
inventory=self.inventory,
source='file',
source_path=os.path.abspath(self.source),
overwrite=self.overwrite,
overwrite_vars=self.overwrite_vars,
)
self.inventory_update = self.inventory_source.create_inventory_update(
_eager_fields=dict(
job_args=json.dumps(sys.argv),
job_env=dict(os.environ.items()),
job_cwd=os.getcwd())
)
# FIXME: Wait or raise error if inventory is being updated by another
# source.
def _batch_add_m2m(self, related_manager, *objs, **kwargs):
key = (related_manager.instance.pk, related_manager.through._meta.db_table)
flush = bool(kwargs.get('flush', False))
@@ -894,21 +842,21 @@ class Command(BaseCommand):
source_vars = self.all_group.variables
remote_license_type = source_vars.get('tower_metadata', {}).get('license_type', None)
if remote_license_type is None:
raise CommandError('Unexpected Error: Tower inventory plugin missing needed metadata!')
raise PermissionDenied('Unexpected Error: Tower inventory plugin missing needed metadata!')
if local_license_type != remote_license_type:
raise CommandError('Tower server licenses must match: source: {} local: {}'.format(
raise PermissionDenied('Tower server licenses must match: source: {} local: {}'.format(
remote_license_type, local_license_type
))
def check_license(self):
license_info = get_licenser().validate()
local_license_type = license_info.get('license_type', 'UNLICENSED')
if license_info.get('license_key', 'UNLICENSED') == 'UNLICENSED':
if local_license_type == 'UNLICENSED':
logger.error(LICENSE_NON_EXISTANT_MESSAGE)
raise CommandError('No license found!')
raise PermissionDenied('No license found!')
elif local_license_type == 'open':
return
available_instances = license_info.get('available_instances', 0)
instance_count = license_info.get('instance_count', 0)
free_instances = license_info.get('free_instances', 0)
time_remaining = license_info.get('time_remaining', 0)
hard_error = license_info.get('trial', False) is True or license_info['instance_count'] == 10
@@ -916,24 +864,24 @@ class Command(BaseCommand):
if time_remaining <= 0:
if hard_error:
logger.error(LICENSE_EXPIRED_MESSAGE)
raise CommandError("License has expired!")
raise PermissionDenied("License 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.source for f in TOWER_SOURCE_FILES):
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,
'available_instances': available_instances,
'instance_count': instance_count,
}
if hard_error:
logger.error(LICENSE_MESSAGE % d)
raise CommandError('License count exceeded!')
raise PermissionDenied('License count exceeded!')
else:
logger.warning(LICENSE_MESSAGE % d)
@@ -948,7 +896,7 @@ class Command(BaseCommand):
active_count = Host.objects.org_active_count(org.id)
if active_count > org.max_hosts:
raise CommandError('Host limit for organization exceeded!')
raise PermissionDenied('Host limit for organization exceeded!')
def mark_license_failure(self, save=True):
self.inventory_update.license_error = True
@@ -959,16 +907,103 @@ class Command(BaseCommand):
self.inventory_update.save(update_fields=['org_host_limit_error'])
def handle(self, *args, **options):
self.verbosity = int(options.get('verbosity', 1))
self.set_logging_level()
self.inventory_name = options.get('inventory_name', None)
self.inventory_id = options.get('inventory_id', None)
venv_path = options.get('venv', None)
# Load inventory and related objects from database.
inventory_name = options.get('inventory_name', None)
inventory_id = options.get('inventory_id', None)
if inventory_name and inventory_id:
raise CommandError('--inventory-name and --inventory-id are mutually exclusive')
elif not inventory_name and not inventory_id:
raise CommandError('--inventory-name or --inventory-id is required')
with advisory_lock('inventory_{}_import'.format(inventory_id)):
# Obtain rest of the options needed to run update
raw_source = options.get('source', None)
if not raw_source:
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:
q = dict(id=inventory_id)
else:
q = dict(name=inventory_name)
try:
inventory = Inventory.objects.get(**q)
except Inventory.DoesNotExist:
raise CommandError('Inventory with %s = %s cannot be found' % list(q.items())[0])
except Inventory.MultipleObjectsReturned:
raise CommandError('Inventory with %s = %s returned multiple results' % list(q.items())[0])
logger.info('Updating inventory %d: %s' % (inventory.pk, inventory.name))
# Create ad-hoc inventory source and inventory update objects
with ignore_inventory_computed_fields():
source = Command.get_source_absolute_path(raw_source)
inventory_source, created = InventorySource.objects.get_or_create(
inventory=inventory,
source='file',
source_path=os.path.abspath(source),
overwrite=bool(options.get('overwrite', False)),
overwrite_vars=bool(options.get('overwrite_vars', False)),
)
inventory_update = inventory_source.create_inventory_update(
_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()
logger.debug('Finished loading from source: %s', source)
status, tb, exc = 'error', '', None
try:
self.perform_update(options, data, inventory_update)
status = 'successful'
except Exception as e:
exc = e
if isinstance(e, KeyboardInterrupt):
status = 'canceled'
else:
tb = traceback.format_exc()
with ignore_inventory_computed_fields():
inventory_update = InventoryUpdate.objects.get(pk=inventory_update.pk)
inventory_update.result_traceback = tb
inventory_update.status = status
inventory_update.save(update_fields=['status', 'result_traceback'])
inventory_source.status = status
inventory_source.save(update_fields=['status'])
if exc:
logger.error(str(exc))
if exc:
if isinstance(exc, CommandError):
sys.exit(1)
raise exc
def perform_update(self, options, data, inventory_update):
"""Shared method for both awx-manage CLI updates and inventory updates
from the tasks system.
This saves the inventory data to the database, calling load_into_database
but also wraps that method in a host of options processing
"""
# outside of normal options, these are needed as part of programatic interface
self.inventory = inventory_update.inventory
self.inventory_source = inventory_update.inventory_source
self.inventory_update = inventory_update
# the update options, could be parser object or dict
self.overwrite = bool(options.get('overwrite', False))
self.overwrite_vars = bool(options.get('overwrite_vars', False))
self.keep_vars = bool(options.get('keep_vars', False))
self.is_custom = bool(options.get('custom', False))
self.source = options.get('source', None)
self.enabled_var = options.get('enabled_var', None)
self.enabled_value = options.get('enabled_value', None)
self.group_filter = options.get('group_filter', None) or r'^.+$'
@@ -976,17 +1011,6 @@ class Command(BaseCommand):
self.exclude_empty_groups = bool(options.get('exclude_empty_groups', False))
self.instance_id_var = options.get('instance_id_var', None)
self.invoked_from_dispatcher = False if os.getenv('INVENTORY_SOURCE_ID', None) is None else True
# Load inventory and related objects from database.
if self.inventory_name and self.inventory_id:
raise CommandError('--inventory-name and --inventory-id are mutually exclusive')
elif not self.inventory_name and not self.inventory_id:
raise CommandError('--inventory-name or --inventory-id is required')
if (self.overwrite or self.overwrite_vars) and self.keep_vars:
raise CommandError('--overwrite/--overwrite-vars and --keep-vars are mutually exclusive')
if not self.source:
raise CommandError('--source is required')
try:
self.group_filter_re = re.compile(self.group_filter)
except re.error:
@@ -997,146 +1021,115 @@ class Command(BaseCommand):
raise CommandError('invalid regular expression for --host-filter')
begin = time.time()
with advisory_lock('inventory_{}_update'.format(self.inventory_id)):
self.load_inventory_from_database()
# Since perform_update can be invoked either through the awx-manage CLI
# or from the task system, we need to create a new lock at this level
# (even though inventory_import.Command.handle -- which calls
# perform_update -- has its own lock, inventory_ID_import)
with advisory_lock('inventory_{}_perform_update'.format(self.inventory.id)):
try:
self.check_license()
except CommandError as e:
except PermissionDenied as e:
self.mark_license_failure(save=True)
raise e
try:
# Check the per-org host limits
self.check_org_host_limit()
except CommandError as e:
except PermissionDenied as e:
self.mark_org_limits_failure(save=True)
raise e
status, tb, exc = 'error', '', None
try:
if settings.SQL_DEBUG:
queries_before = len(connection.queries)
if settings.SQL_DEBUG:
queries_before = len(connection.queries)
# Update inventory update for this command line invocation.
with ignore_inventory_computed_fields():
iu = self.inventory_update
if iu.status != 'running':
with transaction.atomic():
self.inventory_update.status = 'running'
self.inventory_update.save()
# Update inventory update for this command line invocation.
with ignore_inventory_computed_fields():
# TODO: move this to before perform_update
iu = self.inventory_update
if iu.status != 'running':
with transaction.atomic():
self.inventory_update.status = 'running'
self.inventory_update.save()
source = self.get_source_absolute_path(self.source)
logger.info('Processing JSON output...')
inventory = MemInventory(
group_filter_re=self.group_filter_re, host_filter_re=self.host_filter_re)
inventory = dict_to_mem_data(data, inventory=inventory)
data = AnsibleInventoryLoader(source=source, is_custom=self.is_custom,
venv_path=venv_path, verbosity=self.verbosity).load()
logger.info('Loaded %d groups, %d hosts', len(inventory.all_group.all_groups),
len(inventory.all_group.all_hosts))
logger.debug('Finished loading from source: %s', source)
logger.info('Processing JSON output...')
inventory = MemInventory(
group_filter_re=self.group_filter_re, host_filter_re=self.host_filter_re)
inventory = dict_to_mem_data(data, inventory=inventory)
if self.exclude_empty_groups:
inventory.delete_empty_groups()
del data # forget dict from import, could be large
self.all_group = inventory.all_group
logger.info('Loaded %d groups, %d hosts', len(inventory.all_group.all_groups),
len(inventory.all_group.all_hosts))
if settings.DEBUG:
# depending on inventory source, this output can be
# *exceedingly* verbose - crawling a deeply nested
# inventory/group data structure and printing metadata about
# each host and its memberships
#
# it's easy for this scale of data to overwhelm pexpect,
# (and it's likely only useful for purposes of debugging the
# actual inventory import code), so only print it if we have to:
# https://github.com/ansible/ansible-tower/issues/7414#issuecomment-321615104
self.all_group.debug_tree()
if self.exclude_empty_groups:
inventory.delete_empty_groups()
self.all_group = inventory.all_group
if settings.DEBUG:
# depending on inventory source, this output can be
# *exceedingly* verbose - crawling a deeply nested
# inventory/group data structure and printing metadata about
# each host and its memberships
#
# it's easy for this scale of data to overwhelm pexpect,
# (and it's likely only useful for purposes of debugging the
# actual inventory import code), so only print it if we have to:
# https://github.com/ansible/ansible-tower/issues/7414#issuecomment-321615104
self.all_group.debug_tree()
with batch_role_ancestor_rebuilding():
# If using with transaction.atomic() with try ... catch,
# with transaction.atomic() must be inside the try section of the code as per Django docs
try:
# Ensure that this is managed as an atomic SQL transaction,
# and thus properly rolled back if there is an issue.
with transaction.atomic():
# Merge/overwrite inventory into database.
if settings.SQL_DEBUG:
logger.warning('loading into database...')
with ignore_inventory_computed_fields():
if getattr(settings, 'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC', True):
with batch_role_ancestor_rebuilding():
# If using with transaction.atomic() with try ... catch,
# with transaction.atomic() must be inside the try section of the code as per Django docs
try:
# Ensure that this is managed as an atomic SQL transaction,
# and thus properly rolled back if there is an issue.
with transaction.atomic():
# Merge/overwrite inventory into database.
if settings.SQL_DEBUG:
logger.warning('loading into database...')
with ignore_inventory_computed_fields():
if getattr(settings, 'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC', True):
self.load_into_database()
else:
with disable_activity_stream():
self.load_into_database()
else:
with disable_activity_stream():
self.load_into_database()
if settings.SQL_DEBUG:
queries_before2 = len(connection.queries)
self.inventory.update_computed_fields()
if settings.SQL_DEBUG:
logger.warning('update computed fields took %d queries',
len(connection.queries) - queries_before2)
# Check if the license is valid.
# If the license is not valid, a CommandError will be thrown,
# and inventory update will be marked as invalid.
# with transaction.atomic() will roll back the changes.
license_fail = True
self.check_license()
if settings.SQL_DEBUG:
queries_before2 = len(connection.queries)
self.inventory.update_computed_fields()
if settings.SQL_DEBUG:
logger.warning('update computed fields took %d queries',
len(connection.queries) - queries_before2)
# Check the per-org host limits
license_fail = False
self.check_org_host_limit()
except CommandError as e:
if license_fail:
self.mark_license_failure()
else:
self.mark_org_limits_failure()
raise e
# Check if the license is valid.
# If the license is not valid, a CommandError will be thrown,
# and inventory update will be marked as invalid.
# with transaction.atomic() will roll back the changes.
license_fail = True
self.check_license()
if settings.SQL_DEBUG:
logger.warning('Inventory import completed for %s in %0.1fs',
self.inventory_source.name, time.time() - begin)
# Check the per-org host limits
license_fail = False
self.check_org_host_limit()
except PermissionDenied as e:
if license_fail:
self.mark_license_failure(save=True)
else:
logger.info('Inventory import completed for %s in %0.1fs',
self.inventory_source.name, time.time() - begin)
status = 'successful'
self.mark_org_limits_failure(save=True)
raise e
# If we're in debug mode, then log the queries and time
# used to do the operation.
if settings.SQL_DEBUG:
queries_this_import = connection.queries[queries_before:]
sqltime = sum(float(x['time']) for x in queries_this_import)
logger.warning('Inventory import required %d queries '
'taking %0.3fs', len(queries_this_import),
sqltime)
except Exception as e:
if isinstance(e, KeyboardInterrupt):
status = 'canceled'
exc = e
elif isinstance(e, CommandError):
exc = e
logger.warning('Inventory import completed for %s in %0.1fs',
self.inventory_source.name, time.time() - begin)
else:
tb = traceback.format_exc()
exc = e
logger.info('Inventory import completed for %s in %0.1fs',
self.inventory_source.name, time.time() - begin)
if not self.invoked_from_dispatcher:
with ignore_inventory_computed_fields():
self.inventory_update = InventoryUpdate.objects.get(pk=self.inventory_update.pk)
self.inventory_update.result_traceback = tb
self.inventory_update.status = status
self.inventory_update.save(update_fields=['status', 'result_traceback'])
self.inventory_source.status = status
self.inventory_source.save(update_fields=['status'])
if exc:
logger.error(str(exc))
if exc:
if isinstance(exc, CommandError):
sys.exit(1)
raise exc
# If we're in debug mode, then log the queries and time
# used to do the operation.
if settings.SQL_DEBUG:
queries_this_import = connection.queries[queries_before:]
sqltime = sum(float(x['time']) for x in queries_this_import)
logger.warning('Inventory import required %d queries '
'taking %0.3fs', len(queries_this_import),
sqltime)

View File

@@ -19,7 +19,9 @@ class Command(BaseCommand):
profile_sql.delay(
threshold=options['threshold'], minutes=options['minutes']
)
print(f"Logging initiated with a threshold of {options['threshold']} second(s) and a duration of"
f" {options['minutes']} minute(s), any queries that meet criteria can"
f" be found in /var/log/tower/profile/."
)
if options['threshold'] > 0:
print(f"SQL profiling initiated with a threshold of {options['threshold']} second(s) and a"
f" duration of {options['minutes']} minute(s), any queries that meet criteria can"
f" be found in /var/log/tower/profile/.")
else:
print("SQL profiling disabled.")

View File

@@ -1,13 +1,9 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
import uuid
import logging
import threading
import time
import cProfile
import pstats
import os
import urllib.parse
from django.conf import settings
@@ -22,6 +18,7 @@ from django.urls import reverse, resolve
from awx.main.utils.named_url_graph import generate_graph, GraphNode
from awx.conf import fields, register
from awx.main.utils.profiling import AWXProfiler
logger = logging.getLogger('awx.main.middleware')
@@ -32,11 +29,14 @@ class TimingMiddleware(threading.local, MiddlewareMixin):
dest = '/var/log/tower/profile'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.prof = AWXProfiler("TimingMiddleware")
def process_request(self, request):
self.start_time = time.time()
if settings.AWX_REQUEST_PROFILE:
self.prof = cProfile.Profile()
self.prof.enable()
self.prof.start()
def process_response(self, request, response):
if not hasattr(self, 'start_time'): # some tools may not invoke process_request
@@ -44,33 +44,10 @@ class TimingMiddleware(threading.local, MiddlewareMixin):
total_time = time.time() - self.start_time
response['X-API-Total-Time'] = '%0.3fs' % total_time
if settings.AWX_REQUEST_PROFILE:
self.prof.disable()
cprofile_file = self.save_profile_file(request)
response['cprofile_file'] = cprofile_file
response['X-API-Profile-File'] = self.prof.stop()
perf_logger.info('api response times', extra=dict(python_objects=dict(request=request, response=response)))
return response
def save_profile_file(self, request):
if not os.path.isdir(self.dest):
os.makedirs(self.dest)
filename = '%.3fs-%s.pstats' % (pstats.Stats(self.prof).total_tt, uuid.uuid4())
filepath = os.path.join(self.dest, filename)
with open(filepath, 'w') as f:
f.write('%s %s\n' % (request.method, request.get_full_path()))
pstats.Stats(self.prof, stream=f).sort_stats('cumulative').print_stats()
if settings.AWX_REQUEST_PROFILE_WITH_DOT:
from gprof2dot import main as generate_dot
raw = os.path.join(self.dest, filename) + '.raw'
pstats.Stats(self.prof).dump_stats(raw)
generate_dot([
'-n', '2.5', '-f', 'pstats', '-o',
os.path.join( self.dest, filename).replace('.pstats', '.dot'),
raw
])
os.remove(raw)
return filepath
class SessionTimeoutMiddleware(MiddlewareMixin):
"""
@@ -204,4 +181,4 @@ class MigrationRanCheckMiddleware(MiddlewareMixin):
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:migrations_notran"))
return redirect(reverse("ui_next:migrations_notran"))

View File

@@ -1,11 +1,7 @@
# Generated by Django 2.2.11 on 2020-05-01 13:25
from django.db import migrations, models
from awx.main.migrations._inventory_source import create_scm_script_substitute
def convert_cloudforms_to_scm(apps, schema_editor):
create_scm_script_substitute(apps, 'cloudforms')
from awx.main.migrations._inventory_source import delete_cloudforms_inv_source
class Migration(migrations.Migration):
@@ -15,7 +11,7 @@ class Migration(migrations.Migration):
]
operations = [
migrations.RunPython(convert_cloudforms_to_scm),
migrations.RunPython(delete_cloudforms_inv_source),
migrations.AlterField(
model_name='inventorysource',
name='source',

View File

@@ -0,0 +1,13 @@
from django.db import migrations
from awx.main.migrations._inventory_source import delete_cloudforms_inv_source
class Migration(migrations.Migration):
dependencies = [
('main', '0121_delete_toweranalyticsstate'),
]
operations = [
migrations.RunPython(delete_cloudforms_inv_source),
]

View File

@@ -0,0 +1,23 @@
from django.db import migrations, models
from awx.main.migrations._hg_removal import delete_hg_scm
class Migration(migrations.Migration):
dependencies = [
('main', '0122_really_remove_cloudforms_inventory'),
]
operations = [
migrations.RunPython(delete_hg_scm),
migrations.AlterField(
model_name='project',
name='scm_type',
field=models.CharField(blank=True, choices=[('', 'Manual'), ('git', 'Git'), ('svn', 'Subversion'), ('insights', 'Red Hat Insights'), ('archive', 'Remote Archive')], default='', help_text='Specifies the source control system used to store the project.', max_length=8, verbose_name='SCM Type'),
),
migrations.AlterField(
model_name='projectupdate',
name='scm_type',
field=models.CharField(blank=True, choices=[('', 'Manual'), ('git', 'Git'), ('svn', 'Subversion'), ('insights', 'Red Hat Insights'), ('archive', 'Remote Archive')], default='', help_text='Specifies the source control system used to store the project.', max_length=8, verbose_name='SCM Type'),
),
]

View File

@@ -0,0 +1,19 @@
import logging
from awx.main.utils.common import set_current_apps
logger = logging.getLogger('awx.main.migrations')
def delete_hg_scm(apps, schema_editor):
set_current_apps(apps)
Project = apps.get_model('main', 'Project')
ProjectUpdate = apps.get_model('main', 'ProjectUpdate')
ProjectUpdate.objects.filter(project__scm_type='hg').update(scm_type='')
update_ct = Project.objects.filter(scm_type='hg').update(scm_type='')
if update_ct:
logger.warn('Changed {} mercurial projects to manual, deprecation period ended'.format(
update_ct
))

View File

@@ -5,6 +5,7 @@ from uuid import uuid4
from django.utils.encoding import smart_text
from django.utils.timezone import now
from awx.main.utils.common import set_current_apps
from awx.main.utils.common import parse_yaml_or_json
logger = logging.getLogger('awx.main.migrations')
@@ -91,43 +92,14 @@ def back_out_new_instance_id(apps, source, new_id):
))
def create_scm_script_substitute(apps, source):
"""Only applies for cloudforms in practice, but written generally.
Given a source type, this will replace all inventory sources of that type
with SCM inventory sources that source the script from Ansible core
"""
# the revision in the Ansible 2.9 stable branch this project will start out as
# it can still be updated manually later (but staying within 2.9 branch), if desired
ansible_rev = '6f83b9aff42331e15c55a171de0a8b001208c18c'
def delete_cloudforms_inv_source(apps, schema_editor):
set_current_apps(apps)
InventorySource = apps.get_model('main', 'InventorySource')
ContentType = apps.get_model('contenttypes', 'ContentType')
Project = apps.get_model('main', 'Project')
if not InventorySource.objects.filter(source=source).exists():
logger.debug('No sources of type {} to migrate'.format(source))
return
proj_name = 'Replacement project for {} type sources - {}'.format(source, uuid4())
right_now = now()
project = Project.objects.create(
name=proj_name,
created=right_now,
modified=right_now,
description='Created by migration',
polymorphic_ctype=ContentType.objects.get(model='project'),
# project-specific fields
scm_type='git',
scm_url='https://github.com/ansible/ansible.git',
scm_branch='stable-2.9',
scm_revision=ansible_rev
)
ct = 0
for inv_src in InventorySource.objects.filter(source=source).iterator():
inv_src.source = 'scm'
inv_src.source_project = project
inv_src.source_path = 'contrib/inventory/{}.py'.format(source)
inv_src.scm_last_revision = ansible_rev
inv_src.save(update_fields=['source', 'source_project', 'source_path', 'scm_last_revision'])
logger.debug('Changed inventory source {} to scm type'.format(inv_src.pk))
ct += 1
InventoryUpdate = apps.get_model('main', 'InventoryUpdate')
CredentialType = apps.get_model('main', 'CredentialType')
InventoryUpdate.objects.filter(inventory_source__source='cloudforms').delete()
InventorySource.objects.filter(source='cloudforms').delete()
ct = CredentialType.objects.filter(namespace='cloudforms').first()
if ct:
logger.info('Changed total of {} inventory sources from {} type to scm'.format(ct, source))
ct.credentials.all().delete()
ct.delete()

View File

@@ -1,9 +1,13 @@
import json
import re
import logging
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import iri_to_uri
FrozenInjectors = dict()
logger = logging.getLogger('awx.main.migrations')
class PluginFileInjector(object):
@@ -129,6 +133,7 @@ class azure_rm(PluginFileInjector):
ret['exclude_host_filters'].append("location not in {}".format(repr(python_regions)))
return ret
class ec2(PluginFileInjector):
plugin_name = 'aws_ec2'
namespace = 'amazon'
@@ -586,6 +591,7 @@ class openstack(PluginFileInjector):
ret['inventory_hostname'] = use_host_name_for_name(source_vars['use_hostnames'])
return ret
class rhv(PluginFileInjector):
"""ovirt uses the custom credential templating, and that is all
"""

View File

@@ -819,6 +819,11 @@ ManagedCredentialType(
'It is only needed for Keystone v3 authentication '
'URLs. Refer to Ansible Tower documentation for '
'common scenarios.')
}, {
'id': 'region',
'label': ugettext_noop('Region Name'),
'type': 'string',
'help_text': ugettext_noop('For some cloud providers, like OVH, region must be specified'),
}, {
'id': 'verify_ssl',
'label': ugettext_noop('Verify SSL'),
@@ -881,33 +886,6 @@ ManagedCredentialType(
}
)
ManagedCredentialType(
namespace='cloudforms',
kind='cloud',
name=ugettext_noop('Red Hat CloudForms'),
managed_by_tower=True,
inputs={
'fields': [{
'id': 'host',
'label': ugettext_noop('CloudForms URL'),
'type': 'string',
'help_text': ugettext_noop('Enter the URL for the virtual machine that '
'corresponds to your CloudForms instance. '
'For example, https://cloudforms.example.org')
}, {
'id': 'username',
'label': ugettext_noop('Username'),
'type': 'string'
}, {
'id': 'password',
'label': ugettext_noop('Password'),
'type': 'string',
'secret': True,
}],
'required': ['host', 'username', 'password'],
}
)
ManagedCredentialType(
namespace='gce',
kind='cloud',

View File

@@ -82,6 +82,7 @@ def _openstack_data(cred):
if cred.has_input('domain'):
openstack_auth['domain_name'] = cred.get_input('domain', default='')
verify_state = cred.get_input('verify_ssl', default=True)
openstack_data = {
'clouds': {
'devstack': {
@@ -90,6 +91,10 @@ def _openstack_data(cred):
},
},
}
if cred.has_input('project_region_name'):
openstack_data['clouds']['devstack']['region_name'] = cred.get_input('project_region_name', default='')
return openstack_data

View File

@@ -798,6 +798,10 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
if self.project:
for name in ('awx', 'tower'):
r['{}_project_revision'.format(name)] = self.project.scm_revision
r['{}_project_scm_branch'.format(name)] = self.project.scm_branch
if self.scm_branch:
for name in ('awx', 'tower'):
r['{}_job_scm_branch'.format(name)] = self.scm_branch
if self.job_template:
for name in ('awx', 'tower'):
r['{}_job_template_id'.format(name)] = self.job_template.pk

View File

@@ -12,7 +12,7 @@ from django.core.mail.message import EmailMessage
from django.db import connection
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_str, force_text
from jinja2 import sandbox
from jinja2 import sandbox, ChainableUndefined
from jinja2.exceptions import TemplateSyntaxError, UndefinedError, SecurityError
# AWX
@@ -429,7 +429,7 @@ class JobNotificationMixin(object):
raise RuntimeError("Define me")
def build_notification_message(self, nt, status):
env = sandbox.ImmutableSandboxedEnvironment()
env = sandbox.ImmutableSandboxedEnvironment(undefined=ChainableUndefined)
from awx.api.serializers import UnifiedJobSerializer
job_serialization = UnifiedJobSerializer(self).to_representation(self)

View File

@@ -52,7 +52,6 @@ class ProjectOptions(models.Model):
SCM_TYPE_CHOICES = [
('', _('Manual')),
('git', _('Git')),
('hg', _('Mercurial')),
('svn', _('Subversion')),
('insights', _('Red Hat Insights')),
('archive', _('Remote Archive')),

View File

@@ -674,7 +674,7 @@ class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificatio
return self.status == 'running'
class WorkflowApprovalTemplate(UnifiedJobTemplate):
class WorkflowApprovalTemplate(UnifiedJobTemplate, RelatedJobsMixin):
FIELDS_TO_PRESERVE_AT_COPY = ['description', 'timeout',]
@@ -702,6 +702,12 @@ class WorkflowApprovalTemplate(UnifiedJobTemplate):
def workflow_job_template(self):
return self.workflowjobtemplatenodes.first().workflow_job_template
'''
RelatedJobsMixin
'''
def _get_related_jobs(self):
return UnifiedJob.objects.filter(unified_job_template=self)
class WorkflowApproval(UnifiedJob, JobNotificationMixin):
class Meta:

View File

@@ -57,6 +57,7 @@ class WebhookBackend(AWXBaseEmailBackend, CustomNotificationBase):
def send_messages(self, messages):
sent_messages = 0
self.headers['Content-Type'] = 'application/json'
if 'User-Agent' not in self.headers:
self.headers['User-Agent'] = "Tower {}".format(get_awx_version())
if self.http_method.lower() not in ['put','post']:
@@ -68,7 +69,7 @@ class WebhookBackend(AWXBaseEmailBackend, CustomNotificationBase):
auth = (self.username, self.password)
r = chosen_method("{}".format(m.recipients()[0]),
auth=auth,
json=m.body,
data=json.dumps(m.body, ensure_ascii=False).encode('utf-8'),
headers=self.headers,
verify=(not self.disable_ssl_verification))
if r.status_code >= 400:

View File

@@ -12,6 +12,24 @@ from awx.main.utils.common import parse_yaml_or_json
logger = logging.getLogger('awx.main.scheduler')
def deepmerge(a, b):
"""
Merge dict structures and return the result.
>>> a = {'first': {'all_rows': {'pass': 'dog', 'number': '1'}}}
>>> b = {'first': {'all_rows': {'fail': 'cat', 'number': '5'}}}
>>> import pprint; pprint.pprint(deepmerge(a, b))
{'first': {'all_rows': {'fail': 'cat', 'number': '5', 'pass': 'dog'}}}
"""
if isinstance(a, dict) and isinstance(b, dict):
return dict([(k, deepmerge(a.get(k), b.get(k)))
for k in set(a.keys()).union(b.keys())])
elif b is None:
return a
else:
return b
class PodManager(object):
def __init__(self, task=None):
@@ -128,11 +146,13 @@ class PodManager(object):
pod_spec = {**default_pod_spec, **pod_spec_override}
if self.task:
pod_spec['metadata']['name'] = self.pod_name
pod_spec['metadata']['labels'] = {
'ansible-awx': settings.INSTALL_UUID,
'ansible-awx-job-id': str(self.task.id)
}
pod_spec['metadata'] = deepmerge(
pod_spec.get('metadata', {}),
dict(name=self.pod_name,
labels={
'ansible-awx': settings.INSTALL_UUID,
'ansible-awx-job-id': str(self.task.id)
}))
pod_spec['spec']['containers'][0]['name'] = self.pod_name
return pod_spec

View File

@@ -14,6 +14,7 @@ from django.db import transaction, connection
from django.utils.translation import ugettext_lazy as _, gettext_noop
from django.utils.timezone import now as tz_now
from django.conf import settings
from django.db.models import Q
# AWX
from awx.main.dispatch.reaper import reap_job
@@ -67,7 +68,7 @@ class TaskManager():
'''
Init AFTER we know this instance of the task manager will run because the lock is acquired.
'''
instances = Instance.objects.filter(capacity__gt=0, enabled=True)
instances = Instance.objects.filter(~Q(hostname=None), capacity__gt=0, enabled=True)
self.real_instances = {i.hostname: i for i in instances}
instances_partial = [SimpleNamespace(obj=instance,
@@ -284,7 +285,7 @@ class TaskManager():
for group in InstanceGroup.objects.all():
if group.is_containerized or group.controller_id:
continue
match = group.fit_task_to_most_remaining_capacity_instance(task)
match = group.fit_task_to_most_remaining_capacity_instance(task, group.instances.all())
if match:
break
task.instance_group = rampart_group
@@ -528,7 +529,8 @@ class TaskManager():
logger.debug("Starting {} in group {} instance {} (remaining_capacity={})".format(
task.log_format, rampart_group.name, execution_instance.hostname, remaining_capacity))
execution_instance = self.real_instances[execution_instance.hostname]
if execution_instance:
execution_instance = self.real_instances[execution_instance.hostname]
self.graph[rampart_group.name]['graph'].add_job(task)
self.start_task(task, rampart_group, task.get_jobs_fail_chain(), execution_instance)
found_acceptable_queue = True

View File

@@ -121,6 +121,27 @@ def sync_superuser_status_to_rbac(instance, **kwargs):
Role.singleton(ROLE_SINGLETON_SYSTEM_ADMINISTRATOR).members.remove(instance)
def sync_rbac_to_superuser_status(instance, sender, **kwargs):
'When the is_superuser flag is false but a user has the System Admin role, update the database to reflect that'
if kwargs['action'] in ['post_add', 'post_remove', 'post_clear']:
new_status_value = bool(kwargs['action'] == 'post_add')
if hasattr(instance, 'singleton_name'): # duck typing, role.members.add() vs user.roles.add()
role = instance
if role.singleton_name == ROLE_SINGLETON_SYSTEM_ADMINISTRATOR:
if kwargs['pk_set']:
kwargs['model'].objects.filter(pk__in=kwargs['pk_set']).update(is_superuser=new_status_value)
elif kwargs['action'] == 'post_clear':
kwargs['model'].objects.all().update(is_superuser=False)
else:
user = instance
if kwargs['action'] == 'post_clear':
user.is_superuser = False
user.save(update_fields=['is_superuser'])
elif kwargs['model'].objects.filter(pk__in=kwargs['pk_set'], singleton_name=ROLE_SINGLETON_SYSTEM_ADMINISTRATOR).exists():
user.is_superuser = new_status_value
user.save(update_fields=['is_superuser'])
def rbac_activity_stream(instance, sender, **kwargs):
# Only if we are associating/disassociating
if kwargs['action'] in ['pre_add', 'pre_remove']:
@@ -197,6 +218,7 @@ m2m_changed.connect(rebuild_role_ancestor_list, Role.parents.through)
m2m_changed.connect(rbac_activity_stream, Role.members.through)
m2m_changed.connect(rbac_activity_stream, Role.parents.through)
post_save.connect(sync_superuser_status_to_rbac, sender=User)
m2m_changed.connect(sync_rbac_to_superuser_status, Role.members.through)
pre_delete.connect(cleanup_detached_labels_on_deleted_parent, sender=UnifiedJob)
pre_delete.connect(cleanup_detached_labels_on_deleted_parent, sender=UnifiedJobTemplate)

View File

@@ -23,7 +23,6 @@ import fcntl
from pathlib import Path
from uuid import uuid4
import urllib.parse as urlparse
import shlex
# Django
from django.conf import settings
@@ -64,7 +63,7 @@ from awx.main.models import (
build_safe_env, enforce_bigint_pk_migration
)
from awx.main.constants import ACTIVE_STATES
from awx.main.exceptions import AwxTaskError
from awx.main.exceptions import AwxTaskError, PostRunError
from awx.main.queue import CallbackQueueDispatcher
from awx.main.isolated import manager as isolated_manager
from awx.main.dispatch.publish import task
@@ -79,6 +78,7 @@ from awx.main.utils.external_logging import reconfigure_rsyslog
from awx.main.utils.safe_yaml import safe_dump, sanitize_jinja
from awx.main.utils.reload import stop_local_services
from awx.main.utils.pglock import advisory_lock
from awx.main.utils.handlers import SpecialInventoryHandler
from awx.main.consumers import emit_channel_notification
from awx.main import analytics
from awx.conf import settings_registry
@@ -313,7 +313,7 @@ def delete_project_files(project_path):
@task(queue='tower_broadcast_all')
def profile_sql(threshold=1, minutes=1):
if threshold == 0:
if threshold <= 0:
cache.delete('awx-profile-sql-threshold')
logger.error('SQL PROFILING DISABLED')
else:
@@ -378,6 +378,7 @@ def gather_analytics():
from awx.conf.models import Setting
from rest_framework.fields import DateTimeField
from awx.main.signals import disable_activity_stream
if not settings.INSIGHTS_TRACKING_STATE:
return
if not (settings.AUTOMATION_ANALYTICS_URL and settings.REDHAT_USERNAME and settings.REDHAT_PASSWORD):
@@ -414,7 +415,8 @@ def gather_analytics():
if not _gather_and_ship(incremental_collectors, since=start, until=until):
break
start = until
settings.AUTOMATION_ANALYTICS_LAST_GATHER = until
with disable_activity_stream():
settings.AUTOMATION_ANALYTICS_LAST_GATHER = until
if subset:
_gather_and_ship(subset, since=since, until=gather_time)
@@ -1225,6 +1227,13 @@ class BaseTask(object):
Ansible runner puts a parent_uuid on each event, no matter what the type.
AWX only saves the parent_uuid if the event is for a Job.
'''
# cache end_line locally for RunInventoryUpdate tasks
# which generate job events from two 'streams':
# ansible-inventory and the awx.main.commands.inventory_import
# logger
if isinstance(self, RunInventoryUpdate):
self.end_line = event_data['end_line']
if event_data.get(self.event_data_key, None):
if self.event_data_key != 'job_id':
event_data.pop('parent_uuid', None)
@@ -1253,7 +1262,7 @@ class BaseTask(object):
# so it *should* have a negligible performance impact
task = event_data.get('event_data', {}).get('task_action')
try:
if task in ('git', 'hg', 'svn'):
if task in ('git', 'svn'):
event_data_json = json.dumps(event_data)
event_data_json = UriCleaner.remove_sensitive(event_data_json)
event_data = json.loads(event_data_json)
@@ -1521,6 +1530,12 @@ class BaseTask(object):
try:
self.post_run_hook(self.instance, status)
except PostRunError as exc:
if status == 'successful':
status = exc.status
extra_update_fields['job_explanation'] = exc.args[0]
if exc.tb:
extra_update_fields['result_traceback'] = exc.tb
except Exception:
logger.exception('{} Post run hook errored.'.format(self.instance.log_format))
@@ -2141,7 +2156,7 @@ class RunProjectUpdate(BaseTask):
elif not scm_branch:
raise RuntimeError('Could not determine a revision to run from project.')
elif not scm_branch:
scm_branch = {'hg': 'tip'}.get(project_update.scm_type, 'HEAD')
scm_branch = 'HEAD'
galaxy_creds_are_defined = (
project_update.project.organization and
@@ -2150,7 +2165,7 @@ class RunProjectUpdate(BaseTask):
if not galaxy_creds_are_defined and (
settings.AWX_ROLES_ENABLED or settings.AWX_COLLECTIONS_ENABLED
):
logger.debug(
logger.warning(
'Galaxy role/collection syncing is enabled, but no '
f'credentials are configured for {project_update.project.organization}.'
)
@@ -2160,7 +2175,7 @@ class RunProjectUpdate(BaseTask):
'local_path': os.path.basename(project_update.project.local_path),
'project_path': project_update.get_project_path(check_if_exists=False), # deprecated
'insights_url': settings.INSIGHTS_URL_BASE,
'awx_license_type': get_license(show_key=False).get('license_type', 'UNLICENSED'),
'awx_license_type': get_license().get('license_type', 'UNLICENSED'),
'awx_version': get_awx_version(),
'scm_url': scm_url,
'scm_branch': scm_branch,
@@ -2417,9 +2432,10 @@ class RunProjectUpdate(BaseTask):
shutil.rmtree(stage_path) # cannot trust content update produced
if self.job_private_data_dir:
# copy project folder before resetting to default branch
# because some git-tree-specific resources (like submodules) might matter
self.make_local_copy(instance, self.job_private_data_dir)
if status == 'successful':
# copy project folder before resetting to default branch
# because some git-tree-specific resources (like submodules) might matter
self.make_local_copy(instance, self.job_private_data_dir)
if self.original_branch:
# for git project syncs, non-default branches can be problems
# restore to branch the repo was on before this run
@@ -2461,6 +2477,14 @@ class RunInventoryUpdate(BaseTask):
event_model = InventoryUpdateEvent
event_data_key = 'inventory_update_id'
# TODO: remove once inv updates run in containers
def should_use_proot(self, inventory_update):
'''
Return whether this task should use proot.
'''
return getattr(settings, 'AWX_PROOT_ENABLED', False)
# TODO: remove once inv updates run in containers
@property
def proot_show_paths(self):
return [settings.AWX_ANSIBLE_COLLECTIONS_PATHS]
@@ -2485,15 +2509,11 @@ class RunInventoryUpdate(BaseTask):
return injector.build_private_data(inventory_update, private_data_dir)
def build_env(self, inventory_update, private_data_dir, isolated, private_data_files=None):
"""Build environment dictionary for inventory import.
"""Build environment dictionary for ansible-inventory.
This used to be the mechanism by which any data that needs to be passed
to the inventory update script is set up. In particular, this is how
inventory update is aware of its proper credentials.
Most environment injection is now accomplished by the credential
injectors. The primary purpose this still serves is to
still point to the inventory update INI or config file.
Most environment variables related to credentials or configuration
are accomplished by the inventory source injectors (in this method)
or custom credential type injectors (in main run method).
"""
env = super(RunInventoryUpdate, self).build_env(inventory_update,
private_data_dir,
@@ -2501,8 +2521,11 @@ class RunInventoryUpdate(BaseTask):
private_data_files=private_data_files)
if private_data_files is None:
private_data_files = {}
self.add_awx_venv(env)
# Pass inventory source ID to inventory script.
# TODO: remove once containers replace custom venvs
self.add_ansible_venv(inventory_update.ansible_virtualenv_path, env, isolated=isolated)
# Legacy environment variables, were used as signal to awx-manage command
# now they are provided in case some scripts may be relying on them
env['INVENTORY_SOURCE_ID'] = str(inventory_update.inventory_source_id)
env['INVENTORY_UPDATE_ID'] = str(inventory_update.pk)
env.update(STANDARD_INVENTORY_UPDATE_ENV)
@@ -2565,47 +2588,25 @@ class RunInventoryUpdate(BaseTask):
if inventory is None:
raise RuntimeError('Inventory Source is not associated with an Inventory.')
# Piece together the initial command to run via. the shell.
args = ['awx-manage', 'inventory_import']
args.extend(['--inventory-id', str(inventory.pk)])
args = ['ansible-inventory', '--list', '--export']
# Add appropriate arguments for overwrite if the inventory_update
# object calls for it.
if inventory_update.overwrite:
args.append('--overwrite')
if inventory_update.overwrite_vars:
args.append('--overwrite-vars')
# Add arguments for the source inventory file/script/thing
source_location = self.pseudo_build_inventory(inventory_update, private_data_dir)
args.append('-i')
args.append(source_location)
# Declare the virtualenv the management command should activate
# as it calls ansible-inventory
args.extend(['--venv', inventory_update.ansible_virtualenv_path])
args.append('--output')
args.append(os.path.join(private_data_dir, 'artifacts', 'output.json'))
src = inventory_update.source
if inventory_update.enabled_var:
args.extend(['--enabled-var', shlex.quote(inventory_update.enabled_var)])
args.extend(['--enabled-value', shlex.quote(inventory_update.enabled_value)])
if os.path.isdir(source_location):
playbook_dir = source_location
else:
if getattr(settings, '%s_ENABLED_VAR' % src.upper(), False):
args.extend(['--enabled-var',
getattr(settings, '%s_ENABLED_VAR' % src.upper())])
if getattr(settings, '%s_ENABLED_VALUE' % src.upper(), False):
args.extend(['--enabled-value',
getattr(settings, '%s_ENABLED_VALUE' % src.upper())])
if inventory_update.host_filter:
args.extend(['--host-filter', shlex.quote(inventory_update.host_filter)])
if getattr(settings, '%s_EXCLUDE_EMPTY_GROUPS' % src.upper()):
args.append('--exclude-empty-groups')
if getattr(settings, '%s_INSTANCE_ID_VAR' % src.upper(), False):
args.extend(['--instance-id-var',
"'{}'".format(getattr(settings, '%s_INSTANCE_ID_VAR' % src.upper())),])
# Add arguments for the source inventory script
args.append('--source')
args.append(self.pseudo_build_inventory(inventory_update, private_data_dir))
if src == 'custom':
args.append("--custom")
args.append('-v%d' % inventory_update.verbosity)
if settings.DEBUG:
args.append('--traceback')
playbook_dir = os.path.dirname(source_location)
args.extend(['--playbook-dir', playbook_dir])
if inventory_update.verbosity:
args.append('-' + 'v' * min(5, inventory_update.verbosity * 2 + 1))
return args
def build_inventory(self, inventory_update, private_data_dir):
@@ -2645,11 +2646,9 @@ class RunInventoryUpdate(BaseTask):
def build_cwd(self, inventory_update, private_data_dir):
'''
There are two cases where the inventory "source" is in a different
There is one case where the inventory "source" is in a different
location from the private data:
- deprecated vendored inventory scripts in awx/plugins/inventory
- SCM, where source needs to live in the project folder
in these cases, the inventory does not exist in the standard tempdir
'''
src = inventory_update.source
if src == 'scm' and inventory_update.source_project_update:
@@ -2707,6 +2706,75 @@ class RunInventoryUpdate(BaseTask):
# This follows update, not sync, so make copy here
RunProjectUpdate.make_local_copy(source_project, private_data_dir)
def post_run_hook(self, inventory_update, status):
if status != 'successful':
return # nothing to save, step out of the way to allow error reporting
private_data_dir = inventory_update.job_env['AWX_PRIVATE_DATA_DIR']
expected_output = os.path.join(private_data_dir, 'artifacts', 'output.json')
with open(expected_output) as f:
data = json.load(f)
# build inventory save options
options = dict(
overwrite=inventory_update.overwrite,
overwrite_vars=inventory_update.overwrite_vars,
)
src = inventory_update.source
if inventory_update.enabled_var:
options['enabled_var'] = inventory_update.enabled_var
options['enabled_value'] = inventory_update.enabled_value
else:
if getattr(settings, '%s_ENABLED_VAR' % src.upper(), False):
options['enabled_var'] = getattr(settings, '%s_ENABLED_VAR' % src.upper())
if getattr(settings, '%s_ENABLED_VALUE' % src.upper(), False):
options['enabled_value'] = getattr(settings, '%s_ENABLED_VALUE' % src.upper())
if inventory_update.host_filter:
options['host_filter'] = inventory_update.host_filter
if getattr(settings, '%s_EXCLUDE_EMPTY_GROUPS' % src.upper()):
options['exclude_empty_groups'] = True
if getattr(settings, '%s_INSTANCE_ID_VAR' % src.upper(), False):
options['instance_id_var'] = getattr(settings, '%s_INSTANCE_ID_VAR' % src.upper())
# Verbosity is applied to saving process, as well as ansible-inventory CLI option
if inventory_update.verbosity:
options['verbosity'] = inventory_update.verbosity
handler = SpecialInventoryHandler(
self.event_handler, self.cancel_callback,
verbosity=inventory_update.verbosity,
job_timeout=self.get_instance_timeout(self.instance),
start_time=inventory_update.started,
counter=self.event_ct, initial_line=self.end_line
)
inv_logger = logging.getLogger('awx.main.commands.inventory_import')
formatter = inv_logger.handlers[0].formatter
formatter.job_start = inventory_update.started
handler.formatter = formatter
inv_logger.handlers[0] = handler
from awx.main.management.commands.inventory_import import Command as InventoryImportCommand
cmd = InventoryImportCommand()
try:
# save the inventory data to database.
# canceling exceptions will be handled in the global post_run_hook
cmd.perform_update(options, data, inventory_update)
except PermissionDenied as exc:
logger.exception('License error saving {} content'.format(inventory_update.log_format))
raise PostRunError(str(exc), status='error')
except PostRunError:
logger.exception('Error saving {} content, rolling back changes'.format(inventory_update.log_format))
raise
except Exception:
logger.exception('Exception saving {} content, rolling back changes.'.format(
inventory_update.log_format))
raise PostRunError(
'Error occured while saving inventory data, see traceback or server logs',
status='error', tb=traceback.format_exc())
@task(queue=get_local_queuename)
class RunAdHocCommand(BaseTask):

View File

@@ -1,34 +0,0 @@
import pytest
import random
from awx.main.models import Project
from awx.main.analytics import collectors
@pytest.mark.django_db
def test_empty():
assert collectors.projects_by_scm_type(None) == {
'manual': 0,
'git': 0,
'svn': 0,
'hg': 0,
'insights': 0,
'archive': 0,
}
@pytest.mark.django_db
@pytest.mark.parametrize('scm_type', [t[0] for t in Project.SCM_TYPE_CHOICES])
def test_multiple(scm_type):
expected = {
'manual': 0,
'git': 0,
'svn': 0,
'hg': 0,
'insights': 0,
'archive': 0,
}
for i in range(random.randint(0, 10)):
Project(scm_type=scm_type).save()
expected[scm_type or 'manual'] += 1
assert collectors.projects_by_scm_type(None) == expected

View File

@@ -675,33 +675,6 @@ def test_net_create_ok(post, organization, admin):
assert cred.inputs['authorize'] is True
#
# Cloudforms Credentials
#
@pytest.mark.django_db
def test_cloudforms_create_ok(post, organization, admin):
params = {
'credential_type': 1,
'name': 'Best credential ever',
'inputs': {
'host': 'some_host',
'username': 'some_username',
'password': 'some_password',
}
}
cloudforms = CredentialType.defaults['cloudforms']()
cloudforms.save()
params['organization'] = organization.id
response = post(reverse('api:credential_list'), params, admin)
assert response.status_code == 201
assert Credential.objects.count() == 1
cred = Credential.objects.all()[:1].get()
assert cred.inputs['host'] == 'some_host'
assert cred.inputs['username'] == 'some_username'
assert decrypt_field(cred, 'password') == 'some_password'
#
# GCE Credentials
#

View File

@@ -99,3 +99,12 @@ def test_changing_overwrite_behavior_okay_if_not_used(post, patch, organization,
expect=200
)
assert Project.objects.get(pk=r1.data['id']).allow_override is False
@pytest.mark.django_db
def test_scm_project_local_path_invalid(get, patch, project, admin):
url = reverse('api:project_detail', kwargs={'pk': project.id})
resp = patch(url, {'local_path': '/foo/bar'}, user=admin, expect=400)
assert resp.data['local_path'] == [
'Cannot change local_path for git-based projects'
]

View File

@@ -282,10 +282,6 @@ def test_prefetch_ujt_project_capabilities(alice, project, job_template, mocker)
list_serializer.child.to_representation(project)
assert 'capability_map' not in list_serializer.child.context
# Models for which the prefetch is valid for do
list_serializer.child.to_representation(job_template)
assert set(list_serializer.child.context['capability_map'][job_template.id].keys()) == set(('copy', 'edit', 'start'))
@pytest.mark.django_db
def test_prefetch_group_capabilities(group, rando):

View File

@@ -349,7 +349,7 @@ def test_months_with_31_days(post, admin_user):
('MINUTELY', 1, 60),
('MINUTELY', 15, 15 * 60),
('HOURLY', 1, 3600),
('HOURLY', 4, 3600 * 4),
('HOURLY', 2, 3600 * 2),
))
def test_really_old_dtstart(post, admin_user, freq, delta, total_seconds):
url = reverse('api:schedule_rrule')

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@ from collections import OrderedDict
from django.db.models.deletion import Collector, SET_NULL, CASCADE
from django.core.management import call_command
from awx.main.management.commands.deletion import AWXCollector
from awx.main.utils.deletion import AWXCollector
from awx.main.models import (
JobTemplate, User, Job, JobEvent, Notification,
WorkflowJobNode, JobHostSummary

View File

@@ -9,6 +9,9 @@ import os
# Django
from django.core.management.base import CommandError
# for license errors
from rest_framework.exceptions import PermissionDenied
# AWX
from awx.main.management.commands import inventory_import
from awx.main.models import Inventory, Host, Group, InventorySource
@@ -83,7 +86,7 @@ class MockLoader:
return self._data
def mock_logging(self):
def mock_logging(self, level):
pass
@@ -322,6 +325,6 @@ def test_tower_version_compare():
"version": "2.0.1-1068-g09684e2c41"
}
}
with pytest.raises(CommandError):
with pytest.raises(PermissionDenied):
cmd.remote_tower_license_compare('very_supported')
cmd.remote_tower_license_compare('open')

View File

@@ -1,13 +0,0 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
from awx.main.utils.common import StubLicense
def test_stub_license():
license_actual = StubLicense().validate()
assert license_actual['license_key'] == 'OPEN'
assert license_actual['valid_key']
assert license_actual['compliant']
assert license_actual['license_type'] == 'open'

View File

@@ -16,7 +16,7 @@ def test_awx_virtualenv_from_settings(inventory, project, machine_credential):
)
jt.credentials.add(machine_credential)
job = jt.create_unified_job()
assert job.ansible_virtualenv_path == '/venv/ansible'
assert job.ansible_virtualenv_path == '/var/lib/awx/venv/ansible'
@pytest.mark.django_db
@@ -43,28 +43,28 @@ def test_awx_custom_virtualenv(inventory, project, machine_credential, organizat
jt.credentials.add(machine_credential)
job = jt.create_unified_job()
job.organization.custom_virtualenv = '/venv/fancy-org'
job.organization.custom_virtualenv = '/var/lib/awx/venv/fancy-org'
job.organization.save()
assert job.ansible_virtualenv_path == '/venv/fancy-org'
assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-org'
job.project.custom_virtualenv = '/venv/fancy-proj'
job.project.custom_virtualenv = '/var/lib/awx/venv/fancy-proj'
job.project.save()
assert job.ansible_virtualenv_path == '/venv/fancy-proj'
assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-proj'
job.job_template.custom_virtualenv = '/venv/fancy-jt'
job.job_template.custom_virtualenv = '/var/lib/awx/venv/fancy-jt'
job.job_template.save()
assert job.ansible_virtualenv_path == '/venv/fancy-jt'
assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-jt'
@pytest.mark.django_db
def test_awx_custom_virtualenv_without_jt(project):
project.custom_virtualenv = '/venv/fancy-proj'
project.custom_virtualenv = '/var/lib/awx/venv/fancy-proj'
project.save()
job = Job(project=project)
job.save()
job = Job.objects.get(pk=job.id)
assert job.ansible_virtualenv_path == '/venv/fancy-proj'
assert job.ansible_virtualenv_path == '/var/lib/awx/venv/fancy-proj'
@pytest.mark.django_db

View File

@@ -79,7 +79,6 @@ def test_default_cred_types():
'aws',
'azure_kv',
'azure_rm',
'cloudforms',
'conjur',
'galaxy_api_token',
'gce',

View File

@@ -214,6 +214,9 @@ def test_inventory_update_injected_content(this_kind, inventory, fake_credential
f"'{inventory_filename}' file not found in inventory update runtime files {content.keys()}"
env.pop('ANSIBLE_COLLECTIONS_PATHS', None) # collection paths not relevant to this test
env.pop('PYTHONPATH')
env.pop('VIRTUAL_ENV')
env.pop('PROOT_TMP_DIR')
base_dir = os.path.join(DATA, 'plugins')
if not os.path.exists(base_dir):
os.mkdir(base_dir)

View File

@@ -5,7 +5,7 @@ from awx.main.migrations import _inventory_source as invsrc
from django.apps import apps
from awx.main.models import InventorySource
from awx.main.models import InventorySource, InventoryUpdate, ManagedCredentialType, CredentialType, Credential
@pytest.mark.parametrize('vars,id_var,result', [
@@ -42,16 +42,40 @@ def test_apply_new_instance_id(inventory_source):
@pytest.mark.django_db
def test_replacement_scm_sources(inventory):
inv_source = InventorySource.objects.create(
name='test',
inventory=inventory,
organization=inventory.organization,
source='ec2'
def test_cloudforms_inventory_removal(inventory):
ManagedCredentialType(
name='Red Hat CloudForms',
namespace='cloudforms',
kind='cloud',
managed_by_tower=True,
inputs={},
)
invsrc.create_scm_script_substitute(apps, 'ec2')
inv_source.refresh_from_db()
assert inv_source.source == 'scm'
assert inv_source.source_project
project = inv_source.source_project
assert 'Replacement project for' in project.name
CredentialType.defaults['cloudforms']().save()
cloudforms = CredentialType.objects.get(namespace='cloudforms')
Credential.objects.create(
name='test',
credential_type=cloudforms,
)
for source in ('ec2', 'cloudforms'):
i = InventorySource.objects.create(
name='test',
inventory=inventory,
organization=inventory.organization,
source=source,
)
InventoryUpdate.objects.create(
name='test update',
inventory_source=i,
source=source,
)
assert Credential.objects.count() == 1
assert InventorySource.objects.count() == 2 # ec2 + cf
assert InventoryUpdate.objects.count() == 2 # ec2 + cf
invsrc.delete_cloudforms_inv_source(apps, None)
assert InventorySource.objects.count() == 1 # ec2
assert InventoryUpdate.objects.count() == 1 # ec2
assert InventorySource.objects.first().source == 'ec2'
assert InventoryUpdate.objects.first().source == 'ec2'
assert Credential.objects.count() == 0
assert CredentialType.objects.filter(namespace='cloudforms').exists() is False

View File

@@ -1,6 +1,5 @@
import glob
import json
import os
from django.conf import settings
@@ -30,8 +29,7 @@ def test_python_and_js_licenses():
# Check variations of '-' and '_' in filenames due to python
for fname in [name, name.replace('-','_')]:
if entry.startswith(fname) and entry.endswith('.tar.gz'):
entry = entry[:-7]
(n, v) = entry.rsplit('-',1)
v = entry.split(name + '-')[1].split('.tar.gz')[0]
return v
return None
@@ -66,28 +64,6 @@ def test_python_and_js_licenses():
ret[name] = { 'name': name, 'version': version}
return ret
def read_ui_requirements(path):
def json_deps(jsondata):
ret = {}
deps = jsondata.get('dependencies',{})
for key in deps.keys():
key = key.lower()
devonly = deps[key].get('dev',False)
if not devonly:
if key not in ret.keys():
depname = key.replace('/','-')
ret[depname] = {
'name': depname,
'version': deps[key]['version']
}
ret.update(json_deps(deps[key]))
return ret
with open('%s/package-lock.json' % path) as f:
jsondata = json.load(f)
return json_deps(jsondata)
def remediate_licenses_and_requirements(licenses, requirements):
errors = []
items = list(licenses.keys())
@@ -114,12 +90,9 @@ def test_python_and_js_licenses():
base_dir = settings.BASE_DIR
api_licenses = index_licenses('%s/../docs/licenses' % base_dir)
ui_licenses = index_licenses('%s/../docs/licenses/ui' % base_dir)
api_requirements = read_api_requirements('%s/../requirements' % base_dir)
ui_requirements = read_ui_requirements('%s/ui' % base_dir)
errors = []
errors += remediate_licenses_and_requirements(ui_licenses, ui_requirements)
errors += remediate_licenses_and_requirements(api_licenses, api_requirements)
if errors:
raise Exception('Included licenses not consistent with requirements:\n%s' %

View File

@@ -4,7 +4,7 @@ from unittest import mock
from django.test import TransactionTestCase
from awx.main.access import UserAccess, RoleAccess, TeamAccess
from awx.main.models import User, Organization, Inventory
from awx.main.models import User, Organization, Inventory, Role
class TestSysAuditorTransactional(TransactionTestCase):
@@ -170,4 +170,34 @@ def test_org_admin_cannot_delete_member_attached_to_other_group(org_admin, org_m
access = UserAccess(org_admin)
other_org.member_role.members.add(org_member)
assert not access.can_delete(org_member)
@pytest.mark.parametrize('reverse', (True, False))
@pytest.mark.django_db
def test_consistency_of_is_superuser_flag(reverse):
users = [User.objects.create(username='rando_{}'.format(i)) for i in range(2)]
for u in users:
assert u.is_superuser is False
system_admin = Role.singleton('system_administrator')
if reverse:
for u in users:
u.roles.add(system_admin)
else:
system_admin.members.add(*[u.id for u in users]) # like .add(42, 54)
for u in users:
u.refresh_from_db()
assert u.is_superuser is True
users[0].roles.clear()
for u in users:
u.refresh_from_db()
assert users[0].is_superuser is False
assert users[1].is_superuser is True
system_admin.members.clear()
for u in users:
u.refresh_from_db()
assert u.is_superuser is False

View File

@@ -33,32 +33,6 @@ class TestInvalidOptions:
assert 'inventory-id' in str(err.value)
assert 'exclusive' in str(err.value)
def test_invalid_options_id_and_keep_vars(self):
# You can't overwrite and keep_vars at the same time, that wouldn't make sense
cmd = Command()
with pytest.raises(CommandError) as err:
cmd.handle(
inventory_id=42, overwrite=True, keep_vars=True
)
assert 'overwrite-vars' in str(err.value)
assert 'exclusive' in str(err.value)
def test_invalid_options_id_but_no_source(self):
# Need a source to import
cmd = Command()
with pytest.raises(CommandError) as err:
cmd.handle(
inventory_id=42, overwrite=True, keep_vars=True
)
assert 'overwrite-vars' in str(err.value)
assert 'exclusive' in str(err.value)
with pytest.raises(CommandError) as err:
cmd.handle(
inventory_id=42, overwrite_vars=True, keep_vars=True
)
assert 'overwrite-vars' in str(err.value)
assert 'exclusive' in str(err.value)
def test_invalid_options_missing_source(self):
cmd = Command()
with pytest.raises(CommandError) as err:

View File

@@ -39,6 +39,8 @@ from awx.main import tasks
from awx.main.utils import encrypt_field, encrypt_value
from awx.main.utils.safe_yaml import SafeLoader
from awx.main.utils.licensing import Licenser
class TestJobExecution(object):
EXAMPLE_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nxyz==\n-----END PRIVATE KEY-----'
@@ -178,7 +180,7 @@ def test_openstack_client_config_generation(mocker, source, expected, private_da
'source_vars_dict': {},
'get_cloud_credential': mocker.Mock(return_value=credential),
'get_extra_credentials': lambda x: [],
'ansible_virtualenv_path': '/venv/foo'
'ansible_virtualenv_path': '/var/lib/awx/venv/foo'
})
cloud_config = update.build_private_data(inventory_update, private_data_dir)
cloud_credential = yaml.safe_load(
@@ -222,6 +224,52 @@ def test_openstack_client_config_generation_with_project_domain_name(mocker, sou
'source_vars_dict': {},
'get_cloud_credential': mocker.Mock(return_value=credential),
'get_extra_credentials': lambda x: [],
'ansible_virtualenv_path': '/var/lib/awx/venv/foo'
})
cloud_config = update.build_private_data(inventory_update, private_data_dir)
cloud_credential = yaml.safe_load(
cloud_config.get('credentials')[credential]
)
assert cloud_credential['clouds'] == {
'devstack': {
'auth': {
'auth_url': 'https://keystone.openstack.example.org',
'password': 'secrete',
'project_name': 'demo-project',
'username': 'demo',
'domain_name': 'my-demo-domain',
'project_domain_name': 'project-domain',
},
'verify': expected,
'private': True,
}
}
@pytest.mark.parametrize("source,expected", [
(None, True), (False, False), (True, True)
])
def test_openstack_client_config_generation_with_project_region_name(mocker, source, expected, private_data_dir):
update = tasks.RunInventoryUpdate()
credential_type = CredentialType.defaults['openstack']()
inputs = {
'host': 'https://keystone.openstack.example.org',
'username': 'demo',
'password': 'secrete',
'project': 'demo-project',
'domain': 'my-demo-domain',
'project_domain_name': 'project-domain',
'project_region_name': 'region-name',
}
if source is not None:
inputs['verify_ssl'] = source
credential = Credential(pk=1, credential_type=credential_type, inputs=inputs)
inventory_update = mocker.Mock(**{
'source': 'openstack',
'source_vars_dict': {},
'get_cloud_credential': mocker.Mock(return_value=credential),
'get_extra_credentials': lambda x: [],
'ansible_virtualenv_path': '/venv/foo'
})
cloud_config = update.build_private_data(inventory_update, private_data_dir)
@@ -240,6 +288,7 @@ def test_openstack_client_config_generation_with_project_domain_name(mocker, sou
},
'verify': expected,
'private': True,
'region_name': 'region-name',
}
}
@@ -265,7 +314,7 @@ def test_openstack_client_config_generation_with_private_source_vars(mocker, sou
'source_vars_dict': {'private': source},
'get_cloud_credential': mocker.Mock(return_value=credential),
'get_extra_credentials': lambda x: [],
'ansible_virtualenv_path': '/venv/foo'
'ansible_virtualenv_path': '/var/lib/awx/venv/foo'
})
cloud_config = update.build_private_data(inventory_update, private_data_dir)
cloud_credential = yaml.load(
@@ -623,13 +672,13 @@ class TestGenericRun():
def test_invalid_custom_virtualenv(self, patch_Job, private_data_dir):
job = Job(project=Project(), inventory=Inventory())
job.project.custom_virtualenv = '/venv/missing'
job.project.custom_virtualenv = '/var/lib/awx/venv/missing'
task = tasks.RunJob()
with pytest.raises(tasks.InvalidVirtualenvError) as e:
task.build_env(job, private_data_dir)
assert 'Invalid virtual environment selected: /venv/missing' == str(e.value)
assert 'Invalid virtual environment selected: /var/lib/awx/venv/missing' == str(e.value)
class TestAdhocRun(TestJobExecution):
@@ -1830,7 +1879,10 @@ class TestProjectUpdateGalaxyCredentials(TestJobExecution):
task = RunProjectUpdate()
env = task.build_env(project_update, private_data_dir)
task.build_extra_vars_file(project_update, private_data_dir)
with mock.patch.object(Licenser, 'validate', lambda *args, **kw: {}):
task.build_extra_vars_file(project_update, private_data_dir)
assert task.__vars__['roles_enabled'] is False
assert task.__vars__['collections_enabled'] is False
for k in env:
@@ -1850,7 +1902,10 @@ class TestProjectUpdateGalaxyCredentials(TestJobExecution):
project_update.project.organization.galaxy_credentials.add(public_galaxy)
task = RunProjectUpdate()
env = task.build_env(project_update, private_data_dir)
task.build_extra_vars_file(project_update, private_data_dir)
with mock.patch.object(Licenser, 'validate', lambda *args, **kw: {}):
task.build_extra_vars_file(project_update, private_data_dir)
assert task.__vars__['roles_enabled'] is True
assert task.__vars__['collections_enabled'] is True
assert sorted([
@@ -1901,19 +1956,16 @@ class TestProjectUpdateCredentials(TestJobExecution):
parametrize = {
'test_username_and_password_auth': [
dict(scm_type='git'),
dict(scm_type='hg'),
dict(scm_type='svn'),
dict(scm_type='archive'),
],
'test_ssh_key_auth': [
dict(scm_type='git'),
dict(scm_type='hg'),
dict(scm_type='svn'),
dict(scm_type='archive'),
],
'test_awx_task_env': [
dict(scm_type='git'),
dict(scm_type='hg'),
dict(scm_type='svn'),
dict(scm_type='archive'),
]
@@ -1935,7 +1987,9 @@ class TestProjectUpdateCredentials(TestJobExecution):
assert settings.PROJECTS_ROOT in process_isolation['process_isolation_show_paths']
task._write_extra_vars_file = mock.Mock()
task.build_extra_vars_file(project_update, private_data_dir)
with mock.patch.object(Licenser, 'validate', lambda *args, **kw: {}):
task.build_extra_vars_file(project_update, private_data_dir)
call_args, _ = task._write_extra_vars_file.call_args_list[0]
_, extra_vars = call_args
@@ -2051,8 +2105,8 @@ class TestInventoryUpdateCredentials(TestJobExecution):
credential, env, {}, [], private_data_dir
)
assert '--custom' in ' '.join(args)
script = args[args.index('--source') + 1]
assert '-i' in ' '.join(args)
script = args[args.index('-i') + 1]
with open(script, 'r') as f:
assert f.read() == inventory_update.source_script.script
assert env['FOO'] == 'BAR'
@@ -2140,10 +2194,6 @@ class TestInventoryUpdateCredentials(TestJobExecution):
return cred
inventory_update.get_cloud_credential = get_cred
inventory_update.get_extra_credentials = mocker.Mock(return_value=[])
inventory_update.source_vars = {
'include_powerstate': 'yes',
'group_by_resource_group': 'no'
}
private_data_files = task.build_private_data_files(inventory_update, private_data_dir)
env = task.build_env(inventory_update, private_data_dir, False, private_data_files)
@@ -2177,11 +2227,6 @@ class TestInventoryUpdateCredentials(TestJobExecution):
return cred
inventory_update.get_cloud_credential = get_cred
inventory_update.get_extra_credentials = mocker.Mock(return_value=[])
inventory_update.source_vars = {
'include_powerstate': 'yes',
'group_by_resource_group': 'no',
'group_by_security_group': 'no'
}
private_data_files = task.build_private_data_files(inventory_update, private_data_dir)
env = task.build_env(inventory_update, private_data_dir, False, private_data_files)
@@ -2296,21 +2341,14 @@ class TestInventoryUpdateCredentials(TestJobExecution):
inventory_update.get_cloud_credential = get_cred
inventory_update.get_extra_credentials = mocker.Mock(return_value=[])
inventory_update.source_vars = {
'satellite6_group_patterns': '[a,b,c]',
'satellite6_group_prefix': 'hey_',
'satellite6_want_hostcollections': True,
'satellite6_want_ansible_ssh_host': True,
'satellite6_rich_params': True,
'satellite6_want_facts': False
}
private_data_files = task.build_private_data_files(inventory_update, private_data_dir)
env = task.build_env(inventory_update, private_data_dir, False, private_data_files)
safe_env = build_safe_env(env)
env["FOREMAN_SERVER"] == "https://example.org",
env["FOREMAN_USER"] == "bob",
env["FOREMAN_PASSWORD"] == "secret",
assert env["FOREMAN_SERVER"] == "https://example.org"
assert env["FOREMAN_USER"] == "bob"
assert env["FOREMAN_PASSWORD"] == "secret"
assert safe_env["FOREMAN_PASSWORD"] == tasks.HIDDEN_PASSWORD
@pytest.mark.parametrize('verify', [True, False])
def test_tower_source(self, verify, inventory_update, private_data_dir, mocker):

View File

@@ -55,8 +55,7 @@ __all__ = [
'model_instance_diff', 'parse_yaml_or_json', 'RequireDebugTrueOrTest',
'has_model_field_prefetched', 'set_environ', 'IllegalArgumentError',
'get_custom_venv_choices', 'get_external_account', 'task_manager_bulk_reschedule',
'schedule_task_manager', 'classproperty', 'create_temporary_fifo', 'truncate_stdout',
'StubLicense'
'schedule_task_manager', 'classproperty', 'create_temporary_fifo', 'truncate_stdout'
]
@@ -190,7 +189,7 @@ def get_awx_version():
def get_awx_http_client_headers():
license = get_license(show_key=False).get('license_type', 'UNLICENSED')
license = get_license().get('license_type', 'UNLICENSED')
headers = {
'Content-Type': 'application/json',
'User-Agent': '{} {} ({})'.format(
@@ -202,34 +201,15 @@ def get_awx_http_client_headers():
return headers
class StubLicense(object):
features = {
'activity_streams': True,
'ha': True,
'ldap': True,
'multiple_organizations': True,
'surveys': True,
'system_tracking': True,
'rebranding': True,
'enterprise_auth': True,
'workflows': True,
}
def validate(self):
return dict(license_key='OPEN',
valid_key=True,
compliant=True,
features=self.features,
license_type='open')
def get_licenser(*args, **kwargs):
from awx.main.utils.licensing import Licenser, OpenLicense
try:
from tower_license import TowerLicense
return TowerLicense(*args, **kwargs)
except ImportError:
return StubLicense(*args, **kwargs)
if os.path.exists('/var/lib/awx/.tower_version'):
return Licenser(*args, **kwargs)
else:
return OpenLicense()
except Exception as e:
raise ValueError(_('Error importing Tower License: %s') % e)
def update_scm_url(scm_type, url, username=True, password=True,
@@ -242,9 +222,8 @@ def update_scm_url(scm_type, url, username=True, password=True,
'''
# Handle all of the URL formats supported by the SCM systems:
# git: https://www.kernel.org/pub/software/scm/git/docs/git-clone.html#URLS
# hg: http://www.selenic.com/mercurial/hg.1.html#url-paths
# svn: http://svnbook.red-bean.com/en/1.7/svn-book.html#svn.advanced.reposurls
if scm_type not in ('git', 'hg', 'svn', 'insights', 'archive'):
if scm_type not in ('git', 'svn', 'insights', 'archive'):
raise ValueError(_('Unsupported SCM type "%s"') % str(scm_type))
if not url.strip():
return ''
@@ -276,8 +255,8 @@ def update_scm_url(scm_type, url, username=True, password=True,
# SCP style before passed to git module.
parts = urllib.parse.urlsplit('git+ssh://%s' % modified_url)
# Handle local paths specified without file scheme (e.g. /path/to/foo).
# Only supported by git and hg.
elif scm_type in ('git', 'hg'):
# Only supported by git.
elif scm_type == 'git':
if not url.startswith('/'):
parts = urllib.parse.urlsplit('file:///%s' % url)
else:
@@ -288,7 +267,6 @@ def update_scm_url(scm_type, url, username=True, password=True,
# Validate that scheme is valid for given scm_type.
scm_type_schemes = {
'git': ('ssh', 'git', 'git+ssh', 'http', 'https', 'ftp', 'ftps', 'file'),
'hg': ('http', 'https', 'ssh', 'file'),
'svn': ('http', 'https', 'svn', 'svn+ssh', 'file'),
'insights': ('http', 'https'),
'archive': ('http', 'https'),
@@ -320,12 +298,6 @@ def update_scm_url(scm_type, url, username=True, password=True,
if scm_type == 'git' and parts.scheme.endswith('ssh') and parts.hostname in special_git_hosts and netloc_password:
#raise ValueError('Password not allowed for SSH access to %s.' % parts.hostname)
netloc_password = ''
special_hg_hosts = ('bitbucket.org', 'altssh.bitbucket.org')
if scm_type == 'hg' and parts.scheme == 'ssh' and parts.hostname in special_hg_hosts and netloc_username != 'hg':
raise ValueError(_('Username must be "hg" for SSH access to %s.') % parts.hostname)
if scm_type == 'hg' and parts.scheme == 'ssh' and netloc_password:
#raise ValueError('Password not supported for SSH with Mercurial.')
netloc_password = ''
if netloc_username and parts.scheme != 'file' and scm_type not in ("insights", "archive"):
netloc = u':'.join([urllib.parse.quote(x,safe='') for x in (netloc_username, netloc_password) if x])

View File

@@ -9,6 +9,7 @@ import socket
from datetime import datetime
from dateutil.tz import tzutc
from django.utils.timezone import now
from django.core.serializers.json import DjangoJSONEncoder
from django.conf import settings
@@ -17,8 +18,15 @@ class TimeFormatter(logging.Formatter):
'''
Custom log formatter used for inventory imports
'''
def __init__(self, start_time=None, **kwargs):
if start_time is None:
self.job_start = now()
else:
self.job_start = start_time
super(TimeFormatter, self).__init__(**kwargs)
def format(self, record):
record.relativeSeconds = record.relativeCreated / 1000.0
record.relativeSeconds = (now() - self.job_start).total_seconds()
return logging.Formatter.format(self, record)

View File

@@ -7,6 +7,10 @@ import os.path
# Django
from django.conf import settings
from django.utils.timezone import now
# AWX
from awx.main.exceptions import PostRunError
class RSysLogHandler(logging.handlers.SysLogHandler):
@@ -40,6 +44,58 @@ class RSysLogHandler(logging.handlers.SysLogHandler):
pass
class SpecialInventoryHandler(logging.Handler):
"""Logging handler used for the saving-to-database part of inventory updates
ran by the task system
this dispatches events directly to be processed by the callback receiver,
as opposed to ansible-runner
"""
def __init__(self, event_handler, cancel_callback, job_timeout, verbosity,
start_time=None, counter=0, initial_line=0, **kwargs):
self.event_handler = event_handler
self.cancel_callback = cancel_callback
self.job_timeout = job_timeout
if start_time is None:
self.job_start = now()
else:
self.job_start = start_time
self.last_check = self.job_start
self.counter = counter
self.skip_level = [logging.WARNING, logging.INFO, logging.DEBUG, 0][verbosity]
self._current_line = initial_line
super(SpecialInventoryHandler, self).__init__(**kwargs)
def emit(self, record):
# check cancel and timeout status regardless of log level
this_time = now()
if (this_time - self.last_check).total_seconds() > 0.5: # cancel callback is expensive
self.last_check = this_time
if self.cancel_callback():
raise PostRunError('Inventory update has been canceled', status='canceled')
if self.job_timeout and ((this_time - self.job_start).total_seconds() > self.job_timeout):
raise PostRunError('Inventory update has timed out', status='canceled')
# skip logging for low severity logs
if record.levelno < self.skip_level:
return
self.counter += 1
msg = self.format(record)
n_lines = len(msg.strip().split('\n')) # don't count line breaks at boundry of text
dispatch_data = dict(
created=now().isoformat(),
event='verbose',
counter=self.counter,
stdout=msg,
start_line=self._current_line,
end_line=self._current_line + n_lines
)
self._current_line += n_lines
self.event_handler(dispatch_data)
ColorHandler = logging.StreamHandler
if settings.COLOR_LOGS is True:

439
awx/main/utils/licensing.py Normal file
View File

@@ -0,0 +1,439 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
'''
This is intended to be a lightweight license class for verifying subscriptions, and parsing subscription data
from entitlement certificates.
The Licenser class can do the following:
- Parse an Entitlement cert to generate license
'''
import base64
import configparser
from datetime import datetime, timezone
import collections
import copy
import io
import json
import logging
import re
import requests
import time
import zipfile
from dateutil.parser import parse as parse_date
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography import x509
# Django
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.main.models import Host
MAX_INSTANCES = 9999999
logger = logging.getLogger(__name__)
def rhsm_config():
path = '/etc/rhsm/rhsm.conf'
config = configparser.ConfigParser()
config.read(path)
return config
def validate_entitlement_manifest(data):
buff = io.BytesIO()
buff.write(base64.b64decode(data))
try:
z = zipfile.ZipFile(buff)
except zipfile.BadZipFile as e:
raise ValueError(_("Invalid manifest: a subscription manifest zip file is required.")) from e
buff = io.BytesIO()
files = z.namelist()
if 'consumer_export.zip' not in files or 'signature' not in files:
raise ValueError(_("Invalid manifest: missing required files."))
export = z.open('consumer_export.zip').read()
sig = z.open('signature').read()
with open('/etc/tower/candlepin-redhat-ca.crt', 'rb') as f:
cert = x509.load_pem_x509_certificate(f.read(), backend=default_backend())
key = cert.public_key()
try:
key.verify(sig, export, padding=padding.PKCS1v15(), algorithm=hashes.SHA256())
except InvalidSignature as e:
raise ValueError(_("Invalid manifest: signature verification failed.")) from e
buff.write(export)
z = zipfile.ZipFile(buff)
subs = []
for f in z.filelist:
if f.filename.startswith('export/entitlements') and f.filename.endswith('.json'):
subs.append(json.loads(z.open(f).read()))
if subs:
return subs
raise ValueError(_("Invalid manifest: manifest contains no subscriptions."))
class OpenLicense(object):
def validate(self):
return dict(
license_type='open',
valid_key=True,
subscription_name='OPEN',
product_name="AWX",
)
class Licenser(object):
# warn when there is a month (30 days) left on the subscription
SUBSCRIPTION_TIMEOUT = 60 * 60 * 24 * 30
UNLICENSED_DATA = dict(
subscription_name=None,
sku=None,
support_level=None,
instance_count=0,
license_date=0,
license_type="UNLICENSED",
product_name="Red Hat Ansible Automation Platform",
valid_key=False
)
def __init__(self, **kwargs):
self._attrs = dict(
instance_count=0,
license_date=0,
license_type='UNLICENSED',
)
self.config = rhsm_config()
if not kwargs:
license_setting = getattr(settings, 'LICENSE', None)
if license_setting is not None:
kwargs = license_setting
if 'company_name' in kwargs:
kwargs.pop('company_name')
self._attrs.update(kwargs)
if 'valid_key' in self._attrs:
if not self._attrs['valid_key']:
self._unset_attrs()
else:
self._unset_attrs()
def _unset_attrs(self):
self._attrs = self.UNLICENSED_DATA.copy()
def license_from_manifest(self, manifest):
def is_appropriate_manifest_sub(sub):
if sub['pool']['activeSubscription'] is False:
return False
now = datetime.now(timezone.utc)
if parse_date(sub['startDate']) > now:
return False
if parse_date(sub['endDate']) < now:
return False
products = sub['pool']['providedProducts']
if any(product.get('productId') == '480' for product in products):
return True
return False
def _can_aggregate(sub, license):
# We aggregate multiple subs into a larger meta-sub, if they match
#
# No current sub in aggregate
if not license:
return True
# Same SKU type (SER vs MCT vs others)?
if license['sku'][0:3] != sub['pool']['productId'][0:3]:
return False
return True
# Parse output for subscription metadata to build config
license = dict()
for sub in manifest:
if not is_appropriate_manifest_sub(sub):
logger.warning("Subscription %s (%s) in manifest is not active or for another product" %
(sub['pool']['productName'], sub['pool']['productId']))
continue
if not _can_aggregate(sub, license):
logger.warning("Subscription %s (%s) in manifest does not match other manifest subscriptions" %
(sub['pool']['productName'], sub['pool']['productId']))
continue
license.setdefault('sku', sub['pool']['productId'])
license.setdefault('subscription_name', sub['pool']['productName'])
license.setdefault('pool_id', sub['pool']['id'])
license.setdefault('product_name', sub['pool']['productName'])
license.setdefault('valid_key', True)
license.setdefault('license_type', 'enterprise')
license.setdefault('satellite', False)
# Use the nearest end date
endDate = parse_date(sub['endDate'])
currentEndDateStr = license.get('license_date', '4102462800') # 2100-01-01
currentEndDate = datetime.fromtimestamp(int(currentEndDateStr), timezone.utc)
if endDate < currentEndDate:
license['license_date'] = endDate.strftime('%s')
instances = sub['quantity']
license['instance_count'] = license.get('instance_count', 0) + instances
license['subscription_name'] = re.sub(r'[\d]* Managed Nodes', '%d Managed Nodes' % license['instance_count'], license['subscription_name'])
if not license:
logger.error("No valid subscriptions found in manifest")
self._attrs.update(license)
settings.LICENSE = self._attrs
return self._attrs
def update(self, **kwargs):
# Update attributes of the current license.
if 'instance_count' in kwargs:
kwargs['instance_count'] = int(kwargs['instance_count'])
if 'license_date' in kwargs:
kwargs['license_date'] = int(kwargs['license_date'])
self._attrs.update(kwargs)
def validate_rh(self, user, pw):
try:
host = 'https://' + str(self.config.get("server", "hostname"))
except Exception:
logger.exception('Cannot access rhsm.conf, make sure subscription manager is installed and configured.')
host = None
if not host:
host = getattr(settings, 'REDHAT_CANDLEPIN_HOST', None)
if not user:
raise ValueError('subscriptions_username is required')
if not pw:
raise ValueError('subscriptions_password is required')
if host and user and pw:
if 'subscription.rhsm.redhat.com' in host:
json = self.get_rhsm_subs(host, user, pw)
else:
json = self.get_satellite_subs(host, user, pw)
return self.generate_license_options_from_entitlements(json)
return []
def get_rhsm_subs(self, host, user, pw):
verify = getattr(settings, 'REDHAT_CANDLEPIN_VERIFY', True)
json = []
try:
subs = requests.get(
'/'.join([host, 'subscription/users/{}/owners'.format(user)]),
verify=verify,
auth=(user, pw)
)
except requests.exceptions.ConnectionError as error:
raise error
except OSError as error:
raise OSError('Unable to open certificate bundle {}. Check that Ansible Tower is running on Red Hat Enterprise Linux.'.format(verify)) from error # noqa
subs.raise_for_status()
for sub in subs.json():
resp = requests.get(
'/'.join([
host,
'subscription/owners/{}/pools/?match=*tower*'.format(sub['key'])
]),
verify=verify,
auth=(user, pw)
)
resp.raise_for_status()
json.extend(resp.json())
return json
def get_satellite_subs(self, host, user, pw):
port = None
try:
verify = str(self.config.get("rhsm", "repo_ca_cert"))
port = str(self.config.get("server", "port"))
except Exception as e:
logger.exception('Unable to read rhsm config to get ca_cert location. {}'.format(str(e)))
verify = getattr(settings, 'REDHAT_CANDLEPIN_VERIFY', True)
if port:
host = ':'.join([host, port])
json = []
try:
orgs = requests.get(
'/'.join([host, 'katello/api/organizations']),
verify=verify,
auth=(user, pw)
)
except requests.exceptions.ConnectionError as error:
raise error
except OSError as error:
raise OSError('Unable to open certificate bundle {}. Check that Ansible Tower is running on Red Hat Enterprise Linux.'.format(verify)) from error # noqa
orgs.raise_for_status()
for org in orgs.json()['results']:
resp = requests.get(
'/'.join([
host,
'/katello/api/organizations/{}/subscriptions/?search=Red Hat Ansible Automation'.format(org['id'])
]),
verify=verify,
auth=(user, pw)
)
resp.raise_for_status()
results = resp.json()['results']
if results != []:
for sub in results:
# Parse output for subscription metadata to build config
license = dict()
license['productId'] = sub['product_id']
license['quantity'] = int(sub['quantity'])
license['support_level'] = sub['support_level']
license['subscription_name'] = sub['name']
license['id'] = sub['upstream_pool_id']
license['endDate'] = sub['end_date']
license['productName'] = "Red Hat Ansible Automation"
license['valid_key'] = True
license['license_type'] = 'enterprise'
license['satellite'] = True
json.append(license)
return json
def is_appropriate_sat_sub(self, sub):
if 'Red Hat Ansible Automation' not in sub['subscription_name']:
return False
return True
def is_appropriate_sub(self, sub):
if sub['activeSubscription'] is False:
return False
# Products that contain Ansible Tower
products = sub.get('providedProducts', [])
if any(product.get('productId') == '480' for product in products):
return True
return False
def generate_license_options_from_entitlements(self, json):
from dateutil.parser import parse
ValidSub = collections.namedtuple('ValidSub', 'sku name support_level end_date trial quantity pool_id satellite')
valid_subs = []
for sub in json:
satellite = sub.get('satellite')
if satellite:
is_valid = self.is_appropriate_sat_sub(sub)
else:
is_valid = self.is_appropriate_sub(sub)
if is_valid:
try:
end_date = parse(sub.get('endDate'))
except Exception:
continue
now = datetime.utcnow()
now = now.replace(tzinfo=end_date.tzinfo)
if end_date < now:
# If the sub has a past end date, skip it
continue
try:
quantity = int(sub['quantity'])
if quantity == -1:
# effectively, unlimited
quantity = MAX_INSTANCES
except Exception:
continue
sku = sub['productId']
trial = sku.startswith('S') # i.e.,, SER/SVC
support_level = ''
pool_id = sub['id']
if satellite:
support_level = sub['support_level']
else:
for attr in sub.get('productAttributes', []):
if attr.get('name') == 'support_level':
support_level = attr.get('value')
valid_subs.append(ValidSub(
sku, sub['productName'], support_level, end_date, trial, quantity, pool_id, satellite
))
if valid_subs:
licenses = []
for sub in valid_subs:
license = self.__class__(subscription_name='Red Hat Ansible Automation Platform')
license._attrs['instance_count'] = int(sub.quantity)
license._attrs['sku'] = sub.sku
license._attrs['support_level'] = sub.support_level
license._attrs['license_type'] = 'enterprise'
if sub.trial:
license._attrs['trial'] = True
license._attrs['license_type'] = 'trial'
license._attrs['instance_count'] = min(
MAX_INSTANCES, license._attrs['instance_count']
)
human_instances = license._attrs['instance_count']
if human_instances == MAX_INSTANCES:
human_instances = 'Unlimited'
subscription_name = re.sub(
r' \([\d]+ Managed Nodes',
' ({} Managed Nodes'.format(human_instances),
sub.name
)
license._attrs['subscription_name'] = subscription_name
license._attrs['satellite'] = satellite
license._attrs['valid_key'] = True
license.update(
license_date=int(sub.end_date.strftime('%s'))
)
license.update(
pool_id=sub.pool_id
)
licenses.append(license._attrs.copy())
return licenses
raise ValueError(
'No valid Red Hat Ansible Automation subscription could be found for this account.' # noqa
)
def validate(self):
# Return license attributes with additional validation info.
attrs = copy.deepcopy(self._attrs)
type = attrs.get('license_type', 'none')
if (type == 'UNLICENSED' or False):
attrs.update(dict(valid_key=False, compliant=False))
return attrs
attrs['valid_key'] = True
if Host:
current_instances = Host.objects.active_count()
else:
current_instances = 0
instance_count = int(attrs.get('instance_count', 0))
attrs['current_instances'] = current_instances
free_instances = (instance_count - current_instances)
attrs['free_instances'] = max(0, free_instances)
license_date = int(attrs.get('license_date', 0) or 0)
current_date = int(time.time())
time_remaining = license_date - current_date
attrs['time_remaining'] = time_remaining
if attrs.setdefault('trial', False):
attrs['grace_period_remaining'] = time_remaining
else:
attrs['grace_period_remaining'] = (license_date + 2592000) - current_date
attrs['compliant'] = bool(time_remaining > 0 and free_instances >= 0)
attrs['date_warning'] = bool(time_remaining < self.SUBSCRIPTION_TIMEOUT)
attrs['date_expired'] = bool(time_remaining <= 0)
return attrs

151
awx/main/utils/profiling.py Normal file
View File

@@ -0,0 +1,151 @@
import cProfile
import functools
import pstats
import os
import uuid
import datetime
import json
import sys
class AWXProfileBase:
def __init__(self, name, dest):
self.name = name
self.dest = dest
self.results = {}
def generate_results(self):
raise RuntimeError("define me")
def output_results(self, fname=None):
if not os.path.isdir(self.dest):
os.makedirs(self.dest)
if fname:
fpath = os.path.join(self.dest, fname)
with open(fpath, 'w') as f:
f.write(json.dumps(self.results, indent=2))
class AWXTiming(AWXProfileBase):
def __init__(self, name, dest='/var/log/tower/timing'):
super().__init__(name, dest)
self.time_start = None
self.time_end = None
def start(self):
self.time_start = datetime.datetime.now()
def stop(self):
self.time_end = datetime.datetime.now()
self.generate_results()
self.output_results()
def generate_results(self):
diff = (self.time_end - self.time_start).total_seconds()
self.results = {
'name': self.name,
'diff': f'{diff}-seconds',
}
def output_results(self):
fname = f"{self.results['diff']}-{self.name}-{uuid.uuid4()}.time"
super().output_results(fname)
def timing(name, *init_args, **init_kwargs):
def decorator_profile(func):
@functools.wraps(func)
def wrapper_profile(*args, **kwargs):
timing = AWXTiming(name, *init_args, **init_kwargs)
timing.start()
res = func(*args, **kwargs)
timing.stop()
return res
return wrapper_profile
return decorator_profile
class AWXProfiler(AWXProfileBase):
def __init__(self, name, dest='/var/log/tower/profile', dot_enabled=True):
'''
Try to do as little as possible in init. Instead, do the init
only when the profiling is started.
'''
super().__init__(name, dest)
self.started = False
self.dot_enabled = dot_enabled
self.results = {
'total_time_seconds': 0,
}
def generate_results(self):
self.results['total_time_seconds'] = pstats.Stats(self.prof).total_tt
def output_results(self):
super().output_results()
filename_base = '%.3fs-%s-%s-%s' % (self.results['total_time_seconds'], self.name, self.pid, uuid.uuid4())
pstats_filepath = os.path.join(self.dest, f"{filename_base}.pstats")
extra_data = ""
if self.dot_enabled:
try:
from gprof2dot import main as generate_dot
except ImportError:
extra_data = 'Dot graph generation failed due to package "gprof2dot" being unavailable.'
else:
raw_filepath = os.path.join(self.dest, f"{filename_base}.raw")
dot_filepath = os.path.join(self.dest, f"{filename_base}.dot")
pstats.Stats(self.prof).dump_stats(raw_filepath)
generate_dot([
'-n', '2.5', '-f', 'pstats', '-o',
dot_filepath,
raw_filepath
])
os.remove(raw_filepath)
with open(pstats_filepath, 'w') as f:
print(f"{self.name}, {extra_data}", file=f)
pstats.Stats(self.prof, stream=f).sort_stats('cumulative').print_stats()
return pstats_filepath
def start(self):
self.prof = cProfile.Profile()
self.pid = os.getpid()
self.prof.enable()
self.started = True
def is_started(self):
return self.started
def stop(self):
if self.started:
self.prof.disable()
self.generate_results()
res = self.output_results()
self.started = False
return res
else:
print("AWXProfiler::stop() called without calling start() first", file=sys.stderr)
return None
def profile(name, *init_args, **init_kwargs):
def decorator_profile(func):
@functools.wraps(func)
def wrapper_profile(*args, **kwargs):
prof = AWXProfiler(name, *init_args, **init_kwargs)
prof.start()
res = func(*args, **kwargs)
prof.stop()
return res
return wrapper_profile
return decorator_profile

View File

@@ -1,15 +0,0 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.plugins.action import ActionBase
class ActionModule(ActionBase):
def run(self, tmp=None, task_vars=None):
self._supports_check_mode = False
result = super(ActionModule, self).run(tmp, task_vars)
result['changed'] = result['failed'] = False
result['msg'] = ''
self._display.deprecated("Mercurial support is deprecated")
return result

View File

@@ -9,6 +9,9 @@
- ansible.posix
tasks:
- name: "Output job the playbook is running for"
debug:
msg: "Checking on job {{ job_id }}"
- name: Determine if daemon process is alive.
shell: "ansible-runner is-alive {{src}}"

View File

@@ -48,12 +48,6 @@
tags:
- update_git
- block:
- name: include hg tasks
include_tasks: project_update_hg_tasks.yml
tags:
- update_hg
- block:
- name: update project using svn
subversion:
@@ -150,7 +144,6 @@
msg: "Repository Version {{ scm_version }}"
tags:
- update_git
- update_hg
- update_svn
- update_insights
- update_archive

View File

@@ -1,20 +0,0 @@
---
- name: Mercurial support is deprecated.
hg_deprecation:
- name: update project using hg
hg:
dest: "{{project_path|quote}}"
repo: "{{scm_url|quote}}"
revision: "{{scm_branch|quote}}"
force: "{{scm_clean}}"
register: hg_result
- name: Set the hg repository version
set_fact:
scm_version: "{{ hg_result['after'] }}"
when: "'after' in hg_result"
- name: parse hg version string properly
set_fact:
scm_version: "{{scm_version|regex_replace('^([A-Za-z0-9]+).*$', '\\1')}}"

View File

@@ -13,6 +13,10 @@
- ansible.posix
tasks:
- name: "Output job the playbook is running for"
debug:
msg: "Checking on job {{ job_id }}"
- name: synchronize job environment with isolated host
synchronize:
copy_links: true

View File

@@ -91,7 +91,6 @@ USE_L10N = True
USE_TZ = True
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'ui', 'static'),
os.path.join(BASE_DIR, 'ui_next', 'build', 'static'),
os.path.join(BASE_DIR, 'static'),
)
@@ -117,7 +116,7 @@ LOGIN_URL = '/api/login/'
# Absolute filesystem path to the directory to host projects (with playbooks).
# This directory should not be web-accessible.
PROJECTS_ROOT = os.path.join(BASE_DIR, 'projects')
PROJECTS_ROOT = '/var/lib/awx/projects/'
# Absolute filesystem path to the directory to host collections for
# running inventory imports, isolated playbooks
@@ -126,10 +125,10 @@ AWX_ANSIBLE_COLLECTIONS_PATHS = os.path.join(BASE_DIR, 'vendor', 'awx_ansible_co
# Absolute filesystem path to the directory for job status stdout (default for
# development and tests, default for production defined in production.py). This
# directory should not be web-accessible
JOBOUTPUT_ROOT = os.path.join(BASE_DIR, 'job_output')
JOBOUTPUT_ROOT = '/var/lib/awx/job_status/'
# Absolute filesystem path to the directory to store logs
LOG_ROOT = os.path.join(BASE_DIR)
LOG_ROOT = '/var/log/tower/'
# The heartbeat file for the tower scheduler
SCHEDULE_METADATA_LOCATION = os.path.join(BASE_DIR, '.tower_cycle')
@@ -197,9 +196,9 @@ LOCAL_STDOUT_EXPIRE_TIME = 2592000
# events into the database
JOB_EVENT_WORKERS = 4
# The number of seconds (must be an integer) to buffer callback receiver bulk
# The number of seconds to buffer callback receiver bulk
# writes in memory before flushing via JobEvent.objects.bulk_create()
JOB_EVENT_BUFFER_SECONDS = 1
JOB_EVENT_BUFFER_SECONDS = .1
# The interval at which callback receiver statistics should be
# recorded
@@ -249,8 +248,7 @@ TEMPLATES = [
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'awx.ui.context_processors.settings',
'awx.ui.context_processors.version',
'awx.ui.context_processors.csp',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
],
@@ -664,7 +662,7 @@ INV_ENV_VARIABLE_BLOCKED = ("HOME", "USER", "_", "TERM")
# ----------------
EC2_ENABLED_VAR = 'ec2_state'
EC2_ENABLED_VALUE = 'running'
EC2_INSTANCE_ID_VAR = 'ec2_id'
EC2_INSTANCE_ID_VAR = 'instance_id'
EC2_EXCLUDE_EMPTY_GROUPS = True
# ------------
@@ -934,6 +932,14 @@ LOGGING = {
'backupCount': 5,
'formatter':'simple',
},
'isolated_manager': {
'level': 'WARNING',
'class':'logging.handlers.RotatingFileHandler',
'filename': os.path.join(LOG_ROOT, 'isolated_manager.log'),
'maxBytes': 1024 * 1024 * 5, # 5 MB
'backupCount': 5,
'formatter':'simple',
},
},
'loggers': {
'django': {
@@ -983,6 +989,11 @@ LOGGING = {
'awx.main.wsbroadcast': {
'handlers': ['wsbroadcast'],
},
'awx.isolated.manager': {
'level': 'WARNING',
'handlers': ['console', 'file', 'isolated_manager'],
'propagate': True
},
'awx.isolated.manager.playbooks': {
'handlers': ['management_playbooks'],
'propagate': False

View File

@@ -148,9 +148,9 @@ include(optional('/etc/tower/settings.py'), scope=locals())
include(optional('/etc/tower/conf.d/*.py'), scope=locals())
# Installed differently in Dockerfile compared to production versions
AWX_ANSIBLE_COLLECTIONS_PATHS = '/vendor/awx_ansible_collections'
AWX_ANSIBLE_COLLECTIONS_PATHS = '/var/lib/awx/vendor/awx_ansible_collections'
BASE_VENV_PATH = "/venv/"
BASE_VENV_PATH = "/var/lib/awx/venv/"
ANSIBLE_VENV_PATH = os.path.join(BASE_VENV_PATH, "ansible")
AWX_VENV_PATH = os.path.join(BASE_VENV_PATH, "awx")
@@ -184,3 +184,6 @@ else:
pass
AWX_CALLBACK_PROFILE = True
if 'sqlite3' not in DATABASES['default']['ENGINE']: # noqa
DATABASES['default'].setdefault('OPTIONS', dict()).setdefault('application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63]) # noqa

View File

@@ -48,56 +48,12 @@ if "pytest" in sys.modules:
}
}
# Absolute filesystem path to the directory to host projects (with playbooks).
# This directory should NOT be web-accessible.
PROJECTS_ROOT = '/var/lib/awx/projects/'
# Location for cross-development of inventory plugins
AWX_ANSIBLE_COLLECTIONS_PATHS = '/vendor/awx_ansible_collections'
# Absolute filesystem path to the directory for job status stdout
# This directory should not be web-accessible
JOBOUTPUT_ROOT = os.path.join(BASE_DIR, 'job_status')
AWX_ANSIBLE_COLLECTIONS_PATHS = '/var/lib/awx/vendor/awx_ansible_collections'
# The UUID of the system, for HA.
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
USE_TZ = True
TIME_ZONE = 'UTC'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
# SECURITY WARNING: keep the secret key used in production secret!
# Hardcoded values can leak through source control. Consider loading
# the secret key from an environment variable or a file instead.
SECRET_KEY = 'p7z7g1ql4%6+(6nlebb6hdk7sd^&fnjpal308%n%+p^_e6vo1y'
# HTTP headers and meta keys to search to determine remote host name or IP. Add
# additional items to this list, such as "HTTP_X_FORWARDED_FOR", if behind a
# reverse proxy.
REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
# If Tower is behind a reverse proxy/load balancer, use this setting to
# whitelist the proxy IP addresses from which Tower should trust custom
# REMOTE_HOST_HEADERS header values
# REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']
# PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']
# If this setting is an empty list (the default), the headers specified by
# REMOTE_HOST_HEADERS will be trusted unconditionally')
PROXY_IP_WHITELIST = []
# Define additional environment variables to be passed to ansible subprocesses
#AWX_TASK_ENV['FOO'] = 'BAR'
# If set, use -vvv for project updates instead of -v for more output.
# PROJECT_UPDATE_VVV=True
@@ -108,40 +64,6 @@ PROXY_IP_WHITELIST = []
# Enable logging to syslog. Setting level to ERROR captures 500 errors,
# WARNING also logs 4xx responses.
LOGGING['handlers']['syslog'] = {
'level': 'WARNING',
'filters': ['require_debug_false'],
'class': 'logging.NullHandler',
'formatter': 'simple',
}
LOGGING['loggers']['django.request']['handlers'] = ['console']
LOGGING['loggers']['rest_framework.request']['handlers'] = ['console']
LOGGING['loggers']['awx']['handlers'] = ['console', 'external_logger']
LOGGING['loggers']['awx.main.commands.run_callback_receiver']['handlers'] = [] # propogates to awx
LOGGING['loggers']['awx.main.tasks']['handlers'] = ['console', 'external_logger']
LOGGING['loggers']['awx.main.scheduler']['handlers'] = ['console', 'external_logger']
LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console']
LOGGING['loggers']['social']['handlers'] = ['console']
LOGGING['loggers']['system_tracking_migrations']['handlers'] = ['console']
LOGGING['loggers']['rbac_migrations']['handlers'] = ['console']
LOGGING['loggers']['awx.isolated.manager.playbooks']['handlers'] = ['console']
LOGGING['handlers']['callback_receiver'] = {'class': 'logging.NullHandler'}
LOGGING['handlers']['fact_receiver'] = {'class': 'logging.NullHandler'}
LOGGING['handlers']['task_system'] = {'class': 'logging.NullHandler'}
LOGGING['handlers']['tower_warnings'] = {'class': 'logging.NullHandler'}
LOGGING['handlers']['rbac_migrations'] = {'class': 'logging.NullHandler'}
LOGGING['handlers']['system_tracking_migrations'] = {'class': 'logging.NullHandler'}
LOGGING['handlers']['management_playbooks'] = {'class': 'logging.NullHandler'}
# Enable the following lines to also log to a file.
#LOGGING['handlers']['file'] = {
# 'class': 'logging.FileHandler',
# 'filename': os.path.join(BASE_DIR, 'awx.log'),
# 'formatter': 'simple',
#}
# Enable the following lines to turn on lots of permissions-related logging.
#LOGGING['loggers']['awx.main.access']['level'] = 'DEBUG'
#LOGGING['loggers']['awx.main.signals']['level'] = 'DEBUG'
@@ -154,81 +76,6 @@ LOGGING['handlers']['management_playbooks'] = {'class': 'logging.NullHandler'}
#LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console']
#LOGGING['loggers']['django_auth_ldap']['level'] = 'DEBUG'
###############################################################################
# SCM TEST SETTINGS
###############################################################################
# Define these variables to enable more complete testing of project support for
# SCM updates. The test repositories listed do not have to contain any valid
# playbooks.
try:
path = os.path.expanduser(os.path.expandvars('~/.ssh/id_rsa'))
TEST_SSH_KEY_DATA = open(path, 'rb').read()
except IOError:
TEST_SSH_KEY_DATA = ''
TEST_GIT_USERNAME = ''
TEST_GIT_PASSWORD = ''
TEST_GIT_KEY_DATA = TEST_SSH_KEY_DATA
TEST_GIT_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com.git'
TEST_GIT_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs.git'
TEST_GIT_PRIVATE_SSH = 'git@github.com:ansible/product-docs.git'
TEST_HG_USERNAME = ''
TEST_HG_PASSWORD = ''
TEST_HG_KEY_DATA = TEST_SSH_KEY_DATA
TEST_HG_PUBLIC_HTTPS = 'https://bitbucket.org/cchurch/django-hotrunner'
TEST_HG_PRIVATE_HTTPS = ''
TEST_HG_PRIVATE_SSH = ''
TEST_SVN_USERNAME = ''
TEST_SVN_PASSWORD = ''
TEST_SVN_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com'
TEST_SVN_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs'
# To test repo access via SSH login to localhost.
import getpass
try:
TEST_SSH_LOOPBACK_USERNAME = getpass.getuser()
except KeyError:
TEST_SSH_LOOPBACK_USERNAME = 'root'
TEST_SSH_LOOPBACK_PASSWORD = ''
###############################################################################
# INVENTORY IMPORT TEST SETTINGS
###############################################################################
# Define these variables to enable more complete testing of inventory import
# from cloud providers.
# EC2 credentials
TEST_AWS_ACCESS_KEY_ID = ''
TEST_AWS_SECRET_ACCESS_KEY = ''
TEST_AWS_REGIONS = 'all'
# Check IAM STS credentials
TEST_AWS_SECURITY_TOKEN = ''
# Rackspace credentials
TEST_RACKSPACE_USERNAME = ''
TEST_RACKSPACE_API_KEY = ''
TEST_RACKSPACE_REGIONS = 'all'
# VMware credentials
TEST_VMWARE_HOST = ''
TEST_VMWARE_USER = ''
TEST_VMWARE_PASSWORD = ''
# OpenStack credentials
TEST_OPENSTACK_HOST = ''
TEST_OPENSTACK_USER = ''
TEST_OPENSTACK_PASSWORD = ''
TEST_OPENSTACK_PROJECT = ''
# Azure credentials.
TEST_AZURE_USERNAME = ''
TEST_AZURE_KEY_DATA = ''
BROADCAST_WEBSOCKET_SECRET = '🤖starscream🤖'
BROADCAST_WEBSOCKET_PORT = 8013
BROADCAST_WEBSOCKET_VERIFY_CERT = False

View File

@@ -1,199 +0,0 @@
# Copyright (c) 2015 Ansible, Inc. (formerly AnsibleWorks, Inc.)
# All Rights Reserved.
# Local Django settings for AWX project. Rename to "local_settings.py" and
# edit as needed for your development environment.
# All variables defined in awx/settings/development.py will already be loaded
# into the global namespace before this file is loaded, to allow for reading
# and updating the default settings as needed.
###############################################################################
# MISC PROJECT SETTINGS
###############################################################################
# Database settings to use PostgreSQL for development.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'awx-dev',
'USER': 'awx-dev',
'PASSWORD': 'AWXsome1',
'HOST': 'localhost',
'PORT': '',
}
}
# Use SQLite for unit tests instead of PostgreSQL. If the lines below are
# commented out, Django will create the test_awx-dev database in PostgreSQL to
# run unit tests.
if is_testing(sys.argv):
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'awx.sqlite3'),
'TEST': {
# Test database cannot be :memory: for tests.
'NAME': os.path.join(BASE_DIR, 'awx_test.sqlite3'),
},
}
}
# AMQP configuration.
BROKER_URL = 'amqp://guest:guest@localhost:5672'
# Absolute filesystem path to the directory to host projects (with playbooks).
# This directory should NOT be web-accessible.
PROJECTS_ROOT = os.path.join(BASE_DIR, 'projects')
# Absolute filesystem path to the directory for job status stdout
# This directory should not be web-accessible
JOBOUTPUT_ROOT = os.path.join(BASE_DIR, 'job_status')
# The UUID of the system, for HA.
SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = None
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
# SECURITY WARNING: keep the secret key used in production secret!
# Hardcoded values can leak through source control. Consider loading
# the secret key from an environment variable or a file instead.
SECRET_KEY = 'p7z7g1ql4%6+(6nlebb6hdk7sd^&fnjpal308%n%+p^_e6vo1y'
# HTTP headers and meta keys to search to determine remote host name or IP. Add
# additional items to this list, such as "HTTP_X_FORWARDED_FOR", if behind a
# reverse proxy.
REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
# If Tower is behind a reverse proxy/load balancer, use this setting to
# whitelist the proxy IP addresses from which Tower should trust custom
# REMOTE_HOST_HEADERS header values
# REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']
# PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']
# If this setting is an empty list (the default), the headers specified by
# REMOTE_HOST_HEADERS will be trusted unconditionally')
PROXY_IP_WHITELIST = []
# Define additional environment variables to be passed to ansible subprocesses
#AWX_TASK_ENV['FOO'] = 'BAR'
# If set, use -vvv for project updates instead of -v for more output.
# PROJECT_UPDATE_VVV=True
###############################################################################
# LOGGING SETTINGS
###############################################################################
# Enable logging to syslog. Setting level to ERROR captures 500 errors,
# WARNING also logs 4xx responses.
LOGGING['handlers']['syslog'] = {
'level': 'WARNING',
'filters': [],
'class': 'logging.handlers.SysLogHandler',
'address': '/dev/log',
'facility': 'local0',
'formatter': 'simple',
}
# Enable the following lines to also log to a file.
#LOGGING['handlers']['file'] = {
# 'class': 'logging.FileHandler',
# 'filename': os.path.join(BASE_DIR, 'awx.log'),
# 'formatter': 'simple',
#}
# Enable the following lines to turn on lots of permissions-related logging.
#LOGGING['loggers']['awx.main.access']['level'] = 'DEBUG'
#LOGGING['loggers']['awx.main.signals']['level'] = 'DEBUG'
#LOGGING['loggers']['awx.main.permissions']['level'] = 'DEBUG'
# Enable the following line to turn on database settings logging.
#LOGGING['loggers']['awx.conf']['level'] = 'DEBUG'
# Enable the following lines to turn on LDAP auth logging.
#LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console']
#LOGGING['loggers']['django_auth_ldap']['level'] = 'DEBUG'
###############################################################################
# SCM TEST SETTINGS
###############################################################################
# Define these variables to enable more complete testing of project support for
# SCM updates. The test repositories listed do not have to contain any valid
# playbooks.
try:
path = os.path.expanduser(os.path.expandvars('~/.ssh/id_rsa'))
TEST_SSH_KEY_DATA = file(path, 'rb').read()
except IOError:
TEST_SSH_KEY_DATA = ''
TEST_GIT_USERNAME = ''
TEST_GIT_PASSWORD = ''
TEST_GIT_KEY_DATA = TEST_SSH_KEY_DATA
TEST_GIT_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com.git'
TEST_GIT_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs.git'
TEST_GIT_PRIVATE_SSH = 'git@github.com:ansible/product-docs.git'
TEST_HG_USERNAME = ''
TEST_HG_PASSWORD = ''
TEST_HG_KEY_DATA = TEST_SSH_KEY_DATA
TEST_HG_PUBLIC_HTTPS = 'https://bitbucket.org/cchurch/django-hotrunner'
TEST_HG_PRIVATE_HTTPS = ''
TEST_HG_PRIVATE_SSH = ''
TEST_SVN_USERNAME = ''
TEST_SVN_PASSWORD = ''
TEST_SVN_PUBLIC_HTTPS = 'https://github.com/ansible/ansible.github.com'
TEST_SVN_PRIVATE_HTTPS = 'https://github.com/ansible/product-docs'
# To test repo access via SSH login to localhost.
import getpass
TEST_SSH_LOOPBACK_USERNAME = getpass.getuser()
TEST_SSH_LOOPBACK_PASSWORD = ''
###############################################################################
# INVENTORY IMPORT TEST SETTINGS
###############################################################################
# Define these variables to enable more complete testing of inventory import
# from cloud providers.
# EC2 credentials
TEST_AWS_ACCESS_KEY_ID = ''
TEST_AWS_SECRET_ACCESS_KEY = ''
TEST_AWS_REGIONS = 'all'
# Check IAM STS credentials
TEST_AWS_SECURITY_TOKEN = ''
# Rackspace credentials
TEST_RACKSPACE_USERNAME = ''
TEST_RACKSPACE_API_KEY = ''
TEST_RACKSPACE_REGIONS = 'all'
# VMware credentials
TEST_VMWARE_HOST = ''
TEST_VMWARE_USER = ''
TEST_VMWARE_PASSWORD = ''
# OpenStack credentials
TEST_OPENSTACK_HOST = ''
TEST_OPENSTACK_USER = ''
TEST_OPENSTACK_PASSWORD = ''
TEST_OPENSTACK_PROJECT = ''
# Azure credentials.
TEST_AZURE_USERNAME = ''
TEST_AZURE_KEY_DATA = ''

View File

@@ -30,10 +30,6 @@ SECRET_KEY = None
# See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []
# Absolute filesystem path to the directory for job status stdout
# This directory should not be web-accessible
JOBOUTPUT_ROOT = '/var/lib/awx/job_status/'
# The heartbeat file for the tower scheduler
SCHEDULE_METADATA_LOCATION = '/var/lib/awx/.tower_cycle'
@@ -46,15 +42,6 @@ AWX_VENV_PATH = os.path.join(BASE_VENV_PATH, "awx")
AWX_ISOLATED_USERNAME = 'awx'
LOGGING['handlers']['tower_warnings']['filename'] = '/var/log/tower/tower.log' # noqa
LOGGING['handlers']['callback_receiver']['filename'] = '/var/log/tower/callback_receiver.log' # noqa
LOGGING['handlers']['dispatcher']['filename'] = '/var/log/tower/dispatcher.log' # noqa
LOGGING['handlers']['wsbroadcast']['filename'] = '/var/log/tower/wsbroadcast.log' # noqa
LOGGING['handlers']['task_system']['filename'] = '/var/log/tower/task_system.log' # noqa
LOGGING['handlers']['management_playbooks']['filename'] = '/var/log/tower/management_playbooks.log' # noqa
LOGGING['handlers']['system_tracking_migrations']['filename'] = '/var/log/tower/tower_system_tracking_migrations.log' # noqa
LOGGING['handlers']['rbac_migrations']['filename'] = '/var/log/tower/tower_rbac_migrations.log' # noqa
# Store a snapshot of default settings at this point before loading any
# customizable config files.
DEFAULTS_SNAPSHOT = {}
@@ -102,6 +89,7 @@ except IOError:
else:
raise
# The below runs AFTER all of the custom settings are imported.
CELERYBEAT_SCHEDULE.update({ # noqa
'isolated_heartbeat': {
@@ -110,3 +98,5 @@ CELERYBEAT_SCHEDULE.update({ # noqa
'options': {'expires': AWX_ISOLATED_PERIODIC_CHECK * 2}, # noqa
}
})
DATABASES['default'].setdefault('OPTIONS', dict()).setdefault('application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63]) # noqa

View File

@@ -445,7 +445,8 @@ class LDAPGroupTypeField(fields.ChoiceField, DependsOnMixin):
default_error_messages = {
'type_error': _('Expected an instance of LDAPGroupType but got {input_type} instead.'),
'missing_parameters': _('Missing required parameters in {dependency}.')
'missing_parameters': _('Missing required parameters in {dependency}.'),
'invalid_parameters': _('Invalid group_type parameters. Expected instance of dict but got {parameters_type} instead.')
}
def __init__(self, choices=None, **kwargs):
@@ -465,7 +466,6 @@ class LDAPGroupTypeField(fields.ChoiceField, DependsOnMixin):
if not data:
return None
params = self.get_depends_on() or {}
cls = find_class_in_modules(data)
if not cls:
return None
@@ -475,8 +475,16 @@ class LDAPGroupTypeField(fields.ChoiceField, DependsOnMixin):
# Backwords compatability. Before AUTH_LDAP_GROUP_TYPE_PARAMS existed
# MemberDNGroupType was the only group type, of the underlying lib, that
# took a parameter.
params = self.get_depends_on() or {}
params_sanitized = dict()
for attr in inspect.getargspec(cls.__init__).args[1:]:
cls_args = inspect.getargspec(cls.__init__).args[1:]
if cls_args:
if not isinstance(params, dict):
self.fail('invalid_parameters', parameters_type=type(params))
for attr in cls_args:
if attr in params:
params_sanitized[attr] = params[attr]

View File

@@ -25,7 +25,7 @@ class BaseRedirectView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
last_path = self.request.COOKIES.get('lastPath', '')
last_path = urllib.parse.quote(urllib.parse.unquote(last_path).strip('"'))
url = reverse('ui:index')
url = reverse('ui_next:index')
if last_path:
return '%s#%s' % (url, last_path)
else:

View File

@@ -1,19 +0,0 @@
Gruntfile.js
karma.*.js
webpack.*.js
nightwatch.*.js
etc
coverage
grunt-tasks
node_modules
po
static
templates
client/src/**/*.js
client/assets/**/*.js
test/spec/**/*.js
!client/src/app.start.js
!client/src/vendor.js

View File

@@ -1,72 +0,0 @@
const path = require('path');
module.exports = {
root: true,
extends: [
'airbnb-base'
],
plugins: [
'import',
'disable'
],
settings: {
'import/resolver': {
webpack: {
config: path.join(__dirname, 'build/webpack.development.js')
}
},
'eslint-plugin-disable': {
paths: {
import: ['**/build/*.js']
}
}
},
env: {
browser: true,
node: true
},
globals: {
angular: true,
d3: true,
$: true,
_: true,
codemirror: true,
jsyaml: true,
crypto: true
},
rules: {
'arrow-parens': 'off',
'comma-dangle': 'off',
indent: ['error', 4, {
SwitchCase: 1
}],
'max-len': ['error', {
code: 100,
ignoreStrings: true,
ignoreTemplateLiterals: true,
}],
'no-continue': 'off',
'no-debugger': 'off',
'no-mixed-operators': 'off',
'no-param-reassign': 'off',
'no-plusplus': 'off',
'no-underscore-dangle': 'off',
'no-use-before-define': 'off',
'no-multiple-empty-lines': ['error', { max: 1 }],
'object-curly-newline': 'off',
'space-before-function-paren': ['error', 'always'],
'no-trailing-spaces': ['error'],
'prefer-destructuring': ['error', {
'VariableDeclarator': {
'array': false,
'object': true
},
'AssignmentExpression': {
'array': false,
'object': true
}
}, {
'enforceForRenamedProperties': false
}]
}
};

View File

@@ -1,49 +0,0 @@
{
"browser": true,
"node": true,
"jquery": true,
"esnext": true,
"globalstrict": true,
"curly": true,
"immed": true,
"latedef": "nofunc",
"noarg": true,
"nonew": true,
"maxerr": 10000,
"notypeof": true,
"globals": {
"$ENV": true,
"require": true,
"global": true,
"beforeEach": false,
"inject": false,
"module": false,
"angular":false,
"alert":false,
"$AnsibleConfig":true,
"$basePath":true,
"jsyaml":false,
"_":false,
"d3":false,
"Donut3D":false,
"nv":false,
"it": false,
"xit": false,
"expect": false,
"context": false,
"describe": false,
"moment": false,
"spyOn": false,
"jasmine": false,
"dagre": false,
"crypto": false
},
"strict": false,
"quotmark": false,
"trailing": true,
"undef": true,
"unused": true,
"eqeqeq": true,
"indent": 4,
"newcap": false
}

View File

@@ -1 +0,0 @@
progress=false

View File

@@ -1,20 +0,0 @@
module.exports = function(grunt) {
// Load grunt tasks & configurations automatically from dir grunt/
require('load-grunt-tasks')(grunt);
// display task timings
require('time-grunt')(grunt);
var options = {
config: {
src: './grunt-tasks/*.js'
},
pkg: grunt.file.readJSON('package.json')
};
var configs = require('load-grunt-configs')(grunt, options);
// Project configuration.
grunt.initConfig(configs);
grunt.loadNpmTasks('grunt-newer');
grunt.loadNpmTasks('grunt-angular-gettext');
};

View File

@@ -1,103 +0,0 @@
# AWX UI
## Requirements
- node.js 10.x LTS
- npm >=6.x
- bzip2, gcc-c++, git, make
## Development
The API development server will need to be running. See [CONTRIBUTING.md](../../CONTRIBUTING.md).
```shell
# Build ui for the devel environment - reachable at https://localhost:8043
make ui-devel
# Alternatively, start the ui development server. While running, the ui will be reachable
# at https://localhost:3000 and updated automatically when code changes.
make ui-docker
# When using docker machine, use this command to start the ui development server instead.
DOCKER_MACHINE_NAME=default make ui-docker-machine
```
## Development with an external server
If you normally run awx on an external host/server (in this example, `awx.local`),
you'll need to reconfigure the webpack proxy slightly for `make ui-docker` to
work:
```javascript
/awx/settings/development.py
+
+CSRF_TRUSTED_ORIGINS = ['awx.local:8043']
awx/ui/build/webpack.watch.js
- host: '127.0.0.1',
+ host: '0.0.0.0',
+ disableHostCheck: true,
/awx/ui/package.json
@@ -7,7 +7,7 @@
"config": {
...
+ "django_host": "awx.local"
},
```
## Testing
```shell
# run linters
make jshint
# run unit tests
make ui-test-ci
# run e2e tests - see awx/ui/test/e2e for more information
npm --prefix awx/ui run e2e
```
**Note**: Unit tests are run on your host machine and not in the development containers.
## Adding dependencies
```shell
# add an exact development or build dependency
npm install --prefix awx/ui --save-dev --save-exact dev-package@1.2.3
# add an exact production dependency
npm install --prefix awx/ui --save --save-exact prod-package@1.23
# add the updated package.json and package-lock.json files to scm
git add awx/ui/package.json awx/ui/package-lock.json
```
## Removing dependencies
```shell
# remove a development or build dependency
npm uninstall --prefix awx/ui --save-dev dev-package
# remove a production dependency
npm uninstall --prefix awx/ui --save prod-package
```
## Building for Production
```shell
# built files are placed in awx/ui/static
make ui-release
```
## Internationalization
Application strings marked for translation are extracted and used to generate `.pot` files using the following command:
```shell
# extract strings and generate .pot files
make pot
```
To include the translations in the development environment, we compile them prior to building the ui:
```shell
# remove any prior ui builds
make clean-ui
# compile the .pot files to javascript files usable by the application
make languages
# build the ui with translations included
make ui-devel
```
**Note**: Python 3.6 is required to compile the `.pot` files.

View File

@@ -2,3 +2,4 @@
# All Rights Reserved.
default_app_config = 'awx.ui.apps.UIConfig'

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