Compare commits

..

599 Commits

Author SHA1 Message Date
softwarefactory-project-zuul[bot]
442d539ff8 Merge pull request #7176 from nixocio/ui_issue_5819
Add support Prompt on Launch for Workflow Job Template

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-09 18:37:59 +00:00
softwarefactory-project-zuul[bot]
3952946d9c Merge pull request #7296 from shanemcd/twelve-dot-o-dot-o
Bump version to 12.0.0

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-09 17:06:36 +00:00
softwarefactory-project-zuul[bot]
3fa34dad04 Merge pull request #7302 from ryanpetrello/redis-no-tcp
remove TCP ports for redis (it only listens on a unix domain socket)

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-09 16:59:13 +00:00
Ryan Petrello
1233462419 add some new changelog entries for 12.0.0 2020-06-09 12:39:10 -04:00
Ryan Petrello
0ad78874ce remove TCP ports for redis (it only listens on a unix domain socket) 2020-06-09 12:29:33 -04:00
Shane McDonald
2bbbb04499 Bump version to 12.0.0 2020-06-09 12:19:17 -04:00
nixocio
fa1294922b Add support Prompt on Launch for Workflow Job Template
Add support Prompt on Launch for Workflow Job Template

see: https://github.com/ansible/awx/issues/5819
2020-06-09 11:40:19 -04:00
softwarefactory-project-zuul[bot]
277b6897fa Merge pull request #7240 from rebeccahhh/memcache-memories
remove memcache entirely, add in some django redis to cover it's absence

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-09 15:37:04 +00:00
Rebeccah
d7f9e66710 added changelog entry 2020-06-09 11:09:04 -04:00
softwarefactory-project-zuul[bot]
81d388d137 Merge pull request #7283 from fosterseth/fix-parents_converge_settable_api
Make all_parents_must_converge settable when creating node

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-09 15:03:53 +00:00
Rebeccah
60800d6740 add license file for django-redis 2020-06-09 10:24:23 -04:00
Rebeccah
02cf4585f8 remove memcache license file 2020-06-09 10:24:23 -04:00
Rebeccah
669d4535b1 adding isolate db location and ingore for django_redis exceptions 2020-06-09 10:24:23 -04:00
Rebeccah Hunter
b09d9cbe41 removed django-redis as a dependency
Co-authored-by: Shane McDonald <me@shanemcd.com>
2020-06-09 10:24:23 -04:00
Rebeccah
d2bbe7aa1a remove memcache from everywhere and add djagno-redis to cover it 2020-06-09 10:24:23 -04:00
softwarefactory-project-zuul[bot]
246aee623b Merge pull request #7293 from AlanCoding/lint_failure
fix lint failures

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-09 03:12:02 +00:00
softwarefactory-project-zuul[bot]
6b3ec46fe8 Merge pull request #7291 from mabashian/ui-websocket-extensions
Manually bumps websocket-extensions to 0.1.14 (awx/ui)

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-09 01:07:47 +00:00
AlanCoding
9dec359898 fix lint failures 2020-06-08 20:11:11 -04:00
softwarefactory-project-zuul[bot]
222998281f Merge pull request #7292 from ryanpetrello/sock-it-to-me
don't block on log aggregator socket.send() calls

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 22:34:53 +00:00
Ryan Petrello
7164049062 don't block on log aggregator socket.send() calls
see: https://github.com/ansible/tower/issues/4391
2020-06-08 18:07:33 -04:00
Seth Foster
e768d5e7fc Make all_parents_must_converge settable when creating node
When targeting, ../workflow_job_templates/id#/workflow_nodes/ endpoint,
user could not set all_parents_must_converge to true.

awx issue #7063
2020-06-08 17:51:15 -04:00
softwarefactory-project-zuul[bot]
e5ec761434 Merge pull request #7270 from john-westcott-iv/fix_tower_settings_none
Prevent exception for Non value

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 21:05:58 +00:00
softwarefactory-project-zuul[bot]
40b020c370 Merge pull request #7284 from AlexSCorey/7232-ApplicationsRouteStub
Adds routing stubs for Applications

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 20:13:52 +00:00
softwarefactory-project-zuul[bot]
2a566f575f Merge pull request #7290 from mabashian/ui-next-websocket-extensions
Manually bumps websocket-extensions to 0.1.14 (awx/ui_next)

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 19:54:16 +00:00
Alex Corey
2784409c46 Fixes folder name 2020-06-08 15:34:25 -04:00
softwarefactory-project-zuul[bot]
946a86f350 Merge pull request #6780 from tchellomello/rfe_saml_mapping_2688
Adds SAML Attribute Mapping to Teams and Orgs

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 18:58:23 +00:00
mabashian
57a6c8d693 Manually bumps websocket-extensions to 0.1.14 in awx/ui 2020-06-08 14:29:52 -04:00
mabashian
142c0da9f0 Manually bumps websocket-extensions to 0.1.14 2020-06-08 14:14:59 -04:00
softwarefactory-project-zuul[bot]
28baa8b24b Merge pull request #7280 from apollo13/patch-1
Send content-type with mattermost notifications, fixes #7264

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-06-08 17:27:05 +00:00
Marcelo Moreira de Mello
3f8bc0d7c8 Adds SAML Attribute Mapping to Teams and Orgs
Signed-off-by: Marcelo Moreira de Mello <tchello.mello@gmail.com>
2020-06-08 12:40:33 -04:00
Alex Corey
0df4047d3d Adds routing stubs for Applications 2020-06-08 11:55:21 -04:00
softwarefactory-project-zuul[bot]
feb9c5700c Merge pull request #7257 from jbradberry/fix-deadlock
Force worker processes to have a different signal handler from the parent

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 15:34:25 +00:00
Florian Apolloner
cf6235f6ea Send content-type with mattermost notifications, fixes #7264 2020-06-08 16:30:52 +02:00
beeankha
b457c8f133 Update a task in tower_settings integration test playbook 2020-06-08 09:57:16 -04:00
softwarefactory-project-zuul[bot]
824d798d81 Merge pull request #7116 from john-westcott-iv/token_modules
Initial cut at tower_token module

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 12:26:43 +00:00
John Westcott IV
76dcd6d72a Fixing scooby doo fingers 2020-06-08 07:49:58 -04:00
John Westcott IV
64846c3347 Fixing truthy issues 2020-06-08 07:09:45 -04:00
John Westcott IV
95b8bd63ea Fixing linting issues 2020-06-08 07:06:45 -04:00
John Westcott IV
3b60529488 Fixes in testing and parameter processing 2020-06-08 06:42:33 -04:00
softwarefactory-project-zuul[bot]
7a59922f0f Merge pull request #7245 from sean-m-sullivan/organization_job_template
tower_job_template to use organizations

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-08 02:12:00 +00:00
sean-m-sullivan
360352b78e updated version 2020-06-06 20:12:47 -05:00
sean-m-sullivan
21abf5a788 updated to remove version and add docs 2020-06-06 20:11:46 -05:00
softwarefactory-project-zuul[bot]
62dbb6bfdb Merge pull request #7261 from shanemcd/auto-qs
Add queue / instance group registration to heartbeat for k8s installs

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-06 13:32:08 +00:00
Shane McDonald
460f31a05d Fix up test that was only failing in dev env
I'm not sure how this one slipped by. The default config is built into the
image, but we were bind-mounting an empty directory on top of it.
2020-06-06 08:58:43 -04:00
Shane McDonald
91dbc2de30 Add queue / instance group registration to heartbeat for k8s installs
There is some history here.

https://github.com/ansible/awx/pull/7190 <- This PR was an attempt at fixing a
bug notting ran into where some jobs on k8s installs would get stuck in Waiting
forever.

The PR mentioned above introduced a bug where there are no instance groups on a
fresh k8s-based install. This is because this process currently happens in the
launch scripts, before the database is up.

With this patch, queue / instance group registration happens in the heartbeat,
right after auto-registering the instance.
2020-06-06 08:58:35 -04:00
softwarefactory-project-zuul[bot]
e603cfd7ab Merge pull request #7239 from AlexSCorey/6863-CopyProjectsAndInventories
Adds ux for unsynced projects

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-05 23:59:33 +00:00
softwarefactory-project-zuul[bot]
3cdeb48d3f Merge pull request #7271 from jladdjr/bump_foreman_collection_0.8.1
Bump foreman collection to 0.8.1

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-05 22:04:23 +00:00
John Westcott IV
1f17e02fe9 Adding more documenation and added existing_token_id param 2020-06-05 16:19:23 -04:00
John Westcott IV
0e54f76f80 Fixing missing raw from merge type 2020-06-05 16:10:26 -04:00
Jim Ladd
5df08711e9 Bump foreman collection to 0.8.1
* New release includes:
  'add host_filters and want_ansible_ssh_host like script used to have'
2020-06-05 11:25:11 -07:00
John Westcott IV
41d0548af6 Fixing truthy linting issue 2020-06-05 13:53:20 -04:00
John Westcott IV
11da8e254d Changing documention and fixing sanity tests 2020-06-05 13:53:20 -04:00
John Westcott IV
30346618f1 Adding more through testing of tower_oauthtoken including failure messages 2020-06-05 13:53:20 -04:00
John Westcott IV
7c88a51992 Adding more details about tower_oauthtoken parameter 2020-06-05 13:50:39 -04:00
John Westcott IV
1a0407ba50 Fixing ny -> my typos 2020-06-05 13:50:39 -04:00
John Westcott IV
1dbea4614b Rebasing and fixing oauthtoken docs 2020-06-05 13:50:39 -04:00
John Westcott IV
6e9a43513e Removed some debugging and added an exmaple 2020-06-05 13:50:09 -04:00
John Westcott IV
e50c8fc9c9 Updated docs and added block on tests 2020-06-05 13:50:09 -04:00
John Westcott IV
e6416d770b Initial cut at tower_token module 2020-06-05 13:50:09 -04:00
John Westcott IV
4de7de3ce9 Prevent exception for Non value 2020-06-05 13:29:37 -04:00
softwarefactory-project-zuul[bot]
e6b1e55274 Merge pull request #7229 from AlanCoding/very_sane
Comply with updated Ansible sanity test rules

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-05 16:23:53 +00:00
softwarefactory-project-zuul[bot]
f9a7db6045 Merge pull request #7216 from AlanCoding/inventory_token
Sync inventory param processing with modules (token and config file support)

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-05 15:20:01 +00:00
Alex Corey
edb0df788b Improves copy clipaboard message and some prop names 2020-06-05 10:47:01 -04:00
Alex Corey
40cd87f253 Adds message for unsynced projects for copy to clipboard button 2020-06-05 10:47:01 -04:00
softwarefactory-project-zuul[bot]
22a9c29961 Merge pull request #7262 from ryanpetrello/dep-src-minus
remove LGPL source for dependencies we've since removed

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-05 00:45:12 +00:00
Ryan Petrello
951f13c066 remove lgpg source for dependencies we've since removed 2020-06-04 18:45:33 -04:00
softwarefactory-project-zuul[bot]
4a5edf7b88 Merge pull request #7184 from wenottingham/a-preview-of-whats-to-come
Remove dev env futzing of supervisord.conf permissions

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-04 21:47:02 +00:00
Jeff Bradberry
ced8f42835 Force worker processes to have a different signal handler from the parent
Situations have come up where the 5+ minute kill signal for
run_task_manager is emitted to the worker process running it, but
since the worker improperly inherited the AWXConsumerBase().stop()
handler a deadlock ultimately was triggered on the database
connection.
2020-06-04 15:41:28 -04:00
softwarefactory-project-zuul[bot]
8c51993278 Merge pull request #7242 from nixocio/ui_update_jt_form
Modify JobTemplateForm to use formik `setValue`

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-04 19:34:39 +00:00
softwarefactory-project-zuul[bot]
5fcf1a2d5e Merge pull request #7249 from AndrewCopeland/conjur-url-encoding
URL encode '/' to '%2F' for conjur credential plugin

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-06-04 19:22:40 +00:00
softwarefactory-project-zuul[bot]
61a1cfa35a Merge pull request #7208 from nixocio/ui_issue_7016
Add error feedback in Preview Step

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-04 19:04:43 +00:00
AndrewCopeland
4531c418e2 URL encode '/' to '%2F' for conjur credential plugin 2020-06-04 09:57:00 -04:00
softwarefactory-project-zuul[bot]
7623257a6c Merge pull request #7244 from ansible/jakemcdermott-remove-auth-props
Remove unneeded auth props

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-04 13:50:42 +00:00
sean-m-sullivan
3fa3ddf04b tower_job_template to use organizations 2020-06-04 00:12:02 -05:00
Jake McDermott
fdb53bd1af Remove unneeded auth props 2020-06-03 19:52:53 -04:00
softwarefactory-project-zuul[bot]
0615252cf7 Merge pull request #7223 from jakemcdermott/ui-next-app-container
Add AppContainer and move bootstrapping to App component

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-03 23:21:16 +00:00
Jake McDermott
cb453de6a4 Add AppContainer and move bootstrapping to App component 2020-06-03 18:20:26 -04:00
nixocio
9c57f550ed Modify JobTemplateForm to use formik setValue
Modify JobTemplateForm to use formik `setValue`. Following the same
convention used in the `.WorkflowJobTemplateForm`. Also, replace the
usage of `useFormikContext` to `useField`.
2020-06-03 16:06:41 -04:00
softwarefactory-project-zuul[bot]
7060fbd3c2 Merge pull request #7228 from wenottingham/one-container-only-vasili
Move to one container image rather than two mostly-identical ones

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-03 16:27:34 +00:00
softwarefactory-project-zuul[bot]
974b219858 Merge pull request #7202 from AlexSCorey/6590-InventorySourceNotifications
Adds inventory sources notifications list

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-03 15:56:53 +00:00
AlanCoding
4657680f9e Get sanity tests to work for ansible.tower and Ansible 2.10 2020-06-03 11:42:56 -04:00
Bill Nottingham
64e3135754 Only build one awx image instead of separate web and task images 2020-06-03 10:48:48 -04:00
Alex Corey
68a8dda869 Adds inventory sources notifications list 2020-06-03 10:22:03 -04:00
softwarefactory-project-zuul[bot]
fb8b90254c Merge pull request #7183 from AlexSCorey/7104-UserTeamsDisassociate
Adds disassociate functionality and an empty state for Sys Admin

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-03 14:04:44 +00:00
AlanCoding
86f1ba984a Comply with updated Ansible sanity test rules 2020-06-03 08:44:11 -04:00
AlanCoding
e3814c6f0f Share inventory plugin auth code with modules
refactor shared auth option definitions to repeat less
2020-06-02 21:17:12 -04:00
Bill Nottingham
559d917184 Make supervisor more consistent
Configs go in /etc, sockets in /var/run/supervisor for all invocations.
2020-06-02 19:51:16 -04:00
softwarefactory-project-zuul[bot]
ec2c121762 Merge pull request #7219 from AlanCoding/config_bug
fix bug with config file [general] section

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 23:31:45 +00:00
AlanCoding
0c3d27e818 fix bug with config file [general] section 2020-06-02 19:05:45 -04:00
softwarefactory-project-zuul[bot]
0a3ac25c1a Merge pull request #7226 from beeankha/update_collections_readme
Make edits to auth portion of Collection readme

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 20:46:27 +00:00
softwarefactory-project-zuul[bot]
101c70c152 Merge pull request #7222 from john-westcott-iv/fix_fail_json
Fixing fail_json error

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 20:38:07 +00:00
softwarefactory-project-zuul[bot]
80fb713f91 Merge pull request #7224 from john-westcott-iv/utilize_has_yaml
Now respecting the HAS_YAML variable

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 20:32:32 +00:00
beeankha
22d1c8a59c Make edits to auth portion of Collection readme 2020-06-02 16:14:24 -04:00
nixocio
68568be235 Add error feedback in Preview Step
Add error feedback in Preview Step.

closes: https://github.com/ansible/awx/issues/7016
2020-06-02 15:21:22 -04:00
John Westcott IV
aa54cf097b Now respecting the HAS_YAML variable 2020-06-02 14:54:44 -04:00
John Westcott IV
24571166f6 Fixing fail_json error 2020-06-02 14:40:53 -04:00
Alex Corey
af70e3bb49 updates sys admin message 2020-06-02 14:36:17 -04:00
softwarefactory-project-zuul[bot]
990eead3ac Merge pull request #7204 from rooftopcellist/label_tests
Add basic functional tests for labels

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 18:23:21 +00:00
softwarefactory-project-zuul[bot]
5e5026aae8 Merge pull request #7129 from keithjgrant/6594-user-teams-list
User teams list

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 17:32:37 +00:00
softwarefactory-project-zuul[bot]
3dec277331 Merge pull request #7125 from mabashian/5880-cred-plugins
Adds basic credential plugin support to relevant fields in the static credential forms

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 17:25:48 +00:00
softwarefactory-project-zuul[bot]
41894e30ac Merge pull request #7081 from keithjgrant/6640-jt-form-loading
JT form loading UX

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 16:45:05 +00:00
Keith Grant
8cdb05e4a2 add org name to user team search columns 2020-06-02 09:13:42 -07:00
mabashian
66df922956 Wrap credential form submission code in useRequest to avoid the "unmounted component" errors we've seen if we try to push a new route onto the history but the coomponent is already unmounted. 2020-06-02 12:06:13 -04:00
Keith Grant
455cd74492 fix tests 2020-06-02 08:46:37 -07:00
Keith Grant
e57bd88bd2 add Lookup test for disabled isLoading state 2020-06-02 08:46:37 -07:00
Keith Grant
af118fec99 Disable field inputs while fetching data
In the JT form, disable the Lookup and Select box fields for any
fields that need to fetch data, until data fetching is complete
2020-06-02 08:46:37 -07:00
softwarefactory-project-zuul[bot]
9d3b19341d Merge pull request #7166 from nixocio/ui_update_translation_process
Add section about issues to be translated

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
             https://github.com/jakemcdermott
2020-06-02 15:42:26 +00:00
softwarefactory-project-zuul[bot]
87607dd997 Merge pull request #7186 from jakemcdermott/ui-next-route-config
Relocate route config, remove route render props, refactor top-level routes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 14:41:50 +00:00
Alex Corey
15d6c5fb7a Adds disassociate functionality and an empty state for Sys Admin 2020-06-02 10:16:53 -04:00
Jake McDermott
718d3728dd Relocate route config and remove route render props 2020-06-02 10:08:40 -04:00
softwarefactory-project-zuul[bot]
7e0dc41bf7 Merge pull request #7214 from ryanpetrello/conjur-changelog
update the changelog for a conjur credential plugin bug

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 12:15:15 +00:00
Ryan Petrello
72c7ace1a0 update the changelog for a conjur credential plugin bug
see: https://github.com/ansible/awx/issues/7191
2020-06-02 07:38:08 -04:00
softwarefactory-project-zuul[bot]
644ecdb1fb Merge pull request #7200 from ryanpetrello/conjur-quote-plus
properly quote conjur URLs that contain spaces

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-02 01:23:06 +00:00
softwarefactory-project-zuul[bot]
0abfa428c4 Merge pull request #7205 from mabashian/http-proxy-audit
Bump http-proxy to >1.18.1

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-01 20:29:34 +00:00
mabashian
b01e312b8f Remove unnecessary sleep 2020-06-01 16:08:44 -04:00
mabashian
78ade1d99d Build inputSourcesMap using an array reduce method instead of forEach with a local variable. 2020-06-01 15:55:18 -04:00
softwarefactory-project-zuul[bot]
568e70b68b Merge pull request #7196 from rooftopcellist/labels_changelog
Changelog entry for label removal issue

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-06-01 18:47:53 +00:00
mabashian
5367bc4d3b Adds test coverage for cred plugin prompt 2020-06-01 14:46:13 -04:00
mabashian
df069f3874 Adds prop type checking to a few components that were missing it. Adds basic test coverage for credential plugin field and selected components. Adds foundation for credential plugin prompt component tests (more coverage to come in a later commit). 2020-06-01 14:46:13 -04:00
mabashian
e927680cc2 Fix linting errors 2020-06-01 14:46:13 -04:00
mabashian
4b95297bd4 Adds basic credential plugin support to relevant fields in the static credential forms. 2020-06-01 14:46:13 -04:00
mabashian
068d9660b3 Addresses npm audit security report vulnerabilities with http-proxy which is a dependency of some of our dependencies. 2020-06-01 14:40:33 -04:00
Christian Adams
58737a64e1 Add basic functional tests for labels 2020-06-01 14:22:29 -04:00
Ryan Petrello
cfe8a1722c properly quote conjur URLs that contain spaces
see: https://github.com/ansible/awx/issues/7191
2020-06-01 09:48:15 -04:00
Christian Adams
e373ae1e27 Changelog entry for label removal issue 2020-06-01 00:42:38 -04:00
softwarefactory-project-zuul[bot]
9d42b8f0f2 Merge pull request #7189 from wenottingham/aaargh
Hardcode --kubeconfig and therefore only support OpenShift 3.11+

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-29 23:44:16 +00:00
softwarefactory-project-zuul[bot]
54167d9693 Merge pull request #7190 from shanemcd/less-bounce
Stop bouncing k8s deployment post-install

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-29 20:31:15 +00:00
Shane McDonald
747fdf38d8 Stop bouncing k8s deployment post-install
We shouldnt need to do this now that RabbitMQ autoclustering is gone.
2020-05-29 13:47:33 -04:00
Bill Nottingham
0f0e401c98 Hardcode --kubeconfig and therefore only support OpenShift 3.11+
Avoid trying to parse inconsitent oc --version output
2020-05-29 13:41:49 -04:00
softwarefactory-project-zuul[bot]
80e22ff2ce Merge pull request #7185 from mstrent/devel
Add subnet configuration to Docker Compose to avoid conflicts.

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-29 17:10:29 +00:00
softwarefactory-project-zuul[bot]
d205685541 Merge pull request #7103 from AlexSCorey/6921-UserAndTeamsAccessAdd
Adds support to user and team access add

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
             https://github.com/AlexSCorey
2020-05-29 13:54:28 +00:00
softwarefactory-project-zuul[bot]
3b06d7b02b Merge pull request #7143 from rooftopcellist/rm_label_500
[WIP] Allow org admins to remove labels

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-29 13:32:42 +00:00
Alex Corey
ca6ae24032 makes whole card selectable 2020-05-29 09:19:28 -04:00
Alex Corey
585ca082e3 Improves naming and updates resource list and adds search functionality 2020-05-29 09:19:28 -04:00
Alex Corey
4f6d7e56eb Adds support to user and team access add 2020-05-29 09:19:28 -04:00
nixocio
8527991cb2 Add section about issues to be translated
Add steps related to issues to be translated.
2020-05-29 09:04:39 -04:00
softwarefactory-project-zuul[bot]
9de83fdcfe Merge pull request #7172 from keithjgrant/7142-prompt-extra-vars
Preserve extra_vars when they are not prompted

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-29 12:17:03 +00:00
softwarefactory-project-zuul[bot]
c1ec84d4a9 Merge pull request #7168 from Wilk42/devel
Absent not working for tower_workflow_job_template_node Fix

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-29 02:23:08 +00:00
excalibrax
1f2481211b update to workflow node delete 2020-05-28 16:00:46 -05:00
Christian Adams
d3086206b4 allow org admins to remove labels 2020-05-28 14:36:43 -04:00
softwarefactory-project-zuul[bot]
b1853d815b Merge pull request #7177 from kdelee/firehose_event_time
Set event time and date in firehose script

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-28 17:42:02 +00:00
Bill Nottingham
131f5ff018 Remove dev env futzing of supervisord.conf permissions
If we just link it into the dev env, we don't need to copy it at
startup, and we don't need write permissions on it.
2020-05-28 13:12:57 -04:00
Elijah DeLee
efa5a95cf1 fix flake8 2020-05-28 13:00:37 -04:00
mstrent
8d6d5eeed8 Add subnet configuratin to Docker Compose to avoid conflicts.
The out of the box subnet Docker Compose selects may conflict with your existing LAN subnets. This makes it configurable.
2020-05-28 09:17:45 -07:00
softwarefactory-project-zuul[bot]
38025e1926 Merge pull request #7182 from nixocio/ui_issue_7170
Add Wizard buttons as internationalization

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-28 15:10:28 +00:00
softwarefactory-project-zuul[bot]
0e24cb3eac Merge pull request #7171 from nixocio/ui_issue_6718
Add "of" to "Run on" field in schedule form

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-28 15:06:38 +00:00
nixocio
6cf195a27e Add Wizard buttons as internationalization
See: https://www.patternfly.org/v4/documentation/react/components/wizard#props

See: https://github.com/ansible/awx/issues/7170
2020-05-28 10:26:44 -04:00
softwarefactory-project-zuul[bot]
39b37817a1 Merge pull request #6265 from djj106/devel
Add support for importing host/group descriptions

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-28 01:53:03 +00:00
softwarefactory-project-zuul[bot]
6d46ee7a01 Merge pull request #7124 from Akasurde/awx_7052
vmware_vm_inventory: Replace guest.guestId with config.guestId

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-28 01:48:28 +00:00
Elijah DeLee
90ca2fd59b be a bit more respectful of event request
minimum events made now is 10,000, used to be 10,000*number of cores.

could dig deeper but this is better for debugging changes to script
2020-05-27 19:34:12 -04:00
softwarefactory-project-zuul[bot]
a5602cc2e7 Merge pull request #7178 from ryanpetrello/sumologic-fix
add a changelog note for the sumologic token fix

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 23:06:43 +00:00
softwarefactory-project-zuul[bot]
4fbab7f1b3 Merge pull request #7175 from ryanpetrello/cred-plugin-fifoooooooh-noooooooo
remove the usage of create_temporary_fifo from credential plugins

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 23:06:35 +00:00
Elijah DeLee
5d5edf6535 create timestamp outside loop
this may be expensive
2020-05-27 18:43:26 -04:00
Elijah DeLee
a599afa81c Also apply time delta to job
This way they all happened on the same day
2020-05-27 18:29:11 -04:00
Ryan Petrello
49dfb5dcaf add a changelog note for the sumologic token fix
see: https://github.com/ansible/awx/issues/7139
2020-05-27 18:25:15 -04:00
Elijah DeLee
1835787772 add option to set hour delta on firehose 2020-05-27 17:56:07 -04:00
Elijah DeLee
00060c9572 make time delta for firehose events configurable
This was hardcoded to back in january, which make it of limited use testing
automation analytics behavior when there are many events, we need it to be sometime in the past two months.

Will take another pass to do the hours delta
2020-05-27 17:47:38 -04:00
Ryan Petrello
01c89398b7 remove the usage of create_temporary_fifo from credential plugins
this resolves an issue that causes an endless hang on with Cyberark AIM
lookups when a certificate *and* key are specified

the underlying issue here is that we can't rely on the underyling Python
ssl implementation to *only* read from the fifo that stores the pem data
*only once*; in reality, we need to just use *actual* tempfiles for
stability purposes

see: https://github.com/ansible/awx/issues/6986
see: https://github.com/urllib3/urllib3/issues/1880
2020-05-27 17:46:00 -04:00
Keith Grant
fe7df910e2 add tests for preview step extra vars 2020-05-27 11:29:44 -07:00
nixocio
1c8fb0636c Add "of" to "Run on" field in schedule form
Also, add a few strings to internationalization.

closes: https://github.com/ansible/awx/issues/6718
2020-05-27 14:26:07 -04:00
Keith Grant
5eeb8b0337 fix extra_vars when not prompted during launch 2020-05-27 11:15:41 -07:00
softwarefactory-project-zuul[bot]
f4dfbcdf18 Merge pull request #7149 from beeankha/fix_collection_routing
Update meta/routing.yml (to meta/runtime.yml) for AWX Collection

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 18:08:13 +00:00
softwarefactory-project-zuul[bot]
02171ce2a1 Merge pull request #7169 from beeankha/specify_approval_notifications_for_pagerduty
Update Pagerduty and Grafana Approval Notifications

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 18:04:08 +00:00
softwarefactory-project-zuul[bot]
193bd6d05b Merge pull request #7159 from rooftopcellist/sumologic_conf
Correctly parse sumologic url paths

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 17:36:38 +00:00
beeankha
0d7af90e8c Update Pagerduty and Grafana approval notifications 2020-05-27 13:03:28 -04:00
Christian Adams
4d5af1d191 Correctly parse sumologic url paths
- Sumologic includes a token with a '==' at the end of it's host path.
   This adds rsyslog conf parsing tests and does not escape equals
   signs.
2020-05-27 13:02:07 -04:00
softwarefactory-project-zuul[bot]
df9a8d537f Merge pull request #7113 from marshmalien/7024-inv-group-host-alert
Fix inventory group host list error modal dismissal

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 16:21:16 +00:00
softwarefactory-project-zuul[bot]
09caf729f1 Merge pull request #7147 from beeankha/pagerduty_approval_notification_fix
Fix Approval Notifications for PagerDuty

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 14:57:10 +00:00
softwarefactory-project-zuul[bot]
f042b8adf5 Merge pull request #7167 from ryanpetrello/typo-playbooks
fix a typo in the playbook discovery tooling

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 14:51:15 +00:00
Ryan Petrello
8b97e3f8bb fix a typo in the playbook discovery tooling 2020-05-27 10:24:34 -04:00
softwarefactory-project-zuul[bot]
61d5dc4cb2 Merge pull request #7068 from mabashian/pf-upgrades
Upgrade patternfly deps to latest stable versions

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-27 14:19:35 +00:00
beeankha
8ab885de93 Update changelog 2020-05-27 09:34:51 -04:00
softwarefactory-project-zuul[bot]
1b1a93dd4b Merge pull request #7120 from fherbert/playbook_symlinks
Add option to follow symlinks when scanning for playbooks

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-26 22:26:49 +00:00
beeankha
1e8a9a7df3 Rename routing.yml to runtime.yml 2020-05-26 16:57:09 -04:00
Francois Herbert
e2d3407f66 Fixup indenting for linting 2020-05-27 08:04:25 +12:00
softwarefactory-project-zuul[bot]
d42f57d726 Merge pull request #7034 from tchellomello/ca_trust_dir
Fixes ca_trust_dir mapping for k8s and openshift

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-26 20:03:00 +00:00
softwarefactory-project-zuul[bot]
d239c82ff5 Merge pull request #7101 from keithjgrant/5996-inventory-removable
make Inventory optional if prompt-on-launch is true

Reviewed-by: Daniel Sami
             https://github.com/dsesami
2020-05-26 20:01:56 +00:00
softwarefactory-project-zuul[bot]
a480e79e21 Merge pull request #7110 from john-westcott-iv/tower_job_tmplate_webhook_service
Tower job template webhook service

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-26 19:56:33 +00:00
beeankha
09e62df84a Fix approval notifications for PagerDuty 2020-05-26 15:47:30 -04:00
Francois Herbert
b939637266 Add warning regarding infinite recursion 2020-05-27 07:15:13 +12:00
softwarefactory-project-zuul[bot]
ffe328dcf9 Merge pull request #7146 from john-westcott-iv/fix_module_docs
Fixing tower_schedule oauth_token

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-26 17:00:15 +00:00
John Westcott IV
10a6ad92b7 Fixing tower_schedule oauth_token 2020-05-26 12:31:55 -04:00
softwarefactory-project-zuul[bot]
ca1c7b38db Merge pull request #7118 from john-westcott-iv/module_docs
Moving tower_oauthtoken into a doc fragement

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-26 16:15:36 +00:00
John Westcott IV
dbeb7ec67c Fixing space issue 2020-05-26 11:23:41 -04:00
Abhijeet Kasurde
cb1b42a93e vmware_vm_inventory: Replace guest.guestId with config.guestId
guest.guestId is optional value and may not be populated everytime.
Use config.guestId instead which is mandatory.
Removed 'tag' property from properties since this property is never
populated.

Partially fixes https://github.com/ansible/awx/issues/7052

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2020-05-23 19:59:26 +05:30
Keith Grant
75fd703530 add UserTeamList tests 2020-05-22 11:05:32 -07:00
John Westcott IV
33aee7f830 Allowing auth_legacy to be converted into tower.tower namespace 2020-05-22 06:32:29 -04:00
Francois Herbert
4042e78757 Add option to follow symlinks when scanning for playbooks 2020-05-22 16:06:28 +12:00
Keith Grant
1bb29ec5f7 add user teams list 2020-05-21 16:24:11 -07:00
softwarefactory-project-zuul[bot]
b81c9dbeea Merge pull request #7117 from ryanpetrello/changelog-head-start
add some recent changes to the changelog for the next major release

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
             https://github.com/beeankha
2020-05-21 18:48:22 +00:00
softwarefactory-project-zuul[bot]
0dab3e920f Merge pull request #7085 from marshmalien/inv-src-detail-sync-btn
Add inventory source detail sync button

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 18:44:46 +00:00
softwarefactory-project-zuul[bot]
496c0c5921 Merge pull request #6733 from john-westcott-iv/tower_schedule
Initial version of tower_schedule

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 18:34:57 +00:00
softwarefactory-project-zuul[bot]
ebade7b9b7 Merge pull request #7027 from jakemcdermott/basic-websockets
Add basic output updates with websockets

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 18:18:42 +00:00
Marliana Lara
902a31d073 Switch tooltips to FieldTooltips 2020-05-21 14:10:47 -04:00
Ryan Petrello
43825faa72 add some recent changes to the changelog for the next major release 2020-05-21 13:50:41 -04:00
Jake McDermott
d40497aca5 Add basic output updates with websockets 2020-05-21 13:48:55 -04:00
John Westcott IV
c61e875bf8 Moving tower_oauthtoken into a doc fragement 2020-05-21 13:44:29 -04:00
softwarefactory-project-zuul[bot]
24691f6c75 Merge pull request #7114 from ryanpetrello/awxkit-version
don't use symlinks for awxkit VERSION

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 17:28:50 +00:00
softwarefactory-project-zuul[bot]
f5eb673898 Merge pull request #7028 from marshmalien/6576-inv-src-edit-form
Add inventory source edit form

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 16:49:38 +00:00
Ryan Petrello
d35e87ace7 test that CI works for version checking 2020-05-21 12:46:40 -04:00
softwarefactory-project-zuul[bot]
95a722255b Merge pull request #7075 from beeankha/bye_bye_hipchat
Remove HipChat Notification Type

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 16:41:54 +00:00
softwarefactory-project-zuul[bot]
385365a78f Merge pull request #7035 from nixocio/ui_issue_7011
Add source control branch to prompt launch

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 16:36:50 +00:00
Ryan Petrello
0c6b7fdb59 don't use symlinks for awxkit VERSION
as much as I'd like this to just work, certain versions of pip just
don't support it -_-

see: https://github.com/ansible/awx/issues/7107
see: https://github.com/pypa/pip/issues/7555

so unfortunately, we just have to track these as two distinct files and
just keep them in sync
2020-05-21 12:10:33 -04:00
Marliana Lara
580f098990 Fix inventory group host list error modal dismissal 2020-05-21 11:41:04 -04:00
John Westcott IV
d733903a22 Removing ignore_errors from examples 2020-05-21 10:42:13 -04:00
John Westcott IV
a2243d91d2 Now actually checking the version instead of just getting it 2020-05-21 09:15:06 -04:00
softwarefactory-project-zuul[bot]
d4084c0b13 Merge pull request #7108 from nixocio/ui_issue_7105
Make consistent usage of `useRequest` to delete items

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-21 12:55:34 +00:00
John Westcott IV
00f8dd9e6a Adding '' option to webhook_service 2020-05-21 08:25:32 -04:00
nixocio
77691a9631 Make consistent usage of useRequest to delete items
Make consistent usage of `useRequest` to delete items. This change is
required to avoid warnings such as `Warning: Can't perform a React state
update on an unmounted component.`

See: https://github.com/ansible/awx/issues/7105
2020-05-20 17:29:34 -04:00
softwarefactory-project-zuul[bot]
7939f2d320 Merge pull request #7106 from ryanpetrello/no-symlinks
Revert "follow symlinks while discovering valid playbooks"

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-20 21:04:29 +00:00
Ryan Petrello
53be991cfe Revert "follow symlinks while discovering valid playbooks"
This reverts commit 3dd21d720e.
2020-05-20 16:30:44 -04:00
beeankha
ce5272eae6 Make edits to Changelog, remove all HipChat-related params from tower_notification module 2020-05-20 16:27:01 -04:00
John Westcott IV
a4ec6f6763 Validating the version of python-dateutil 2020-05-20 14:41:43 -04:00
John Westcott IV
cc037cb4b5 Removing ignore_errors for tasks which should succeed 2020-05-20 14:41:27 -04:00
nixocio
226dac7b24 Add source control branch to prompt launch
Add source control branch to prompt launch.

Also, add missing tooltips for `JobTemplateForm`.

closes: https://github.com/ansible/awx/issues/7011
2020-05-20 14:24:04 -04:00
Marliana Lara
ea5e35910f Fix project lookup autocomplete behavior
* Refactor credential lookup to use useRequest hook
* Update unit tests
2020-05-20 12:29:02 -04:00
Keith Grant
455dfa6caa make Inventory optional if prompt-on-launch is true 2020-05-20 09:19:37 -07:00
softwarefactory-project-zuul[bot]
c2c6f2a197 Merge pull request #7079 from wenottingham/short-circuit
Always check configuration before gathering data.

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-20 16:03:27 +00:00
Bill Nottingham
17139f1f82 Always check configuration before gathering data.
We shouldn't perform expensive operations if we won't be able to send it.
Only log at debug level, otherwise every node will log this every 5
minutes.
2020-05-20 11:03:13 -04:00
softwarefactory-project-zuul[bot]
574838740f Merge pull request #7098 from Spredzy/fix_builds
Fix artifact builds

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-20 13:38:11 +00:00
softwarefactory-project-zuul[bot]
f8681cfb6b Merge pull request #7082 from AlanCoding/only_roles
Narrow function of task to be strictly role install

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-20 13:23:00 +00:00
Yanis Guenane
5a69074b09 Fix artifact builds 2020-05-20 14:54:02 +02:00
beeankha
dea7ec7845 Update changelog and README text 2020-05-19 20:48:09 -04:00
softwarefactory-project-zuul[bot]
81272a8150 Merge pull request #7088 from wenottingham/rsyslog-dev-env
Fix rsyslog in the dev env by using a local dir volume

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 21:56:23 +00:00
softwarefactory-project-zuul[bot]
5dfe53f158 Merge pull request #7023 from nixocio/ui_issue_6971
Modify handleDelete for JobTemplateDetails and WorkflowJobTemplateDetail

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 21:42:18 +00:00
softwarefactory-project-zuul[bot]
fe7a51f8f7 Merge pull request #7089 from jakemcdermott/update-zuul-download-script
Use man pages

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 21:42:13 +00:00
Jake McDermott
7ea96ad468 Use man pages 2020-05-19 17:05:51 -04:00
Bill Nottingham
63494c94b7 Fix rsyslog in the dev env by using a local dir volume
We broke this in the image refactor.
2020-05-19 17:00:09 -04:00
softwarefactory-project-zuul[bot]
0618822fe5 Merge pull request #7080 from nixocio/ui_add_items_to_translation
Make consistent usage of `pluralizedItemName` for internationalization

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 20:51:17 +00:00
softwarefactory-project-zuul[bot]
a306397586 Merge pull request #7077 from jakemcdermott/zuul-retry-chromium-download
Retry chromium download in zuul

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 20:35:19 +00:00
softwarefactory-project-zuul[bot]
785a8d9c77 Merge pull request #7084 from ryanpetrello/wsbroadcast-noisy-startup
make the run_wsbroadcast command less noisy at startup

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 20:22:29 +00:00
softwarefactory-project-zuul[bot]
a2e5639128 Merge pull request #7087 from ryanpetrello/egg-info-speedup
speed up .egg-info generation on certain systems

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 20:17:26 +00:00
beeankha
bc4d789da0 Remove HipChat notification type 2020-05-19 15:00:27 -04:00
Ryan Petrello
296995e8bd speed up .egg-info generation on certain systems 2020-05-19 15:00:13 -04:00
nixocio
1f7a36490d Update deletion of items for JobTemplateDetails and WorkflowJobTemplateDetail
Update deletion of items for JobTemplateDetails and WorkflowJobTemplateDetail
to remove warnings related update on an unmounted component. Use custom
hook `useRequest`.

closes: https://github.com/ansible/awx/issues/6971
2020-05-19 14:00:54 -04:00
Marliana Lara
f9fb9b120b Add inventory source detail sync button 2020-05-19 13:33:32 -04:00
Ryan Petrello
fbe679e651 make the run_wsbroadcast command less noisy at startup
this command yells a lot until migrations are finished; let's make it
not do that

see: https://github.com/ansible/awx/issues/7000
2020-05-19 13:09:49 -04:00
AlanCoding
751ca57390 Narrow function of task to be strictly role install 2020-05-19 12:30:10 -04:00
nixocio
10f8983554 Make consistent usage of pluralizedItemName for internationalization
Make consistent usage of `pluralizedItemName` for internationalization.
Component `PaginatedDataList`.
2020-05-19 11:47:57 -04:00
softwarefactory-project-zuul[bot]
bfdd136a46 Merge pull request #7071 from JoelKle/fix_host_port
AWX installer docker-compose params `host_port` and `host_port_ssl` can also be undefined to prevent exposing a port.

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 15:37:32 +00:00
softwarefactory-project-zuul[bot]
e74fb194bc Merge pull request #6988 from AlexSCorey/6946-SurveyFormValidationError
6946 survey form validation error

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 15:32:38 +00:00
Jake McDermott
17efb34c6a Retry chromium download in zuul 2020-05-19 10:19:38 -04:00
JoelKle
39c32fb5d0 AWX installer docker-compose params host_port and host_port_ssl
can also be undefined to prevent exposing a port.

Signed-off-by: JoelKle <34544090+JoelKle@users.noreply.github.com>
2020-05-19 10:03:29 +02:00
softwarefactory-project-zuul[bot]
87e3d62684 Merge pull request #7069 from wenottingham/api-doesnt-live-here-anymore
Remove obsolete settings

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-19 00:06:28 +00:00
Bill Nottingham
057933f030 Remove more unused settings from defaults (and some cases, the database) 2020-05-18 18:20:05 -04:00
Bill Nottingham
73b9d25371 Remove gather interval setting
This is a) the wrong settings key name
b) the same as the default in awx/main/conf.py anyway.
2020-05-18 17:55:07 -04:00
Bill Nottingham
73b0506e96 Remove obsolete setting.
This hasn't been used for years now.
2020-05-18 17:41:15 -04:00
mabashian
d6f7692a7d Upgrade patternfly deps to latest stable versions 2020-05-18 15:46:48 -04:00
softwarefactory-project-zuul[bot]
973e6f4213 Merge pull request #6699 from mabashian/5879-gce
Adds support for GCE credentials in credential form(s)

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-18 19:34:40 +00:00
mabashian
da1a19ce88 Fixes pathing after aliases removed 2020-05-18 15:06:20 -04:00
softwarefactory-project-zuul[bot]
38f1393030 Merge pull request #7042 from jakemcdermott/fix-disabled-management-job-notifications
Enable management job notications for admins

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-18 18:44:03 +00:00
softwarefactory-project-zuul[bot]
9a66364a9d Merge pull request #7065 from mabashian/6998-convergence-approval
Fixes bug where all_parents_must_converge was not being set for new or existing approval nodes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-18 18:28:54 +00:00
mabashian
67b826b438 Moves credential mocks out to data json files 2020-05-18 14:25:36 -04:00
mabashian
428527052c Use credential type value from hook value instead of accessing it directly 2020-05-18 14:23:47 -04:00
mabashian
4a9d39c3fa Adds support for GCE credentials in credential form(s) 2020-05-18 14:23:47 -04:00
mabashian
f29144ba91 Fixes bug where all_parents_must_converge was not being set for new or existing approval nodes. 2020-05-18 13:23:57 -04:00
softwarefactory-project-zuul[bot]
49edaab861 Merge pull request #7048 from rooftopcellist/update_po_files_11.2.0
Update PO and POT translation files for 11.2.0

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-18 17:08:23 +00:00
Marliana Lara
e509bbfbb3 Update lookups to use useRequest hook 2020-05-18 12:38:07 -04:00
softwarefactory-project-zuul[bot]
4b02e4ab57 Merge pull request #7045 from rooftopcellist/mark_after_db
Mark job_explanation strings after they are read from the db

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-18 15:46:27 +00:00
softwarefactory-project-zuul[bot]
60d2409321 Merge pull request #6743 from john-westcott-iv/version_warning
Adding version checking to collection

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
             https://github.com/beeankha
2020-05-18 15:16:35 +00:00
softwarefactory-project-zuul[bot]
9d420df632 Merge pull request #6950 from AlexSCorey/6903-InventorySourceSyncAll
Adds Inventory Source Sync Button

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-18 14:18:27 +00:00
Marliana Lara
71ef219ffb Add inventory source edit form 2020-05-18 10:15:00 -04:00
Alan Rominger
22cdc129ad Patches from tinkering with tests and default to devel version (#8)
This causes make install_collection to avoid templating the version
  so that it can still be used as-is in development
2020-05-18 08:51:39 -04:00
Christian Adams
048c394897 Update PO and POT translation files for 11.2.0 2020-05-15 22:53:36 -04:00
Christian Adams
19ccb5e213 Mark job_explanation strings after they are read from the db
- For strings that need to be translated, but are saved in the db:
   * They must be marked for translation using gettext_noop() to be
   translated.
   * And must also be marked for translation with _() when read from db
   and shown to the user.
   * [Ref]: https://docs.djangoproject.com/en/3.0/topics/i18n/translation/#marking-strings-as-no-op
2020-05-15 22:50:50 -04:00
softwarefactory-project-zuul[bot]
8006b24ae3 Merge pull request #7046 from rooftopcellist/rm_dockerfile-sync
Remove unneeded dockerfile-sync

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-15 23:08:08 +00:00
softwarefactory-project-zuul[bot]
95dd3dbfbd Merge pull request #7044 from jladdjr/foreman_group_prefix_should_apply_to_all_groups
foreman: use group_prefix for all groups

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-15 21:56:31 +00:00
Christian Adams
7e0ef6dd7b Remove unneeded dockerfile-sync 2020-05-15 17:43:07 -04:00
Jake McDermott
a66d44d2ff Enable management job notications for admins 2020-05-15 15:24:03 -04:00
Jim Ladd
d242932837 foreman: use group_prefix for all groups
* awx's "compatibility layer" for the foreman plugin had the
  group_prefix hard-coded to 'foreman_'
2020-05-15 11:59:29 -07:00
softwarefactory-project-zuul[bot]
99701e4112 Merge pull request #7039 from ryanpetrello/more-downstream-fixes-to-merge
merge in a few downstream fixes

Reviewed-by: Chris Meyers
             https://github.com/chrismeyersfsu
2020-05-15 17:15:50 +00:00
softwarefactory-project-zuul[bot]
556cd40440 Merge pull request #7038 from ryanpetrello/idle-button-i18n
mark the idle dialog continue button for translation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-15 17:10:09 +00:00
Ryan Petrello
c7bb5a3e7b Merge branch 'downstream' into devel 2020-05-15 12:38:47 -04:00
Ryan Petrello
3c195eed9f mark the idle dialog continue button for translation 2020-05-15 12:35:05 -04:00
softwarefactory-project-zuul[bot]
c7db982ab1 Merge pull request #7032 from ryanpetrello/egg-info-bye-bye
stop pre-generating awx.egg-info for the development environment

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-15 16:19:18 +00:00
Ryan Petrello
54178a1982 stop pre-generating awx.egg-info 2020-05-15 11:47:53 -04:00
softwarefactory-project-zuul[bot]
b69b53f527 Merge pull request #7030 from beeankha/fix_misc_flake8
Clearing Up Linter Errors

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-15 14:47:04 +00:00
softwarefactory-project-zuul[bot]
d0270a1bac Merge pull request #7017 from wenottingham/honey-i-shrunk-the-container
Rework dev & prod container builds

Reviewed-by: Christian Adams <rooftopcellist@gmail.com>
             https://github.com/rooftopcellist
2020-05-15 14:36:53 +00:00
beeankha
438929007e Unpin specific flake8 version 2020-05-15 10:02:59 -04:00
AlanCoding
b904ad68a6 recover line deletes 2020-05-15 09:44:31 -04:00
John Westcott IV
b7ab6ba9bb Attempting to fix py2 test issues 2020-05-15 09:26:34 -04:00
beeankha
b80127dd40 Fix up unit tests (no more double mocking) 2020-05-15 09:26:33 -04:00
beeankha
09c10a6f59 Fix linter issue 2020-05-15 09:26:33 -04:00
Caleb Boylan
7478a2aa5e Rework some of our package tooling 2020-05-15 09:26:33 -04:00
beeankha
6a9423626c Add field numbering specification in module_util file, update unit tests 2020-05-15 09:26:29 -04:00
John Westcott IV
31a11cf6bb Attempting to fix py2 test issues 2020-05-15 09:24:44 -04:00
beeankha
4321c63165 Remove silence_warning (because of autouse), add version/type warning tests to module_utils unit test file 2020-05-15 09:24:44 -04:00
beeankha
8c5d236066 Update unit tests to not pull in version warnings 2020-05-15 09:24:43 -04:00
John Westcott IV
81eb9bb78a Now using new X-API headers to test version and type 2020-05-15 09:24:43 -04:00
John Westcott IV
762d8a287e Adding version checking to collection 2020-05-15 09:24:43 -04:00
Shane McDonald
c370cb4d93 Get OpenShift / arbitrary user ids working again 2020-05-15 08:32:43 -04:00
Marcelo Moreira de Mello
736e7a33ac Fixes ca_trust_dir mapping for k8s and openshift
Signed-off-by: Marcelo Moreira de Mello <tchello.mello@gmail.com>
2020-05-15 02:37:33 -04:00
beeankha
83bb3bba08 Move import line up 2020-05-14 18:33:11 -04:00
softwarefactory-project-zuul[bot]
30610f1a62 Merge pull request #7014 from nixocio/ui_update_chip_group
Update usage of new custom `ChipGroup`

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-14 21:35:37 +00:00
beeankha
a3e95ab171 Fix unit test failure 2020-05-14 16:39:39 -04:00
softwarefactory-project-zuul[bot]
275c43bd4a Merge pull request #7026 from 0xflotus/patch-1
(docs): enabled syntax highlighting for http patch

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-05-14 20:11:00 +00:00
beeankha
479ab8550d Fix misc. linter errors 2020-05-14 15:43:50 -04:00
Bill Nottingham
6924466c0b Also precreate /venv in /dev with modifiable permissions. 2020-05-14 15:33:21 -04:00
Bill Nottingham
1808bed2e8 Add nss for the chrome UI unit tests 2020-05-14 15:32:06 -04:00
Bill Nottingham
d5817fd87a Remove repo files no longer used in build process 2020-05-14 15:02:32 -04:00
Bill Nottingham
8b51e8eb82 Stage rsyslog.conf from existing version so we don't have two copies. 2020-05-14 15:02:32 -04:00
Bill Nottingham
66245d3094 Reorganize both dev and prod container builds
Use only one (templated) docker file for both builds.

Move to two-stage container builds in order to save space in the
final image.
2020-05-14 15:02:32 -04:00
Bill Nottingham
a057277823 Install config-watcher as 0755 rather than chmod'ing it later 2020-05-14 15:02:11 -04:00
softwarefactory-project-zuul[bot]
7852f4f054 Merge pull request #7029 from rooftopcellist/rm_redundant_target
Remove redundant dev image build make target

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-14 18:46:31 +00:00
Alex Corey
d0bbf8c711 Fixes testing issues and removes list item action buttons 2020-05-14 13:32:48 -04:00
Christian Adams
c02f6b9ece Remove redundant dev image build make target 2020-05-14 13:21:46 -04:00
softwarefactory-project-zuul[bot]
e078ac1c80 Merge pull request #7020 from Wilk42/devel
Support adding/removing notifications to multiple awx modules

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-14 17:15:49 +00:00
0xflotus
5d82d89dc2 enabled syntax highlighting 2020-05-14 18:54:06 +02:00
0xflotus
78e51d5159 (docs): enabled syntax highlighting for http patch 2020-05-14 18:49:48 +02:00
excalibrax
2d1bc58bb2 update lint 2020-05-14 11:22:32 -05:00
excalibrax
5a47cd8f94 update lint 2020-05-14 11:14:12 -05:00
Alex Corey
6c4bf5bf7d Adds Inventory Source Sync Button 2020-05-14 12:02:55 -04:00
excalibrax
ca992246d1 update organization 2020-05-13 20:44:22 -05:00
excalibrax
ca0130fc64 update organizations and approvals 2020-05-13 20:33:23 -05:00
excalibrax
b41a55f297 updated notifications 2020-05-13 18:39:21 -05:00
excalibrax
b3323a24e4 updated projects to use notifications 2020-05-13 17:35:31 -05:00
softwarefactory-project-zuul[bot]
1b144470b0 Merge pull request #7003 from keithjgrant/survey-launch-fix
Fix launch prompt errors when no survey present

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-13 22:20:40 +00:00
Keith Grant
3c77e5b005 fix import 2020-05-13 14:13:55 -07:00
softwarefactory-project-zuul[bot]
660ca5f6ff Merge pull request #7013 from chrismeyersfsu/fix-schema_generator
fix schema check

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-13 21:05:49 +00:00
Keith Grant
aa28909313 add PreviewStep tests 2020-05-13 13:08:10 -07:00
Keith Grant
e532f4c0c5 fix launch prompt errors when no survey present 2020-05-13 13:08:10 -07:00
nixocio
ce7ea1fbcb Update usage of new custom ChipGroup
Update usage of new custom `ChipGroup`.

See: https://github.com/ansible/awx/pull/6935/fies

Also: https://www.patternfly.org/v4/documentation/react/components/chipgroup
2020-05-13 15:23:46 -04:00
softwarefactory-project-zuul[bot]
23a20b9db0 Merge pull request #7009 from chrismeyersfsu/fix-websocket_stats_on_kubernetes
fix websocket stats on kubernetes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-13 19:05:24 +00:00
chris meyers
8bf426479c fix schema check
* Not sure how or when, but ours crawling tests set the cluster node id
to NOT start with `awx-`. That is fine, the schema checker just needs to
account for that.
2020-05-13 14:39:26 -04:00
chris meyers
155faa0138 delete and re-add host when ip address changes
* The websocket backplane interconnect is done via ip address for
Kubernetes and OpenShift. On init run_wsbroadcast reads all Instances
from the DB and makes a decision to use the ip address or the hostname
based, with preference given to the ip address if defined. For
Kubernetes and OpenShift the nodes can load the Instance before the
ip_address is set. This would cause the connection to be tried by
hostname rather than ip address. This changeset ensures that an ip
address set after an Instance record is created will be detected and
used.
2020-05-13 14:12:07 -04:00
softwarefactory-project-zuul[bot]
bba9d86078 Merge pull request #6949 from fosterseth/install-collections-isolated
Vendor collections for isolated jobs to work in ansible 2.10

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-13 18:01:10 +00:00
Seth Foster
09e5093b96 flake 8 version test 2020-05-13 13:32:11 -04:00
Seth Foster
4da0e0dd80 Vendor collections for isolated jobs to work in ansible 2.10
kubectl and synchronize are now part of community.kubernetes
and ansible.posix collections, respectively. This change installs
these collections to a local directory to be used in inventory and
isolated management playbooks.

awx issue #6930
2020-05-13 10:41:01 -04:00
chris meyers
90c02db386 track stats by hostname not remote host/ip
* broadcast websockets have stats tracked (i.e. connection status,
number of messages total, messages per minute, etc). Previous to this
change, stats were tracked by ip address, if it was defined on the
instance, XOR hostname. This changeset tracks stats by hostname.
2020-05-13 09:47:37 -04:00
softwarefactory-project-zuul[bot]
ba4ae7c104 Merge pull request #6992 from ryanpetrello/job-host-summary-optimization
drastically optimize job host summary creation

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-05-13 13:13:23 +00:00
softwarefactory-project-zuul[bot]
d2acd15783 Merge pull request #6954 from jakemcdermott/5957-statics
Add basic static file building for ui_next

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 22:14:53 +00:00
Jake McDermott
7971cc5c17 Update CI Dockerfile to use new build tooling 2020-05-12 17:50:06 -04:00
Jake McDermott
6098ee8f7f Add style-components macro where needed
We need to import the styled-components macro whenever we use the
css= prop.
2020-05-12 17:50:00 -04:00
Jake McDermott
41fa3e0473 Update readme with new build info 2020-05-12 17:49:57 -04:00
Jake McDermott
3ad62f586b Update i18n for new build tools 2020-05-12 17:49:52 -04:00
Jake McDermott
43f32f98a9 Fix tests 2020-05-12 17:49:49 -04:00
Jake McDermott
abcf8fea96 Add tooling for building static files 2020-05-12 17:49:45 -04:00
Jake McDermott
10f324110e Remove build and test configuration for aliases 2020-05-12 17:49:41 -04:00
Jake McDermott
0f335170c5 Remove import aliases from ui_next
For posterity, the script used to remove the aliases is included with
this commit:

    python3 tools/dealias.py awx/ui_next/src
    npm run lint -- --fix
    npm run prettier
2020-05-12 17:49:23 -04:00
softwarefactory-project-zuul[bot]
12a04bf42e Merge pull request #6989 from nixocio/ui_update_string_cap
Update strings to follow `sentence capitalization` style

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 20:53:04 +00:00
softwarefactory-project-zuul[bot]
4378dc62bb Merge pull request #6968 from AlexSCorey/6919-UserAccessList
Adds User Access List

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 20:47:47 +00:00
softwarefactory-project-zuul[bot]
99de79dfc2 Merge pull request #6952 from AlexSCorey/6863-CopyProjectsAndInventories
Adds Copy Button to Inventory List and Project List

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 20:43:57 +00:00
Ryan Petrello
74308f3dad further optimize job host summary queries 2020-05-12 16:38:28 -04:00
Shane McDonald
c3ff7ab247 Do not start services when generating swagger docs 2020-05-12 16:35:09 -04:00
softwarefactory-project-zuul[bot]
74c7d9686a Merge pull request #7001 from AlexSCorey/6920-TeamsAccessList
Adds Teams Access List and tests

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 20:09:58 +00:00
Alex Corey
d566b465aa Adds Copy Button to Inventory List and Project List 2020-05-12 15:48:21 -04:00
softwarefactory-project-zuul[bot]
6aa972a6e9 Merge pull request #6975 from marshmalien/6574-inv-src-details
Add inventory source detail view

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 18:57:04 +00:00
Ryan Petrello
917c6b405e properly update .failed, .last_job_id, and last_job_host_summary 2020-05-12 14:46:57 -04:00
softwarefactory-project-zuul[bot]
deadf197a3 Merge pull request #6955 from keithjgrant/5909-jt-launch-prompt-4
JT Launch prompt preview & validation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 18:45:48 +00:00
Keith Grant
90f6d4ed05 fix merging of survey values into extra_vars 2020-05-12 10:23:25 -07:00
Keith Grant
70a9a72c25 fix promptdetail test 2020-05-12 10:14:46 -07:00
softwarefactory-project-zuul[bot]
d2698c2cb1 Merge pull request #6935 from nixocio/ui_issue_6861
Add `Preview`, `more` and `Show Less` for translation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 17:06:03 +00:00
Alex Corey
09e72bc0ae Adds Teams Access List and tests 2020-05-12 11:38:11 -04:00
Christian Adams
a38a7ad9b6 Merge pull request #4327 from ansible/i18n_release_3.7.0_translations
UI translation strings for release_3.7.0 branch
2020-05-12 11:10:07 -04:00
softwarefactory-project-zuul[bot]
c3afe3f815 Merge pull request #6994 from wenottingham/extra-logs
Remove extraneous re-install of rsyslog

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-12 14:37:59 +00:00
nixocio
8f6b654696 Add Preview, more and Show less for translation
Also, create a new custom component called `ChipGroup` to avoid repeat
code related to the total of chips to be translated.

See: https://www.patternfly.org/v4/documentation/react/components/chipgroup

closes:https://github.com/ansible/awx/issues/6861
2020-05-12 09:53:00 -04:00
Ryan Petrello
3cb2475307 properly handle host summary bulk updates if hosts go missing 2020-05-12 09:38:59 -04:00
ansible-translation-bot
732f2fb828 UI translation strings for release_3.7.0 branch 2020-05-12 13:15:21 +00:00
Alan Rominger
2e2fe40d2a Add options to ovirt inventory file (#4307)
fixes schema differences from script
  add back in default groups from script
  change hostnames to reflect script
  add in some hostvars

Generally allow giving plugin options from source variables
  allows testing with insecure connection with ovirt_insecure
    this is a behavior change from the script
2020-05-11 22:45:19 -04:00
Bill Nottingham
caa4e90fa0 Remove extraneous re-install of rsyslog 2020-05-11 22:24:16 -04:00
softwarefactory-project-zuul[bot]
bb0abf37e0 Merge pull request #6993 from gamuniz/venv_permission_fix
added try/except to virtual env

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-11 23:39:51 +00:00
Keith Grant
e3a3a47229 delete unused file 2020-05-11 15:51:35 -07:00
gamuniz
8b2c65a3fa removed pass per feedback 2020-05-11 18:02:25 -04:00
Ryan Petrello
e7347d15c1 drastically optimize job host summary creation
see: https://github.com/ansible/awx/issues/6991
2020-05-11 17:13:06 -04:00
Gabe Muniz
1590c69590 added try/except to virtual env 2020-05-11 17:10:01 -04:00
nixocio
d6b56d8794 Update strings to follow sentence capitalization style
Also, add note about `sentence capitalization` in the ui_next docs.

See: https://www.patternfly.org/v4/design-guidelines/content/grammar-and-terminology#capitalization
2020-05-11 17:09:22 -04:00
Bill Nottingham
d96fd7e06f Merge pull request #4322 from wenottingham/the-girl-with-the-pycurl
Don't uninstall pycurl, but do build it from source.
2020-05-11 16:39:39 -04:00
Marliana Lara
4e8bbdaae7 Add inventory source details 2020-05-11 15:58:45 -04:00
Chris Meyers
cb7036382b Merge pull request #4320 from chrismeyersfsu/fix-ws_group_timeout
cleanup channel groups on start
2020-05-11 15:52:04 -04:00
Bill Nottingham
725437571d Set a default pycurl SSL backend. 2020-05-11 15:25:44 -04:00
softwarefactory-project-zuul[bot]
9fd396cbe0 Merge pull request #6940 from jlmitch5/makeIdSearchANumber
make job id search use number field

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-11 19:23:20 +00:00
Alex Corey
10ccb57062 Fixes empty chip issue when user adds empty new line. 2020-05-11 15:10:31 -04:00
John Mitchell
1d3efecd99 make job id search use number field 2020-05-11 14:57:31 -04:00
softwarefactory-project-zuul[bot]
6a003919c0 Merge pull request #6936 from jlmitch5/defaultsInQS
add defaults to qs instead of passing as additional params to api requests

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-11 18:30:35 +00:00
softwarefactory-project-zuul[bot]
3f94657cdb Merge pull request #6937 from jlmitch5/addDescripToTemplatesList
adds description-based search to templates list

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-11 18:27:51 +00:00
Keith Grant
dfecd4ad9d fix tests 2020-05-11 11:17:09 -07:00
Keith Grant
0b207e02ab set fields touched when steps marked as visited 2020-05-11 11:17:09 -07:00
Keith Grant
59e3306a3c merge survey fields into rest of jt promt form 2020-05-11 11:17:09 -07:00
Keith Grant
da8f486c5d flush out prompt validation errors 2020-05-11 11:17:09 -07:00
Keith Grant
1ac92b0493 add rough jt launch prompt validation 2020-05-11 11:17:09 -07:00
Keith Grant
11752e123d converting prompt steps to hook-based approach 2020-05-11 11:17:09 -07:00
Keith Grant
5c2eebf692 working on prompts validation 2020-05-11 11:17:09 -07:00
Keith Grant
9b3b20c96b mask passwords in launch preview step 2020-05-11 11:17:09 -07:00
Keith Grant
91d4948564 use PromptDetail in launch prompt preview 2020-05-11 11:17:09 -07:00
Bill Nottingham
345f1db994 Don't uninstall pycurl, but do build it from source.
oVirt requires something newer, but we can't use the wheel.
2020-05-11 13:11:19 -04:00
Alex Corey
9360d3fabc fixes erroneously invalidating responses 2020-05-11 12:17:22 -04:00
softwarefactory-project-zuul[bot]
1ca3d1fe3b Merge pull request #6979 from wenottingham/nobody-pexpects-a-timeout-inquisition
Remove pexpect_timeout setting for ansible-runner

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-11 15:33:07 +00:00
chris meyers
216454d298 cleanup channel groups on start
* There are 2 data-structures that django channels redis uses: (1) zset
and (2) list. (1) is used for group membership where the key is the
logic user group and the value(s) are websocket clients. The score of
the zset entry is used for group expiration. We can not rely on group
expiration for clean-up because there is no interface privided by redis
channels to refresh the expiration. Choosing a small value for
group_expiry could result on our websocket backplane group expiring,
which would result in job events not being delivered. Instead, we
increase the group expiration to 5 years and clean up on daphne service
start.
* The list (2) data-structure is used by django channels redis to queue
websocket events per-websocket-client as needed. The need arises to
queue per-websocket-client events when the consumer can not keep up with
the producer. The consumer here is daphne, the producer is AWX.
* When AWX is operating healthy group membership in Redis is reflective
of the real-world. When AWX is unhealthy i.e. daphne cycles, the zset
will contain stale websocket client entries. This can be observed by
running `zrange asgi::group:jobs-status_changed 0 -1`. If the entries
returned look like:
specific.fUkXXpYj!DKOIfwPICNgw
specific.fUkXXpYj!FQcdopZeiRdG
specific.lpTSAgnk!IOKldfzcfdDp
specific.lpTSAgnk!NbvRUZsDpIQx
The entries with `fUkXXpYj` are stale. Note that this changeset fixes
this by removing all `asgi:*` entries on daphne start.
* Also note that individual message themselves have an expiration that
is configurable and defaults to 60.
* Also note that zset's tracking group membership will be deleted by
django channels redis when they are empty.
2020-05-11 11:02:57 -04:00
softwarefactory-project-zuul[bot]
6b8359fc2f Merge pull request #6980 from ryanpetrello/yet-another-downstream-merge
merge in a few downstream fixes 

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-08 21:14:54 +00:00
Ryan Petrello
086d6951b4 Merge branch 'downstream' into devel 2020-05-08 16:48:48 -04:00
Bill Nottingham
8cdffd0dd0 Remove pexpect_timeout setting for ansible-runner
PEXPECT_TIMEOUT has never(?) been an actual setting, and 5 is the
runner default anyway.
2020-05-08 16:31:11 -04:00
Ryan Petrello
9668d18203 Merge pull request #4313 from ryanpetrello/more-fips-monkey-business
monkey-patch another Django names_digest for FIPS support
2020-05-08 15:14:25 -04:00
softwarefactory-project-zuul[bot]
5e02e6e4a4 Merge pull request #6974 from ansible/jakemcdermott-document-installer-prereqs
Document node and npm installation prerequisites

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-08 18:50:12 +00:00
Jake McDermott
6f872bf752 Document node and npm installation prerequisites 2020-05-08 14:25:00 -04:00
Ryan Petrello
814f033d46 monkey-patch another Django names_digest for FIPS support 2020-05-08 14:12:50 -04:00
softwarefactory-project-zuul[bot]
ff573e06b3 Merge pull request #6916 from nixocio/ui_issue_6742
Use Webhook Fields in WFJT Form

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-08 17:49:43 +00:00
Alex Corey
2cbcbddc52 Adds more testing for Urls 2020-05-08 12:15:02 -04:00
Alex Corey
68d56d5616 Adds User Access List 2020-05-08 12:03:27 -04:00
nixocio
0b8aabbd16 Use Webhook Fields in WFJT Form
Update WorkflowJobTemplateForm to use `WebhookSubForm`. Also, update
related unit-tests.

closes: https://github.com/ansible/awx/issues/6742
2020-05-08 11:55:23 -04:00
softwarefactory-project-zuul[bot]
8c57a92a65 Merge pull request #6898 from marshmalien/6575-inv-src-add
Add inventory source create form

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-08 14:12:03 +00:00
softwarefactory-project-zuul[bot]
77ee2191ed Merge pull request #6926 from nixocio/ui_issue_6887
Fix Button 'Create' - to be marked for translation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-08 14:07:51 +00:00
softwarefactory-project-zuul[bot]
a3463e87b5 Merge pull request #6924 from nixocio/ui_issue_6859
Fix Survey, check label 'Required' translation

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-08 14:07:43 +00:00
Christian Adams
c494c38966 Merge pull request #4294 from ansible/i18n_release_3.7.0_translations
[WIP] UI translation strings for release_3.7.0 branch
2020-05-08 09:56:40 -04:00
Marliana Lara
58c85ab03f Add cache timeout and inventory file validation 2020-05-07 23:26:31 -04:00
Bill Nottingham
64add6e907 Merge pull request #4305 from wenottingham/why-fix-a-parser-when-you-can-delete-it
Remove ssh version checking.
2020-05-07 17:07:56 -04:00
beeankha
10be375137 Update Makefile to find correct python path for testing 2020-05-07 16:37:04 -04:00
Bill Nottingham
4c6cac90fd Remove ssh version checking.
6.6 was added in RHEL 7.1, which is well before our supported platforms.
2020-05-07 15:30:55 -04:00
John Westcott IV
1d91387f58 Adding validation of rrule output thorugh awx searlizer 2020-05-07 14:42:47 -04:00
AlanCoding
d825cca9f2 Unit testing of tower_schedule
Move previously integration tests of lookup plugin to unit tests
  delete all integration tests except some basic demo tests

do simple create unit test
2020-05-07 14:42:47 -04:00
John Westcott IV
694c7e8af5 Remocing doc fragment extension 2020-05-07 14:42:47 -04:00
John Westcott IV
2ed3a39b46 Changing import 2020-05-07 14:42:47 -04:00
beeankha
dd49f747a0 Fix linter error 2020-05-07 14:42:47 -04:00
John Westcott IV
0eb7e22d1f Adding requirements on pytz and python.dateutil for rrule lookup plugin 2020-05-07 14:42:47 -04:00
beeankha
677ff99eb4 Make minor changes to fix sanity test results 2020-05-07 14:42:47 -04:00
John Westcott IV
12805954e0 Adding rrule lookup plugin 2020-05-07 14:42:46 -04:00
John Westcott IV
0e1a2b899a Initial version of tower_schedule 2020-05-07 14:42:46 -04:00
Christian Adams
bae9c03258 Merge pull request #4302 from rooftopcellist/rsyslog_conf_race
Prevent Rsyslog config race condition when writing to file
2020-05-07 14:21:57 -04:00
softwarefactory-project-zuul[bot]
420c75f76f Merge pull request #6965 from beeankha/jt_integration_test_edit
Update JT Integration Test

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-07 18:07:38 +00:00
softwarefactory-project-zuul[bot]
d58ea85584 Merge pull request #6964 from beeankha/notifications_for_wfjt_module
Add Notification Association Functionality to tower_workflow_job_template Module

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-07 17:13:31 +00:00
Christian Adams
37125102ab Clean up rsyslog config temp dir
- dir is cleaned up at end of 'with' context
2020-05-07 12:48:50 -04:00
beeankha
c6d77a1183 Update JT integration test 2020-05-07 12:02:08 -04:00
beeankha
8f1fccefeb Add notification association functionality to tower_workflow_job_template module, along with updated integration/unit tests 2020-05-07 11:44:43 -04:00
Marliana Lara
4b53875a71 Clear inv src subform values when source value changes
* Test that inv file field resets when project value changes
* Remove project and inv file path from API request when type is SCM
* Update checkbox tooltip to accept node proptypes
* Format option field tooltips
2020-05-07 08:57:08 -04:00
softwarefactory-project-zuul[bot]
b9e45e62c0 Merge pull request #6948 from shanemcd/fix-oc-4.3
Fix installer for oc 4.3

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-07 00:46:03 +00:00
Christian Adams
0675b9e8fa Make rsyslog.conf writes atomic
- This writes the rsyslog.conf in a temporary dir, then replaces the
   original in one atomic operation.
2020-05-06 17:54:51 -04:00
Jim Ladd
e64f9c6963 Merge pull request #4298 from jladdjr/add_foreman_options
pass along all foreman options to plugin, add support for group_patterns
2020-05-06 11:28:02 -07:00
Christian Adams
d0a7f7f4e9 Merge pull request #4297 from rooftopcellist/rsyslog_term
Rsyslog config race condition between saving and writing the file
2020-05-06 13:41:13 -04:00
AlanCoding
e24c511aef Update test files for sat6 updates 2020-05-06 11:49:04 -04:00
Shane McDonald
a461df0e4d Fix installer for oc 4.3 2020-05-06 11:40:07 -04:00
softwarefactory-project-zuul[bot]
3aa6e8a457 Merge pull request #6942 from beeankha/fix_jt_module_param_override
Fix tower_job_template module so that params are not overridden (unless specified) in subsequent tasks

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-06 14:48:20 +00:00
beeankha
a3cd858665 Add JT module unit test 2020-05-06 08:47:45 -04:00
Jim Ladd
84c854bdf3 add support for keyed_groups 2020-05-06 00:29:55 -07:00
Jim Ladd
e243513a0d pass along all foreman options to plugin 2020-05-05 19:36:55 -07:00
softwarefactory-project-zuul[bot]
9a23056073 Merge pull request #6943 from ryanpetrello/devel
merge in a few downstream fixes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-06 00:47:06 +00:00
Ryan Petrello
e7e716742a Merge branch 'downstream' into devel 2020-05-05 20:12:24 -04:00
Alan Rominger
961c5589c1 Refresh inventory collection requirements (#4296)
* Refresh inventory collection requirements

Fix bug specific to Docker development where the right folder of
  install was not specified in the setting

Add initial rhv/ovirt version for consistency

* Update unit test to ovirt name change
2020-05-05 18:22:00 -04:00
Alan Rominger
1ca29df0de Fix for schedule delete 500 from Gabe (#4290) 2020-05-05 18:11:51 -04:00
Marliana Lara
b717aabcc9 Add inventory source add form 2020-05-05 17:00:37 -04:00
beeankha
52a272e8e4 Fix JT parameter defaults so that previously input values are not overridden by nonexistent params; update integration test 2020-05-05 16:36:10 -04:00
Christian Adams
e41d33991a Prevent a race condition when writing the rsyslog.conf 2020-05-05 15:55:08 -04:00
Christian Adams
c565130b35 TERM rsyslogd instead of KILL for more graceful shutdown 2020-05-05 15:38:57 -04:00
John Mitchell
7782b1ddf4 adds description-based search to templates list 2020-05-05 15:20:21 -04:00
John Mitchell
9a891794d9 add defaults to qs instead of passing as additional params to api request 2020-05-05 14:55:39 -04:00
softwarefactory-project-zuul[bot]
de8c37fd3d Merge pull request #6915 from chrismeyersfsu/rm_memcache_fact_cache
remove memcached based fact caching plugin

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-05 17:27:43 +00:00
Ryan Petrello
a7ca6e2eea Merge pull request #4293 from chrismeyersfsu/fix-ws_disconnect_log
missing f"" on log statement
2020-05-05 11:16:13 -04:00
softwarefactory-project-zuul[bot]
e080c1f4c2 Merge pull request #6846 from AlexSCorey/4969-Copy
Copy Feature for Templates and Credentials

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-04 21:13:52 +00:00
softwarefactory-project-zuul[bot]
5fd11d8829 Merge pull request #6900 from AlexSCorey/6777-SyncInventorySourceList
Adds Sync Functionality to Inventory Source List

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-04 21:11:27 +00:00
nixocio
44311c163c Fix Button 'Create' - to be marked for translation
Fix Button 'Create' - to be marked for translation

closes: https://github.com/ansible/awx/issues/6887
2020-05-04 16:41:07 -04:00
chris meyers
ba7e2c9bc4 missing f"" on log statement 2020-05-04 15:57:56 -04:00
Shane McDonald
e9cda0c819 Merge pull request #4292 from shanemcd/fix-inventory-plugin-permissions
Fix permissions for vendored collections in dev env
2020-05-04 15:38:17 -04:00
nixocio
60976b6aca Fix Survey, check label 'Required' translation
Fix Survey, check label 'Required' translation.

closes: https://github.com/ansible/awx/issues/6859
2020-05-04 14:43:21 -04:00
Shane McDonald
a98887deb0 Update INVENTORY_COLLECTIONS_ROOT in dev env settings 2020-05-04 14:23:05 -04:00
Shane McDonald
b12c0def7d Fix permissions for vendored collections in dev env 2020-05-04 12:44:04 -04:00
softwarefactory-project-zuul[bot]
63fec77f82 Merge pull request #6912 from AlanCoding/ignored_but_not_forgotten
Remove defunct entry from view method return tuple

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-04 16:23:55 +00:00
roofotpcellist
462cfa2344 UI translation strings for release_3.7.0 branch 2020-05-04 15:37:35 +00:00
chris meyers
503b86d41c remove memcached based fact caching plugin
* AWX uses the JSON fact caching module that ships with Ansible
2020-05-04 09:28:21 -04:00
softwarefactory-project-zuul[bot]
c6d6536078 Merge pull request #6909 from AlanCoding/git_success
Allow performing git project updates when Ansible 2.10 (ansible-base) is installed

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-01 18:49:24 +00:00
softwarefactory-project-zuul[bot]
d688f7b833 Merge pull request #6910 from ryanpetrello/devel
merge in a few downstream fixes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-05-01 18:19:49 +00:00
AlanCoding
d54e5e5ed8 Remove defunct entry from view method return tuple 2020-05-01 14:10:14 -04:00
Ryan Petrello
2997911fd4 Merge branch 'downstream' into devel 2020-05-01 13:53:30 -04:00
Ryan Petrello
9c5f04b1e0 Merge pull request #4287 from ryanpetrello/flake8-whoops
fix busted flake8
2020-05-01 13:52:52 -04:00
Ryan Petrello
b4b261b918 fix busted flake8 2020-05-01 13:51:37 -04:00
AlanCoding
6d1746f99c yamllint fixes 2020-05-01 11:50:01 -04:00
Ryan Petrello
cd21dd69f5 Merge pull request #4284 from ryanpetrello/more-event-sanitization-tweaks
only sanitize project update events for the scm modules
2020-05-01 11:48:24 -04:00
Ryan Petrello
bf65b40241 only sanitize project update events for the scm modules
these are the only modules in the project update playbook that actually
utilize the SCM URL (which is what potentially contains sensitive data)
2020-05-01 11:39:46 -04:00
AlanCoding
fcca0cee37 use include_tasks to make hg dependency optional 2020-05-01 10:37:37 -04:00
Alex Corey
1ea924aa13 improves isLoading state and removes unnecessary RBAC 2020-05-01 08:05:49 -04:00
softwarefactory-project-zuul[bot]
d1671d72dc Merge pull request #6885 from ryanpetrello/remove-extra-credentials
remove the deprecated extra_credentials endpoints

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-30 20:16:01 +00:00
softwarefactory-project-zuul[bot]
4cf38db19c Merge pull request #6837 from nixocio/ui_issue_6171
Add Edit/Delete buttons to JT Schedule Details

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-30 20:08:33 +00:00
Alex Corey
77fd2d677a Adds Sync Functionality 2020-04-30 15:30:04 -04:00
softwarefactory-project-zuul[bot]
b0ab3fbe10 Merge pull request #6834 from jlmitch5/searchFixes2
fix the scm_type search on projects lists and make search keys show labels instead of api values

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-30 17:29:07 +00:00
Alex Corey
008cd9985a Adds Copy Button component 2020-04-30 12:25:48 -04:00
softwarefactory-project-zuul[bot]
f9b3fb4321 Merge pull request #6895 from ansible/shanemcd-patch-1
Remove problematic variable

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-30 15:56:49 +00:00
Shane McDonald
9be1fd56d2 Remove problematic variable
This is already here: https://github.com/ansible/awx/blob/devel/installer/roles/kubernetes/defaults/main.yml#L58

Was also causing downstream stuff to break.
2020-04-30 11:09:06 -04:00
softwarefactory-project-zuul[bot]
6d07064ca2 Merge pull request #6740 from AlexSCorey/6573-InventorySourceList
Inventory source list

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-30 14:47:38 +00:00
Ryan Petrello
18607107a7 remove the deprecated extra_credentials endpoints 2020-04-30 10:22:02 -04:00
John Mitchell
697b0c634d add additional merge params test, remove unnecessary span container from search chips 2020-04-29 16:53:08 -04:00
John Mitchell
fd91c8e329 update project type search to scm_type 2020-04-29 16:53:08 -04:00
John Mitchell
6f80e5b67b use labels in chips for select based filters 2020-04-29 16:53:08 -04:00
Alex Corey
8d31d09d4a Adds copy button to JTList 2020-04-29 15:46:52 -04:00
nixocio
271b19bf09 Add Edit/Delete buttons to JT Schedule Details
Also, add unit-tests to the related changes.

Closes: https://github.com/ansible/awx/issues/6171
2020-04-29 15:39:28 -04:00
softwarefactory-project-zuul[bot]
72de660ea1 Merge pull request #6880 from ryanpetrello/fix-awxkit-new-pip
Keep awxkit's requirements on the setup.py

Reviewed-by: Jacob Callahan
             https://github.com/JacobCallahan
2020-04-29 19:24:57 +00:00
softwarefactory-project-zuul[bot]
042c854ad3 Merge pull request #6877 from ryanpetrello/install-doc-cleanup
cleanup and clarify some installation instructions

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-29 18:53:31 +00:00
Ryan Petrello
9aed49e146 update the 11.2.0 changelog 2020-04-29 14:49:09 -04:00
Elyézer Rezende
5c91f66316 Keep awxkit's requirements on the setup.py
awxkit's setup.py was making use of pip internal structures to parse the
requirements.txt file. This is not a good thing as they may change,
actually that just happened.

To avoid this in the future, move the list of requirements to setup.py
and make requirements.txt list `.` as the only item. This way we keep a
single place to update requirements in the future and avoid accessing
pip's internals.
2020-04-29 14:47:21 -04:00
Ryan Petrello
99c7f2f70d Merge pull request #4278 from elyezer/drop-awxkit-requirements-txt
[3.7.0] Keep awxkit's requirements on the setup.py
2020-04-29 14:46:58 -04:00
softwarefactory-project-zuul[bot]
5e223db945 Merge pull request #6808 from AlexSCorey/6694-WebhookDataOnJTDEETs
Adds webhook fields to job template details

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-29 18:43:53 +00:00
Elyézer Rezende
e4921abfff Keep awxkit's requirements on the setup.py
awxkit's setup.py was making use of pip internal structures to parse the
requirements.txt file. This is not a good thing as they may change,
actually that just happened.

To avoid this in the future, move the list of requirements to setup.py
and make requirements.txt list `.` as the only item. This way we keep a
single place to update requirements in the future and avoid accessing
pip's internals.
2020-04-29 14:11:06 -04:00
Ryan Petrello
67e2f19aaf cleanup and clarify some installation instructions 2020-04-29 14:09:04 -04:00
softwarefactory-project-zuul[bot]
e940f1f7df Merge pull request #6849 from ggiinnoo/ssl-seperate-key
Added variable to inventory to add a separate SSL key file

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-29 14:38:32 +00:00
softwarefactory-project-zuul[bot]
ebee75e91e Merge pull request #6868 from john-westcott-iv/sdb_notigy_host_ox_x
Set SDB_NOTIFY_HOST on non-docker OS X

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-29 14:01:04 +00:00
softwarefactory-project-zuul[bot]
e641433c68 Merge pull request #6860 from ryanpetrello/version-11-2-0
bump version 11.2.0

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-29 00:31:30 +00:00
softwarefactory-project-zuul[bot]
c5dc03d4a9 Merge pull request #6867 from AlexSCorey/TestDebug
Fixes failing test

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-28 23:18:33 +00:00
John Westcott IV
3a6a7c100a Going for a more generic 'just pass' option 2020-04-28 16:47:08 -04:00
John Westcott IV
cd07305c08 Set SDB_NOTIFY_HOST on non-docker OS X 2020-04-28 16:37:35 -04:00
Alex Corey
c39423d5ca Fixes failing test 2020-04-28 16:26:46 -04:00
Chris Meyers
cd15a5c082 Merge pull request #4275 from chrismeyersfsu/redis_throttle_reconnect
exponential backoff on cb receiver reconnect
2020-04-28 15:42:45 -04:00
Ryan Petrello
6b976c4239 Merge pull request #4276 from rebeccahhh/release_3.7.0
put remaining correct links for 'Source Variables' in Source Page
2020-04-28 15:31:37 -04:00
chris meyers
a8f52c1639 actually do exponential calc rather than *2
* Log the time til reconnect attemp to log message rather than attempt
number
2020-04-28 15:24:08 -04:00
Rebeccah
867475ad49 added in (what I believe to be) the correct links 2020-04-28 14:14:40 -04:00
Ryan Petrello
3f00329abd bump version 11.2.0 2020-04-28 13:55:59 -04:00
softwarefactory-project-zuul[bot]
def3114b5b Merge pull request #6856 from ryanpetrello/devel
merge in a few downstream fixes

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-28 17:21:28 +00:00
softwarefactory-project-zuul[bot]
fcc99baaa8 Merge pull request #6848 from vandreykiv/devel
Updated ingress template for kubernetes to support HTTP and HTTPS when annotations not set

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-28 16:52:46 +00:00
chris meyers
2ecd055d1e sleep backoff on cb receiver reconnect
* Sleep before trying to reconnect
Most common reason for entering this reconnect loop is when Redis
service stops before the callback receiver when stopping tower services.
2020-04-28 12:47:40 -04:00
Ryan Petrello
aad371d224 Merge branch 'downstream' into devel 2020-04-28 12:18:13 -04:00
Vyacheslav Andreykiv
d5cb6ad58a Update main.yml
Reverted formating changes
2020-04-28 08:56:29 -07:00
ggiinnoo
0bad717db7 Wrong syntax 2020-04-28 17:51:41 +02:00
softwarefactory-project-zuul[bot]
b31abbba82 Merge pull request #6220 from kawsark/devel
Modified hashivault.py to support approle

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-28 15:50:21 +00:00
Ryan Petrello
0d30a67756 Merge pull request #4273 from wenottingham/certscertscerts
Allow unsigned certs in logging if cert verification is disabled.
2020-04-28 11:17:19 -04:00
Bill Nottingham
5d24acf613 Allow unsigned certs in logging if cert verification is disabled. 2020-04-28 11:16:54 -04:00
Ryan Petrello
94692c2364 Merge pull request #4272 from chrismeyersfsu/sos_report_redis_logs
sos report redis logs
2020-04-28 11:00:41 -04:00
Ryan Petrello
29abe35799 Merge pull request #4268 from fosterseth/fix-ip_conflict_cluster
Unset IP address of old instance if conflicting with new instance IP
2020-04-28 10:59:27 -04:00
Seth Foster
6652464e25 Unset old instance IP when conflicting new instance IP
With AWX_AUTO_DEPROVISION_INSTANCES on, instances
are registered with an ip address. However, new
instances might try to register before old instances
are deprivisioned. In this case old IPs can conflict with
the new ones. This will check for an ip conflict and unset
the IP of conflicting instance (set to None)

ansible/awx issue 6750
2020-04-28 10:52:15 -04:00
Pierre-Louis Bonicoli
f9d5860d63 Fix pylint errors 2020-04-28 10:33:41 -04:00
Pierre-Louis Bonicoli
d8ac2f5263 Avoid to repeat default value 2020-04-28 10:33:40 -04:00
Pierre-Louis Bonicoli
fdae3cd092 Explicitly references AppRole 2020-04-28 10:33:40 -04:00
Pierre-Louis Bonicoli
139384acc4 Simplify test branches 2020-04-28 10:33:40 -04:00
Pierre-Louis Bonicoli
9d85e8655d Both methods return a token: rename variable 2020-04-28 10:33:40 -04:00
Pierre-Louis Bonicoli
9fdd9061d3 Remove extraneous call to bool built-in function 2020-04-28 10:33:39 -04:00
kawsark
d3d4ce3804 Modified hashivault.py to support approle 2020-04-28 10:33:37 -04:00
chris meyers
960aa9df16 add redis logs to sosreport
* rhel8 /var/log/redis/redis.log
* rhel7 scl location
2020-04-28 09:12:42 -04:00
ggiinnoo
41a8d32dcc Added variable to inventory to add a separate key file 2020-04-28 11:13:47 +02:00
Bianca Henderson
12b47405f0 Merge pull request #4265 from john-westcott-iv/release_3.7.0
Restructuring modules so that lookup don't happen if deleting
2020-04-27 17:39:11 -04:00
Vyacheslav Andreykiv (Intel)
7659ffca1e fixed ingress template 2020-04-27 14:33:42 -07:00
Alan Rominger
41014e62b7 Avoid applying galaxy settings if no user settings exist (#4262) 2020-04-27 16:15:11 -04:00
Alex Corey
df1489bcee Addresses some object mutation issues and improves testing 2020-04-27 15:49:22 -04:00
Alex Corey
4c72ab896a Adds Inventory Source List 2020-04-27 15:49:22 -04:00
softwarefactory-project-zuul[bot]
c2e9df74e4 Merge pull request #6790 from fherbert/feature/awx_cli_job_monitor
Add ability to monitor jobs and workflow_jobs via awx cli, fixes #6165

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-27 19:48:33 +00:00
Ryan Petrello
e1cedcfb04 Merge pull request #4266 from rooftopcellist/rsyslog_followup
Increase stopwait time for rsyslogd service
2020-04-27 15:26:49 -04:00
Francois Herbert
d0384799fd Add ability to monitor jobs and workflow_jobs via awx cli, fixes #6165
Signed-off-by: Francois Herbert <francois@herbert.org.nz>

Fixup linting

Remove timeout option, not really required and it's making the api test fail
2020-04-27 15:09:16 -04:00
Jim Ladd
45f8f0f412 Merge pull request #4264 from jladdjr/satellite6_want_ansible_ssh_host
Add support for satellite6_want_ansible_ssh_host
2020-04-27 11:39:03 -07:00
Christian Adams
c07b6285da Increase stopwait time for rsyslogd service 2020-04-27 14:33:46 -04:00
John Westcott IV
f17ced8f9c Fixing integration tests for deprecation warnings 2020-04-27 14:25:23 -04:00
softwarefactory-project-zuul[bot]
17702c94f7 Merge pull request #6833 from lewisface/devel
Keystone v3 support for OpenStack Credential

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2020-04-27 18:13:52 +00:00
John Westcott IV
7f66f084f1 Restructuring modules so that lookup don't happen if deleting 2020-04-27 14:11:23 -04:00
Jim Ladd
616e7082b3 Add support for satellite6_want_ansible_ssh_host
* defaults to IPv6, falls back to IP
2020-04-27 11:04:56 -07:00
softwarefactory-project-zuul[bot]
83051e9138 Merge pull request #6005 from donomur/ca-trust-fix
Add CA trust volume to k8s installer management pod

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-27 17:36:20 +00:00
softwarefactory-project-zuul[bot]
33ff4ad9be Merge pull request #6762 from shaynecm/devel
Update inventory file 

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-27 17:34:55 +00:00
softwarefactory-project-zuul[bot]
e5bdd44e13 Merge pull request #5398 from dvaerum/patch-1
If pg_hostname is defined don't try to upgrade PostgreSQL

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-27 17:22:02 +00:00
Chris Meyers
fa73fe76b2 Merge pull request #4263 from ansible/fix-sliding_window_3_7_0
fix sliding window per/minute calc
2020-04-27 13:20:39 -04:00
Donovan Murphy
fb567dad1e add CA trust volume to management pod
Signed-off-by: Donovan Murphy <dono@dono.email>
2020-04-27 13:01:32 -04:00
softwarefactory-project-zuul[bot]
88f44cb185 Merge pull request #6811 from wenottingham/ssh_aaaaaaarghs
Don't override ANSIBLE_SSH_ARGS for ad-hoc commands.

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-27 16:44:23 +00:00
Dennis Vestergaard Værum
fd2d0966e2 If pg_hostname is defined don't try to upgrade PostgreSQL 2020-04-27 12:12:37 -04:00
Ryan Petrello
efe9d85685 Merge pull request #4260 from jlmitch5/fixNotificationPagination
make sure right endpoint is getting called for notification pagination
2020-04-27 09:18:34 -04:00
Ryan Petrello
1f1069e9f3 Merge pull request #4261 from jlmitch5/fixLicenseTranslation
Remove unnecessary nesting license translate directive
2020-04-24 16:03:10 -04:00
chris meyers
ac46013fcc fix sliding window per/minute calc
* Add tests to ensure correctness
2020-04-24 15:55:11 -04:00
Christian Adams
f6a2d41e4c Remove unnecessary or translation 2020-04-24 15:35:56 -04:00
John Mitchell
3b84ff7002 remove unnecessary nesting translate directive from license partial 2020-04-24 15:35:56 -04:00
John Mitchell
b1b6af4ad5 make sure right endpoint is getting called for notification pagination 2020-04-24 15:32:14 -04:00
Ryan Petrello
04e6482f36 Merge pull request #6832 from ghjm/service_command
Improve the ansible-tower-service script
2020-04-24 15:24:40 -04:00
softwarefactory-project-zuul[bot]
f7a8e30d3e Merge pull request #6818 from ryanpetrello/rsyslogd-debug
add a setting for enabling high rsyslogd verbosity

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-24 19:13:42 +00:00
Graham Mainwaring
d55b223aae Use sysconfig file to get the list of services 2020-04-24 14:08:24 -04:00
Ryan Petrello
e51d0b6fde add a setting for enabling high rsyslogd verbosity 2020-04-24 14:01:17 -04:00
Graham Mainwaring
e36ffa5764 Return more status information from ansible-tower-service status and error check commands better 2020-04-24 11:37:16 -04:00
Dave Lewis
c86692784e Updated data/inventory/scripts/openstack/files/file_reference
Update file_references due to the inclution of project_domain_name in the openstack credentails.
2020-04-24 15:11:49 +01:00
Dave Lewis
952c91dea5 Updated injector.py and added new test into test_tasks.py 2020-04-24 14:06:13 +01:00
softwarefactory-project-zuul[bot]
e7a9604896 Merge pull request #6826 from AlanCoding/vendoring_collections_vmware
Enable VMWare inventory plugin

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-24 12:32:39 +00:00
AlanCoding
8bbd2c7aaa bump collection requirements, vmware patches
New VMWare and azure were released, pick those up

Enable using of VMWare inventory plugin for Ansible 2.9

Few fixes from manual testing with VMWare
  Remove invalid properties which resulted in no hosts imported
  Add some defaults to be more consistent with script
2020-04-23 19:57:53 -04:00
softwarefactory-project-zuul[bot]
9e87ddde69 Merge pull request #6820 from marshmalien/6530-wf-node-detail-cleanup
Show missing detail fields in workflow node view modal 

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-23 20:34:36 +00:00
softwarefactory-project-zuul[bot]
5d40cf7635 Merge pull request #6825 from ryanpetrello/test-other-loggers
allow users to test log aggregration if `awx` isn't in the loggers list

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-23 20:19:08 +00:00
Marliana Lara
75b54d2c14 Add unit tests to check for deleted details 2020-04-23 15:34:23 -04:00
Alex Corey
1bcd71ec9f Adds webhook fields to job template details 2020-04-23 15:19:03 -04:00
Ryan Petrello
31c6b3337c allow users to test log aggregration if awx isn't in the loggers list 2020-04-23 15:15:37 -04:00
softwarefactory-project-zuul[bot]
c0e07198cf Merge pull request #6283 from AlanCoding/vendoring_collections
Use vendored collections for inventory imports

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-23 18:54:50 +00:00
Marliana Lara
a2c3027bd7 Display a "Deleted" label for prompt view node details 2020-04-23 13:08:16 -04:00
softwarefactory-project-zuul[bot]
acdf15640c Merge pull request #6814 from surfer190/patch-1
Change the custom venv vars install line

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-23 15:38:29 +00:00
Dave Lewis
92b74266ca Correct missing "default=''"
On previous commit missed "default=''" so changing:

project_domain_name=cred.get_input('project_domain_name'))
to
project_domain_name=cred.get_input('project_domain_name', default=''))
2020-04-23 11:33:24 +01:00
Dave Lewis
08323a11b6 Addition of project domain name to OpenStack Credential
Keystone v3 requires user_domain_id and project_domain_name to authenticate, but AWX openstack credential only requests the user_domain_id.
Added in project_domain_name into the credential templating. Not added as a required field as this is only needed when using Keystone v3.
2020-04-23 11:24:51 +01:00
surfer190
6390794828 Change the custom venv vars install line
Add the inventory
2020-04-23 11:43:01 +02:00
AlanCoding
ab703e2a32 Add feature docs and document development tooling 2020-04-22 21:41:52 -04:00
AlanCoding
8c657e210c VMWare collection ready but waiting for release
turn off use of VMWare inventory plugin for now

Attempt to roll back general migration to Ansible 2.8
  failed, kept at 2.9 because of compatibility
2020-04-22 21:40:23 -04:00
Bill Nottingham
3f5820adf8 Don't override ANSIBLE_SSH_ARGS for ad-hoc commands.
This reverts 8beed7f4, which says:
    Disable ControlPersist for ad hoc commands, should avoid any
    issues with proot or needing to clean up sockets afterwards.

Given we've switched to the much less finicky bwrap for process
isolation, along with runner-based process killing, this probably
isn't needed any more.
2020-04-22 20:46:18 -04:00
softwarefactory-project-zuul[bot]
a34a63ec7f Merge pull request #6809 from wenottingham/nope-no-scls-here
Don't use SCLs for openshift.

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-22 23:12:45 +00:00
Bill Nottingham
47fef1dcf3 Don't use SCLs for openshift.
This may be a mis-merge?
2020-04-22 17:16:44 -04:00
softwarefactory-project-zuul[bot]
b6be891dc1 Merge pull request #6786 from nixocio/ui_issue_6511
Fix searching for a blank string creates a blank search filter

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-22 21:02:25 +00:00
softwarefactory-project-zuul[bot]
546df65753 Merge pull request #6804 from chrismeyersfsu/fix-collector_tests
lie about last time analytics were collected

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
2020-04-22 20:38:45 +00:00
nixocio
2a86a3e05b Fix searching for a blank string creates a blank search filter
Fix searching for a blank string creates a blank search filter. Also,
add unit-test to the related changes.

closes: https://github.com/ansible/awx/issues/6511
2020-04-22 16:16:10 -04:00
chris meyers
01c56a4f2b lie about last time analytics were collected
* Ensure that everything that we put into the database is returned via
analytics.
2020-04-22 14:10:45 -04:00
AlanCoding
68f5482c42 Update vmware implementation to new agreements 2020-04-21 22:49:20 -04:00
shaynecm
e428aeb97e pre-req's updated
added Python 3.6+ to bring inline with the inventory change
2020-04-21 12:43:19 +01:00
shaynecm
e42915d4cf updated to include py3
amended to be "/usr/bin/env python3" as suggested
2020-04-21 12:40:56 +01:00
shaynecm
1afd8b4309 Update inventory 2020-04-20 19:20:14 +01:00
AlanCoding
50197c6a12 Handle custom script options of hostnames and destination variable 2020-04-18 23:30:50 -04:00
AlanCoding
de0122d64e Respect the ec2 script nested groups option 2020-04-18 19:32:18 -04:00
AlanCoding
fff34f7227 Make inventory non-strict for production and remove comments 2020-04-17 15:43:03 -04:00
AlanCoding
e2f5aa987d Implement vmware plugin host filtering 2020-04-17 14:52:38 -04:00
AlanCoding
84d863ff9d Shorten list of VMWare inventory plugin properties
Do not include summaries

decision on vmware keyed groups

Handle first set of custom user vmware options
2020-04-16 20:56:02 -04:00
AlanCoding
47bdf86dfa Pick up collections paths in openstack inventory update prep
Update amazon.aws version

Update vmware to new release

Pin some more tests due to transitioning to inventory plugins

Remove more temporary hacks
2020-04-16 20:56:02 -04:00
Jim Ladd
6b015c9d81 Call parent get_plugin_env for foreman 2020-04-16 20:56:01 -04:00
AlanCoding
c3f2b3e44d bump versions of Galaxy collection requirements
Implement 2.9 version policy

Update ec2 collection name

Enable ovirt, refresh test files

Put in upstream forks to get it running for now

pick up openstack.cloud fix
2020-04-16 20:56:01 -04:00
Jim Ladd
6807878e2d I think this is the right place for iam_role_arn in the tests? 2020-04-16 20:56:01 -04:00
Jim Ladd
96c6cf9f05 pass iam_role_arn through to aws inv. plugin 2020-04-16 20:56:01 -04:00
Jim Ladd
8a20b5225b enable aws_ec2 plugin 2020-04-16 20:56:00 -04:00
Jim Ladd
0e2786d1f1 compat layer for foreman 2020-04-16 20:56:00 -04:00
Jim Ladd
f38437b6bc foreman plugin updates 2020-04-16 20:56:00 -04:00
AlanCoding
99ae614a63 Vmware was published
implement vmware inventory plugin

Enable the previously broken properties
2020-04-16 20:56:00 -04:00
AlanCoding
fcf75af6a7 Get current cloud sources working from collection
update test data files

Adopt official vendor location

openstack not published yet

Add collections to show paths

Add collections loc to installer settings

Add vendored collections to show path again
2020-04-16 20:55:59 -04:00
Yanis Guenane
541b9607f5 Collections: Adding a requirements.yml file 2020-04-16 20:55:59 -04:00
Darin Johnson
6cd4b1c666 Add support for importing host/group descriptions
Signed-off-by: Darin Johnson <djohnson@sonifi.com>
2020-03-11 15:17:14 -05:00
933 changed files with 48478 additions and 58080 deletions

1
.gitignore vendored
View File

@@ -35,6 +35,7 @@ rsyslog.pid
/tower-license
/tower-license/**
tools/prometheus/data
tools/docker-compose/Dockerfile
# Tower setup playbook testing
setup/test/roles/postgresql

View File

@@ -2,6 +2,51 @@
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>`.
## 12.0.0 (Jun 9, 2020)
- 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.
- Fixed a bug which broke AWX installations with oc version 4.3 (https://github.com/ansible/awx/pull/6948/files)
- Fixed a performance issue that caused notable delay of stdout processing for playbooks run against large numbers of hosts (https://github.com/ansible/awx/issues/6991)
- Fixed a bug that caused CyberArk AIM credential plugin looks to hang forever in some environments (https://github.com/ansible/awx/issues/6986)
- Fixed a bug that caused ANY/ALL converage settings not to properly save when editing approval nodes in the UI (https://github.com/ansible/awx/issues/6998)
- Fixed a bug that broke support for the satellite6_group_prefix source variable (https://github.com/ansible/awx/issues/7031)
- Fixed a bug that prevented changes to workflow node convergence settings when approval nodes were in use (https://github.com/ansible/awx/issues/7063)
- Fixed a bug that caused notifications to fail on newer version of Mattermost (https://github.com/ansible/awx/issues/7264)
- Fixed a bug (by upgrading to 0.8.1 of the foreman collection) that prevented host_filters from working properly with Foreman-based inventory (https://github.com/ansible/awx/issues/7225)
- Fixed a bug that prevented the usage of the Conjur credential plugin with secrets that contain spaces (https://github.com/ansible/awx/issues/7191)
- Fixed a bug in awx-manage run_wsbroadcast --status in kubernetes (https://github.com/ansible/awx/pull/7009)
- Fixed a bug that broke notification toggles for system jobs in the UI (https://github.com/ansible/awx/pull/7042)
- Fixed a bug that broke local pip installs of awxkit (https://github.com/ansible/awx/issues/7107)
- Fixed a bug that prevented PagerDuty notifications from sending for workflow job template approvals (https://github.com/ansible/awx/issues/7094)
- Fixed a bug that broke external log aggregation support for URL paths that include the = character (such as the tokens for SumoLogic) (https://github.com/ansible/awx/issues/7139)
- Fixed a bug that prevented organization admins from removing labels from workflow job templates (https://github.com/ansible/awx/pull/7143)
## 11.2.0 (Apr 29, 2020)
- Inventory updates now use collection-based plugins by default (in Ansible 2.9+):
- amazon.aws.aws_ec2
- community.vmware.vmware_vm_inventory
- azure.azcollection.azure_rm
- google.cloud.gcp_compute
- theforeman.foreman.foreman
- openstack.cloud.openstack
- ovirt.ovirt_collection.ovirt
- awx.awx.tower
- Added support for Approle and LDAP/AD mechanisms to the Hashicorp Vault credential plugin (https://github.com/ansible/awx/issues/5076)
- Added Project (Domain Name) support for the OpenStack Keystone v3 API (https://github.com/ansible/awx/issues/6831)
- Added a new setting for raising log verbosity for rsyslogd (https://github.com/ansible/awx/pull/6818)
- Added the ability to monitor stdout in the CLI for running jobs and workflow jobs (https://github.com/ansible/awx/issues/6165)
- Fixed a bug which prevented the AWX CLI from properly installing with newer versions of pip (https://github.com/ansible/awx/issues/6870)
- Fixed a bug which broke AWX's external logging support when configured with HTTPS endpoints that utilize self-signed certificates (https://github.com/ansible/awx/issues/6851)
- Fixed a local docker installer bug that mistakenly attempted to upgrade PostgreSQL when an external pg_hostname is specified (https://github.com/ansible/awx/pull/5398)
- Fixed a race condition that caused task container crashes when pods are quickly brought down and back up (https://github.com/ansible/awx/issues/6750)
- Fixed a bug that caused 404 errors when attempting to view the second page of the workflow approvals view (https://github.com/ansible/awx/issues/6803)
- Fixed a bug that prevented the use of ANSIBLE_SSH_ARGS for ad-hoc-commands (https://github.com/ansible/awx/pull/6811)
- Fixed a bug that broke AWX installs/upgrades on Red Hat OpenShift (https://github.com/ansible/awx/issues/6791)
## 11.1.0 (Apr 22, 2020)
- Changed rsyslogd to persist queued events to disk (to prevent a risk of out-of-memory errors) (https://github.com/ansible/awx/issues/6746)
- Added the ability to configure the destination and maximum disk size of rsyslogd spool (in the event of a log aggregator outage) (https://github.com/ansible/awx/pull/6763)
@@ -79,7 +124,7 @@ This is a list of high-level changes for each release of AWX. A full list of com
- Updated the bundled version of openstacksdk to address a known issue https://github.com/ansible/awx/issues/5821
- Updated the bundled vmware_inventory plugin to the latest version to address a bug https://github.com/ansible/awx/pull/5668
- Fixed a bug that can cause inventory updates to fail to properly save their output when run within a workflow https://github.com/ansible/awx/pull/5666
- Removed a number of pre-computed fields from the Host and Group models to improve AWX performance. As part of this change, inventory group UIs throughout the interface no longer display status icons https://github.com/ansible/awx/pull/5448
- Removed a number of pre-computed fields from the Host and Group models to improve AWX performance. As part of this change, inventory group UIs throughout the interface no longer display status icons https://github.com/ansible/awx/pull/5448
## 9.1.1 (Jan 14, 2020)

View File

@@ -157,8 +157,7 @@ If you start a second terminal session, you can take a look at the running conta
$ 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
b049a43817b4 memcached:alpine "docker-entrypoint.s…" 28 seconds ago Up 26 seconds 0.0.0.0:11211->11211/tcp tools_memcached_1
40de380e3c2e redis:latest "docker-entrypoint.s…" 28 seconds ago Up 26 seconds 0.0.0.0:6379->6379/tcp tools_redis_1
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
```
**NOTE**

View File

@@ -10,7 +10,6 @@ This document provides a guide for installing AWX.
+ [AWX branding](#awx-branding)
+ [Prerequisites](#prerequisites)
+ [System Requirements](#system-requirements)
+ [AWX Tunables](#awx-tunables)
+ [Choose a deployment platform](#choose-a-deployment-platform)
+ [Official vs Building Images](#official-vs-building-images)
* [Upgrading from previous versions](#upgrading-from-previous-versions)
@@ -49,7 +48,17 @@ This document provides a guide for installing AWX.
### Clone the repo
If you have not already done so, you will need to clone, or create a local copy, of the [AWX repo](https://github.com/ansible/awx). For more on how to clone the repo, view [git clone help](https://git-scm.com/docs/git-clone).
If you have not already done so, you will need to clone, or create a local copy, of the [AWX repo](https://github.com/ansible/awx). We generally recommend that you view the releases page:
https://github.com/ansible/awx/releases
...and clone the latest stable release, e.g.,
`git clone -b x.y.z https://github.com/ansible/awx.git`
Please note that deploying from `HEAD` (or the latest commit) is **not** stable, and that if you want to do this, you should proceed at your own risk (also, see the section #official-vs-building-images for building your own image).
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.
@@ -71,8 +80,11 @@ Before you can run a deployment, you'll need the following installed in your loc
+ We use this module instead of `docker-py` because it is what the `docker-compose` Python module requires.
- [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/)
+ 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`
### System Requirements
@@ -84,10 +96,6 @@ The system that runs the AWX service will need to satisfy the following requirem
- Running Docker, Openshift, or Kubernetes
- If you choose to use an external PostgreSQL database, please note that the minimum version is 10+.
### AWX Tunables
**TODO** add tunable bits
### Choose a deployment platform
We currently support running AWX as a containerized application using Docker images deployed to either an OpenShift cluster, a Kubernetes cluster, or docker-compose. The remainder of this document will walk you through the process of building the images, and deploying them to either platform.
@@ -101,7 +109,7 @@ In the sections below, you'll find deployment details and instructions for each
### Official vs Building Images
When installing AWX you have the option of building your own images or using the images provided on DockerHub (see [awx_web](https://hub.docker.com/r/ansible/awx_web/) and [awx_task](https://hub.docker.com/r/ansible/awx_task/))
When installing AWX you have the option of building your own image or using the image provided on DockerHub (see [awx](https://hub.docker.com/r/ansible/awx/))
This is controlled by the following variables in the `inventory` file
@@ -114,12 +122,16 @@ If these variables are present then all deployments will use these hosted images
*dockerhub_base*
> The base location on DockerHub where the images are hosted (by default this pulls container images named `ansible/awx_web:tag` and `ansible/awx_task:tag`)
> The base location on DockerHub where the images are hosted (by default this pulls a container image named `ansible/awx:tag`)
*dockerhub_version*
> Multiple versions are provided. `latest` always pulls the most recent. You may also select version numbers at different granularities: 1, 1.0, 1.0.1, 1.0.0.123
*use_container_for_build*
> Use a local distribution build container image for building the AWX package. This is helpful if you don't want to bother installing the build-time dependencies as it is taken care of already.
## Upgrading from previous versions
@@ -143,7 +155,7 @@ $ ansible-playbook -i inventory install.yml -e @vars.yml
### Prerequisites
To complete a deployment to OpenShift, you will obviously need access to an OpenShift cluster. For demo and testing purposes, you can use [Minishift](https://github.com/minishift/minishift) to create a single node cluster running inside a virtual machine.
To complete a deployment to OpenShift, you will need access to an OpenShift cluster. For demo and testing purposes, you can use [Minishift](https://github.com/minishift/minishift) to create a single node cluster running inside a virtual machine.
When using OpenShift for deploying AWX make sure you have correct privileges to add the security context 'privileged', otherwise the installation will fail. The privileged context is needed because of the use of [the bubblewrap tool](https://github.com/containers/bubblewrap) to add an additional layer of security when using containers.
@@ -469,11 +481,11 @@ Before starting the install process, review the [inventory](./installer/inventor
*host_port*
> Provide a port number that can be mapped from the Docker daemon host to the web server running inside the AWX container. Defaults to *80*.
> Provide a port number that can be mapped from the Docker daemon host to the web server running inside the AWX container. If undefined no port will be exposed. Defaults to *80*.
*host_port_ssl*
> Provide a port number that can be mapped from the Docker daemon host to the web server running inside the AWX container for SSL support. Defaults to *443*, only works if you also set `ssl_certificate` (see below).
> Provide a port number that can be mapped from the Docker daemon host to the web server running inside the AWX container for SSL support. If undefined no port will be exposed. Defaults to *443*, only works if you also set `ssl_certificate` (see below).
*ssl_certificate*

View File

@@ -10,6 +10,7 @@ recursive-include awx/playbooks *.yml
recursive-include awx/lib/site-packages *
recursive-include awx/plugins *.ps1
recursive-include requirements *.txt
recursive-include requirements *.yml
recursive-include config *
recursive-include docs/licenses *
recursive-exclude awx devonly.py*

View File

@@ -6,12 +6,14 @@ PACKER ?= packer
PACKER_BUILD_OPTS ?= -var 'official=$(OFFICIAL)' -var 'aw_repo_url=$(AW_REPO_URL)'
NODE ?= node
NPM_BIN ?= npm
CHROMIUM_BIN=/tmp/chrome-linux/chrome
DEPS_SCRIPT ?= packaging/bundle/deps.py
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
MANAGEMENT_COMMAND ?= awx-manage
IMAGE_REPOSITORY_AUTH ?=
IMAGE_REPOSITORY_BASE ?= https://gcr.io
VERSION := $(shell cat VERSION)
PYCURL_SSL_LIBRARY ?= openssl
# NOTE: This defaults the container image version to the branch that's active
COMPOSE_TAG ?= $(GIT_BRANCH)
@@ -24,7 +26,7 @@ CELERY_SCHEDULE_FILE ?= /var/lib/awx/beat.db
DEV_DOCKER_TAG_BASE ?= gcr.io/ansible-tower-engineering
# Python packages to install only from source (not from binary wheels)
# Comma separated list
SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio
SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio,pycurl
# These should be upgraded in the AWX and Ansible venv before attempting
# to install the actual requirements
VENV_BOOTSTRAP ?= pip==19.3.1 setuptools==41.6.0
@@ -173,9 +175,9 @@ virtualenv_awx:
# --ignore-install flag is not used because *.txt files should specify exact versions
requirements_ansible: virtualenv_ansible
if [[ "$(PIP_OPTIONS)" == *"--no-index"* ]]; then \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_local.txt | $(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) -r /dev/stdin ; \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_local.txt | PYCURL_SSL_LIBRARY=$(PYCURL_SSL_LIBRARY) $(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) -r /dev/stdin ; \
else \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_git.txt | $(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --no-binary $(SRC_ONLY_PKGS) -r /dev/stdin ; \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_git.txt | PYCURL_SSL_LIBRARY=$(PYCURL_SSL_LIBRARY) $(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --no-binary $(SRC_ONLY_PKGS) -r /dev/stdin ; \
fi
$(VENV_BASE)/ansible/bin/pip uninstall --yes -r requirements/requirements_ansible_uninstall.txt
# Same effect as using --system-site-packages flag on venv creation
@@ -183,9 +185,9 @@ requirements_ansible: virtualenv_ansible
requirements_ansible_py3: virtualenv_ansible_py3
if [[ "$(PIP_OPTIONS)" == *"--no-index"* ]]; then \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_local.txt | $(VENV_BASE)/ansible/bin/pip3 install $(PIP_OPTIONS) -r /dev/stdin ; \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_local.txt | PYCURL_SSL_LIBRARY=$(PYCURL_SSL_LIBRARY) $(VENV_BASE)/ansible/bin/pip3 install $(PIP_OPTIONS) -r /dev/stdin ; \
else \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_git.txt | $(VENV_BASE)/ansible/bin/pip3 install $(PIP_OPTIONS) --no-binary $(SRC_ONLY_PKGS) -r /dev/stdin ; \
cat requirements/requirements_ansible.txt requirements/requirements_ansible_git.txt | PYCURL_SSL_LIBRARY=$(PYCURL_SSL_LIBRARY) $(VENV_BASE)/ansible/bin/pip3 install $(PIP_OPTIONS) --no-binary $(SRC_ONLY_PKGS) -r /dev/stdin ; \
fi
$(VENV_BASE)/ansible/bin/pip3 uninstall --yes -r requirements/requirements_ansible_uninstall.txt
# Same effect as using --system-site-packages flag on venv creation
@@ -209,7 +211,11 @@ requirements_awx: virtualenv_awx
requirements_awx_dev:
$(VENV_BASE)/awx/bin/pip install -r requirements/requirements_dev.txt
requirements: requirements_ansible requirements_awx
requirements_collections:
mkdir -p $(COLLECTION_BASE)
ansible-galaxy collection install -r requirements/collections_requirements.yml -p $(COLLECTION_BASE)
requirements: requirements_ansible requirements_awx requirements_collections
requirements_dev: requirements_awx requirements_ansible_py3 requirements_awx_dev requirements_ansible_dev
@@ -349,8 +355,7 @@ swagger: reports
check: flake8 pep8 # pyflakes pylint
awx-link:
cp -R /tmp/awx.egg-info /awx_devel/ || true
sed -i "s/placeholder/$(shell cat VERSION)/" /awx_devel/awx.egg-info/PKG-INFO
[ -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
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
@@ -361,6 +366,7 @@ test:
. $(VENV_BASE)/awx/bin/activate; \
fi; \
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS)
cmp VERSION awxkit/VERSION || "VERSION and awxkit/VERSION *must* match"
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py2,py3
awx-manage check_migrations --dry-run --check -n 'vNNN_missing_migration_file'
@@ -374,7 +380,11 @@ test_collection:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
PYTHONPATH=$PYTHONPATH:/usr/lib/python3.6/site-packages py.test $(COLLECTION_TEST_DIRS)
PYTHONPATH=$(PYTHONPATH):$(VENV_BASE)/awx/lib/python3.6/site-packages:/usr/lib/python3.6/site-packages py.test $(COLLECTION_TEST_DIRS)
# The python path needs to be modified so that the tests can find Ansible within the container
# First we will use anything expility set as PYTHONPATH
# Second we will load any libraries out of the virtualenv (if it's unspecified that should be ok because python should not load out of an empty directory)
# Finally we will add the system path so that the tests can find the ansible libraries
flake8_collection:
flake8 awx_collection/ # Different settings, in main exclude list
@@ -389,7 +399,7 @@ symlink_collection:
ln -s $(shell pwd)/awx_collection $(COLLECTION_INSTALL)
build_collection:
ansible-playbook -i localhost, awx_collection/template_galaxy.yml -e collection_package=$(COLLECTION_PACKAGE) -e collection_namespace=$(COLLECTION_NAMESPACE) -e collection_version=$(VERSION)
ansible-playbook -i localhost, awx_collection/tools/template_galaxy.yml -e collection_package=$(COLLECTION_PACKAGE) -e collection_namespace=$(COLLECTION_NAMESPACE) -e collection_version=$(VERSION) -e '{"awx_template_version":false}'
ansible-galaxy collection build awx_collection --force --output-path=awx_collection
install_collection: build_collection
@@ -543,11 +553,13 @@ jshint: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) run --prefix awx/ui jshint
$(NPM_BIN) run --prefix awx/ui lint
ui-zuul-lint-and-test: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) run --prefix awx/ui jshint
$(NPM_BIN) run --prefix awx/ui lint
$(NPM_BIN) --prefix awx/ui run test:ci
$(NPM_BIN) --prefix awx/ui run unit
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
# --------------------------------------
@@ -636,7 +648,7 @@ docker-compose-runtest: awx/projects
cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /start_tests.sh
docker-compose-build-swagger: awx/projects
cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /start_tests.sh swagger
cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports --no-deps awx /start_tests.sh swagger
detect-schema-change: genschema
curl https://s3.amazonaws.com/awx-public-ci-files/schema.json -o reference-schema.json
@@ -646,17 +658,16 @@ detect-schema-change: genschema
docker-compose-clean: awx/projects
cd tools && TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose rm -sf
docker-compose-build: awx-devel-build
# Base development image build
awx-devel-build:
docker-compose-build:
ansible localhost -m template -a "src=installer/roles/image_build/templates/Dockerfile.j2 dest=tools/docker-compose/Dockerfile" -e build_dev=True
docker build -t ansible/awx_devel -f tools/docker-compose/Dockerfile \
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) .
docker tag ansible/awx_devel $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
#docker push $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
# For use when developing on "isolated" AWX deployments
docker-compose-isolated-build: awx-devel-build
docker-compose-isolated-build: docker-compose-build
docker build -t ansible/awx_isolated -f tools/docker-isolated/Dockerfile .
docker tag ansible/awx_isolated $(DEV_DOCKER_TAG_BASE)/awx_isolated:$(COMPOSE_TAG)
#docker push $(DEV_DOCKER_TAG_BASE)/awx_isolated:$(COMPOSE_TAG)

View File

@@ -1 +1 @@
11.1.0
12.0.0

View File

@@ -30,6 +30,7 @@ except ImportError:
HAS_DJANGO = False
else:
from django.db.backends.base import schema
from django.db.models import indexes
from django.db.backends.utils import names_digest
@@ -50,6 +51,7 @@ if HAS_DJANGO is True:
return h.hexdigest()[:length]
schema.names_digest = names_digest
indexes.names_digest = names_digest
def find_commands(management_dir):

View File

@@ -806,7 +806,9 @@ class UnifiedJobSerializer(BaseSerializer):
td = now() - obj.started
ret['elapsed'] = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / (10 ** 6 * 1.0)
ret['elapsed'] = float(ret['elapsed'])
# Because this string is saved in the db in the source language,
# it must be marked for translation after it is pulled from the db, not when set
ret['job_explanation'] = _(obj.job_explanation)
return ret
@@ -2306,6 +2308,7 @@ class RoleSerializer(BaseSerializer):
content_model = obj.content_type.model_class()
ret['summary_fields']['resource_type'] = get_type_for_model(content_model)
ret['summary_fields']['resource_type_display_name'] = content_model._meta.verbose_name.title()
ret['summary_fields']['resource_id'] = obj.object_id
return ret
@@ -2756,16 +2759,11 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
if obj.organization_id:
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization_id})
if isinstance(obj, UnifiedJobTemplate):
res['extra_credentials'] = self.reverse(
'api:job_template_extra_credentials_list',
kwargs={'pk': obj.pk}
)
res['credentials'] = self.reverse(
'api:job_template_credentials_list',
kwargs={'pk': obj.pk}
)
elif isinstance(obj, UnifiedJob):
res['extra_credentials'] = self.reverse('api:job_extra_credentials_list', kwargs={'pk': obj.pk})
res['credentials'] = self.reverse('api:job_credentials_list', kwargs={'pk': obj.pk})
return res
@@ -2934,7 +2932,6 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
summary_fields = super(JobTemplateSerializer, self).get_summary_fields(obj)
all_creds = []
# Organize credential data into multitude of deprecated fields
extra_creds = []
if obj.pk:
for cred in obj.credentials.all():
summarized_cred = {
@@ -2945,10 +2942,6 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
'cloud': cred.credential_type.kind == 'cloud'
}
all_creds.append(summarized_cred)
if cred.credential_type.kind in ('cloud', 'net'):
extra_creds.append(summarized_cred)
if self.is_detail_view:
summary_fields['extra_credentials'] = extra_creds
summary_fields['credentials'] = all_creds
return summary_fields
@@ -3023,7 +3016,6 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
summary_fields = super(JobSerializer, self).get_summary_fields(obj)
all_creds = []
# Organize credential data into multitude of deprecated fields
extra_creds = []
if obj.pk:
for cred in obj.credentials.all():
summarized_cred = {
@@ -3034,10 +3026,6 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
'cloud': cred.credential_type.kind == 'cloud'
}
all_creds.append(summarized_cred)
if cred.credential_type.kind in ('cloud', 'net'):
extra_creds.append(summarized_cred)
if self.is_detail_view:
summary_fields['extra_credentials'] = extra_creds
summary_fields['credentials'] = all_creds
return summary_fields
@@ -3612,7 +3600,7 @@ class LaunchConfigurationBaseSerializer(BaseSerializer):
ujt = self.instance.unified_job_template
if ujt is None:
ret = {}
for fd in ('workflow_job_template', 'identifier'):
for fd in ('workflow_job_template', 'identifier', 'all_parents_must_converge'):
if fd in attrs:
ret[fd] = attrs[fd]
return ret
@@ -3899,15 +3887,23 @@ class ProjectUpdateEventSerializer(JobEventSerializer):
return UriCleaner.remove_sensitive(obj.stdout)
def get_event_data(self, obj):
try:
return json.loads(
UriCleaner.remove_sensitive(
json.dumps(obj.event_data)
# the project update playbook uses the git, hg, 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'):
try:
return json.loads(
UriCleaner.remove_sensitive(
json.dumps(obj.event_data)
)
)
)
except Exception:
logger.exception("Failed to sanitize event_data")
return {}
except Exception:
logger.exception("Failed to sanitize event_data")
return {}
else:
return obj.event_data
class AdHocCommandEventSerializer(BaseSerializer):

View File

@@ -23,9 +23,7 @@ from awx.api.views import (
UnifiedJobList,
HostAnsibleFactsDetail,
JobCredentialsList,
JobExtraCredentialsList,
JobTemplateCredentialsList,
JobTemplateExtraCredentialsList,
SchedulePreview,
ScheduleZoneInfo,
OAuth2ApplicationList,
@@ -83,9 +81,7 @@ v2_urls = [
url(r'^credential_types/', include(credential_type_urls)),
url(r'^credential_input_sources/', include(credential_input_source_urls)),
url(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'),
url(r'^jobs/(?P<pk>[0-9]+)/extra_credentials/$', JobExtraCredentialsList.as_view(), name='job_extra_credentials_list'),
url(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/extra_credentials/$', JobTemplateExtraCredentialsList.as_view(), name='job_template_extra_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'),
url(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),

View File

@@ -12,7 +12,7 @@ import socket
import sys
import time
from base64 import b64encode
from collections import OrderedDict, Iterable
from collections import OrderedDict
# Django
@@ -2337,70 +2337,24 @@ class JobTemplateLaunch(RetrieveAPIView):
old field structure to launch endpoint
TODO: delete this method with future API version changes
'''
ignored_fields = {}
modern_data = data.copy()
id_fd = '{}_id'.format('inventory')
if 'inventory' not in modern_data and id_fd in modern_data:
modern_data['inventory'] = modern_data[id_fd]
# Automatically convert legacy launch credential arguments into a list of `.credentials`
if 'credentials' in modern_data and 'extra_credentials' in modern_data:
raise ParseError({"error": _(
"'credentials' cannot be used in combination with 'extra_credentials'."
)})
if 'extra_credentials' in modern_data:
# make a list of the current credentials
existing_credentials = obj.credentials.all()
template_credentials = list(existing_credentials) # save copy of existing
new_credentials = []
if 'extra_credentials' in modern_data:
existing_credentials = [
cred for cred in existing_credentials
if cred.credential_type.kind not in ('cloud', 'net')
]
prompted_value = modern_data.pop('extra_credentials')
# validate type, since these are not covered by a serializer
if not isinstance(prompted_value, Iterable):
msg = _(
"Incorrect type. Expected a list received {}."
).format(prompted_value.__class__.__name__)
raise ParseError({'extra_credentials': [msg], 'credentials': [msg]})
# add the deprecated credential specified in the request
if not isinstance(prompted_value, Iterable) or isinstance(prompted_value, str):
prompted_value = [prompted_value]
# If user gave extra_credentials, special case to use exactly
# the given list without merging with JT credentials
if prompted_value:
obj._deprecated_credential_launch = True # signal to not merge credentials
new_credentials.extend(prompted_value)
# combine the list of "new" and the filtered list of "old"
new_credentials.extend([cred.pk for cred in existing_credentials])
if new_credentials:
# If provided list doesn't contain the pre-existing credentials
# defined on the template, add them back here
for cred_obj in template_credentials:
if cred_obj.pk not in new_credentials:
new_credentials.append(cred_obj.pk)
modern_data['credentials'] = new_credentials
# credential passwords were historically provided as top-level attributes
if 'credential_passwords' not in modern_data:
modern_data['credential_passwords'] = data.copy()
return (modern_data, ignored_fields)
return modern_data
def post(self, request, *args, **kwargs):
obj = self.get_object()
try:
modern_data, ignored_fields = self.modernize_launch_payload(
modern_data = self.modernize_launch_payload(
data=request.data, obj=obj
)
except ParseError as exc:
@@ -2410,8 +2364,6 @@ class JobTemplateLaunch(RetrieveAPIView):
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
ignored_fields.update(serializer._ignored_fields)
if not request.user.can_access(models.JobLaunchConfig, 'add', serializer.validated_data, template=obj):
raise PermissionDenied()
@@ -2427,11 +2379,11 @@ class JobTemplateLaunch(RetrieveAPIView):
data = OrderedDict()
if isinstance(new_job, models.WorkflowJob):
data['workflow_job'] = new_job.id
data['ignored_fields'] = self.sanitize_for_response(ignored_fields)
data['ignored_fields'] = self.sanitize_for_response(serializer._ignored_fields)
data.update(serializers.WorkflowJobSerializer(new_job, context=self.get_serializer_context()).to_representation(new_job))
else:
data['job'] = new_job.id
data['ignored_fields'] = self.sanitize_for_response(ignored_fields)
data['ignored_fields'] = self.sanitize_for_response(serializer._ignored_fields)
data.update(serializers.JobSerializer(new_job, context=self.get_serializer_context()).to_representation(new_job))
headers = {'Location': new_job.get_absolute_url(request)}
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
@@ -2711,22 +2663,6 @@ class JobTemplateCredentialsList(SubListCreateAttachDetachAPIView):
return super(JobTemplateCredentialsList, self).is_valid_relation(parent, sub, created)
class JobTemplateExtraCredentialsList(JobTemplateCredentialsList):
deprecated = True
def get_queryset(self):
sublist_qs = super(JobTemplateExtraCredentialsList, self).get_queryset()
sublist_qs = sublist_qs.filter(credential_type__kind__in=['cloud', 'net'])
return sublist_qs
def is_valid_relation(self, parent, sub, created=False):
valid = super(JobTemplateExtraCredentialsList, self).is_valid_relation(parent, sub, created)
if sub.credential_type.kind not in ('cloud', 'net'):
return {'error': _('Extra credentials must be network or cloud.')}
return valid
class JobTemplateLabelList(DeleteLastUnattachLabelMixin, SubListCreateAttachDetachAPIView):
model = models.Label
@@ -3543,16 +3479,6 @@ class JobCredentialsList(SubListAPIView):
relationship = 'credentials'
class JobExtraCredentialsList(JobCredentialsList):
deprecated = True
def get_queryset(self):
sublist_qs = super(JobExtraCredentialsList, self).get_queryset()
sublist_qs = sublist_qs.filter(credential_type__kind__in=['cloud', 'net'])
return sublist_qs
class JobLabelList(SubListAPIView):
model = models.Label

View File

@@ -4,12 +4,11 @@ import os
import logging
import django
from awx import __version__ as tower_version
# Prepare the AWX environment.
from awx import prepare_env, MODE
from channels.routing import get_default_application # noqa
prepare_env() # NOQA
from channels.routing import get_default_application
"""

View File

@@ -11,7 +11,7 @@ from django.conf import settings, UserSettingsHolder
from django.core.cache import cache as django_cache
from django.core.exceptions import ImproperlyConfigured
from django.db import transaction, connection
from django.db.utils import Error as DBError
from django.db.utils import Error as DBError, ProgrammingError
from django.utils.functional import cached_property
# Django REST Framework
@@ -74,10 +74,19 @@ def _ctit_db_wrapper(trans_safe=False):
logger.debug('Obtaining database settings in spite of broken transaction.')
transaction.set_rollback(False)
yield
except DBError:
except DBError as exc:
if trans_safe:
if 'migrate' not in sys.argv and 'check_migrations' not in sys.argv:
logger.exception('Database settings are not available, using defaults.')
level = logger.exception
if isinstance(exc, ProgrammingError):
if 'relation' in str(exc) and 'does not exist' in str(exc):
# this generally means we can't fetch Tower configuration
# because the database hasn't actually finished migrating yet;
# this is usually a sign that a service in a container (such as ws_broadcast)
# has come up *before* the database has finished migrating, and
# especially that the conf.settings table doesn't exist yet
level = logger.debug
level('Database settings are not available, using defaults.')
else:
logger.exception('Error modifying something related to database settings.')
finally:

View File

@@ -10,6 +10,7 @@ import socket
from socket import SHUT_RDWR
# Django
from django.db import connection
from django.conf import settings
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
@@ -130,7 +131,8 @@ class SettingSingletonDetail(RetrieveUpdateDestroyAPIView):
setting.save(update_fields=['value'])
settings_change_list.append(key)
if settings_change_list:
handle_setting_changes.delay(settings_change_list)
connection.on_commit(lambda: handle_setting_changes.delay(settings_change_list))
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
@@ -145,7 +147,7 @@ class SettingSingletonDetail(RetrieveUpdateDestroyAPIView):
setting.delete()
settings_change_list.append(setting.key)
if settings_change_list:
handle_setting_changes.delay(settings_change_list)
connection.on_commit(lambda: handle_setting_changes.delay(settings_change_list))
# When TOWER_URL_BASE is deleted from the API, reset it to the hostname
# used to make the request as a default.
@@ -170,7 +172,13 @@ class SettingLoggingTest(GenericAPIView):
return Response({'error': 'Logging not enabled'}, status=status.HTTP_409_CONFLICT)
# Send test message to configured logger based on db settings
logging.getLogger('awx').error('AWX Connection Test Message')
try:
default_logger = settings.LOG_AGGREGATOR_LOGGERS[0]
if default_logger != 'awx':
default_logger = f'awx.analytics.{default_logger}'
except IndexError:
default_logger = 'awx'
logging.getLogger(default_logger).error('AWX Connection Test Message')
hostname = getattr(settings, 'LOG_AGGREGATOR_HOST', None)
protocol = getattr(settings, 'LOG_AGGREGATOR_PROTOCOL', None)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -495,7 +495,7 @@ class NotificationAttachMixin(BaseAccess):
# due to this special case, we use symmetrical logic with attach permission
return self._can_attach(notification_template=sub_obj, resource_obj=obj)
return super(NotificationAttachMixin, self).can_unattach(
obj, sub_obj, relationship, relationship, data=data
obj, sub_obj, relationship, data=data
)

View File

@@ -44,8 +44,8 @@ class FixedSlidingWindow():
def cleanup(self, now_bucket=None):
now_bucket = now_bucket or now_seconds()
if self.start_time + 60 <= now_bucket:
self.start_time = now_bucket + 60 + 1
if self.start_time + 60 < now_bucket:
self.start_time = now_bucket - 60
# Delete old entries
for k in list(self.buckets.keys()):
@@ -53,16 +53,15 @@ class FixedSlidingWindow():
del self.buckets[k]
def record(self, ts=None):
ts = ts or datetime.datetime.now()
now_bucket = int((ts - datetime.datetime(1970,1,1)).total_seconds())
now_bucket = ts or dt_to_seconds(datetime.datetime.now())
val = self.buckets.get(now_bucket, 0)
self.buckets[now_bucket] = val + 1
self.cleanup(now_bucket)
def render(self):
self.cleanup()
def render(self, ts=None):
self.cleanup(now_bucket=ts)
return sum(self.buckets.values()) or 0

View File

@@ -246,18 +246,6 @@ register(
category_slug='jobs',
)
register(
'AWX_ISOLATED_VERBOSITY',
field_class=fields.IntegerField,
min_value=0,
max_value=5,
label=_('Verbosity level for isolated node management tasks'),
help_text=_('This can be raised to aid in debugging connection issues for isolated task execution'),
category=_('Jobs'),
category_slug='jobs',
default=0
)
register(
'AWX_ISOLATED_CHECK_INTERVAL',
field_class=fields.IntegerField,
@@ -435,6 +423,19 @@ register(
category_slug='jobs',
)
register(
'AWX_SHOW_PLAYBOOK_LINKS',
field_class=fields.BooleanField,
default=False,
label=_('Follow symlinks'),
help_text=_(
'Follow symbolic links when scanning for playbooks. Be aware that setting this to True can lead '
'to infinite recursion if a link points to a parent directory of itself.'
),
category=_('Jobs'),
category_slug='jobs',
)
register(
'PRIMARY_GALAXY_URL',
field_class=fields.URLField,
@@ -777,16 +778,6 @@ register(
category=_('Logging'),
category_slug='logging',
)
register(
'LOG_AGGREGATOR_AUDIT',
field_class=fields.BooleanField,
allow_null=True,
default=False,
label=_('Enabled external log aggregation auditing'),
help_text=_('When enabled, all external logs emitted by Tower will also be written to /var/log/tower/external.log. This is an experimental setting intended to be used for debugging external log aggregation issues (and may be subject to change in the future).'), # noqa
category=_('Logging'),
category_slug='logging',
)
register(
'LOG_AGGREGATOR_MAX_DISK_USAGE_GB',
field_class=fields.IntegerField,
@@ -810,18 +801,19 @@ register(
category=_('Logging'),
category_slug='logging',
)
register(
'BROKER_DURABILITY',
'LOG_AGGREGATOR_RSYSLOGD_DEBUG',
field_class=fields.BooleanField,
label=_('Message Durability'),
help_text=_('When set (the default), underlying queues will be persisted to disk. Disable this to enable higher message bus throughput.'),
category=_('System'),
category_slug='system',
default=False,
label=_('Enable rsyslogd debugging'),
help_text=_('Enabled high verbosity debugging for rsyslogd. '
'Useful for debugging connection issues for external log aggregation.'),
category=_('Logging'),
category_slug='logging',
)
register(
'AUTOMATION_ANALYTICS_LAST_GATHER',
field_class=fields.DateTimeField,

View File

@@ -104,7 +104,7 @@ class BroadcastConsumer(AsyncJsonWebsocketConsumer):
logger.info(f"client '{self.channel_name}' joined the broadcast group.")
async def disconnect(self, code):
logger.info("client '{self.channel_name}' disconnected from the broadcast group.")
logger.info(f"client '{self.channel_name}' disconnected from the broadcast group.")
await self.channel_layer.group_discard(settings.BROADCAST_WEBSOCKET_GROUP_NAME, self.channel_name)
async def internal_message(self, event):

View File

@@ -1,15 +1,10 @@
from .plugin import CredentialPlugin
from .plugin import CredentialPlugin, CertFiles
from urllib.parse import quote, urlencode, urljoin
from django.utils.translation import ugettext_lazy as _
import requests
# AWX
from awx.main.utils import (
create_temporary_fifo,
)
aim_inputs = {
'fields': [{
'id': 'url',
@@ -81,21 +76,13 @@ def aim_backend(**kwargs):
request_qs = '?' + urlencode(query_params, quote_via=quote)
request_url = urljoin(url, '/'.join(['AIMWebService', 'api', 'Accounts']))
cert = None
if client_cert and client_key:
cert = (
create_temporary_fifo(client_cert.encode()),
create_temporary_fifo(client_key.encode())
with CertFiles(client_cert, client_key) as cert:
res = requests.get(
request_url + request_qs,
timeout=30,
cert=cert,
verify=verify,
)
elif client_cert:
cert = create_temporary_fifo(client_cert.encode())
res = requests.get(
request_url + request_qs,
timeout=30,
cert=cert,
verify=verify,
)
res.raise_for_status()
return res.json()['Content']

View File

@@ -1,16 +1,11 @@
from .plugin import CredentialPlugin
from .plugin import CredentialPlugin, CertFiles
import base64
from urllib.parse import urljoin, quote_plus
from urllib.parse import urljoin, quote
from django.utils.translation import ugettext_lazy as _
import requests
# AWX
from awx.main.utils import (
create_temporary_fifo,
)
conjur_inputs = {
'fields': [{
@@ -55,9 +50,9 @@ conjur_inputs = {
def conjur_backend(**kwargs):
url = kwargs['url']
api_key = kwargs['api_key']
account = quote_plus(kwargs['account'])
username = quote_plus(kwargs['username'])
secret_path = quote_plus(kwargs['secret_path'])
account = quote(kwargs['account'], safe='')
username = quote(kwargs['username'], safe='')
secret_path = quote(kwargs['secret_path'], safe='')
version = kwargs.get('secret_version')
cacert = kwargs.get('cacert', None)
@@ -65,22 +60,20 @@ def conjur_backend(**kwargs):
'headers': {'Content-Type': 'text/plain'},
'data': api_key
}
if cacert:
auth_kwargs['verify'] = create_temporary_fifo(cacert.encode())
# https://www.conjur.org/api.html#authentication-authenticate-post
resp = requests.post(
urljoin(url, '/'.join(['authn', account, username, 'authenticate'])),
**auth_kwargs
)
with CertFiles(cacert) as cert:
# https://www.conjur.org/api.html#authentication-authenticate-post
auth_kwargs['verify'] = cert
resp = requests.post(
urljoin(url, '/'.join(['authn', account, username, 'authenticate'])),
**auth_kwargs
)
resp.raise_for_status()
token = base64.b64encode(resp.content).decode('utf-8')
lookup_kwargs = {
'headers': {'Authorization': 'Token token="{}"'.format(token)},
}
if cacert:
lookup_kwargs['verify'] = create_temporary_fifo(cacert.encode())
# https://www.conjur.org/api.html#secrets-retrieve-a-secret-get
path = urljoin(url, '/'.join([
@@ -92,7 +85,9 @@ def conjur_backend(**kwargs):
if version:
path = '?'.join([path, version])
resp = requests.get(path, timeout=30, **lookup_kwargs)
with CertFiles(cacert) as cert:
lookup_kwargs['verify'] = cert
resp = requests.get(path, timeout=30, **lookup_kwargs)
resp.raise_for_status()
return resp.text

View File

@@ -3,16 +3,11 @@ import os
import pathlib
from urllib.parse import urljoin
from .plugin import CredentialPlugin
from .plugin import CredentialPlugin, CertFiles
import requests
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.main.utils import (
create_temporary_fifo,
)
base_inputs = {
'fields': [{
'id': 'url',
@@ -32,14 +27,33 @@ base_inputs = {
'type': 'string',
'multiline': True,
'help_text': _('The CA certificate used to verify the SSL certificate of the Vault server')
}],
}, {
'id': 'role_id',
'label': _('AppRole role_id'),
'type': 'string',
'multiline': False,
'help_text': _('The Role ID for AppRole Authentication')
}, {
'id': 'secret_id',
'label': _('AppRole secret_id'),
'type': 'string',
'multiline': False,
'secret': True,
'help_text': _('The Secret ID for AppRole Authentication')
}
],
'metadata': [{
'id': 'secret_path',
'label': _('Path to Secret'),
'type': 'string',
'help_text': _('The path to the secret stored in the secret backend e.g, /some/secret/')
},{
'id': 'auth_path',
'label': _('Path to Auth'),
'type': 'string',
'help_text': _('The path where the Authentication method is mounted e.g, approle')
}],
'required': ['url', 'token', 'secret_path'],
'required': ['url', 'secret_path'],
}
hashi_kv_inputs = copy.deepcopy(base_inputs)
@@ -88,8 +102,42 @@ hashi_ssh_inputs['metadata'] = [{
hashi_ssh_inputs['required'].extend(['public_key', 'role'])
def handle_auth(**kwargs):
token = None
if kwargs.get('token'):
token = kwargs['token']
elif kwargs.get('role_id') and kwargs.get('secret_id'):
token = approle_auth(**kwargs)
else:
raise Exception('Either token or AppRole parameters must be set')
return token
def approle_auth(**kwargs):
role_id = kwargs['role_id']
secret_id = kwargs['secret_id']
auth_path = kwargs.get('auth_path') or 'approle'
url = urljoin(kwargs['url'], 'v1')
cacert = kwargs.get('cacert', None)
request_kwargs = {'timeout': 30}
# AppRole Login
request_kwargs['json'] = {'role_id': role_id, 'secret_id': secret_id}
sess = requests.Session()
request_url = '/'.join([url, 'auth', auth_path, 'login']).rstrip('/')
with CertFiles(cacert) as cert:
request_kwargs['verify'] = cert
resp = sess.post(request_url, **request_kwargs)
resp.raise_for_status()
token = resp.json()['auth']['client_token']
return token
def kv_backend(**kwargs):
token = kwargs['token']
token = handle_auth(**kwargs)
url = kwargs['url']
secret_path = kwargs['secret_path']
secret_backend = kwargs.get('secret_backend', None)
@@ -98,8 +146,6 @@ def kv_backend(**kwargs):
api_version = kwargs['api_version']
request_kwargs = {'timeout': 30}
if cacert:
request_kwargs['verify'] = create_temporary_fifo(cacert.encode())
sess = requests.Session()
sess.headers['Authorization'] = 'Bearer {}'.format(token)
@@ -126,7 +172,9 @@ def kv_backend(**kwargs):
path_segments = [secret_path]
request_url = urljoin(url, '/'.join(['v1'] + path_segments)).rstrip('/')
response = sess.get(request_url, **request_kwargs)
with CertFiles(cacert) as cert:
request_kwargs['verify'] = cert
response = sess.get(request_url, **request_kwargs)
response.raise_for_status()
json = response.json()
@@ -144,15 +192,13 @@ def kv_backend(**kwargs):
def ssh_backend(**kwargs):
token = kwargs['token']
token = handle_auth(**kwargs)
url = urljoin(kwargs['url'], 'v1')
secret_path = kwargs['secret_path']
role = kwargs['role']
cacert = kwargs.get('cacert', None)
request_kwargs = {'timeout': 30}
if cacert:
request_kwargs['verify'] = create_temporary_fifo(cacert.encode())
request_kwargs['json'] = {'public_key': kwargs['public_key']}
if kwargs.get('valid_principals'):
@@ -164,7 +210,10 @@ def ssh_backend(**kwargs):
sess.headers['X-Vault-Token'] = token
# https://www.vaultproject.io/api/secret/ssh/index.html#sign-ssh-key
request_url = '/'.join([url, secret_path, 'sign', role]).rstrip('/')
resp = sess.post(request_url, **request_kwargs)
with CertFiles(cacert) as cert:
request_kwargs['verify'] = cert
resp = sess.post(request_url, **request_kwargs)
resp.raise_for_status()
return resp.json()['data']['signed_key']

View File

@@ -1,3 +1,45 @@
import os
import tempfile
from collections import namedtuple
CredentialPlugin = namedtuple('CredentialPlugin', ['name', 'inputs', 'backend'])
class CertFiles():
"""
A context manager used for writing a certificate and (optional) key
to $TMPDIR, and cleaning up afterwards.
This is particularly useful as a shared resource for credential plugins
that want to pull cert/key data out of the database and persist it
temporarily to the file system so that it can loaded into the openssl
certificate chain (generally, for HTTPS requests plugins make via the
Python requests library)
with CertFiles(cert_data, key_data) as cert:
# cert is string representing a path to the cert or pemfile
# temporarily written to disk
requests.post(..., cert=cert)
"""
certfile = None
def __init__(self, cert, key=None):
self.cert = cert
self.key = key
def __enter__(self):
if not self.cert:
return None
self.certfile = tempfile.NamedTemporaryFile('wb', delete=False)
self.certfile.write(self.cert.encode())
if self.key:
self.certfile.write(b'\n')
self.certfile.write(self.key.encode())
self.certfile.flush()
return str(self.certfile.name)
def __exit__(self, *args):
if self.certfile and os.path.exists(self.certfile.name):
os.remove(self.certfile.name)

View File

@@ -8,6 +8,7 @@ import sys
import redis
import json
import psycopg2
import time
from uuid import UUID
from queue import Empty as QueueEmpty
@@ -34,6 +35,7 @@ class WorkerSignalHandler:
def __init__(self):
self.kill_now = False
signal.signal(signal.SIGTERM, signal.SIG_DFL)
signal.signal(signal.SIGINT, self.exit_gracefully)
def exit_gracefully(self, *args, **kwargs):
@@ -116,18 +118,23 @@ class AWXConsumerRedis(AWXConsumerBase):
super(AWXConsumerRedis, self).run(*args, **kwargs)
self.worker.on_start()
queue = redis.Redis.from_url(settings.BROKER_URL)
time_to_sleep = 1
while True:
try:
res = queue.blpop(self.queues)
res = json.loads(res[1])
self.process_task(res)
except redis.exceptions.RedisError:
logger.exception("encountered an error communicating with redis")
except (json.JSONDecodeError, KeyError):
logger.exception("failed to decode JSON message from redis")
if self.should_stop:
return
queue = redis.Redis.from_url(settings.BROKER_URL)
while True:
try:
res = queue.blpop(self.queues)
time_to_sleep = 1
res = json.loads(res[1])
self.process_task(res)
except redis.exceptions.RedisError:
time_to_sleep = min(time_to_sleep * 2, 30)
logger.exception(f"encountered an error communicating with redis. Reconnect attempt in {time_to_sleep} seconds")
time.sleep(time_to_sleep)
except (json.JSONDecodeError, KeyError):
logger.exception("failed to decode JSON message from redis")
if self.should_stop:
return
class AWXConsumerPG(AWXConsumerBase):

View File

@@ -58,7 +58,7 @@ class IsolatedManager(object):
os.chmod(temp.name, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
for host in hosts:
inventory['all']['hosts'][host] = {
"ansible_connection": "kubectl",
"ansible_connection": "community.kubernetes.kubectl",
"ansible_kubectl_config": path,
}
else:
@@ -74,6 +74,7 @@ class IsolatedManager(object):
env['ANSIBLE_RETRY_FILES_ENABLED'] = 'False'
env['ANSIBLE_HOST_KEY_CHECKING'] = str(settings.AWX_ISOLATED_HOST_KEY_CHECKING)
env['ANSIBLE_LIBRARY'] = os.path.join(os.path.dirname(awx.__file__), 'plugins', 'isolated')
env['ANSIBLE_COLLECTIONS_PATHS'] = settings.AWX_ANSIBLE_COLLECTIONS_PATHS
set_pythonpath(os.path.join(settings.ANSIBLE_VENV_PATH, 'lib'), env)
def finished_callback(runner_obj):
@@ -109,7 +110,6 @@ class IsolatedManager(object):
'cancel_callback': self.canceled_callback,
'settings': {
'job_timeout': settings.AWX_ISOLATED_LAUNCH_TIMEOUT,
'pexpect_timeout': getattr(settings, 'PEXPECT_TIMEOUT', 5),
'suppress_ansible_output': True,
},
}

View File

@@ -34,7 +34,7 @@ class Command(BaseCommand):
if clear:
for i in range(12):
sys.stdout.write('\x1b[1A\x1b[2K')
for l in lines:
print(l)
for line in lines:
print(line)
clear = True
time.sleep(.25)

View File

@@ -169,7 +169,7 @@ class AnsibleInventoryLoader(object):
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)]
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:
@@ -649,11 +649,12 @@ class Command(BaseCommand):
if group_name in existing_group_names:
continue
mem_group = self.all_group.all_groups[group_name]
group_desc = mem_group.variables.pop('_awx_description', 'imported')
group = self.inventory.groups.update_or_create(
name=group_name,
defaults={
'variables':json.dumps(mem_group.variables),
'description':'imported'
'description':group_desc
}
)[0]
logger.debug('Group "%s" added', group.name)
@@ -776,8 +777,9 @@ class Command(BaseCommand):
# Create any new hosts.
for mem_host_name in sorted(mem_host_names_to_update):
mem_host = self.all_group.all_hosts[mem_host_name]
host_attrs = dict(variables=json.dumps(mem_host.variables),
description='imported')
import_vars = mem_host.variables
host_desc = import_vars.pop('_awx_description', 'imported')
host_attrs = dict(variables=json.dumps(import_vars), description=host_desc)
enabled = self._get_enabled(mem_host.variables)
if enabled is not None:
host_attrs['enabled'] = enabled
@@ -1078,7 +1080,7 @@ class Command(BaseCommand):
if settings.SQL_DEBUG:
logger.warning('update computed fields took %d queries',
len(connection.queries) - queries_before2)
# Check if the license is valid.
# 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.

View File

@@ -16,31 +16,24 @@ class InstanceNotFound(Exception):
super(InstanceNotFound, self).__init__(*args, **kwargs)
class Command(BaseCommand):
class RegisterQueue:
def __init__(self, queuename, controller, instance_percent, inst_min, hostname_list):
self.instance_not_found_err = None
self.queuename = queuename
self.controller = controller
self.instance_percent = instance_percent
self.instance_min = inst_min
self.hostname_list = hostname_list
def add_arguments(self, parser):
parser.add_argument('--queuename', dest='queuename', type=str,
help='Queue to create/update')
parser.add_argument('--hostnames', dest='hostnames', type=str,
help='Comma-Delimited Hosts to add to the Queue (will not remove already assigned instances)')
parser.add_argument('--controller', dest='controller', type=str,
default='', help='The controlling group (makes this an isolated group)')
parser.add_argument('--instance_percent', dest='instance_percent', type=int, default=0,
help='The percentage of active instances that will be assigned to this group'),
parser.add_argument('--instance_minimum', dest='instance_minimum', type=int, default=0,
help='The minimum number of instance that will be retained for this group from available instances')
def get_create_update_instance_group(self, queuename, instance_percent, instance_min):
def get_create_update_instance_group(self):
created = False
changed = False
(ig, created) = InstanceGroup.objects.get_or_create(name=queuename)
if ig.policy_instance_percentage != instance_percent:
ig.policy_instance_percentage = instance_percent
(ig, created) = InstanceGroup.objects.get_or_create(name=self.queuename)
if ig.policy_instance_percentage != self.instance_percent:
ig.policy_instance_percentage = self.instance_percent
changed = True
if ig.policy_instance_minimum != instance_min:
ig.policy_instance_minimum = instance_min
if ig.policy_instance_minimum != self.instance_min:
ig.policy_instance_minimum = self.instance_min
changed = True
if changed:
@@ -48,12 +41,12 @@ class Command(BaseCommand):
return (ig, created, changed)
def update_instance_group_controller(self, ig, controller):
def update_instance_group_controller(self, ig):
changed = False
control_ig = None
if controller:
control_ig = InstanceGroup.objects.filter(name=controller).first()
if self.controller:
control_ig = InstanceGroup.objects.filter(name=self.controller).first()
if control_ig and ig.controller_id != control_ig.pk:
ig.controller = control_ig
@@ -62,10 +55,10 @@ class Command(BaseCommand):
return (control_ig, changed)
def add_instances_to_group(self, ig, hostname_list):
def add_instances_to_group(self, ig):
changed = False
instance_list_unique = set([x.strip() for x in hostname_list if x])
instance_list_unique = set([x.strip() for x in self.hostname_list if x])
instances = []
for inst_name in instance_list_unique:
instance = Instance.objects.filter(hostname=inst_name)
@@ -86,43 +79,61 @@ class Command(BaseCommand):
return (instances, changed)
def handle(self, **options):
instance_not_found_err = None
queuename = options.get('queuename')
if not queuename:
raise CommandError("Specify `--queuename` to use this command.")
ctrl = options.get('controller')
inst_per = options.get('instance_percent')
inst_min = options.get('instance_minimum')
hostname_list = []
if options.get('hostnames'):
hostname_list = options.get('hostnames').split(",")
def register(self):
with advisory_lock('cluster_policy_lock'):
with transaction.atomic():
changed2 = False
changed3 = False
(ig, created, changed1) = self.get_create_update_instance_group(queuename, inst_per, inst_min)
(ig, created, changed1) = self.get_create_update_instance_group()
if created:
print("Creating instance group {}".format(ig.name))
elif not created:
print("Instance Group already registered {}".format(ig.name))
if ctrl:
(ig_ctrl, changed2) = self.update_instance_group_controller(ig, ctrl)
if self.controller:
(ig_ctrl, changed2) = self.update_instance_group_controller(ig)
if changed2:
print("Set controller group {} on {}.".format(ctrl, queuename))
print("Set controller group {} on {}.".format(self.controller, self.queuename))
try:
(instances, changed3) = self.add_instances_to_group(ig, hostname_list)
(instances, changed3) = self.add_instances_to_group(ig)
for i in instances:
print("Added instance {} to {}".format(i.hostname, ig.name))
except InstanceNotFound as e:
instance_not_found_err = e
self.instance_not_found_err = e
if any([changed1, changed2, changed3]):
print('(changed: True)')
if instance_not_found_err:
print(instance_not_found_err.message)
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--queuename', dest='queuename', type=str,
help='Queue to create/update')
parser.add_argument('--hostnames', dest='hostnames', type=str,
help='Comma-Delimited Hosts to add to the Queue (will not remove already assigned instances)')
parser.add_argument('--controller', dest='controller', type=str,
default='', help='The controlling group (makes this an isolated group)')
parser.add_argument('--instance_percent', dest='instance_percent', type=int, default=0,
help='The percentage of active instances that will be assigned to this group'),
parser.add_argument('--instance_minimum', dest='instance_minimum', type=int, default=0,
help='The minimum number of instance that will be retained for this group from available instances')
def handle(self, **options):
queuename = options.get('queuename')
if not queuename:
raise CommandError("Specify `--queuename` to use this command.")
ctrl = options.get('controller')
inst_per = options.get('instance_percent')
instance_min = options.get('instance_minimum')
hostname_list = []
if options.get('hostnames'):
hostname_list = options.get('hostnames').split(",")
rq = RegisterQueue(queuename, ctrl, inst_per, instance_min, hostname_list)
rq.register()
if rq.instance_not_found_err:
print(rq.instance_not_found_err.message)
sys.exit(1)

View File

@@ -5,17 +5,19 @@ import asyncio
import datetime
import re
import redis
import time
from datetime import datetime as dt
from django.core.management.base import BaseCommand
from django.db import connection
from django.db.models import Q
from django.db.migrations.executor import MigrationExecutor
from awx.main.analytics.broadcast_websocket import (
BroadcastWebsocketStatsManager,
safe_name,
)
from awx.main.wsbroadcast import BroadcastWebsocketManager
from awx.main.models.ha import Instance
logger = logging.getLogger('awx.main.wsbroadcast')
@@ -91,6 +93,36 @@ class Command(BaseCommand):
return host_stats
def handle(self, *arg, **options):
# it's necessary to delay this import in case
# database migrations are still running
from awx.main.models.ha import Instance
executor = MigrationExecutor(connection)
migrating = bool(executor.migration_plan(executor.loader.graph.leaf_nodes()))
registered = False
if not migrating:
try:
Instance.objects.me()
registered = True
except RuntimeError:
pass
if migrating or not registered:
# In containerized deployments, migrations happen in the task container,
# and the services running there don't start until migrations are
# finished.
# *This* service runs in the web container, and it's possible that it can
# start _before_ migrations are finished, thus causing issues with the ORM
# queries it makes (specifically, conf.settings queries).
# This block is meant to serve as a sort of bail-out for the situation
# where migrations aren't yet finished (similar to the migration
# detection middleware that the uwsgi processes have) or when instance
# registration isn't done yet
logger.error('AWX is currently installing/upgrading. Trying again in 5s...')
time.sleep(5)
return
if options.get('status'):
try:
stats_all = BroadcastWebsocketStatsManager.get_stats_sync()
@@ -107,6 +139,7 @@ class Command(BaseCommand):
break
else:
data[family.name] = family.samples[0].value
me = Instance.objects.me()
hostnames = [i.hostname for i in Instance.objects.exclude(Q(hostname=me.hostname) | Q(rampart_groups__controller__isnull=False))]

View File

@@ -121,6 +121,17 @@ class InstanceManager(models.Manager):
if not hostname:
hostname = settings.CLUSTER_HOST_ID
with advisory_lock('instance_registration_%s' % hostname):
if settings.AWX_AUTO_DEPROVISION_INSTANCES:
# detect any instances with the same IP address.
# if one exists, set it to None
inst_conflicting_ip = self.filter(ip_address=ip_address).exclude(hostname=hostname)
if inst_conflicting_ip.exists():
for other_inst in inst_conflicting_ip:
other_hostname = other_inst.hostname
other_inst.ip_address = None
other_inst.save(update_fields=['ip_address'])
logger.warning("IP address {0} conflict detected, ip address unset for host {1}.".format(ip_address, other_hostname))
instance = self.filter(hostname=hostname)
if instance.exists():
instance = instance.get()
@@ -138,8 +149,11 @@ class InstanceManager(models.Manager):
def get_or_register(self):
if settings.AWX_AUTO_DEPROVISION_INSTANCES:
from awx.main.management.commands.register_queue import RegisterQueue
pod_ip = os.environ.get('MY_POD_IP')
return self.register(ip_address=pod_ip)
registered = self.register(ip_address=pod_ip)
RegisterQueue('tower', None, 100, 0, []).register()
return registered
else:
return (False, self.me())

View File

@@ -0,0 +1,24 @@
# Generated by Django 2.2.11 on 2020-05-04 02:26
import awx.main.utils.polymorphic
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0114_v370_remove_deprecated_manual_inventory_sources'),
]
operations = [
migrations.AlterField(
model_name='unifiedjob',
name='schedule',
field=models.ForeignKey(default=None, editable=False, null=True, on_delete=awx.main.utils.polymorphic.SET_NULL, to='main.Schedule'),
),
migrations.AlterField(
model_name='unifiedjobtemplate',
name='next_schedule',
field=models.ForeignKey(default=None, editable=False, null=True, on_delete=awx.main.utils.polymorphic.SET_NULL, related_name='unifiedjobtemplate_as_next_schedule+', to='main.Schedule'),
),
]

View File

@@ -0,0 +1,34 @@
# Generated by Django 2.2.11 on 2020-05-19 02:27
from django.db import migrations, models
def remove_hipchat_notifications(apps, schema_editor):
'''
HipChat notifications are no longer in service, remove any that are found.
'''
Notification = apps.get_model('main', 'Notification')
Notification.objects.filter(notification_type='hipchat').delete()
NotificationTemplate = apps.get_model('main', 'NotificationTemplate')
NotificationTemplate.objects.filter(notification_type='hipchat').delete()
class Migration(migrations.Migration):
dependencies = [
('main', '0115_v370_schedule_set_null'),
]
operations = [
migrations.RunPython(remove_hipchat_notifications),
migrations.AlterField(
model_name='notification',
name='notification_type',
field=models.CharField(choices=[('email', 'Email'), ('grafana', 'Grafana'), ('irc', 'IRC'), ('mattermost', 'Mattermost'), ('pagerduty', 'Pagerduty'), ('rocketchat', 'Rocket.Chat'), ('slack', 'Slack'), ('twilio', 'Twilio'), ('webhook', 'Webhook')], max_length=32),
),
migrations.AlterField(
model_name='notificationtemplate',
name='notification_type',
field=models.CharField(choices=[('email', 'Email'), ('grafana', 'Grafana'), ('irc', 'IRC'), ('mattermost', 'Mattermost'), ('pagerduty', 'Pagerduty'), ('rocketchat', 'Rocket.Chat'), ('slack', 'Slack'), ('twilio', 'Twilio'), ('webhook', 'Webhook')], max_length=32),
),
]

View File

@@ -799,6 +799,10 @@ ManagedCredentialType(
'id': 'project',
'label': ugettext_noop('Project (Tenant Name)'),
'type': 'string',
}, {
'id': 'project_domain_name',
'label': ugettext_noop('Project (Domain Name)'),
'type': 'string',
}, {
'id': 'domain',
'label': ugettext_noop('Domain Name'),

View File

@@ -77,6 +77,8 @@ def _openstack_data(cred):
username=cred.get_input('username', default=''),
password=cred.get_input('password', default=''),
project_name=cred.get_input('project', default=''))
if cred.has_input('project_domain_name'):
openstack_auth['project_domain_name'] = cred.get_input('project_domain_name', default='')
if cred.has_input('domain'):
openstack_auth['domain_name'] = cred.get_input('domain', default='')
verify_state = cred.get_input('verify_ssl', default=True)

View File

@@ -7,7 +7,7 @@ from collections import defaultdict
from django.db import models, DatabaseError, connection
from django.utils.dateparse import parse_datetime
from django.utils.text import Truncator
from django.utils.timezone import utc
from django.utils.timezone import utc, now
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text
@@ -407,11 +407,14 @@ class BasePlaybookEvent(CreatedModifiedModel):
except (KeyError, ValueError):
kwargs.pop('created', None)
host_map = kwargs.pop('host_map', {})
sanitize_event_keys(kwargs, cls.VALID_KEYS)
workflow_job_id = kwargs.pop('workflow_job_id', None)
event = cls(**kwargs)
if workflow_job_id:
setattr(event, 'workflow_job_id', workflow_job_id)
setattr(event, 'host_map', host_map)
event._update_from_event_data()
return event
@@ -484,29 +487,45 @@ class JobEvent(BasePlaybookEvent):
if not self.job or not self.job.inventory:
logger.info('Event {} missing job or inventory, host summaries not updated'.format(self.pk))
return
qs = self.job.inventory.hosts.filter(name__in=hostnames)
job = self.job
from awx.main.models import Host, JobHostSummary # circular import
all_hosts = Host.objects.filter(
pk__in=self.host_map.values()
).only('id')
existing_host_ids = set(h.id for h in all_hosts)
summaries = dict()
for host in hostnames:
host_id = self.host_map.get(host, None)
if host_id not in existing_host_ids:
host_id = None
host_stats = {}
for stat in ('changed', 'dark', 'failures', 'ignored', 'ok', 'processed', 'rescued', 'skipped'):
try:
host_stats[stat] = self.event_data.get(stat, {}).get(host, 0)
except AttributeError: # in case event_data[stat] isn't a dict.
pass
if qs.filter(name=host).exists():
host_actual = qs.get(name=host)
host_summary, created = job.job_host_summaries.get_or_create(host=host_actual, host_name=host_actual.name, defaults=host_stats)
else:
host_summary, created = job.job_host_summaries.get_or_create(host_name=host, defaults=host_stats)
summary = JobHostSummary(
created=now(), modified=now(), job_id=job.id, host_id=host_id, host_name=host, **host_stats
)
summary.failed = bool(summary.dark or summary.failures)
summaries[(host_id, host)] = summary
JobHostSummary.objects.bulk_create(summaries.values())
# update the last_job_id and last_job_host_summary_id
# in single queries
host_mapping = dict(
(summary['host_id'], summary['id'])
for summary in JobHostSummary.objects.filter(job_id=job.id).values('id', 'host_id')
)
for h in all_hosts:
h.last_job_id = job.id
if h.id in host_mapping:
h.last_job_host_summary_id = host_mapping[h.id]
Host.objects.bulk_update(all_hosts, ['last_job_id', 'last_job_host_summary_id'])
if not created:
update_fields = []
for stat, value in host_stats.items():
if getattr(host_summary, stat) != value:
setattr(host_summary, stat, value)
update_fields.append(stat)
if update_fields:
host_summary.save(update_fields=update_fields)
@property
def job_verbosity(self):

View File

@@ -4,6 +4,7 @@
# Python
import datetime
import time
import json
import logging
import re
import copy
@@ -1612,6 +1613,11 @@ class PluginFileInjector(object):
# base injector should be one of None, "managed", or "template"
# this dictates which logic to borrow from playbook injectors
base_injector = None
# every source should have collection, but these are set here
# so that a source without a collection will have null values
namespace = None
collection = None
collection_migration = '2.9' # Starting with this version, we use collections
def __init__(self, ansible_version):
# This is InventoryOptions instance, could be source or inventory update
@@ -1638,7 +1644,11 @@ class PluginFileInjector(object):
"""
if self.plugin_name is None:
raise NotImplementedError('At minimum the plugin name is needed for inventory plugin use.')
return {'plugin': self.plugin_name}
if self.initial_version is None or Version(self.ansible_version) >= Version(self.collection_migration):
proper_name = f'{self.namespace}.{self.collection}.{self.plugin_name}'
else:
proper_name = self.plugin_name
return {'plugin': proper_name}
def inventory_contents(self, inventory_update, private_data_dir):
"""Returns a string that is the content for the inventory file for the inventory plugin
@@ -1693,7 +1703,10 @@ class PluginFileInjector(object):
return injected_env
def get_plugin_env(self, inventory_update, private_data_dir, private_data_files):
return self._get_shared_env(inventory_update, private_data_dir, private_data_files)
env = self._get_shared_env(inventory_update, private_data_dir, private_data_files)
if self.initial_version is None or Version(self.ansible_version) >= Version(self.collection_migration):
env['ANSIBLE_COLLECTIONS_PATHS'] = settings.AWX_ANSIBLE_COLLECTIONS_PATHS
return env
def get_script_env(self, inventory_update, private_data_dir, private_data_files):
injected_env = self._get_shared_env(inventory_update, private_data_dir, private_data_files)
@@ -1738,6 +1751,8 @@ class azure_rm(PluginFileInjector):
initial_version = '2.8' # Driven by unsafe group names issue, hostvars, host names
ini_env_reference = 'AZURE_INI_PATH'
base_injector = 'managed'
namespace = 'azure'
collection = 'azcollection'
def get_plugin_env(self, *args, **kwargs):
ret = super(azure_rm, self).get_plugin_env(*args, **kwargs)
@@ -1869,9 +1884,11 @@ class azure_rm(PluginFileInjector):
class ec2(PluginFileInjector):
plugin_name = 'aws_ec2'
# blocked by https://github.com/ansible/ansible/issues/54059
# initial_version = '2.8' # Driven by unsafe group names issue, parent_group templating, hostvars
initial_version = '2.9' # Driven by unsafe group names issue, parent_group templating, hostvars
ini_env_reference = 'EC2_INI_PATH'
base_injector = 'managed'
namespace = 'amazon'
collection = 'aws'
def get_plugin_env(self, *args, **kwargs):
ret = super(ec2, self).get_plugin_env(*args, **kwargs)
@@ -2011,6 +2028,9 @@ class ec2(PluginFileInjector):
grouping_data['key'] += ' | regex_replace("{rx}", "_")'.format(rx=legacy_regex)
# end compatibility content
if source_vars.get('iam_role_arn', None):
ret['iam_role_arn'] = source_vars['iam_role_arn']
# This was an allowed ec2.ini option, also plugin option, so pass through
if source_vars.get('boto_profile', None):
ret['boto_profile'] = source_vars['boto_profile']
@@ -2019,6 +2039,10 @@ class ec2(PluginFileInjector):
# Using the plugin, but still want dashes whitelisted
ret['use_contrib_script_compatible_sanitization'] = True
if source_vars.get('nested_groups') is False:
for this_keyed_group in keyed_groups:
this_keyed_group.pop('parent_group', None)
if keyed_groups:
ret['keyed_groups'] = keyed_groups
@@ -2030,18 +2054,35 @@ class ec2(PluginFileInjector):
compose_dict.update(self._compat_compose_vars())
# plugin provides "aws_ec2", but not this which the script gave
ret['groups'] = {'ec2': True}
# public_ip as hostname is non-default plugin behavior, script behavior
ret['hostnames'] = [
'network-interface.addresses.association.public-ip',
'dns-name',
'private-dns-name'
]
if source_vars.get('hostname_variable') is not None:
hnames = []
for expr in source_vars.get('hostname_variable').split(','):
if expr == 'public_dns_name':
hnames.append('dns-name')
elif not expr.startswith('tag:') and '_' in expr:
hnames.append(expr.replace('_', '-'))
else:
hnames.append(expr)
ret['hostnames'] = hnames
else:
# public_ip as hostname is non-default plugin behavior, script behavior
ret['hostnames'] = [
'network-interface.addresses.association.public-ip',
'dns-name',
'private-dns-name'
]
# The script returned only running state by default, the plugin does not
# https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html#options
# options: pending | running | shutting-down | terminated | stopping | stopped
inst_filters['instance-state-name'] = ['running']
# end compatibility content
if source_vars.get('destination_variable') or source_vars.get('vpc_destination_variable'):
for fd in ('destination_variable', 'vpc_destination_variable'):
if source_vars.get(fd):
compose_dict['ansible_host'] = source_vars.get(fd)
break
if compose_dict:
ret['compose'] = compose_dict
@@ -2108,6 +2149,8 @@ class gce(PluginFileInjector):
initial_version = '2.8' # Driven by unsafe group names issue, hostvars
ini_env_reference = 'GCE_INI_PATH'
base_injector = 'managed'
namespace = 'google'
collection = 'cloud'
def get_plugin_env(self, *args, **kwargs):
ret = super(gce, self).get_plugin_env(*args, **kwargs)
@@ -2208,14 +2251,118 @@ class gce(PluginFileInjector):
class vmware(PluginFileInjector):
# plugin_name = 'vmware_vm_inventory' # FIXME: implement me
plugin_name = 'vmware_vm_inventory'
initial_version = '2.9'
ini_env_reference = 'VMWARE_INI_PATH'
base_injector = 'managed'
namespace = 'community'
collection = 'vmware'
@property
def script_name(self):
return 'vmware_inventory.py' # exception
def inventory_as_dict(self, inventory_update, private_data_dir):
ret = super(vmware, self).inventory_as_dict(inventory_update, private_data_dir)
ret['strict'] = False
# Documentation of props, see
# https://github.com/ansible/ansible/blob/devel/docs/docsite/rst/scenario_guides/vmware_scenarios/vmware_inventory_vm_attributes.rst
UPPERCASE_PROPS = [
"availableField",
"configIssue",
"configStatus",
"customValue", # optional
"datastore",
"effectiveRole",
"guestHeartbeatStatus", # optional
"layout", # optional
"layoutEx", # optional
"name",
"network",
"overallStatus",
"parentVApp", # optional
"permission",
"recentTask",
"resourcePool",
"rootSnapshot",
"snapshot", # optional
"triggeredAlarmState",
"value"
]
NESTED_PROPS = [
"capability",
"config",
"guest",
"runtime",
"storage",
"summary", # repeat of other properties
]
ret['properties'] = UPPERCASE_PROPS + NESTED_PROPS
ret['compose'] = {'ansible_host': 'guest.ipAddress'} # default value
ret['compose']['ansible_ssh_host'] = ret['compose']['ansible_host']
# the ansible_uuid was unique every host, every import, from the script
ret['compose']['ansible_uuid'] = '99999999 | random | to_uuid'
for prop in UPPERCASE_PROPS:
if prop == prop.lower():
continue
ret['compose'][prop.lower()] = prop
ret['with_nested_properties'] = True
# ret['property_name_format'] = 'lower_case' # only dacrystal/topic/vmware-inventory-plugin-property-format
# process custom options
vmware_opts = dict(inventory_update.source_vars_dict.items())
if inventory_update.instance_filters:
vmware_opts.setdefault('host_filters', inventory_update.instance_filters)
if inventory_update.group_by:
vmware_opts.setdefault('groupby_patterns', inventory_update.group_by)
alias_pattern = vmware_opts.get('alias_pattern')
if alias_pattern:
ret.setdefault('hostnames', [])
for alias in alias_pattern.split(','): # make best effort
striped_alias = alias.replace('{', '').replace('}', '').strip() # make best effort
if not striped_alias:
continue
ret['hostnames'].append(striped_alias)
host_pattern = vmware_opts.get('host_pattern') # not working in script
if host_pattern:
stripped_hp = host_pattern.replace('{', '').replace('}', '').strip() # make best effort
ret['compose']['ansible_host'] = stripped_hp
ret['compose']['ansible_ssh_host'] = stripped_hp
host_filters = vmware_opts.get('host_filters')
if host_filters:
ret.setdefault('filters', [])
for hf in host_filters.split(','):
striped_hf = hf.replace('{', '').replace('}', '').strip() # make best effort
if not striped_hf:
continue
ret['filters'].append(striped_hf)
else:
# default behavior filters by power state
ret['filters'] = ['runtime.powerState == "poweredOn"']
groupby_patterns = vmware_opts.get('groupby_patterns')
ret.setdefault('keyed_groups', [])
if groupby_patterns:
for pattern in groupby_patterns.split(','):
stripped_pattern = pattern.replace('{', '').replace('}', '').strip() # make best effort
ret['keyed_groups'].append({
'prefix': '', 'separator': '',
'key': stripped_pattern
})
else:
# default groups from script
for entry in ('config.guestId', '"templates" if config.template else "guests"'):
ret['keyed_groups'].append({
'prefix': '', 'separator': '',
'key': entry
})
return ret
def build_script_private_data(self, inventory_update, private_data_dir):
cp = configparser.RawConfigParser()
credential = inventory_update.get_cloud_credential()
@@ -2246,6 +2393,8 @@ class openstack(PluginFileInjector):
plugin_name = 'openstack'
# minimum version of 2.7.8 may be theoretically possible
initial_version = '2.8' # Driven by consistency with other sources
namespace = 'openstack'
collection = 'cloud'
@property
def script_name(self):
@@ -2297,7 +2446,10 @@ class openstack(PluginFileInjector):
return self.build_script_private_data(inventory_update, private_data_dir, mk_cache=False)
def get_plugin_env(self, inventory_update, private_data_dir, private_data_files):
return self.get_script_env(inventory_update, private_data_dir, private_data_files)
env = super(openstack, self).get_plugin_env(inventory_update, private_data_dir, private_data_files)
script_env = self.get_script_env(inventory_update, private_data_dir, private_data_files)
env.update(script_env)
return env
def inventory_as_dict(self, inventory_update, private_data_dir):
def use_host_name_for_name(a_bool_maybe):
@@ -2309,12 +2461,10 @@ class openstack(PluginFileInjector):
else:
return 'uuid'
ret = dict(
plugin=self.plugin_name,
fail_on_errors=True,
expand_hostvars=True,
inventory_hostname=use_host_name_for_name(False),
)
ret = super(openstack, self).inventory_as_dict(inventory_update, private_data_dir)
ret['fail_on_errors'] = True
ret['expand_hostvars'] = True
ret['inventory_hostname'] = use_host_name_for_name(False)
# Note: mucking with defaults will break import integrity
# For the plugin, we need to use the same defaults as the old script
# or else imports will conflict. To find script defaults you have
@@ -2339,19 +2489,43 @@ class openstack(PluginFileInjector):
class rhv(PluginFileInjector):
"""ovirt uses the custom credential templating, and that is all
"""
# plugin_name = 'FIXME' # contribute inventory plugin to Ansible
plugin_name = 'ovirt'
base_injector = 'template'
initial_version = '2.9'
namespace = 'ovirt'
collection = 'ovirt'
@property
def script_name(self):
return 'ovirt4.py' # exception
def inventory_as_dict(self, inventory_update, private_data_dir):
ret = super(rhv, self).inventory_as_dict(inventory_update, private_data_dir)
ret['ovirt_insecure'] = False # Default changed from script
# TODO: process strict option upstream
ret['compose'] = {
'ansible_host': '(devices.values() | list)[0][0] if devices else None'
}
ret['keyed_groups'] = []
for key in ('cluster', 'status'):
ret['keyed_groups'].append({'prefix': key, 'separator': '_', 'key': key})
ret['keyed_groups'].append({'prefix': 'tag', 'separator': '_', 'key': 'tags'})
ret['ovirt_hostname_preference'] = ['name', 'fqdn']
source_vars = inventory_update.source_vars_dict
for key, value in source_vars.items():
if key == 'plugin':
continue
ret[key] = value
return ret
class satellite6(PluginFileInjector):
plugin_name = 'foreman'
ini_env_reference = 'FOREMAN_INI_PATH'
# initial_version = '2.8' # FIXME: turn on after plugin is validated
initial_version = '2.9'
# No base injector, because this does not work in playbooks. Bug??
namespace = 'theforeman'
collection = 'foreman'
@property
def script_name(self):
@@ -2413,18 +2587,123 @@ class satellite6(PluginFileInjector):
# this assumes that this is merged
# https://github.com/ansible/ansible/pull/52693
credential = inventory_update.get_cloud_credential()
ret = {}
ret = super(satellite6, self).get_plugin_env(inventory_update, private_data_dir, private_data_files)
if credential:
ret['FOREMAN_SERVER'] = credential.get_input('host', default='')
ret['FOREMAN_USER'] = credential.get_input('username', default='')
ret['FOREMAN_PASSWORD'] = credential.get_input('password', default='')
return ret
def inventory_as_dict(self, inventory_update, private_data_dir):
ret = super(satellite6, self).inventory_as_dict(inventory_update, private_data_dir)
group_patterns = '[]'
group_prefix = 'foreman_'
want_hostcollections = False
want_ansible_ssh_host = False
want_facts = True
foreman_opts = inventory_update.source_vars_dict.copy()
for k, v in foreman_opts.items():
if k == 'satellite6_group_patterns' and isinstance(v, str):
group_patterns = v
elif k == 'satellite6_group_prefix' and isinstance(v, str):
group_prefix = v
elif k == 'satellite6_want_hostcollections' and isinstance(v, bool):
want_hostcollections = v
elif k == 'satellite6_want_ansible_ssh_host' and isinstance(v, bool):
want_ansible_ssh_host = v
elif k == 'satellite6_want_facts' and isinstance(v, bool):
want_facts = v
else:
ret[k] = str(v)
# Compatibility content
group_by_hostvar = {
"environment": {"prefix": "{}environment_".format(group_prefix),
"separator": "",
"key": "foreman['environment_name'] | lower | regex_replace(' ', '') | "
"regex_replace('[^A-Za-z0-9_]', '_') | regex_replace('none', '')"},
"location": {"prefix": "{}location_".format(group_prefix),
"separator": "",
"key": "foreman['location_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')"},
"organization": {"prefix": "{}organization_".format(group_prefix),
"separator": "",
"key": "foreman['organization_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')"},
"lifecycle_environment": {"prefix": "{}lifecycle_environment_".format(group_prefix),
"separator": "",
"key": "foreman['content_facet_attributes']['lifecycle_environment_name'] | "
"lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')"},
"content_view": {"prefix": "{}content_view_".format(group_prefix),
"separator": "",
"key": "foreman['content_facet_attributes']['content_view_name'] | "
"lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')"}
}
ret['legacy_hostvars'] = True # convert hostvar structure to the form used by the script
ret['want_params'] = True
ret['group_prefix'] = group_prefix
ret['want_hostcollections'] = want_hostcollections
ret['want_facts'] = want_facts
if want_ansible_ssh_host:
ret['compose'] = {'ansible_ssh_host': "foreman['ip6'] | default(foreman['ip'], true)"}
ret['keyed_groups'] = [group_by_hostvar[grouping_name] for grouping_name in group_by_hostvar]
def form_keyed_group(group_pattern):
"""
Converts foreman group_pattern to
inventory plugin keyed_group
e.g. {app_param}-{tier_param}-{dc_param}
becomes
"%s-%s-%s" | format(app_param, tier_param, dc_param)
"""
if type(group_pattern) is not str:
return None
params = re.findall('{[^}]*}', group_pattern)
if len(params) == 0:
return None
param_names = []
for p in params:
param_names.append(p[1:-1].strip()) # strip braces and space
# form keyed_group key by
# replacing curly braces with '%s'
# (for use with jinja's format filter)
key = group_pattern
for p in params:
key = key.replace(p, '%s', 1)
# apply jinja filter to key
key = '"{}" | format({})'.format(key, ', '.join(param_names))
keyed_group = {'key': key,
'separator': ''}
return keyed_group
try:
group_patterns = json.loads(group_patterns)
if type(group_patterns) is list:
for group_pattern in group_patterns:
keyed_group = form_keyed_group(group_pattern)
if keyed_group:
ret['keyed_groups'].append(keyed_group)
except json.JSONDecodeError:
logger.warning('Could not parse group_patterns. Expected JSON-formatted string, found: {}'
.format(group_patterns))
return ret
class cloudforms(PluginFileInjector):
# plugin_name = 'FIXME' # contribute inventory plugin to Ansible
ini_env_reference = 'CLOUDFORMS_INI_PATH'
# Also no base_injector because this does not work in playbooks
# namespace = '' # does not have a collection
# collection = ''
def build_script_private_data(self, inventory_update, private_data_dir):
cp = configparser.RawConfigParser()
@@ -2460,6 +2739,8 @@ class tower(PluginFileInjector):
plugin_name = 'tower'
base_injector = 'template'
initial_version = '2.8' # Driven by "include_metadata" hostvars
namespace = 'awx'
collection = 'awx'
def get_script_env(self, inventory_update, private_data_dir, private_data_files):
env = super(tower, self).get_script_env(inventory_update, private_data_dir, private_data_files)
@@ -2468,6 +2749,7 @@ class tower(PluginFileInjector):
return env
def inventory_as_dict(self, inventory_update, private_data_dir):
ret = super(tower, self).inventory_as_dict(inventory_update, private_data_dir)
# Credentials injected as env vars, same as script
try:
# plugin can take an actual int type
@@ -2475,11 +2757,9 @@ class tower(PluginFileInjector):
except ValueError:
# inventory_id could be a named URL
identifier = iri_to_uri(inventory_update.instance_filters)
return {
'plugin': self.plugin_name,
'inventory_id': identifier,
'include_metadata': True # used for license check
}
ret['inventory_id'] = identifier
ret['include_metadata'] = True # used for license check
return ret
for cls in PluginFileInjector.__subclasses__():

View File

@@ -439,13 +439,9 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
field = self._meta.get_field(field_name)
if isinstance(field, models.ManyToManyField):
old_value = set(old_value.all())
if getattr(self, '_deprecated_credential_launch', False):
# TODO: remove this code branch when support for `extra_credentials` goes away
new_value = set(kwargs[field_name])
else:
new_value = set(kwargs[field_name]) - old_value
if not new_value:
continue
new_value = set(kwargs[field_name]) - old_value
if not new_value:
continue
if new_value == old_value:
# no-op case: Fields the same as template's value
@@ -1133,20 +1129,6 @@ class JobHostSummary(CreatedModifiedModel):
self.failed = bool(self.dark or self.failures)
update_fields.append('failed')
super(JobHostSummary, self).save(*args, **kwargs)
self.update_host_last_job_summary()
def update_host_last_job_summary(self):
update_fields = []
if self.host is None:
return
if self.host.last_job_id != self.job_id:
self.host.last_job_id = self.job_id
update_fields.append('last_job_id')
if self.host.last_job_host_summary_id != self.id:
self.host.last_job_host_summary_id = self.id
update_fields.append('last_job_host_summary_id')
if update_fields:
self.host.save(update_fields=update_fields)
class SystemJobOptions(BaseModel):

View File

@@ -23,7 +23,6 @@ from awx.main.notifications.email_backend import CustomEmailBackend
from awx.main.notifications.slack_backend import SlackBackend
from awx.main.notifications.twilio_backend import TwilioBackend
from awx.main.notifications.pagerduty_backend import PagerDutyBackend
from awx.main.notifications.hipchat_backend import HipChatBackend
from awx.main.notifications.webhook_backend import WebhookBackend
from awx.main.notifications.mattermost_backend import MattermostBackend
from awx.main.notifications.grafana_backend import GrafanaBackend
@@ -44,7 +43,6 @@ class NotificationTemplate(CommonModelNameNotUnique):
('twilio', _('Twilio'), TwilioBackend),
('pagerduty', _('Pagerduty'), PagerDutyBackend),
('grafana', _('Grafana'), GrafanaBackend),
('hipchat', _('HipChat'), HipChatBackend),
('webhook', _('Webhook'), WebhookBackend),
('mattermost', _('Mattermost'), MattermostBackend),
('rocketchat', _('Rocket.Chat'), RocketChatBackend),

View File

@@ -199,7 +199,7 @@ class ProjectOptions(models.Model):
results = []
project_path = self.get_project_path()
if project_path:
for dirpath, dirnames, filenames in os.walk(smart_str(project_path), followlinks=True):
for dirpath, dirnames, filenames in os.walk(smart_str(project_path), followlinks=settings.AWX_SHOW_PLAYBOOK_LINKS):
if skip_directory(dirpath):
continue
for filename in filenames:

View File

@@ -150,7 +150,7 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
default=None,
editable=False,
related_name='%(class)s_as_next_schedule+',
on_delete=models.SET_NULL,
on_delete=polymorphic.SET_NULL,
)
status = models.CharField(
max_length=32,
@@ -413,9 +413,8 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
if 'extra_vars' in validated_kwargs:
unified_job.handle_extra_data(validated_kwargs['extra_vars'])
if not getattr(self, '_deprecated_credential_launch', False):
# Create record of provided prompts for relaunch and rescheduling
unified_job.create_config_from_prompts(kwargs, parent=self)
# Create record of provided prompts for relaunch and rescheduling
unified_job.create_config_from_prompts(kwargs, parent=self)
# manually issue the create activity stream entry _after_ M2M relations
# have been associated to the UJ
@@ -587,7 +586,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
null=True,
default=None,
editable=False,
on_delete=models.SET_NULL,
on_delete=polymorphic.SET_NULL,
)
dependent_jobs = models.ManyToManyField(
'self',

View File

@@ -13,6 +13,19 @@ from django.utils.translation import ugettext_lazy as _
from awx.main.notifications.base import AWXBaseEmailBackend
from awx.main.notifications.custom_notification_base import CustomNotificationBase
DEFAULT_MSG = CustomNotificationBase.DEFAULT_MSG
DEFAULT_APPROVAL_RUNNING_MSG = CustomNotificationBase.DEFAULT_APPROVAL_RUNNING_MSG
DEFAULT_APPROVAL_RUNNING_BODY = CustomNotificationBase.DEFAULT_APPROVAL_RUNNING_BODY
DEFAULT_APPROVAL_APPROVED_MSG = CustomNotificationBase.DEFAULT_APPROVAL_APPROVED_MSG
DEFAULT_APPROVAL_APPROVED_BODY = CustomNotificationBase.DEFAULT_APPROVAL_APPROVED_BODY
DEFAULT_APPROVAL_TIMEOUT_MSG = CustomNotificationBase.DEFAULT_APPROVAL_TIMEOUT_MSG
DEFAULT_APPROVAL_TIMEOUT_BODY = CustomNotificationBase.DEFAULT_APPROVAL_TIMEOUT_BODY
DEFAULT_APPROVAL_DENIED_MSG = CustomNotificationBase.DEFAULT_APPROVAL_DENIED_MSG
DEFAULT_APPROVAL_DENIED_BODY = CustomNotificationBase.DEFAULT_APPROVAL_DENIED_BODY
logger = logging.getLogger('awx.main.notifications.grafana_backend')
@@ -25,31 +38,13 @@ class GrafanaBackend(AWXBaseEmailBackend, CustomNotificationBase):
sender_parameter = None
DEFAULT_BODY = "{{ job_metadata }}"
default_messages = {
"started": {
"body": DEFAULT_BODY, "message": CustomNotificationBase.DEFAULT_MSG
},
"success": {
"body": DEFAULT_BODY, "message": CustomNotificationBase.DEFAULT_MSG
},
"error": {
"body": DEFAULT_BODY, "message": CustomNotificationBase.DEFAULT_MSG
},
"workflow_approval": {
"running": {
"message": CustomNotificationBase.DEFAULT_APPROVAL_RUNNING_MSG, "body": None
},
"approved": {
"message": CustomNotificationBase.DEFAULT_APPROVAL_APPROVED_MSG, "body": None
},
"timed_out": {
"message": CustomNotificationBase.DEFAULT_APPROVAL_TIMEOUT_MSG, "body": None
},
"denied": {
"message": CustomNotificationBase.DEFAULT_APPROVAL_DENIED_MSG, "body": None
}
}
}
default_messages = {"started": {"body": DEFAULT_BODY, "message": DEFAULT_MSG},
"success": {"body": DEFAULT_BODY, "message": DEFAULT_MSG},
"error": {"body": DEFAULT_BODY, "message": DEFAULT_MSG},
"workflow_approval": {"running": {"message": DEFAULT_APPROVAL_RUNNING_MSG, "body": DEFAULT_APPROVAL_RUNNING_BODY},
"approved": {"message": DEFAULT_APPROVAL_APPROVED_MSG,"body": DEFAULT_APPROVAL_APPROVED_BODY},
"timed_out": {"message": DEFAULT_APPROVAL_TIMEOUT_MSG, "body": DEFAULT_APPROVAL_TIMEOUT_BODY},
"denied": {"message": DEFAULT_APPROVAL_DENIED_MSG, "body": DEFAULT_APPROVAL_DENIED_BODY}}}
def __init__(self, grafana_key,dashboardId=None, panelId=None, annotation_tags=None, grafana_no_verify_ssl=False, isRegion=True,
fail_silently=False, **kwargs):

View File

@@ -1,54 +0,0 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved.
import logging
import requests
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
from awx.main.notifications.base import AWXBaseEmailBackend
from awx.main.notifications.custom_notification_base import CustomNotificationBase
logger = logging.getLogger('awx.main.notifications.hipchat_backend')
class HipChatBackend(AWXBaseEmailBackend, CustomNotificationBase):
init_parameters = {"token": {"label": "Token", "type": "password"},
"rooms": {"label": "Destination Rooms", "type": "list"},
"color": {"label": "Notification Color", "type": "string"},
"api_url": {"label": "API Url (e.g: https://mycompany.hipchat.com)", "type": "string"},
"notify": {"label": "Notify room", "type": "bool"},
"message_from": {"label": "Label to be shown with notification", "type": "string"}}
recipient_parameter = "rooms"
sender_parameter = "message_from"
def __init__(self, token, color, api_url, notify, fail_silently=False, **kwargs):
super(HipChatBackend, self).__init__(fail_silently=fail_silently)
self.token = token
if color is not None:
self.color = color.lower()
self.api_url = api_url
self.notify = notify
def send_messages(self, messages):
sent_messages = 0
for m in messages:
for rcp in m.recipients():
r = requests.post("{}/v2/room/{}/notification".format(self.api_url, rcp),
params={"auth_token": self.token},
verify=False,
json={"color": self.color,
"message": m.subject,
"notify": self.notify,
"from": m.from_email,
"message_format": "text"})
if r.status_code != 204:
logger.error(smart_text(_("Error sending messages: {}").format(r.text)))
if not self.fail_silently:
raise Exception(smart_text(_("Error sending message to hipchat: {}").format(r.text)))
sent_messages += 1
return sent_messages

View File

@@ -3,7 +3,6 @@
import logging
import requests
import json
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -45,7 +44,7 @@ class MattermostBackend(AWXBaseEmailBackend, CustomNotificationBase):
payload['text'] = m.subject
r = requests.post("{}".format(m.recipients()[0]),
data=json.dumps(payload), verify=(not self.mattermost_no_verify_ssl))
json=payload, verify=(not self.mattermost_no_verify_ssl))
if r.status_code >= 400:
logger.error(smart_text(_("Error sending notification mattermost: {}").format(r.text)))
if not self.fail_silently:

View File

@@ -11,9 +11,20 @@ from django.utils.translation import ugettext_lazy as _
from awx.main.notifications.base import AWXBaseEmailBackend
from awx.main.notifications.custom_notification_base import CustomNotificationBase
DEFAULT_BODY = CustomNotificationBase.DEFAULT_BODY
DEFAULT_MSG = CustomNotificationBase.DEFAULT_MSG
DEFAULT_APPROVAL_RUNNING_MSG = CustomNotificationBase.DEFAULT_APPROVAL_RUNNING_MSG
DEFAULT_APPROVAL_RUNNING_BODY = CustomNotificationBase.DEFAULT_APPROVAL_RUNNING_BODY
DEFAULT_APPROVAL_APPROVED_MSG = CustomNotificationBase.DEFAULT_APPROVAL_APPROVED_MSG
DEFAULT_APPROVAL_APPROVED_BODY = CustomNotificationBase.DEFAULT_APPROVAL_APPROVED_BODY
DEFAULT_APPROVAL_TIMEOUT_MSG = CustomNotificationBase.DEFAULT_APPROVAL_TIMEOUT_MSG
DEFAULT_APPROVAL_TIMEOUT_BODY = CustomNotificationBase.DEFAULT_APPROVAL_TIMEOUT_BODY
DEFAULT_APPROVAL_DENIED_MSG = CustomNotificationBase.DEFAULT_APPROVAL_DENIED_MSG
DEFAULT_APPROVAL_DENIED_BODY = CustomNotificationBase.DEFAULT_APPROVAL_DENIED_BODY
logger = logging.getLogger('awx.main.notifications.pagerduty_backend')
@@ -30,10 +41,10 @@ class PagerDutyBackend(AWXBaseEmailBackend, CustomNotificationBase):
default_messages = {"started": {"message": DEFAULT_MSG, "body": DEFAULT_BODY},
"success": {"message": DEFAULT_MSG, "body": DEFAULT_BODY},
"error": {"message": DEFAULT_MSG, "body": DEFAULT_BODY},
"workflow_approval": {"running": {"message": DEFAULT_MSG, "body": DEFAULT_BODY},
"approved": {"message": DEFAULT_MSG,"body": DEFAULT_BODY},
"timed_out": {"message": DEFAULT_MSG, "body": DEFAULT_BODY},
"denied": {"message": DEFAULT_MSG, "body": DEFAULT_BODY}}}
"workflow_approval": {"running": {"message": DEFAULT_APPROVAL_RUNNING_MSG, "body": DEFAULT_APPROVAL_RUNNING_BODY},
"approved": {"message": DEFAULT_APPROVAL_APPROVED_MSG,"body": DEFAULT_APPROVAL_APPROVED_BODY},
"timed_out": {"message": DEFAULT_APPROVAL_TIMEOUT_MSG, "body": DEFAULT_APPROVAL_TIMEOUT_BODY},
"denied": {"message": DEFAULT_APPROVAL_DENIED_MSG, "body": DEFAULT_APPROVAL_DENIED_BODY}}}
def __init__(self, subdomain, token, fail_silently=False, **kwargs):
super(PagerDutyBackend, self).__init__(fail_silently=fail_silently)

View File

@@ -1,14 +1,37 @@
import redis
import logging
from django.conf.urls import url
from django.conf import settings
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from . import consumers
logger = logging.getLogger('awx.main.routing')
class AWXProtocolTypeRouter(ProtocolTypeRouter):
def __init__(self, *args, **kwargs):
try:
r = redis.Redis.from_url(settings.BROKER_URL)
for k in r.scan_iter('asgi:*', 500):
logger.debug(f"cleaning up Redis key {k}")
r.delete(k)
except redis.exceptions.RedisError as e:
logger.warn("encountered an error communicating with redis.")
raise e
super().__init__(*args, **kwargs)
websocket_urlpatterns = [
url(r'websocket/$', consumers.EventConsumer),
url(r'websocket/broadcast/$', consumers.BroadcastConsumer),
]
application = ProtocolTypeRouter({
application = AWXProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(websocket_urlpatterns)
),

View File

@@ -152,8 +152,8 @@ class SimpleDAG(object):
return self._get_children_by_label(this_ord, label)
else:
nodes = []
for l in self.node_from_edges_by_label.keys():
nodes.extend(self._get_children_by_label(this_ord, l))
for label_obj in self.node_from_edges_by_label.keys():
nodes.extend(self._get_children_by_label(this_ord, label_obj))
return nodes
def _get_parents_by_label(self, node_index, label):
@@ -168,8 +168,8 @@ class SimpleDAG(object):
return self._get_parents_by_label(this_ord, label)
else:
nodes = []
for l in self.node_to_edges_by_label.keys():
nodes.extend(self._get_parents_by_label(this_ord, l))
for label_obj in self.node_to_edges_by_label.keys():
nodes.extend(self._get_parents_by_label(this_ord, label_obj))
return nodes
def get_root_nodes(self):

View File

@@ -10,7 +10,7 @@ import random
# Django
from django.db import transaction, connection
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, gettext_noop
from django.utils.timezone import now as tz_now
# AWX
@@ -114,7 +114,7 @@ class TaskManager():
logger.info('Refusing to start recursive workflow-in-workflow id={}, wfjt={}, ancestors={}'.format(
job.id, spawn_node.unified_job_template.pk, [wa.pk for wa in workflow_ancestors]))
display_list = [spawn_node.unified_job_template] + workflow_ancestors
job.job_explanation = _(
job.job_explanation = gettext_noop(
"Workflow Job spawned from workflow could not start because it "
"would result in recursion (spawn order, most recent first: {})"
).format(', '.join(['<{}>'.format(tmp) for tmp in display_list]))
@@ -123,8 +123,8 @@ class TaskManager():
job.id, spawn_node.unified_job_template.pk, [wa.pk for wa in workflow_ancestors]))
if not job._resources_sufficient_for_launch():
can_start = False
job.job_explanation = _("Job spawned from workflow could not start because it "
"was missing a related resource such as project or inventory")
job.job_explanation = gettext_noop("Job spawned from workflow could not start because it "
"was missing a related resource such as project or inventory")
if can_start:
if workflow_job.start_args:
start_args = json.loads(decrypt_field(workflow_job, 'start_args'))
@@ -132,8 +132,8 @@ class TaskManager():
start_args = {}
can_start = job.signal_start(**start_args)
if not can_start:
job.job_explanation = _("Job spawned from workflow could not start because it "
"was not in the right state or required manual credentials")
job.job_explanation = gettext_noop("Job spawned from workflow could not start because it "
"was not in the right state or required manual credentials")
if not can_start:
job.status = 'failed'
job.save(update_fields=['status', 'job_explanation'])
@@ -173,7 +173,7 @@ class TaskManager():
workflow_job.status = new_status
if reason:
logger.info(reason)
workflow_job.job_explanation = _("No error handling paths found, marking workflow as failed")
workflow_job.job_explanation = gettext_noop("No error handling paths found, marking workflow as failed")
update_fields.append('job_explanation')
workflow_job.start_args = '' # blank field to remove encrypted passwords
workflow_job.save(update_fields=update_fields)
@@ -581,3 +581,4 @@ class TaskManager():
logger.debug("Starting Scheduler")
with task_manager_bulk_reschedule():
self._schedule()
logger.debug("Finishing Scheduler")

View File

@@ -150,9 +150,9 @@ def rbac_activity_stream(instance, sender, **kwargs):
def cleanup_detached_labels_on_deleted_parent(sender, instance, **kwargs):
for l in instance.labels.all():
if l.is_candidate_for_detach():
l.delete()
for label in instance.labels.all():
if label.is_candidate_for_detach():
label.delete()
def save_related_job_templates(sender, instance, **kwargs):
@@ -393,7 +393,7 @@ def activity_stream_create(sender, instance, created, **kwargs):
'{} ({})'.format(c.name, c.id)
for c in instance.credentials.iterator()
]
changes['labels'] = [l.name for l in instance.labels.iterator()]
changes['labels'] = [label.name for label in instance.labels.iterator()]
if 'extra_vars' in changes:
changes['extra_vars'] = instance.display_extra_vars()
if type(instance) == OAuth2AccessToken:

View File

@@ -31,7 +31,7 @@ from django.db.models.fields.related import ForeignKey
from django.utils.timezone import now, timedelta
from django.utils.encoding import smart_str
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, gettext_noop
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
@@ -67,7 +67,7 @@ from awx.main.queue import CallbackQueueDispatcher
from awx.main.isolated import manager as isolated_manager
from awx.main.dispatch.publish import task
from awx.main.dispatch import get_local_queuename, reaper
from awx.main.utils import (get_ssh_version, update_scm_url,
from awx.main.utils import (update_scm_url,
ignore_inventory_computed_fields,
ignore_inventory_group_removal, extract_ansible_vars, schedule_task_manager,
get_awx_version)
@@ -141,7 +141,7 @@ def dispatch_startup():
# and Tower fall out of use/support, we can probably just _assume_ that
# everybody has moved to bigint, and remove this code entirely
enforce_bigint_pk_migration()
# Update Tower's rsyslog.conf file based on loggins settings in the db
reconfigure_rsyslog()
@@ -288,7 +288,7 @@ def handle_setting_changes(setting_keys):
setting.startswith('LOG_AGGREGATOR')
for setting in setting_keys
]):
connection.on_commit(reconfigure_rsyslog)
reconfigure_rsyslog()
@task(queue='tower_broadcast_all')
@@ -358,6 +358,9 @@ def gather_analytics():
from rest_framework.fields import DateTimeField
if not settings.INSIGHTS_TRACKING_STATE:
return
if not (settings.AUTOMATION_ANALYTICS_URL and settings.REDHAT_USERNAME and settings.REDHAT_PASSWORD):
logger.debug('Not gathering analytics, configuration is invalid')
return
last_gather = Setting.objects.filter(key='AUTOMATION_ANALYTICS_LAST_GATHER').first()
if last_gather:
last_time = DateTimeField().to_internal_value(last_gather.value)
@@ -558,7 +561,8 @@ def awx_periodic_scheduler():
continue
if not can_start:
new_unified_job.status = 'failed'
new_unified_job.job_explanation = "Scheduled job could not start because it was not in the right state or required manual credentials"
new_unified_job.job_explanation = gettext_noop("Scheduled job could not start because it \
was not in the right state or required manual credentials")
new_unified_job.save(update_fields=['status', 'job_explanation'])
new_unified_job.websocket_emit_status("failed")
emit_channel_notification('schedules-changed', dict(id=schedule.id, group_name="schedules"))
@@ -897,21 +901,14 @@ class BaseTask(object):
private_data = self.build_private_data(instance, private_data_dir)
private_data_files = {'credentials': {}}
if private_data is not None:
ssh_ver = get_ssh_version()
ssh_too_old = True if ssh_ver == "unknown" else Version(ssh_ver) < Version("6.0")
openssh_keys_supported = ssh_ver != "unknown" and Version(ssh_ver) >= Version("6.5")
for credential, data in private_data.get('credentials', {}).items():
# Bail out now if a private key was provided in OpenSSH format
# and we're running an earlier version (<6.5).
if 'OPENSSH PRIVATE KEY' in data and not openssh_keys_supported:
raise RuntimeError(OPENSSH_KEY_ERROR)
# OpenSSH formatted keys must have a trailing newline to be
# accepted by ssh-add.
if 'OPENSSH PRIVATE KEY' in data and not data.endswith('\n'):
data += '\n'
# For credentials used with ssh-add, write to a named pipe which
# will be read then closed, instead of leaving the SSH key on disk.
if credential and credential.credential_type.namespace in ('ssh', 'scm') and not ssh_too_old:
if credential and credential.credential_type.namespace in ('ssh', 'scm'):
try:
os.mkdir(os.path.join(private_data_dir, 'env'))
except OSError as e:
@@ -1222,6 +1219,8 @@ class BaseTask(object):
else:
event_data['host_name'] = ''
event_data['host_id'] = ''
if event_data.get('event') == 'playbook_on_stats':
event_data['host_map'] = self.host_map
if isinstance(self, RunProjectUpdate):
# it's common for Ansible's SCM modules to print
@@ -1232,10 +1231,12 @@ class BaseTask(object):
# this is a _little_ expensive to filter
# with regex, but project updates don't have many events,
# so it *should* have a negligible performance impact
task = event_data.get('event_data', {}).get('task_action')
try:
event_data_json = json.dumps(event_data)
event_data_json = UriCleaner.remove_sensitive(event_data_json)
event_data = json.loads(event_data_json)
if task in ('git', 'hg', 'svn'):
event_data_json = json.dumps(event_data)
event_data_json = UriCleaner.remove_sensitive(event_data_json)
event_data = json.loads(event_data_json)
except json.JSONDecodeError:
pass
@@ -1421,7 +1422,6 @@ class BaseTask(object):
'status_handler': self.status_handler,
'settings': {
'job_timeout': self.get_instance_timeout(self.instance),
'pexpect_timeout': getattr(settings, 'PEXPECT_TIMEOUT', 5),
'suppress_ansible_output': True,
**process_isolation_params,
**resource_profiling_params,
@@ -2074,29 +2074,34 @@ class RunProjectUpdate(BaseTask):
if settings.GALAXY_IGNORE_CERTS:
env['ANSIBLE_GALAXY_IGNORE'] = True
# Set up the public Galaxy server, if enabled
galaxy_configured = False
if settings.PUBLIC_GALAXY_ENABLED:
galaxy_servers = [settings.PUBLIC_GALAXY_SERVER]
galaxy_servers = [settings.PUBLIC_GALAXY_SERVER] # static setting
else:
galaxy_configured = True
galaxy_servers = []
# Set up fallback Galaxy servers, if configured
if settings.FALLBACK_GALAXY_SERVERS:
galaxy_configured = True
galaxy_servers = settings.FALLBACK_GALAXY_SERVERS + galaxy_servers
# Set up the primary Galaxy server, if configured
if settings.PRIMARY_GALAXY_URL:
galaxy_configured = True
galaxy_servers = [{'id': 'primary_galaxy'}] + galaxy_servers
for key in GALAXY_SERVER_FIELDS:
value = getattr(settings, 'PRIMARY_GALAXY_{}'.format(key.upper()))
if value:
galaxy_servers[0][key] = value
for server in galaxy_servers:
for key in GALAXY_SERVER_FIELDS:
if not server.get(key):
continue
env_key = ('ANSIBLE_GALAXY_SERVER_{}_{}'.format(server.get('id', 'unnamed'), key)).upper()
env[env_key] = server[key]
if galaxy_servers:
# now set the precedence of galaxy servers
env['ANSIBLE_GALAXY_SERVER_LIST'] = ','.join([server.get('id', 'unnamed') for server in galaxy_servers])
if galaxy_configured:
for server in galaxy_servers:
for key in GALAXY_SERVER_FIELDS:
if not server.get(key):
continue
env_key = ('ANSIBLE_GALAXY_SERVER_{}_{}'.format(server.get('id', 'unnamed'), key)).upper()
env[env_key] = server[key]
if galaxy_servers:
# now set the precedence of galaxy servers
env['ANSIBLE_GALAXY_SERVER_LIST'] = ','.join([server.get('id', 'unnamed') for server in galaxy_servers])
return env
def _build_scm_url_extra_vars(self, project_update):
@@ -2407,7 +2412,7 @@ class RunInventoryUpdate(BaseTask):
@property
def proot_show_paths(self):
return [self.get_path_to('..', 'plugins', 'inventory')]
return [self.get_path_to('..', 'plugins', 'inventory'), settings.AWX_ANSIBLE_COLLECTIONS_PATHS]
def build_private_data(self, inventory_update, private_data_dir):
"""
@@ -2737,9 +2742,12 @@ class RunAdHocCommand(BaseTask):
env['ANSIBLE_LOAD_CALLBACK_PLUGINS'] = '1'
env['ANSIBLE_SFTP_BATCH_MODE'] = 'False'
# Specify empty SSH args (should disable ControlPersist entirely for
# ad hoc commands).
env.setdefault('ANSIBLE_SSH_ARGS', '')
# Create a directory for ControlPath sockets that is unique to each
# ad hoc command and visible inside the proot environment (when enabled).
cp_dir = os.path.join(private_data_dir, 'cp')
if not os.path.exists(cp_dir):
os.mkdir(cp_dir, 0o700)
env['ANSIBLE_SSH_CONTROL_PATH'] = cp_dir
return env

View File

@@ -107,11 +107,6 @@ def workflow_job_template_factory():
return create_workflow_job_template
@pytest.fixture
def get_ssh_version(mocker):
return mocker.patch('awx.main.tasks.get_ssh_version', return_value='OpenSSH_6.9p1, LibreSSL 2.1.8')
@pytest.fixture
def job_template_with_survey_passwords_unit(job_template_with_survey_passwords_factory):
return job_template_with_survey_passwords_factory(persisted=False)

View File

@@ -39,5 +39,5 @@ keyed_groups:
prefix: ''
separator: ''
plain_host_names: true
plugin: azure_rm
plugin: azure.azcollection.azure_rm
use_contrib_script_compatible_sanitization: true

View File

@@ -1,6 +1,6 @@
boto_profile: /tmp/my_boto_stuff
compose:
ansible_host: public_ip_address
ansible_host: public_dns_name
ec2_account_id: owner_id
ec2_ami_launch_index: ami_launch_index | string
ec2_architecture: architecture
@@ -50,9 +50,8 @@ filters:
groups:
ec2: true
hostnames:
- network-interface.addresses.association.public-ip
- dns-name
- private-dns-name
iam_role_arn: arn:aws:iam::123456789012:role/test-role
keyed_groups:
- key: placement.availability_zone
parent_group: zones
@@ -75,7 +74,7 @@ keyed_groups:
parent_group: '{{ placement.region }}'
prefix: ''
separator: ''
plugin: aws_ec2
plugin: amazon.aws.aws_ec2
regions:
- us-east-2
- ap-south-1

View File

@@ -40,7 +40,7 @@ keyed_groups:
- key: image
prefix: ''
separator: ''
plugin: gcp_compute
plugin: google.cloud.gcp_compute
projects:
- fooo
retrieve_image_info: true

View File

@@ -8,6 +8,7 @@ clouds:
auth_url: https://foo.invalid
domain_name: fooo
password: fooo
project_domain_name: fooo
project_name: fooo
username: fooo
private: false

View File

@@ -1,4 +1,4 @@
expand_hostvars: true
fail_on_errors: true
inventory_hostname: uuid
plugin: openstack
plugin: openstack.cloud.openstack

View File

@@ -0,0 +1,7 @@
{
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"OVIRT_INI_PATH": "{{ file_reference }}",
"OVIRT_PASSWORD": "fooo",
"OVIRT_URL": "https://foo.invalid",
"OVIRT_USERNAME": "fooo"
}

View File

@@ -0,0 +1,5 @@
[ovirt]
ovirt_url=https://foo.invalid
ovirt_username=fooo
ovirt_password=fooo
ovirt_ca_file=fooo

View File

@@ -0,0 +1,20 @@
base_source_var: value_of_var
compose:
ansible_host: (devices.values() | list)[0][0] if devices else None
groups:
dev: '"dev" in tags'
keyed_groups:
- key: cluster
prefix: cluster
separator: _
- key: status
prefix: status
separator: _
- key: tags
prefix: tag
separator: _
ovirt_hostname_preference:
- name
- fqdn
ovirt_insecure: false
plugin: ovirt.ovirt.ovirt

View File

@@ -1 +1,29 @@
plugin: foreman
base_source_var: value_of_var
compose:
ansible_ssh_host: foreman['ip6'] | default(foreman['ip'], true)
group_prefix: foo_group_prefix
keyed_groups:
- key: foreman['environment_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_') | regex_replace('none', '')
prefix: foo_group_prefixenvironment_
separator: ''
- key: foreman['location_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
prefix: foo_group_prefixlocation_
separator: ''
- key: foreman['organization_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
prefix: foo_group_prefixorganization_
separator: ''
- key: foreman['content_facet_attributes']['lifecycle_environment_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
prefix: foo_group_prefixlifecycle_environment_
separator: ''
- key: foreman['content_facet_attributes']['content_view_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
prefix: foo_group_prefixcontent_view_
separator: ''
- key: '"%s-%s-%s" | format(app, tier, color)'
separator: ''
- key: '"%s-%s" | format(app, color)'
separator: ''
legacy_hostvars: true
plugin: theforeman.foreman.foreman
want_facts: true
want_hostcollections: true
want_params: true

View File

@@ -1,3 +1,3 @@
include_metadata: true
inventory_id: 42
plugin: tower
plugin: awx.awx.tower

View File

@@ -0,0 +1,7 @@
{
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"VMWARE_HOST": "https://foo.invalid",
"VMWARE_PASSWORD": "fooo",
"VMWARE_USER": "fooo",
"VMWARE_VALIDATE_CERTS": "False"
}

View File

@@ -0,0 +1,55 @@
compose:
ansible_host: guest.ipAddress
ansible_ssh_host: guest.ipAddress
ansible_uuid: 99999999 | random | to_uuid
availablefield: availableField
configissue: configIssue
configstatus: configStatus
customvalue: customValue
effectiverole: effectiveRole
guestheartbeatstatus: guestHeartbeatStatus
layoutex: layoutEx
overallstatus: overallStatus
parentvapp: parentVApp
recenttask: recentTask
resourcepool: resourcePool
rootsnapshot: rootSnapshot
triggeredalarmstate: triggeredAlarmState
filters:
- config.zoo == "DC0_H0_VM0"
hostnames:
- config.foo
keyed_groups:
- key: config.asdf
prefix: ''
separator: ''
plugin: community.vmware.vmware_vm_inventory
properties:
- availableField
- configIssue
- configStatus
- customValue
- datastore
- effectiveRole
- guestHeartbeatStatus
- layout
- layoutEx
- name
- network
- overallStatus
- parentVApp
- permission
- recentTask
- resourcePool
- rootSnapshot
- snapshot
- triggeredAlarmState
- value
- capability
- config
- guest
- runtime
- storage
- summary
strict: false
with_nested_properties: true

View File

@@ -1,9 +1,11 @@
[ec2]
base_source_var = value_of_var
boto_profile = /tmp/my_boto_stuff
iam_role_arn = arn:aws:iam::123456789012:role/test-role
hostname_variable = public_dns_name
destination_variable = public_dns_name
regions = us-east-2,ap-south-1
regions_exclude = us-gov-west-1,cn-north-1
destination_variable = public_dns_name
vpc_destination_variable = ip_address
route53 = False
all_instances = True

View File

@@ -10,6 +10,7 @@ clouds:
auth_url: https://foo.invalid
domain_name: fooo
password: fooo
project_domain_name: fooo
project_name: fooo
username: fooo
private: false

View File

@@ -6,12 +6,12 @@ user = fooo
password = fooo
[ansible]
group_patterns = foo_group_patterns
group_patterns = ["{app}-{tier}-{color}", "{app}-{color}"]
want_facts = True
want_hostcollections = True
group_prefix = foo_group_prefix
want_ansible_ssh_host = True
rich_params = True
rich_params = False
[cache]
path = /tmp

View File

@@ -5,6 +5,7 @@ username = fooo
password = fooo
server = https://foo.invalid
base_source_var = value_of_var
host_filters = foobaa
groupby_patterns = fouo
alias_pattern = {{ config.foo }}
host_filters = {{ config.zoo == "DC0_H0_VM0" }}
groupby_patterns = {{ config.asdf }}

View File

@@ -105,9 +105,6 @@ class TestSwaggerGeneration():
'get', 'put', 'patch', 'delete'
]
# Test deprecated paths
assert paths['/api/v2/jobs/{id}/extra_credentials/']['get']['deprecated'] is True
@pytest.mark.parametrize('path', [
'/api/',
'/api/v2/',
@@ -177,7 +174,7 @@ class TestSwaggerGeneration():
data
)
data = re.sub(
r'"action_node": "awx-[^"]+"',
r'"action_node": "[^"]+"',
'"action_node": "awx"',
data
)

View File

@@ -319,11 +319,11 @@ def create_organization(name, roles=None, persisted=True, **kwargs):
users = generate_users(org, teams, False, persisted, users=kwargs.get('users'))
if 'labels' in kwargs:
for l in kwargs['labels']:
if type(l) is Label:
labels[l.name] = l
for label_obj in kwargs['labels']:
if type(label_obj) is Label:
labels[label_obj.name] = label_obj
else:
labels[l] = mk_label(l, organization=org, persisted=persisted)
labels[label_obj] = mk_label(label_obj, organization=org, persisted=persisted)
if 'notification_templates' in kwargs:
for nt in kwargs['notification_templates']:

View File

@@ -5,6 +5,7 @@ import shutil
import csv
from django.utils.timezone import now
from datetime import timedelta
from django.db.backends.sqlite3.base import SQLiteCursorWrapper
from awx.main.analytics import collectors
@@ -73,7 +74,7 @@ def test_copy_tables_unified_job_query(
Ensure that various unified job types are in the output of the query.
"""
time_start = now()
time_start = now() - timedelta(hours=9)
inv_src = InventorySource.objects.create(
name="inventory_update1", inventory=inventory, source="gce"
)
@@ -87,7 +88,7 @@ def test_copy_tables_unified_job_query(
with tempfile.TemporaryDirectory() as tmpdir:
collectors.copy_tables(time_start, tmpdir, subset="unified_jobs")
with open(os.path.join(tmpdir, "unified_jobs_table.csv")) as f:
lines = "".join([l for l in f])
lines = "".join([line for line in f])
assert project_update_name in lines
assert inventory_update_name in lines
@@ -130,7 +131,7 @@ def workflow_job(states=["new", "new", "new", "new", "new"]):
@pytest.mark.django_db
def test_copy_tables_workflow_job_node_query(sqlite_copy_expert, workflow_job):
time_start = now()
time_start = now() - timedelta(hours=9)
with tempfile.TemporaryDirectory() as tmpdir:
collectors.copy_tables(time_start, tmpdir, subset="workflow_job_node_query")
@@ -138,9 +139,9 @@ def test_copy_tables_workflow_job_node_query(sqlite_copy_expert, workflow_job):
reader = csv.reader(f)
# Pop the headers
next(reader)
lines = [l for l in reader]
lines = [line for line in reader]
ids = [int(l[0]) for l in lines]
ids = [int(line[0]) for line in lines]
assert ids == list(
workflow_job.workflow_nodes.all().values_list("id", flat=True)

View File

@@ -24,41 +24,6 @@ def job_template(job_template, project, inventory):
return job_template
@pytest.mark.django_db
def test_extra_credentials_filtering(get, job_template, admin,
machine_credential, vault_credential, credential):
job_template.credentials.add(machine_credential)
job_template.credentials.add(vault_credential)
job_template.credentials.add(credential)
url = reverse(
'api:job_template_extra_credentials_list',
kwargs={'pk': job_template.pk}
)
resp = get(url, admin, expect=200)
assert resp.data['count'] == 1
assert resp.data['results'][0]['id'] == credential.pk
@pytest.mark.django_db
def test_extra_credentials_requires_cloud_or_net(get, post, job_template, admin,
machine_credential, vault_credential, credential,
net_credential):
url = reverse(
'api:job_template_extra_credentials_list',
kwargs={'pk': job_template.pk}
)
for cred in (machine_credential, vault_credential):
resp = post(url, {'associate': True, 'id': cred.pk}, admin, expect=400)
assert 'Extra credentials must be network or cloud.' in smart_str(resp.content)
post(url, {'associate': True, 'id': credential.pk}, admin, expect=204)
assert get(url, admin).data['count'] == 1
post(url, {'associate': True, 'id': net_credential.pk}, admin, expect=204)
assert get(url, admin).data['count'] == 2
@pytest.mark.django_db
def test_prevent_multiple_machine_creds(get, post, job_template, admin, machine_credential):
url = reverse(
@@ -115,52 +80,6 @@ def test_prevent_multiple_machine_creds_at_launch(get, post, job_template, admin
assert 'Cannot assign multiple Machine credentials.' in smart_str(resp.content)
@pytest.mark.django_db
def test_extra_credentials_unique_by_kind(get, post, job_template, admin,
credentialtype_aws):
url = reverse(
'api:job_template_extra_credentials_list',
kwargs={'pk': job_template.pk}
)
def _new_cred(name):
return {
'name': name,
'credential_type': credentialtype_aws.pk,
'inputs': {
'username': 'bob',
'password': 'secret',
}
}
post(url, _new_cred('First Cred'), admin, expect=201)
assert get(url, admin).data['count'] == 1
resp = post(url, _new_cred('Second Cred'), admin, expect=400)
assert 'Cannot assign multiple Amazon Web Services credentials.' in smart_str(resp.content)
@pytest.mark.django_db
def test_extra_credentials_at_launch(get, post, job_template, admin, credential):
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
pk = post(url, {'extra_credentials': [credential.pk]}, admin, expect=201).data['job']
summary_fields = get(reverse('api:job_detail', kwargs={'pk': pk}), admin).data['summary_fields']
assert len(summary_fields['credentials']) == 1
@pytest.mark.django_db
def test_modify_extra_credentials_at_launch(get, post, job_template, admin,
machine_credential, vault_credential, credential):
job_template.credentials.add(machine_credential)
job_template.credentials.add(vault_credential)
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
pk = post(url, {'extra_credentials': [credential.pk]}, admin, expect=201).data['job']
summary_fields = get(reverse('api:job_detail', kwargs={'pk': pk}), admin).data['summary_fields']
assert len(summary_fields['credentials']) == 3
@pytest.mark.django_db
def test_ssh_password_prompted_at_launch(get, post, job_template, admin, machine_credential):
job_template.credentials.add(machine_credential)
@@ -229,25 +148,6 @@ def test_vault_credential_with_password_at_launch(get, post, job_template, admin
signal_start.assert_called_with(vault_password='testing123')
@pytest.mark.django_db
def test_extra_creds_prompted_at_launch(get, post, job_template, admin, net_credential):
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
resp = post(url, {'extra_credentials': [net_credential.pk]}, admin, expect=201)
summary_fields = get(
reverse('api:job_detail', kwargs={'pk': resp.data['job']}),
admin
).data['summary_fields']
assert len(summary_fields['credentials']) == 1
@pytest.mark.django_db
def test_invalid_mixed_credentials_specification(get, post, job_template, admin, net_credential):
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
post(url=url, data={'credentials': [net_credential.pk], 'extra_credentials': [net_credential.pk]},
user=admin, expect=400)
@pytest.mark.django_db
def test_deprecated_credential_activity_stream(patch, admin_user, machine_credential, job_template):
job_template.credentials.add(machine_credential)

View File

@@ -22,20 +22,6 @@ from awx.main.models import (
)
@pytest.mark.django_db
def test_extra_credentials(get, organization_factory, job_template_factory, credential):
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
jt.credentials.add(credential)
jt.save()
job = jt.create_unified_job()
url = reverse('api:job_extra_credentials_list', kwargs={'pk': job.pk})
response = get(url, user=objs.superusers.admin)
assert response.data.get('count') == 1
@pytest.mark.django_db
def test_job_relaunch_permission_denied_response(
post, get, inventory, project, credential, net_credential, machine_credential):
@@ -50,7 +36,7 @@ def test_job_relaunch_permission_denied_response(
r = get(job.get_absolute_url(), jt_user, expect=200)
assert r.data['summary_fields']['user_capabilities']['start']
# Job has prompted extra_credential, launch denied w/ message
# Job has prompted credential, launch denied w/ message
job.launch_config.credentials.add(net_credential)
r = post(reverse('api:job_relaunch', kwargs={'pk':job.pk}), {}, jt_user, expect=403)
assert 'launched with prompted fields you do not have access to' in r.data['detail']
@@ -70,7 +56,7 @@ def test_job_relaunch_prompts_not_accepted_response(
r = get(job.get_absolute_url(), jt_user, expect=200)
assert r.data['summary_fields']['user_capabilities']['start']
# Job has prompted extra_credential, launch denied w/ message
# Job has prompted credential, launch denied w/ message
job.launch_config.credentials.add(net_credential)
r = post(reverse('api:job_relaunch', kwargs={'pk':job.pk}), {}, jt_user, expect=403)

View File

@@ -304,7 +304,7 @@ def test_job_launch_with_default_creds(machine_credential, vault_credential, dep
@pytest.mark.django_db
def test_job_launch_JT_enforces_unique_credentials_kinds(machine_credential, credentialtype_aws, deploy_jobtemplate):
"""
JT launching should require that extra_credentials have distinct CredentialTypes
JT launching should require that credentials have distinct CredentialTypes
"""
creds = []
for i in range(2):

View File

@@ -45,27 +45,6 @@ def test_create(post, project, machine_credential, inventory, alice, grant_proje
)
@pytest.mark.django_db
def test_extra_credential_creation(get, post, organization_factory, job_template_factory, credentialtype_aws):
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
response = post(url, {
'name': 'My Cred',
'credential_type': credentialtype_aws.pk,
'inputs': {
'username': 'bob',
'password': 'secret',
}
}, objs.superusers.admin)
assert response.status_code == 201
response = get(url, user=objs.superusers.admin)
assert response.data.get('count') == 1
@pytest.mark.django_db
@pytest.mark.parametrize('kind', ['scm', 'insights'])
def test_invalid_credential_kind_xfail(get, post, organization_factory, job_template_factory, kind):
@@ -87,42 +66,6 @@ def test_invalid_credential_kind_xfail(get, post, organization_factory, job_temp
assert 'Cannot assign a Credential of kind `{}`.'.format(kind) in response.data.values()
@pytest.mark.django_db
def test_extra_credential_unique_type_xfail(get, post, organization_factory, job_template_factory, credentialtype_aws):
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
response = post(url, {
'name': 'My Cred',
'credential_type': credentialtype_aws.pk,
'inputs': {
'username': 'bob',
'password': 'secret',
}
}, objs.superusers.admin)
assert response.status_code == 201
response = get(url, user=objs.superusers.admin)
assert response.data.get('count') == 1
# this request should fail because you can't assign the same type (aws)
# twice
response = post(url, {
'name': 'My Cred',
'credential_type': credentialtype_aws.pk,
'inputs': {
'username': 'joe',
'password': 'another-secret',
}
}, objs.superusers.admin)
assert response.status_code == 400
response = get(url, user=objs.superusers.admin)
assert response.data.get('count') == 1
@pytest.mark.django_db
def test_create_with_forks_exceeding_maximum_xfail(alice, post, project, inventory, settings):
project.use_role.members.add(alice)
@@ -143,60 +86,6 @@ def test_create_with_forks_exceeding_maximum_xfail(alice, post, project, invento
assert 'Maximum number of forks (10) exceeded' in str(response.data)
@pytest.mark.django_db
def test_attach_extra_credential(get, post, organization_factory, job_template_factory, credential):
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
response = post(url, {
'associate': True,
'id': credential.id,
}, objs.superusers.admin)
assert response.status_code == 204
response = get(url, user=objs.superusers.admin)
assert response.data.get('count') == 1
@pytest.mark.django_db
def test_detach_extra_credential(get, post, organization_factory, job_template_factory, credential):
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
jt.credentials.add(credential)
jt.save()
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
response = post(url, {
'disassociate': True,
'id': credential.id,
}, objs.superusers.admin)
assert response.status_code == 204
response = get(url, user=objs.superusers.admin)
assert response.data.get('count') == 0
@pytest.mark.django_db
def test_attach_extra_credential_wrong_kind_xfail(get, post, organization_factory, job_template_factory, machine_credential):
"""Extra credentials only allow net + cloud credentials"""
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
response = post(url, {
'associate': True,
'id': machine_credential.id,
}, objs.superusers.admin)
assert response.status_code == 400
response = get(url, user=objs.superusers.admin)
assert response.data.get('count') == 0
@pytest.mark.django_db
@pytest.mark.parametrize(
"grant_project, grant_inventory, expect", [
@@ -368,57 +257,6 @@ def test_launch_with_pending_deletion_inventory_workflow(get, post, organization
assert resp.data['inventory'] == ['The inventory associated with this Workflow is being deleted.']
@pytest.mark.django_db
def test_launch_with_extra_credentials(get, post, organization_factory,
job_template_factory, machine_credential,
credential, net_credential):
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
jt.ask_credential_on_launch = True
jt.save()
resp = post(
reverse('api:job_template_launch', kwargs={'pk': jt.pk}),
dict(
credentials=[machine_credential.pk, credential.pk, net_credential.pk]
),
objs.superusers.admin, expect=201
)
job_pk = resp.data.get('id')
resp = get(reverse('api:job_extra_credentials_list', kwargs={'pk': job_pk}), objs.superusers.admin)
assert resp.data.get('count') == 2
resp = get(reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk}), objs.superusers.admin)
assert resp.data.get('count') == 0
@pytest.mark.django_db
def test_launch_with_extra_credentials_not_allowed(get, post, organization_factory,
job_template_factory, machine_credential,
credential, net_credential):
objs = organization_factory("org", superusers=['admin'])
jt = job_template_factory("jt", organization=objs.organization,
inventory='test_inv', project='test_proj').job_template
jt.credentials.add(machine_credential)
jt.ask_credential_on_launch = False
jt.save()
resp = post(
reverse('api:job_template_launch', kwargs={'pk': jt.pk}),
dict(
credentials=[machine_credential.pk, credential.pk, net_credential.pk]
),
objs.superusers.admin
)
assert 'credentials' in resp.data['ignored_fields'].keys()
job_pk = resp.data.get('id')
resp = get(reverse('api:job_extra_credentials_list', kwargs={'pk': job_pk}), objs.superusers.admin)
assert resp.data.get('count') == 0
@pytest.mark.django_db
def test_jt_without_project(inventory):
data = dict(name="Test", job_type="run",

View File

@@ -71,6 +71,18 @@ def test_node_accepts_prompted_fields(inventory, project, workflow_job_template,
user=admin_user, expect=201)
@pytest.mark.django_db
@pytest.mark.parametrize("field_name, field_value", [
('all_parents_must_converge', True),
('all_parents_must_converge', False),
])
def test_create_node_with_field(field_name, field_value, workflow_job_template, post, admin_user):
url = reverse('api:workflow_job_template_workflow_nodes_list',
kwargs={'pk': workflow_job_template.pk})
res = post(url, {field_name: field_value}, user=admin_user, expect=201)
assert res.data[field_name] == field_value
@pytest.mark.django_db
class TestApprovalNodes():
def test_approval_node_creation(self, post, approval_node, admin_user):

View File

@@ -65,6 +65,7 @@ class TestKeyRegeneration:
assert nc['token'].startswith(PREFIX)
Slack = nt.CLASS_FOR_NOTIFICATION_TYPE[nt.notification_type]
class TestBackend(Slack):
def __init__(self, *args, **kw):

View File

@@ -1,7 +1,9 @@
from unittest import mock
import pytest
from awx.main.models import Job, JobEvent
from django.utils.timezone import now
from awx.main.models import Job, JobEvent, Inventory, Host
@pytest.mark.django_db
@@ -61,3 +63,93 @@ def test_parent_failed(emit, event):
assert events.count() == 2
for e in events.all():
assert e.failed is True
@pytest.mark.django_db
def test_host_summary_generation():
hostnames = [f'Host {i}' for i in range(100)]
inv = Inventory()
inv.save()
Host.objects.bulk_create([
Host(created=now(), modified=now(), name=h, inventory_id=inv.id)
for h in hostnames
])
j = Job(inventory=inv)
j.save()
host_map = dict((host.name, host.id) for host in inv.hosts.all())
JobEvent.create_from_data(
job_id=j.pk,
parent_uuid='abc123',
event='playbook_on_stats',
event_data={
'ok': dict((hostname, len(hostname)) for hostname in hostnames),
'changed': {},
'dark': {},
'failures': {},
'ignored': {},
'processed': {},
'rescued': {},
'skipped': {},
},
host_map=host_map
).save()
assert j.job_host_summaries.count() == len(hostnames)
assert sorted([s.host_name for s in j.job_host_summaries.all()]) == sorted(hostnames)
for s in j.job_host_summaries.all():
assert host_map[s.host_name] == s.host_id
assert s.ok == len(s.host_name)
assert s.changed == 0
assert s.dark == 0
assert s.failures == 0
assert s.ignored == 0
assert s.processed == 0
assert s.rescued == 0
assert s.skipped == 0
for host in Host.objects.all():
assert host.last_job_id == j.id
assert host.last_job_host_summary.host == host
@pytest.mark.django_db
def test_host_summary_generation_with_deleted_hosts():
hostnames = [f'Host {i}' for i in range(10)]
inv = Inventory()
inv.save()
Host.objects.bulk_create([
Host(created=now(), modified=now(), name=h, inventory_id=inv.id)
for h in hostnames
])
j = Job(inventory=inv)
j.save()
host_map = dict((host.name, host.id) for host in inv.hosts.all())
# delete half of the hosts during the playbook run
for h in inv.hosts.all()[:5]:
h.delete()
JobEvent.create_from_data(
job_id=j.pk,
parent_uuid='abc123',
event='playbook_on_stats',
event_data={
'ok': dict((hostname, len(hostname)) for hostname in hostnames),
'changed': {},
'dark': {},
'failures': {},
'ignored': {},
'processed': {},
'rescued': {},
'skipped': {},
},
host_map=host_map
).save()
ids = sorted([s.host_id or -1 for s in j.job_host_summaries.order_by('id').all()])
names = sorted([s.host_name for s in j.job_host_summaries.all()])
assert ids == [-1, -1, -1, -1, -1, 6, 7, 8, 9, 10]
assert names == ['Host 0', 'Host 1', 'Host 2', 'Host 3', 'Host 4', 'Host 5',
'Host 6', 'Host 7', 'Host 8', 'Host 9']

View File

@@ -105,7 +105,10 @@ class TestJobNotificationMixin(object):
assert isinstance(obj[key], dict)
check_structure(expected_structure[key], obj[key])
else:
assert isinstance(obj[key], expected_structure[key])
if key == 'job_explanation':
assert isinstance(str(obj[key]), expected_structure[key])
else:
assert isinstance(obj[key], expected_structure[key])
kwargs = {}
if JobClass is InventoryUpdate:
kwargs['inventory_source'] = inventory_source

View File

@@ -18,6 +18,8 @@ from awx.main.dispatch.worker import BaseWorker, TaskWorker
'''
Prevent logger.<warn, debug, error> calls from triggering database operations
'''
@pytest.fixture(autouse=True)
def _disable_database_settings(mocker):
m = mocker.patch('awx.conf.settings.SettingsWrapper.all_supported_settings', new_callable=mock.PropertyMock)

View File

@@ -16,7 +16,7 @@ DATA = os.path.join(os.path.dirname(data.__file__), 'inventory')
TEST_SOURCE_FIELDS = {
'vmware': {
'instance_filters': 'foobaa',
'instance_filters': '{{ config.name == "only_my_server" }},{{ somevar == "bar"}}',
'group_by': 'fouo'
},
'ec2': {
@@ -38,7 +38,10 @@ TEST_SOURCE_FIELDS = {
INI_TEST_VARS = {
'ec2': {
'boto_profile': '/tmp/my_boto_stuff'
'boto_profile': '/tmp/my_boto_stuff',
'iam_role_arn': 'arn:aws:iam::123456789012:role/test-role',
'hostname_variable': 'public_dns_name',
'destination_variable': 'public_dns_name'
},
'gce': {},
'openstack': {
@@ -47,9 +50,11 @@ INI_TEST_VARS = {
'expand_hostvars': True,
'fail_on_errors': True
},
'rhv': {}, # there are none
'tower': {}, # there are none
'vmware': {
'alias_pattern': "{{ config.foo }}",
'host_filters': '{{ config.zoo == "DC0_H0_VM0" }}',
'groupby_patterns': "{{ config.asdf }}",
# setting VMWARE_VALIDATE_CERTS is duplicated with env var
},
'azure_rm': {
@@ -58,11 +63,10 @@ INI_TEST_VARS = {
'tags': 'Creator:jmarshall, peanutbutter:jelly'
},
'satellite6': {
'satellite6_group_patterns': 'foo_group_patterns',
'satellite6_group_patterns': '["{app}-{tier}-{color}", "{app}-{color}"]',
'satellite6_group_prefix': 'foo_group_prefix',
'satellite6_want_hostcollections': True,
'satellite6_want_ansible_ssh_host': True,
'satellite6_rich_params': True,
'satellite6_want_facts': True
},
@@ -73,6 +77,12 @@ INI_TEST_VARS = {
'nest_tags': 'yes',
'suffix': '.ppt',
'prefer_ipv4': 'yes'
},
'rhv': { # options specific to the plugin
'ovirt_insecure': False,
'groups': {
'dev': '"dev" in tags'
}
}
}
@@ -315,9 +325,10 @@ def test_inventory_update_injected_content(this_kind, script_or_plugin, inventor
with mock.patch('awx.main.models.inventory.PluginFileInjector.should_use_plugin', return_value=use_plugin):
# Also do not send websocket status updates
with mock.patch.object(UnifiedJob, 'websocket_emit_status', mock.Mock()):
# The point of this test is that we replace run with assertions
with mock.patch('awx.main.tasks.ansible_runner.interface.run', substitute_run):
# mocking the licenser is necessary for the tower source
with mock.patch('awx.main.models.inventory.get_licenser', mock_licenser):
# so this sets up everything for a run and then yields control over to substitute_run
task.run(inventory_update.pk)
with mock.patch.object(task, 'get_ansible_version', return_value='2.13'):
# The point of this test is that we replace run with assertions
with mock.patch('awx.main.tasks.ansible_runner.interface.run', substitute_run):
# mocking the licenser is necessary for the tower source
with mock.patch('awx.main.models.inventory.get_licenser', mock_licenser):
# so this sets up everything for a run and then yields control over to substitute_run
task.run(inventory_update.pk)

View File

@@ -0,0 +1,37 @@
import pytest
# awx
from awx.main.models import WorkflowJobTemplate
from awx.api.versioning import reverse
@pytest.mark.django_db
def test_workflow_can_add_label(org_admin,organization, post):
# create workflow
wfjt = WorkflowJobTemplate.objects.create(name='test-wfjt')
wfjt.organization = organization
# create label
wfjt.admin_role.members.add(org_admin)
url = reverse('api:workflow_job_template_label_list', kwargs={'pk': wfjt.pk})
data = {'name': 'dev-label', 'organization': organization.id}
label = post(url, user=org_admin, data=data, expect=201)
assert label.data['name'] == 'dev-label'
@pytest.mark.django_db
def test_workflow_can_remove_label(org_admin, organization, post, get):
# create workflow
wfjt = WorkflowJobTemplate.objects.create(name='test-wfjt')
wfjt.organization = organization
# create label
wfjt.admin_role.members.add(org_admin)
label = wfjt.labels.create(name='dev-label', organization=organization)
# delete label
url = reverse('api:workflow_job_template_label_list', kwargs={'pk': wfjt.pk})
data = {
"id": label.pk,
"disassociate": True
}
post(url, data, org_admin, expect=204)
results = get(url, org_admin, expect=200)
assert results.data['count'] == 0

View File

@@ -128,7 +128,7 @@ def test_job_template_access_admin(role_names, jt_linked, rando):
@pytest.mark.django_db
def test_job_template_extra_credentials_prompts_access(
def test_job_template_credentials_prompts_access(
rando, post, inventory, project, machine_credential, vault_credential):
jt = JobTemplate.objects.create(
name = 'test-jt',
@@ -149,14 +149,14 @@ def test_job_template_extra_credentials_prompts_access(
@pytest.mark.django_db
class TestJobTemplateCredentials:
def test_job_template_cannot_add_extra_credentials(self, job_template, credential, rando):
def test_job_template_cannot_add_credentials(self, job_template, credential, rando):
job_template.admin_role.members.add(rando)
credential.read_role.members.add(rando)
# without permission to credential, user can not attach it
assert not JobTemplateAccess(rando).can_attach(
job_template, credential, 'credentials', {})
def test_job_template_can_add_extra_credentials(self, job_template, credential, rando):
def test_job_template_can_add_credentials(self, job_template, credential, rando):
job_template.admin_role.members.add(rando)
credential.use_role.members.add(rando)
# user has permission to apply credential

View File

@@ -0,0 +1,69 @@
import datetime
from awx.main.analytics.broadcast_websocket import FixedSlidingWindow
from awx.main.analytics.broadcast_websocket import dt_to_seconds
class TestFixedSlidingWindow():
def ts(self, **kwargs):
e = {
'year': 1985,
'month': 1,
'day': 1,
'hour': 1,
}
return dt_to_seconds(datetime.datetime(**kwargs, **e))
def test_record_same_minute(self):
"""
Legend:
- = record()
^ = render()
|---| = 1 minute, 60 seconds
....................
|------------------------------------------------------------|
^^^^^^^^^^^^^^^^^^^^
"""
fsw = FixedSlidingWindow(self.ts(minute=0, second=0, microsecond=0))
for i in range(20):
fsw.record(self.ts(minute=0, second=i, microsecond=0))
assert (i + 1) == fsw.render(self.ts(minute=0, second=i, microsecond=0))
def test_record_same_minute_render_diff_minute(self):
"""
Legend:
- = record()
^ = render()
|---| = 1 minute, 60 seconds
....................
|------------------------------------------------------------|
^^ ^
AB C
|------------------------------------------------------------|
^^^^^^^^^^^^^^^^^^^^^
DEEEEEEEEEEEEEEEEEEEF
"""
fsw = FixedSlidingWindow(self.ts(minute=0, second=0, microsecond=0))
for i in range(20):
fsw.record(self.ts(minute=0, second=i, microsecond=0))
assert 20 == fsw.render(self.ts(minute=0, second=19, microsecond=0)), \
"A. The second of the last record() call"
assert 20 == fsw.render(self.ts(minute=0, second=20, microsecond=0)), \
"B. The second after the last record() call"
assert 20 == fsw.render(self.ts(minute=0, second=59, microsecond=0)), \
"C. Last second in the same minute that all record() called in"
assert 20 == fsw.render(self.ts(minute=1, second=0, microsecond=0)), \
"D. First second of the minute following the minute that all record() calls in"
for i in range(20):
assert 20 - i == fsw.render(self.ts(minute=1, second=i, microsecond=0)), \
"E. Sliding window where 1 record() should drop from the results each time"
assert 0 == fsw.render(self.ts(minute=1, second=20, microsecond=0)), \
"F. First second one minute after all record() calls"

View File

@@ -35,7 +35,7 @@ data_loggly = {
# Test reconfigure logging settings function
# name this whatever you want
@pytest.mark.parametrize(
'enabled, type, host, port, protocol, expected_config', [
'enabled, log_type, host, port, protocol, expected_config', [
(
True,
'loggly',
@@ -44,7 +44,7 @@ data_loggly = {
'https',
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="logs-01.loggly.com" serverport="80" usehttps="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="inputs/1fd38090-2af1-4e1e-8d80-492899da0f71/tag/http/")', # noqa
'action(type="omhttp" server="logs-01.loggly.com" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="inputs/1fd38090-2af1-4e1e-8d80-492899da0f71/tag/http/")', # noqa
])
),
(
@@ -77,7 +77,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="443" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="443" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -88,7 +88,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="80" usehttps="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="80" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -99,7 +99,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -110,7 +110,7 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -121,7 +121,7 @@ data_loggly = {
'https',
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="on" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
@@ -132,12 +132,23 @@ data_loggly = {
None,
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
'action(type="omhttp" server="yoursplunk.org" serverport="8088" usehttps="off" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="services/collector/event")', # noqa
])
),
(
True, # valid sumologic config
'sumologic',
'https://endpoint5.collection.us2.sumologic.com/receiver/v1/http/ZaVnC4dhaV0qoiETY0MrM3wwLoDgO1jFgjOxE6-39qokkj3LGtOroZ8wNaN2M6DtgYrJZsmSi4-36_Up5TbbN_8hosYonLKHSSOSKY845LuLZBCBwStrHQ==', # noqa
None,
'https',
'\n'.join([
'template(name="awx" type="string" string="%rawmsg-after-pri%")\nmodule(load="omhttp")',
'action(type="omhttp" server="endpoint5.collection.us2.sumologic.com" serverport="443" usehttps="on" allowunsignedcerts="off" skipverifyhost="off" action.resumeRetryCount="-1" template="awx" errorfile="/var/log/tower/rsyslog.err" action.resumeInterval="5" restpath="receiver/v1/http/ZaVnC4dhaV0qoiETY0MrM3wwLoDgO1jFgjOxE6-39qokkj3LGtOroZ8wNaN2M6DtgYrJZsmSi4-36_Up5TbbN_8hosYonLKHSSOSKY845LuLZBCBwStrHQ==")', # noqa
])
),
]
)
def test_rsyslog_conf_template(enabled, type, host, port, protocol, expected_config):
def test_rsyslog_conf_template(enabled, log_type, host, port, protocol, expected_config):
mock_settings, _ = _mock_logging_defaults()
@@ -146,7 +157,7 @@ def test_rsyslog_conf_template(enabled, type, host, port, protocol, expected_con
setattr(mock_settings, 'LOGGING', logging_defaults)
setattr(mock_settings, 'LOGGING["handlers"]["external_logger"]["address"]', '/var/run/awx-rsyslog/rsyslog.sock')
setattr(mock_settings, 'LOG_AGGREGATOR_ENABLED', enabled)
setattr(mock_settings, 'LOG_AGGREGATOR_TYPE', type)
setattr(mock_settings, 'LOG_AGGREGATOR_TYPE', log_type)
setattr(mock_settings, 'LOG_AGGREGATOR_HOST', host)
if port:
setattr(mock_settings, 'LOG_AGGREGATOR_PORT', port)

View File

@@ -183,6 +183,51 @@ def test_openstack_client_config_generation(mocker, source, expected, private_da
}
@pytest.mark.parametrize("source,expected", [
(None, True), (False, False), (True, True)
])
def test_openstack_client_config_generation_with_project_domain_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',
}
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)
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", [
(False, False), (True, True)
])
@@ -1807,8 +1852,9 @@ class TestInventoryUpdateCredentials(TestJobExecution):
inventory_update.get_cloud_credential = mocker.Mock(return_value=None)
inventory_update.get_extra_credentials = mocker.Mock(return_value=[])
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)
with mocker.patch('awx.main.tasks._get_ansible_version', mocker.MagicMock(return_value='2.7')):
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)
assert 'AWS_ACCESS_KEY_ID' not in env
assert 'AWS_SECRET_ACCESS_KEY' not in env
@@ -1915,8 +1961,9 @@ class TestInventoryUpdateCredentials(TestJobExecution):
inventory_update.get_cloud_credential = get_cred
inventory_update.get_extra_credentials = mocker.Mock(return_value=[])
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)
with mocker.patch('awx.main.tasks._get_ansible_version', mocker.MagicMock(return_value='2.7')):
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 = {}
credentials = task.build_credentials_list(inventory_update)
@@ -2153,8 +2200,9 @@ class TestInventoryUpdateCredentials(TestJobExecution):
'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)
with mocker.patch('awx.main.tasks._get_ansible_version', mocker.MagicMock(return_value='2.7')):
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)
config = configparser.ConfigParser()
config.read(env['FOREMAN_INI_PATH'])

View File

@@ -64,7 +64,6 @@ def could_be_playbook(project_path, dir_path, filename):
matched = True
break
except IOError:
logger.exception(f'failed to open {playbook_path}')
return None
if not matched:
return None

View File

@@ -43,7 +43,7 @@ logger = logging.getLogger('awx.main.utils')
__all__ = [
'get_object_or_400', 'camelcase_to_underscore', 'underscore_to_camelcase', 'memoize',
'memoize_delete', 'get_ansible_version', 'get_ssh_version', 'get_licenser', 'get_awx_http_client_headers',
'memoize_delete', 'get_ansible_version', 'get_licenser', 'get_awx_http_client_headers',
'get_awx_version', 'update_scm_url', 'get_type_for_model', 'get_model_for_type',
'copy_model_by_class', 'region_sorting', 'copy_m2m_relationships',
'prefetch_page_capabilities', 'to_python_boolean', 'ignore_inventory_computed_fields',
@@ -190,20 +190,6 @@ def get_ansible_version():
return _get_ansible_version('ansible')
@memoize()
def get_ssh_version():
'''
Return SSH version installed.
'''
try:
proc = subprocess.Popen(['ssh', '-V'],
stderr=subprocess.PIPE)
result = smart_str(proc.communicate()[1])
return result.split(" ")[0].split("_")[1]
except Exception:
return 'unknown'
def get_awx_version():
'''
Return AWX version as reported by setuptools.
@@ -1024,14 +1010,17 @@ def get_custom_venv_choices(custom_paths=None):
custom_venv_choices = []
for custom_venv_path in all_venv_paths:
if os.path.exists(custom_venv_path):
custom_venv_choices.extend([
os.path.join(custom_venv_path, x, '')
for x in os.listdir(custom_venv_path)
if x != 'awx' and
os.path.isdir(os.path.join(custom_venv_path, x)) and
os.path.exists(os.path.join(custom_venv_path, x, 'bin', 'activate'))
])
try:
if os.path.exists(custom_venv_path):
custom_venv_choices.extend([
os.path.join(custom_venv_path, x, '')
for x in os.listdir(custom_venv_path)
if x != 'awx' and
os.path.isdir(os.path.join(custom_venv_path, x)) and
os.path.exists(os.path.join(custom_venv_path, x, 'bin', 'activate'))
])
except Exception:
logger.exception("Encountered an error while discovering custom virtual environments.")
return custom_venv_choices

View File

@@ -1,5 +1,6 @@
import os
import shutil
import tempfile
import urllib.parse as urlparse
from django.conf import settings
@@ -22,6 +23,8 @@ def construct_rsyslog_conf_template(settings=settings):
spool_directory = '/var/lib/awx'
max_bytes = settings.MAX_EVENT_RES_DATA
if settings.LOG_AGGREGATOR_RSYSLOGD_DEBUG:
parts.append('$DebugLevel 2')
parts.extend([
'$WorkDirectory /var/lib/awx/rsyslog',
f'$MaxMessageSize {max_bytes}',
@@ -58,6 +61,7 @@ def construct_rsyslog_conf_template(settings=settings):
# https://github.com/rsyslog/rsyslog-doc/blob/master/source/configuration/modules/omhttp.rst
ssl = 'on' if parsed.scheme == 'https' else 'off'
skip_verify = 'off' if settings.LOG_AGGREGATOR_VERIFY_CERT else 'on'
allow_unsigned = 'off' if settings.LOG_AGGREGATOR_VERIFY_CERT else 'on'
if not port:
port = 443 if parsed.scheme == 'https' else 80
@@ -66,6 +70,7 @@ def construct_rsyslog_conf_template(settings=settings):
f'server="{host}"',
f'serverport="{port}"',
f'usehttps="{ssl}"',
f'allowunsignedcerts="{allow_unsigned}"',
f'skipverifyhost="{skip_verify}"',
'action.resumeRetryCount="-1"',
'template="awx"',
@@ -73,7 +78,7 @@ def construct_rsyslog_conf_template(settings=settings):
f'action.resumeInterval="{timeout}"'
]
if parsed.path:
path = urlparse.quote(parsed.path[1:])
path = urlparse.quote(parsed.path[1:], safe='/=')
if parsed.query:
path = f'{path}?{urlparse.quote(parsed.query)}'
params.append(f'restpath="{path}"')
@@ -108,6 +113,10 @@ def construct_rsyslog_conf_template(settings=settings):
def reconfigure_rsyslog():
tmpl = construct_rsyslog_conf_template()
with open('/var/lib/awx/rsyslog/rsyslog.conf', 'w') as f:
f.write(tmpl + '\n')
# Write config to a temp file then move it to preserve atomicity
with tempfile.TemporaryDirectory(prefix='rsyslog-conf-') as temp_dir:
path = temp_dir + '/rsyslog.conf.temp'
with open(path, 'w') as f:
f.write(tmpl + '\n')
shutil.move(path, '/var/lib/awx/rsyslog/rsyslog.conf')
supervisor_service_command(command='restart', service='awx-rsyslogd')

View File

@@ -127,14 +127,14 @@ class LogstashFormatter(LogstashFormatterBase):
pass # best effort here, if it's not valid JSON, then meh
return raw_data
elif kind == 'system_tracking':
data = copy(raw_data['ansible_facts'])
data = copy(raw_data.get('ansible_facts', {}))
else:
data = copy(raw_data)
if isinstance(data, str):
data = json.loads(data)
data_for_log = {}
if kind == 'job_events':
if kind == 'job_events' and raw_data.get('python_objects', {}).get('job_event'):
job_event = raw_data['python_objects']['job_event']
for field_object in job_event._meta.fields:
@@ -165,10 +165,10 @@ class LogstashFormatter(LogstashFormatterBase):
data['ansible_python'].pop('version_info', None)
data_for_log['ansible_facts'] = data
data_for_log['ansible_facts_modified'] = raw_data['ansible_facts_modified']
data_for_log['inventory_id'] = raw_data['inventory_id']
data_for_log['host_name'] = raw_data['host_name']
data_for_log['job_id'] = raw_data['job_id']
data_for_log['ansible_facts_modified'] = raw_data.get('ansible_facts_modified')
data_for_log['inventory_id'] = raw_data.get('inventory_id')
data_for_log['host_name'] = raw_data.get('host_name')
data_for_log['job_id'] = raw_data.get('job_id')
elif kind == 'performance':
def convert_to_type(t, val):
if t is float:

View File

@@ -13,6 +13,10 @@ class RSysLogHandler(logging.handlers.SysLogHandler):
append_nul = False
def _connect_unixsocket(self, address):
super(RSysLogHandler, self)._connect_unixsocket(address)
self.socket.setblocking(False)
def emit(self, msg):
if not settings.LOG_AGGREGATOR_ENABLED:
return
@@ -26,6 +30,14 @@ class RSysLogHandler(logging.handlers.SysLogHandler):
# unfortunately, we can't log that because...rsyslogd is down (and
# would just us back ddown this code path)
pass
except BlockingIOError:
# for <some reason>, rsyslogd is no longer reading from the domain socket, and
# we're unable to write any more to it without blocking (we've seen this behavior
# from time to time when logging is totally misconfigured;
# in this scenario, it also makes more sense to just drop the messages,
# because the alternative is blocking the socket.send() in the
# Python process, which we definitely don't want to do)
pass
ColorHandler = logging.StreamHandler

View File

@@ -37,7 +37,7 @@ def get_broadcast_hosts():
.order_by('hostname') \
.values('hostname', 'ip_address') \
.distinct()
return [i['ip_address'] or i['hostname'] for i in instances]
return {i['hostname']: i['ip_address'] or i['hostname'] for i in instances}
def get_local_host():
@@ -149,19 +149,33 @@ class BroadcastWebsocketTask(WebsocketTask):
class BroadcastWebsocketManager(object):
def __init__(self):
self.event_loop = asyncio.get_event_loop()
'''
{
'hostname1': BroadcastWebsocketTask(),
'hostname2': BroadcastWebsocketTask(),
'hostname3': BroadcastWebsocketTask(),
}
'''
self.broadcast_tasks = dict()
# parallel dict to broadcast_tasks that tracks stats
self.local_hostname = get_local_host()
self.stats_mgr = BroadcastWebsocketStatsManager(self.event_loop, self.local_hostname)
async def run_per_host_websocket(self):
while True:
future_remote_hosts = get_broadcast_hosts()
known_hosts = get_broadcast_hosts()
future_remote_hosts = known_hosts.keys()
current_remote_hosts = self.broadcast_tasks.keys()
deleted_remote_hosts = set(current_remote_hosts) - set(future_remote_hosts)
new_remote_hosts = set(future_remote_hosts) - set(current_remote_hosts)
remote_addresses = {k: v.remote_host for k, v in self.broadcast_tasks.items()}
for hostname, address in known_hosts.items():
if hostname in self.broadcast_tasks and \
address != remote_addresses[hostname]:
deleted_remote_hosts.add(hostname)
new_remote_hosts.add(hostname)
if deleted_remote_hosts:
logger.warn(f"Removing {deleted_remote_hosts} from websocket broadcast list")
if new_remote_hosts:
@@ -177,7 +191,7 @@ class BroadcastWebsocketManager(object):
broadcast_task = BroadcastWebsocketTask(name=self.local_hostname,
event_loop=self.event_loop,
stats=stats,
remote_host=h)
remote_host=known_hosts[h])
broadcast_task.start()
self.broadcast_tasks[h] = broadcast_task

View File

@@ -5,6 +5,8 @@
- name: Poll for status of active job.
hosts: all
gather_facts: false
collections:
- ansible.posix
tasks:

View File

@@ -48,22 +48,8 @@
- update_git
- block:
- 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')}}"
- name: include hg tasks
include_tasks: project_update_hg_tasks.yml
tags:
- update_hg
@@ -136,9 +122,9 @@
register: doesRequirementsExist
- name: fetch galaxy roles from requirements.yml
command: ansible-galaxy install -r requirements.yml -p {{roles_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
command: ansible-galaxy role install -r roles/requirements.yml -p {{roles_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
args:
chdir: "{{project_path|quote}}/roles"
chdir: "{{project_path|quote}}"
register: galaxy_result
when: doesRequirementsExist.stat.exists
changed_when: "'was installed successfully' in galaxy_result.stdout"
@@ -157,9 +143,9 @@
register: doesCollectionRequirementsExist
- name: fetch galaxy collections from collections/requirements.yml
command: ansible-galaxy collection install -r requirements.yml -p {{collections_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
command: ansible-galaxy collection install -r collections/requirements.yml -p {{collections_destination|quote}}{{ ' -' + 'v' * ansible_verbosity if ansible_verbosity else '' }}
args:
chdir: "{{project_path|quote}}/collections"
chdir: "{{project_path|quote}}"
register: galaxy_collection_result
when: doesCollectionRequirementsExist.stat.exists
changed_when: "'Installing ' in galaxy_collection_result.stdout"

View File

@@ -0,0 +1,17 @@
---
- 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

@@ -9,6 +9,8 @@
gather_facts: false
vars:
secret: "{{ lookup('pipe', 'cat ' + src + '/env/ssh_key') }}"
collections:
- ansible.posix
tasks:
- name: synchronize job environment with isolated host

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