Compare commits

..

805 Commits
5.0.0 ... 6.1.0

Author SHA1 Message Date
Shane McDonald
2d7420317b Bump VERSION to 6.1.0 2019-07-18 13:08:52 -04:00
softwarefactory-project-zuul[bot]
6bdb106128 Merge pull request #4345 from jakemcdermott/fix-4302
fix reference to undefined prop for auditors

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-18 17:07:10 +00:00
softwarefactory-project-zuul[bot]
a128a94842 Merge pull request #4314 from mgs4332/memcached_image
Addition of inventory value for memcached image, allows for custom im…

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-18 16:20:37 +00:00
softwarefactory-project-zuul[bot]
f7a455bc83 Merge pull request #4346 from ansible/chrismeyersfsu-patch-1
Update collections.md

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-18 16:07:37 +00:00
softwarefactory-project-zuul[bot]
f51377ff85 Merge pull request #4339 from jbradberry/make-clean-test-dbs
Update the `make clean` command to clear out the parallelized sqlite3 files

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-18 15:51:24 +00:00
Chris Meyers
dc0862bbe7 Update collections.md 2019-07-18 11:12:51 -04:00
Jake McDermott
5b1350db75 fix reference to undefined prop for auditors 2019-07-18 10:21:50 -04:00
Scholl III, Michael G
12f564e4a3 Addition of inventory value for memcached image, allows for custom image locations for memcached to match other images 2019-07-18 09:24:44 -04:00
Jeff Bradberry
d32394f1b6 Update the make clean command to clear out the parallelized sqlite3 files 2019-07-17 17:06:10 -04:00
softwarefactory-project-zuul[bot]
f5fee8e6e7 Merge pull request #4301 from chrismeyersfsu/tower_modules
Global collections path

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-17 20:11:25 +00:00
softwarefactory-project-zuul[bot]
9eb7042d8c Merge pull request #4072 from rambleraptor/gcp_env_vars
adding additional environment variables for gcp_compute + gcp modules

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-17 20:11:17 +00:00
chris meyers
9b95cc27c4 map in a global collections path 2019-07-17 15:36:09 -04:00
AlanCoding
2439aa409d Adjust inventory update env test to allow duplicate references
change gce injectors to not duplicate the credentials file
2019-07-17 12:30:13 -07:00
Alex Stephen
cb60f12b6b adding additional environment variables for gcp_compute + gcp modules 2019-07-17 12:30:12 -07:00
softwarefactory-project-zuul[bot]
41b0367627 Merge pull request #4337 from ryanpetrello/activity-stream-missing-jt
fix a 500 error for Activity Stream job records w/ a missing JT

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-17 16:17:53 +00:00
Ryan Petrello
c25dbb534f fix a 500 error for Activity Stream job records w/ a missing JT 2019-07-17 10:28:51 -04:00
softwarefactory-project-zuul[bot]
d0d08c2395 Merge pull request #4328 from jakemcdermott/nested-hashi-kv-v2-engine-names
support nested names for hashivault kv v2 secret engine

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-16 18:26:56 +00:00
softwarefactory-project-zuul[bot]
1242ee2b65 Merge pull request #4324 from keithjgrant/4218-lookup-toolbar-width
make lookup toolbar fill width of modal

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-16 18:18:46 +00:00
softwarefactory-project-zuul[bot]
7d0f062d9e Merge pull request #4333 from ansible/nightwatchxsl
Added nightwatch stylesheet to e2e

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-16 18:09:24 +00:00
Keith Grant
aea08eef6b make lookup toolbar fill width of modal 2019-07-16 13:36:38 -04:00
Daniel Sami
aef263fa6c Added nightwatch stylesheet to e2e 2019-07-16 13:34:54 -04:00
Jake McDermott
35d9a8f839 support nested engine names for hashivault kv v2 secret engine
Add a field to hashivault plugins for identifying the secret
backend (mount point). If no secret backend is provided, the
first part of the secret path is used.
2019-07-16 13:13:22 -04:00
softwarefactory-project-zuul[bot]
fef6e0b191 Merge pull request #4332 from ryanpetrello/roll-back-fedora
Roll back the dev environment to CentOS 7 and build a newer sqlite3

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-16 15:19:45 +00:00
Ryan Petrello
b620d8505a build and link a newer sqlite3 to make Django happy 2019-07-16 10:50:49 -04:00
softwarefactory-project-zuul[bot]
9fc1378fd1 Merge pull request #4304 from mabashian/3901-desc
Add host description to relevant lists

Reviewed-by: Michael Abashian
             https://github.com/mabashian
2019-07-16 14:29:43 +00:00
mabashian
b46db98b5a Removes some unused classes. Fix host desc ellipsis and responsiveness. Add desc to group hosts 2019-07-16 09:28:17 -04:00
Jose Ariza
14bdf8deb3 #3348 improved related listing on mobile
Signed-off-by: Jose Ariza <l.jlac001@gmail.com>
2019-07-16 09:28:17 -04:00
Jose Ariza
24df1d7be6 #3348 improved listing on mobile
Signed-off-by: Jose Ariza <l.jlac001@gmail.com>
2019-07-16 09:28:17 -04:00
Jose Ariza
40ead6f9d1 #3348 implemented suggested style changes
Signed-off-by: Jose Ariza <l.jlac001@gmail.com>
2019-07-16 09:28:17 -04:00
Jose Ariza
2a71232dd6 #3348 added description to host list on inventories related hosts
Signed-off-by: Jose Ariza <l.jlac001@gmail.com>
2019-07-16 09:28:17 -04:00
Jose Ariza
8b301f91ab #3348 added description to host list
Signed-off-by: Jose Ariza <l.jlac001@gmail.com>
2019-07-16 09:28:17 -04:00
Ryan Petrello
a4b2d6bf88 Revert "Change the devel containers to be based on Fedora instead of CentOS"
This reverts commit 7936dff188.
2019-07-16 09:18:24 -04:00
softwarefactory-project-zuul[bot]
b8b98b136b Merge pull request #4070 from jbradberry/upgrade-django-2.2
Upgrade Django to 2.2

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-15 22:56:22 +00:00
softwarefactory-project-zuul[bot]
c4b4b319c9 Merge pull request #4323 from keithjgrant/4248-tooltip-permissions-list
fix listed resources in delete tooltip

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-15 13:13:41 +00:00
Jeff Bradberry
dd8ca5acc4 Ensure that the Postgres client is installed 2019-07-12 16:22:52 -04:00
Jeff Bradberry
172864a3a1 Force the username and password to be strings under the Radius backend
The base Radius backend encodes them as utf-8 bytes, which causes the
User object that we create to get the repr of the username, including
the b prefix and single quotes, e.g. "b'foo'".
2019-07-12 15:11:22 -04:00
Jeff Bradberry
a691340986 Update authenticate method on auth backends to add required request param
This became mandatory in Django 2.1.
2019-07-12 15:11:22 -04:00
Jeff Bradberry
261f1427e9 Break up a too-long line in migrations 2019-07-12 15:11:22 -04:00
Jeff Bradberry
9383512772 Remove no longer needed check for override of WSGIHandler 2019-07-12 15:11:22 -04:00
Jeff Bradberry
2d81923e22 Fix up changes in fields in the migrations
Particularly the now-required on_delete parameter for ForeignKey and
OneToOneField.
2019-07-12 15:11:22 -04:00
Jeff Bradberry
1093a662f1 Fix a problem with a change in results from User.has_usable_password 2019-07-12 15:11:22 -04:00
Jeff Bradberry
210517eeb1 Fix a couple of tests trivially affected by the upgrades
- is_anonymous may no longer be called as a method, so no need to mock it
- the message on uniqueness constraint failures has apparently changed
2019-07-12 15:11:22 -04:00
Jeff Bradberry
2ffe3d9a85 Give the 4xx error handler views the correct positional arguments 2019-07-12 15:11:22 -04:00
Jeff Bradberry
6737bd4c19 Replace {} as field default values with the callable dict 2019-07-12 15:11:22 -04:00
Jeff Bradberry
29ad847544 Deal with a change in truncation of strings in Django
which now uses a proper ellipsis character instead of 3 dots.
2019-07-12 15:11:22 -04:00
Jeff Bradberry
b3ef2c928a Remove the custom add and remove methods from OrderedManyToManyDescriptor 2019-07-12 15:11:22 -04:00
Shane McDonald
7936dff188 Change the devel containers to be based on Fedora instead of CentOS
since we need a more recent version of sqlite.
2019-07-12 15:11:22 -04:00
Jeff Bradberry
43c552c7c6 Some flake8 changes 2019-07-12 15:11:21 -04:00
Jeff Bradberry
e0357d53f5 Bump Django to 2.2.2 2019-07-12 15:11:21 -04:00
Jeff Bradberry
beb1dd5ae7 Replace use of the deprecated staticfiles template library with static 2019-07-12 15:11:21 -04:00
Jeff Bradberry
d464df557b Fix another direct assignment of a sequence to a related manager 2019-07-12 15:11:21 -04:00
Jeff Bradberry
5e9f790554 Bump to Django 2.1.9 2019-07-12 15:11:21 -04:00
Jeff Bradberry
47b325896d Remove the django_db mark from TransactionTestCase classes
pytest-django's documentation indicates that it isn't necessary, and
it turns out in Django 2.0+ that this double application of the
transaction machinations was causing the Django ContentType table to
lose its items.
2019-07-12 15:11:21 -04:00
Jeff Bradberry
c85d58e28d The interactive flag for management commands doesn't seem to be a thing anymore 2019-07-12 15:11:21 -04:00
Jeff Bradberry
bcbb768dd3 Remove the use of the deprecated Field.rel attribute
Also, rename a number of variables named `rel` for ease of searching.
2019-07-12 15:11:21 -04:00
Jeff Bradberry
e0693d3746 is_anonymous and is_authenticated no longer support being called as methods 2019-07-12 15:11:21 -04:00
Jeff Bradberry
a6edc46cc3 Field.from_db_value no longer supports the context param in 2.0 2019-07-12 15:11:21 -04:00
Jeff Bradberry
f24b08316d Django's url resolver and pattern classes have been renamed in 2.0+
They are now URLResolver and URLPattern, respectively.  The API has
changed as well, but fortunately it looks like what we are doing here
doesn't depend on anything that was changed.
2019-07-12 15:11:21 -04:00
Jeff Bradberry
25c14382db Update the monkey patch of Django's column name digest to work with 2.0+
BaseDatabaseSchemaEditor no longer has a `_digest` classmethod,
instead there is a call out to a new `names_digest` utility function.
2019-07-12 15:11:21 -04:00
Jeff Bradberry
796d7bf67f Replace the use of the 3rd party jsonbfield library
which was just a backport of Django's built-in JSONField.  Also, bump
the version of django-jsonfield.
2019-07-12 15:11:21 -04:00
Jeff Bradberry
ddef41d394 Bump Django to 2.0.13
This is _very_ broken.
2019-07-12 15:11:21 -04:00
softwarefactory-project-zuul[bot]
c626f51dae Merge pull request #4319 from AlanCoding/azure_template_errors
Ignore Azure templating errors

Reviewed-by: Alan Rominger <arominge@redhat.com>
             https://github.com/AlanCoding
2019-07-12 19:00:36 +00:00
softwarefactory-project-zuul[bot]
a9bb1eba02 Merge pull request #4320 from jdekoning/ssh-machine-creds-fix
Insert signed public key in artifact_dir, fix for issue #4139

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2019-07-12 18:37:57 +00:00
Keith Grant
b1c87c1793 fix listed resources in delete tooltip 2019-07-12 09:43:40 -07:00
AlanCoding
612205d56d Ignore Azure templating errors 2019-07-12 08:11:27 -04:00
Jaap de Koning
94b1455f40 Insert signed public key in artifact_dir, hacky fix for issue #4139
Signed-off-by: Jaap de Koning <jaap.de.koning@bigdatarepublic.nl>
2019-07-12 14:10:14 +02:00
softwarefactory-project-zuul[bot]
b26bd11924 Merge pull request #4315 from AlanCoding/old_migration_methods
Remove unused migration methods

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-12 02:11:08 +00:00
AlanCoding
287159296a remove unused migration methods 2019-07-11 16:09:38 -04:00
softwarefactory-project-zuul[bot]
23100094dc Merge pull request #4313 from ryanpetrello/fix-4162
Remove tooltips from host events in output

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-11 18:29:35 +00:00
softwarefactory-project-zuul[bot]
b2275c0490 Merge pull request #4312 from wenottingham/check-one-check-two
Add some minimal sanity checking before running the updater script.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-11 16:55:56 +00:00
softwarefactory-project-zuul[bot]
d6dba784b1 Merge pull request #4285 from olia-dev/issue-4274
related #4274 - added option to verify server certificate with a specific CA

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
             https://github.com/jakemcdermott
2019-07-11 16:50:26 +00:00
Bill Nottingham
2a68ff49c1 Add some minimal sanity checking before running the updater script. 2019-07-11 12:12:22 -04:00
mabashian
0f8c59523a Remove tooltips from host events in output 2019-07-11 12:07:28 -04:00
softwarefactory-project-zuul[bot]
de02df4907 Merge pull request #4201 from beeankha/helper_method_in_serializer
Add Helper Method in Serializer for get_summary_fields

Reviewed-by: Yanis Guenane
             https://github.com/Spredzy
2019-07-10 14:28:04 +00:00
olia-dev
522dcf5ed3 related #4274 - moved function 'create_temporary_fifo' to 'awx/main/utils/common.py' and referenced it in other plugins (fixed errors) 2019-07-10 12:40:26 +02:00
olia-dev
b2d84a5d89 related #4274 - moved function 'create_temporary_fifo' to 'awx/main/utils/common.py' and referenced it in other plugins (fixed errors) 2019-07-10 12:39:57 +02:00
olia-dev
7b390fa2fc related #4274 - moved function 'create_temporary_fifo' to 'awx/main/utils/common.py' and referenced it in other plugins
Signed-off-by: olia-dev <olia-dev@ktah.net>
2019-07-10 11:41:21 +02:00
softwarefactory-project-zuul[bot]
557ec27303 Merge pull request #4251 from AlexSCorey/JTLaunchButton
Add Launch Button to Job Template Details

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 20:58:46 +00:00
softwarefactory-project-zuul[bot]
f47a37a96b Merge pull request #4259 from AlexSCorey/4216-OrgGetRequestDuplication
Removes duplicated GET request in Org.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 18:44:09 +00:00
softwarefactory-project-zuul[bot]
74d8fca673 Merge pull request #4296 from pebbledavec/patch-1
Removed forwardslash that was breaking paginated workflow node requests.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 18:40:34 +00:00
Alex Corey
7039f82d15 Only reload details whe navigating to details from another tab 2019-07-09 13:43:09 -04:00
softwarefactory-project-zuul[bot]
e34833c8cb Merge pull request #4300 from jakemcdermott/output-updown
get more events on page down or up when needed

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 17:12:27 +00:00
softwarefactory-project-zuul[bot]
f22314caaf Merge pull request #4257 from marshmalien/skeleton-template-add-form
Skeleton template add form

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 17:06:46 +00:00
Marliana Lara
fb0c82598f Address PR feedback 2019-07-09 12:37:50 -04:00
Jake McDermott
90f7e9375f get more events on page down or up when needed
when we page up or down, check if we've moved into the upper or lower
threshold of the scrollbar and request more events to show if we have.
2019-07-09 10:21:48 -04:00
softwarefactory-project-zuul[bot]
ccea920ea3 Merge pull request #4263 from fantashley/easy-custom-venvs
Add dynamic custom venv setup

Reviewed-by: Shane McDonald <me@shanemcd.com>
             https://github.com/shanemcd
2019-07-09 13:23:37 +00:00
softwarefactory-project-zuul[bot]
2d636806db Merge pull request #4123 from clushie/update_openstacksdk_dependencies
Fix outdated openstacksdk version and add pip-compile helper script

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 13:04:12 +00:00
softwarefactory-project-zuul[bot]
bda42332b7 Merge pull request #4295 from JakobP/bug/3857-improve-error-message
Fix #3857. More informative error message for job templates

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 13:00:05 +00:00
olia-dev
2ee03b552d related #4274 - added option to verify server certificate with a specific CA (fixed errors) 2019-07-09 14:14:29 +02:00
olia-dev
7a5efa1adc related #4274 - added option to verify server certificate with a specific CA 2019-07-09 13:59:11 +02:00
pebbledavec
2ff3b5d62c Removed forwardslash that was breaking paginated workflow node requests.
The forward-slash in getWorkflowJobTemplateNodes was incorrectly interpreted as part of the pagesize integer (and thereby throwing an exception) when a complex workflow spanned multiple pages of workflow nodes.
Resolves: #4261
Signed-off-by: Dave Compton <sircompo@gmail.com>
2019-07-09 12:50:40 +01:00
Jakob Pedersen
e23ee41082 Fix issue #3857 with a more informative error message when the usercan not post to /#/templates/add_job_template
The cause can be both missing permissions and no projects being available.

Related #3857

Signed-off-by: Jakob Pedersen <CONS_JPE@jysk.com>
2019-07-09 10:47:19 +02:00
softwarefactory-project-zuul[bot]
2aa32f61f8 Merge pull request #4290 from ryanpetrello/csp-false-positive
specify a ng-csp attribute so Angular doesn't autodetect

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-09 01:58:18 +00:00
Ashley Nelson
036e1ad82e Add dynamic custom venv setup
Add support for python3 venvs
2019-07-08 18:49:31 -05:00
Ryan Petrello
66321a6218 specify a ng-csp attribute so Angular doesn't autodetect
without this, we're getting a false positive log message about an unsafe
eval (which is *actually* just angular auto-detecting whether or not
eval is supported)
2019-07-08 17:32:41 -04:00
softwarefactory-project-zuul[bot]
1f31cc9394 Merge pull request #4101 from jbradberry/fix-4099
Include defined fields from all parent classes of a HybridDictField

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-08 21:15:11 +00:00
Jeff Bradberry
758ad164fe Include defined fields from all parent classes of a HybridDictField
since our settings registry adds a mixin class when doing validation on these.

related #4099
2019-07-08 16:05:03 -04:00
softwarefactory-project-zuul[bot]
be975fc051 Merge pull request #4283 from falcon78921/wip-awx-minor-fix
awx/ui: minor fix on Update on Project Update description

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-08 19:48:28 +00:00
softwarefactory-project-zuul[bot]
04ea39c315 Merge pull request #4282 from saito-hideki/issue/tower_3590
Fix to use "type" as the condition value for Machine credential to cover I18N

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-08 19:36:31 +00:00
beeankha
12e0c31fe6 Rename helper method 2019-07-08 15:03:35 -04:00
Hideki Saito
869d259433 Fix conditional values for handle internationalization
Fix the variable for checking the credential type from "name" to "kind"
 in order to correctly handle I18N.

Signed-off-by: Hideki Saito <saito@fgrep.org>
2019-07-08 15:03:35 -04:00
beeankha
0dba3f53b1 Add in schedule case to helper method, make Activity Stream link point to schedule page 2019-07-08 14:59:07 -04:00
beeankha
73c87f9512 Add helper method in order to reduce repetition 2019-07-08 14:59:07 -04:00
softwarefactory-project-zuul[bot]
7faff07bd9 Merge pull request #4279 from athenahealth/fix-csp-for-safari-websockets
Update Content Security Policy to allow websockets

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-08 18:00:42 +00:00
softwarefactory-project-zuul[bot]
ca83b62c21 Merge pull request #4277 from jainnikhil30/devel
add inventory name and id to meta vars

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-08 16:09:49 +00:00
olia-dev
f77298643f related #4274 - added option to verify server certificate with a specific CA 2019-07-08 10:39:42 +02:00
James McClune
8aa33b9b4a awx/ui: minor fix on Update on Project Update description
In the Inventory Source settings, one of the update options is titled
Update on Project Change. However, the tooltip is titled
Update on Project Update. Looking at the overall AWX codebase, I think
the definitions are fitted more towards Update on Project Update.

Signed-off-by: James McClune <jmcclune@mcclunetechnologies.net>
2019-07-07 23:36:54 -04:00
Jeff Byrnes
987cfed649 Update Content Security Policy to allow websockets
Per #4167 a reasonable CSP was put in place, but unfortunately this
broke WebSockets support in Safari.

This is a quick fix to return support immediately. A more secure
implemetation would be beneficial in the longer term, however.
2019-07-05 16:12:27 -04:00
softwarefactory-project-zuul[bot]
9b6644bc77 Merge pull request #4276 from ryanpetrello/ldap-tls-verify-off
fix a bug that breaks OPT_X_TLS_REQUIRE_CERT=0 for LDAP authentication

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-05 15:58:47 +00:00
jainnikhil30
88a4362a7a add inventory name and id to meta vars 2019-07-05 20:37:36 +05:30
Ryan Petrello
0dcbafaccb fix a bug that breaks OPT_X_TLS_REQUIRE_CERT=0 for LDAP authentication 2019-07-05 10:24:18 -04:00
Alex Corey
3b17170533 more concise conditions for api calls 2019-07-03 16:19:43 -04:00
Marliana Lara
7afaacb5e3 Add Job Template Add form skeleton and test 2019-07-03 15:44:52 -04:00
Marliana Lara
b06421b870 Rename TemplateForm to JobTemplateForm 2019-07-03 15:44:52 -04:00
Alex Corey
320581a6c0 Addresses PR issues 2019-07-03 12:43:40 -04:00
softwarefactory-project-zuul[bot]
d4f50896de Merge pull request #4260 from fantashley/fix-docker-module-name
Change to docker_service for compatibility

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-03 12:28:35 +00:00
softwarefactory-project-zuul[bot]
71812c66d2 Merge pull request #4118 from DanielDisisto/patch-1
Failing requirements update when scm_type != git

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-03 12:17:05 +00:00
softwarefactory-project-zuul[bot]
731d8c21e8 Merge pull request #4252 from ansible/jakemcdermott-fix-readme-snippet
fix README snippet

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-03 11:55:05 +00:00
DanielDisisto
3247983823 Failing requirements update when scm_type != git
The `git_result` variable is incorrectly checked as being `defined` vs. `not skipped`. This causes SVN (or any non-GIT) project update to fail consistently when `doesRequirementsExist.stat.exists` is true

Signed-off-by: DanielDisisto <daniel.disisto@didata.com.au>
2019-07-03 07:51:01 -04:00
Ashley Nelson
485536d4cf Change to docker_service for compatibility 2019-07-02 16:03:43 -05:00
softwarefactory-project-zuul[bot]
b37040a85c Merge pull request #4256 from ryanpetrello/inline-image-csp
allow data: images in our Content Security Policy

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-02 17:13:10 +00:00
Alex Corey
b5b38c1b79 addresses PR Issues 2019-07-02 12:36:13 -04:00
softwarefactory-project-zuul[bot]
84ad1cdfcd Merge pull request #4250 from kialam/fix-254-delete-last-elem-list-page
Fix 254 delete last elem list page

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-02 16:17:51 +00:00
Ryan Petrello
75a72637dd allow data: images in our Content Security Policy
support for custom login logos relies on data:image/*;base64
see: https://github.com/ansible/awx/issues/4253
2019-07-02 11:35:56 -04:00
Kia Lam
74e4c17b63 Address PR feedback and format. 2019-07-02 09:54:07 -04:00
softwarefactory-project-zuul[bot]
c65ae87d69 Merge pull request #4175 from jainnikhil30/devel
fix the hashivault v2 lookup

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-02 12:42:41 +00:00
Phileas Lebada
7feb6515e1 Bump openstacksdk version
Signed-off-by: github.com/clushie <47661139+clushie@users.noreply.github.com>
2019-07-02 13:56:26 +02:00
Phileas Lebada
d3b3b6e8f5 Add cosmetic change with updater.sh
Signed-off-by: github.com/clushie <47661139+clushie@users.noreply.github.com>
2019-07-02 13:56:26 +02:00
Phileas Lebada
48e02f373f Add pip-compile updater.sh script
Signed-off-by: github.com/clushie <47661139+clushie@users.noreply.github.com>
2019-07-02 13:56:26 +02:00
jainnikhil30
dbf8df479b use path instead of *path while dong the join 2019-07-02 07:55:35 -04:00
jainnikhil30
764947c1ae fix the hashivault v2 lookup 2019-07-02 07:55:32 -04:00
Jake McDermott
0b724682da fix README snippet 2019-07-01 19:50:16 -04:00
softwarefactory-project-zuul[bot]
4fb055345d Merge pull request #4199 from mabashian/264-notification-type-column
Show notification type in its own column

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-01 22:57:50 +00:00
Kia Lam
d3ed6ac73a Fix Template list as well. 2019-07-01 16:21:41 -04:00
Kia Lam
d22cafc42e Add unit test. 2019-07-01 16:20:38 -04:00
Kia Lam
58444a75b9 Fix Org list returning a 404 by redirecting user to current page.
- Update itemCount after an org has been successfully deleted.
- Update PaginatedDataList to get current page when the number of items has changed.
2019-07-01 16:20:38 -04:00
softwarefactory-project-zuul[bot]
7178c1d9e0 Merge pull request #4200 from ansible/jakemcdermott-contrib-formatter
run formatting check with ci

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-01 19:28:39 +00:00
Jake McDermott
945d9156a6 do formatting check with ci linter 2019-07-01 14:27:25 -04:00
Jake McDermott
bf86719412 add a note about running the formatter 2019-07-01 14:16:17 -04:00
mabashian
12c0b80102 Prettify files 2019-07-01 13:51:13 -04:00
mabashian
1d2c21249b Show notification type in its own column 2019-07-01 13:49:38 -04:00
softwarefactory-project-zuul[bot]
3371a6f386 Merge pull request #4188 from mabashian/awx-pf-migration
Pull beginning of new ui application using React and Patternfly into AWX

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-01 17:31:32 +00:00
softwarefactory-project-zuul[bot]
e79fbab737 Merge pull request #4196 from shanemcd/devel
Release 6.0.0

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-01 17:03:29 +00:00
Shane McDonald
4f829ab93f Release 6.0.0 2019-07-01 12:47:37 -04:00
mabashian
8f74bad1c1 Roll back changes to test linting and unit test gating 2019-07-01 12:34:09 -04:00
softwarefactory-project-zuul[bot]
5ce78b383d Merge pull request #4190 from ryanpetrello/ldap-dict-order
fix a bug that causes LDAP TLS connection flags to not be set properly

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-01 16:19:51 +00:00
mabashian
02d320de71 Commit to test linting and unit test gating 2019-07-01 12:04:45 -04:00
softwarefactory-project-zuul[bot]
2404faa5d8 Merge pull request #4184 from rooftopcellist/delete_tarball
Delete collection tarball when no longer needed

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-07-01 15:44:49 +00:00
Christian Adams
e72b2fac6d Delete collection tarball when no longer needed
* Delete after shipping it
   * Delete when ship() fails
2019-07-01 11:11:44 -04:00
Ryan Petrello
11b36982cd fix a bug that causes LDAP TLS connection flags to not be set properly
co-authored-by: Jim Ladd <jladd@redhat.com>
2019-06-28 22:15:35 -04:00
softwarefactory-project-zuul[bot]
d438a93fd2 Merge pull request #4183 from ryanpetrello/logging-deadlock
don't ship external logs from the main thread of the dispatcher

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-28 16:24:27 +00:00
mabashian
5cb8bd34ac Adds make targets for linting/tests in ui_next. Modifies existing clean-ui target to clean ui_next as well. 2019-06-28 12:11:07 -04:00
mabashian
b457926b38 Update usage instructions since paths have changed 2019-06-28 10:50:49 -04:00
mabashian
55ce409a12 Run prettier on all the files in awx/ui_next 2019-06-28 09:26:11 -04:00
mabashian
051bbcaeb5 Remove gitignore from awx/ui_next and add rules to base gitignore 2019-06-28 09:23:45 -04:00
mabashian
2de5fbdac7 Merge awx-pf into awx 2019-06-28 09:09:52 -04:00
Ryan Petrello
dfa8d44eb8 don't ship external logs from the main thread of the dispatcher
this is a fairly esoteric change that attempts to work around a bug
we've discovered in cpython itself

context: https://github.com/ansible/awx/issues/4181
2019-06-27 16:24:36 -04:00
softwarefactory-project-zuul[bot]
4470e9ca26 Merge pull request #4178 from rooftopcellist/collection_datetime_str
Fix collection datetime for isolated instance info

Reviewed-by: Elijah DeLee <kdelee@redhat.com>
             https://github.com/kdelee
2019-06-27 20:03:46 +00:00
softwarefactory-project-zuul[bot]
cf0fe729f5 Merge pull request #4039 from mabashian/application-lookup-column
Fix user token application lookup column widths

Reviewed-by: Michael Abashian
             https://github.com/mabashian
2019-06-27 18:31:48 +00:00
mabashian
913e06b865 Fix user token application lookup column widths 2019-06-27 13:32:51 -04:00
Christian Adams
4d7c49372c Fix collection datetime for isolated instance info
* 'last_isolated_check' was a non JSON-serializable object and needed to be a str
2019-06-27 13:31:10 -04:00
Michael Abashian
43592cbe00 Move everything to awx/ui_next (#297) 2019-06-27 11:11:58 -04:00
softwarefactory-project-zuul[bot]
5c338e582a Merge pull request #4167 from ryanpetrello/csp
add a reasonable default Content Security Policy

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-26 20:21:20 +00:00
Michael Abashian
0a6fc8cb89 Fix for unit test failure in jt detail test where getting instance groups wasn't mocked (#296)
Fix for unit test failure in jt detail test where getting instance groups wasn't mocked.
2019-06-26 16:07:58 -04:00
Marliana Lara
5e6562023d Merge pull request #295 from marshmalien/job-template-directory-name
Job template directory name
2019-06-26 15:10:33 -04:00
Marliana Lara
14280ec53b Update launch button hover styles 2019-06-26 14:51:27 -04:00
Marliana Lara
edef496583 Update job template breadcrumb content 2019-06-26 14:49:10 -04:00
Marliana Lara
cfc0a4771f Update the JT Edit directory, file, and component names 2019-06-26 14:45:35 -04:00
Marliana Lara
f6ddb72482 Add key to ansible select options test 2019-06-26 14:41:38 -04:00
Michael Abashian
52851c57d8 Display details about network errors in alert modal and content error components (#288)
Display details about network errors in alert modal and content error components
2019-06-26 11:40:15 -04:00
Ryan Petrello
eacf819caf add a reasonable default Content Security Policy
ideally we'd improve this over time to remove the `unsafe-inline` lines,
but we can't due that today because Angular1 makes use of a lot of
inline <script> and <style> tag generation

see: https://github.com/ansible/awx/issues/2056
2019-06-26 10:46:26 -04:00
Marliana Lara
a503529d05 Merge pull request #291 from marshmalien/skeleton-template-edit-form
Skeleton template edit form
2019-06-26 10:33:22 -04:00
Marliana Lara
a2a245c89e Add unique key prop to ansible select options 2019-06-26 10:21:34 -04:00
softwarefactory-project-zuul[bot]
273415b9aa Merge pull request #4077 from j-shade/devel
fixed row item labels to view horizontally instead of vertically

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-26 12:50:16 +00:00
Jeremy Shade
e612a167e2 fixed row item labels to view horizontally instead of vertically 2019-06-26 08:22:20 -04:00
softwarefactory-project-zuul[bot]
0a7d6e603e Merge pull request #4165 from shanemcd/sane-working-dir
Use the source tree as the working directory for our dev env

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-26 00:58:37 +00:00
Shane McDonald
f05bed6366 Use the source tree as the working directory for our dev env 2019-06-25 18:28:01 -04:00
softwarefactory-project-zuul[bot]
cbe6c5bd3b Merge pull request #4164 from aubrel/devel
Change `docker_service` to `docker_compose`.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-25 21:45:49 +00:00
Marliana Lara
f3bf35311e Address PR feedback and merge conflicts 2019-06-25 16:29:55 -04:00
aubrel
e9ac44f561 Change docker_service to docker_compose.
Signed-off-by: aubrel <red_clover@riseup.net>
2019-06-25 15:58:52 -04:00
Marliana Lara
67d619f9cc Add template edit and form tests 2019-06-25 15:49:28 -04:00
Marliana Lara
463357c81e Add template edit form skeleton 2019-06-25 15:49:24 -04:00
Marliana Lara
7b3e5cd8d5 Refactor AnsibleSelect data prop to accept an array of option objects
* First custom_virtualenv in options list is always default
2019-06-25 15:47:42 -04:00
Alex Corey
ec1fa4dae6 240 jt details skeleton v2 (#273)
* adding package-lock.json

* deleted unsured file

* Adds a Bottom Border Component

* Updates dependencies

* Adds JT Details and tests for it

* merge and rebase

* addresses UI PR issues

* Addresses PR Issues and fixes failing tests.

* Updates to code, fixes package and package-lock.json addresses PR Issues

* fixes package files
2019-06-25 15:28:07 -04:00
Keith Grant
e49b9a202e Prettier configs (#281)
Add .prettierrc and update eslint configs
2019-06-25 11:26:44 -07:00
softwarefactory-project-zuul[bot]
aab29bef5b Merge pull request #4141 from ryanpetrello/ovirt4-dep-bump
bump ovirtsdk version to 4.3.0

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-24 21:18:40 +00:00
Jake McDermott
059fa9001a Merge pull request #287 from jakemcdermott/more-big-pr-fixups
misc cleanup from big prs
2019-06-24 10:22:33 -04:00
softwarefactory-project-zuul[bot]
9f42d9426c Merge pull request #4137 from chrismeyersfsu/fix-smart_inv_race
wrap smart inv cache update w/ advisory lock

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-21 20:25:10 +00:00
softwarefactory-project-zuul[bot]
b369609f07 Merge pull request #4103 from AlexSCorey/79-NotifyOnJobStart
Adds notify on start toggle

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-21 16:51:52 +00:00
Ryan Petrello
01d31231c0 bump ovirtsdk version to 4.3.0
see: bfc6a2a8d6
2019-06-21 12:49:16 -04:00
softwarefactory-project-zuul[bot]
c46be3e718 Merge pull request #4083 from rmkraus/devel
Updated ovirt4 dynamic inventory script.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-21 16:40:29 +00:00
Jake McDermott
cc36b46925 remove network context mock 2019-06-21 12:15:59 -04:00
Jake McDermott
657a6f3a93 use top-level import aliases 2019-06-21 12:10:01 -04:00
Jake McDermott
9dda5404a0 add 'has' prefix to error booleans 2019-06-21 12:01:29 -04:00
Jake McDermott
c3823771a7 Merge pull request #269 from jakemcdermott/jobs-list-skeleton
job list skeleton
2019-06-21 11:54:16 -04:00
Jake McDermott
69426dee08 add basic test coverage for job list 2019-06-21 11:46:40 -04:00
Jake McDermott
22dbe5c0f9 add shared DataListCell component 2019-06-21 11:46:40 -04:00
Jake McDermott
d8452e1259 job list skeleton 2019-06-21 11:46:35 -04:00
softwarefactory-project-zuul[bot]
38aedcdd48 Merge pull request #4136 from Spredzy/revert_makefile
Revert "Makefile: align pip and setuptools bump"

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-21 13:42:26 +00:00
softwarefactory-project-zuul[bot]
59bec99f4c Merge pull request #4128 from tchellomello/k8s-annotations
Introduces the ability to pass annotations to the Kubernetes Ingress Controllers

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-21 13:14:47 +00:00
Alex Corey
b0249a9a8b Addressed PR Issues 2019-06-21 08:58:51 -04:00
chris meyers
acb6d9c4d1 wrap smart inv cache update w/ advisory lock
* Two job templates that use the same smart inventory running at the
same time can easily race to recompute the smart inventory <-> host
mapping. In this case, bulk_create() can throw an error when racing.
* The per-smart-inventory advisory lock ensures that the state of the
system is consistent & that bulk_create() runs in isolation.
2019-06-21 08:52:34 -04:00
Yanis Guenane
78912d20f7 Revert "Makefile: align pip and setuptools bump"
This reverts commit ec92abf014.
2019-06-21 11:52:22 +02:00
Marcelo Mello
52712a0d9a Introduces the ability to pass annotations to the Kubernetes Ingress Controllers 2019-06-20 16:40:08 -04:00
Michael Abashian
cb50cdce0d Add support for launching job templates from the templates list (#277)
Add support for launching job templates from the templates list
2019-06-20 15:21:57 -04:00
Jake McDermott
cd672baa13 Merge pull request #284 from jakemcdermott/move-yaml-test
move yaml test to utils
2019-06-20 15:00:08 -04:00
Jake McDermott
30709d1ab2 Merge pull request #283 from jakemcdermott/has
prefix content error and loading booleans with 'has'
2019-06-20 14:59:52 -04:00
Jake McDermott
f382fce576 move yaml test to utils 2019-06-20 14:47:39 -04:00
Jake McDermott
36d2d03bc7 prefix content error and loading booleans with 'has' 2019-06-20 14:37:46 -04:00
Michael Abashian
b21e491075 Updates to contributing doc (#280) 2019-06-20 13:32:25 -04:00
Alex Corey
a7c787af02 Adds notify on start toggle 2019-06-20 13:07:09 -04:00
Marliana Lara
740402e5a8 Merge pull request #279 from mabashian/templates-routes
Add basic routing for templates
2019-06-20 12:11:22 -04:00
Marliana Lara
5662d8b625 Remove Fragment 2019-06-20 12:01:43 -04:00
mabashian
af6ea1cc58 Notifications plural 2019-06-20 11:34:16 -04:00
mabashian
f185d80b05 Fix border bottom on tabs 2019-06-20 11:33:15 -04:00
mabashian
0a5f29ad22 Add basic routing for templates 2019-06-20 10:57:04 -04:00
softwarefactory-project-zuul[bot]
e269634afc Merge pull request #4112 from jbradberry/fix-3603
Use the `in` operator to test against the Organization membership subquery

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-20 12:56:08 +00:00
Jake McDermott
3b7b27ea20 Merge pull request #276 from jlmitch5/testWatchFix
fix jest.config.js so `npm run test-watch` works
2019-06-20 08:25:56 -04:00
softwarefactory-project-zuul[bot]
4daf574899 Merge pull request #4114 from shanemcd/revert-pip-and-setuptools
Revert pip and setuptools

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-20 02:42:04 +00:00
softwarefactory-project-zuul[bot]
067ba7f8fe Merge pull request #4116 from tchellomello/ca_trust_dir_project_data_dir
Fixes ca_trust_dir and project_data_dir for Kubernetes

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-20 02:19:25 +00:00
Marcelo Mello
7d77727a60 project_data_dir is not required in the awx_task containers 2019-06-19 21:35:49 -04:00
Marcelo Mello
47560fdf7c Fixes ca_trust_dir and project_data_dir for Kubernetes 2019-06-19 21:21:35 -04:00
John Mitchell
7fee9e35c4 fix jest.config.js so npm run test-watch works 2019-06-19 16:41:19 -04:00
Shane McDonald
2882f4afb5 Revert "upgrade pip and setuptools"
This reverts commit 76ebcf914b.
2019-06-19 16:02:52 -04:00
Shane McDonald
aaceccc426 Revert "Fix offline builds"
This reverts commit fe850dff38.
2019-06-19 16:02:43 -04:00
softwarefactory-project-zuul[bot]
1f3242900a Merge pull request #4098 from beeankha/any_notification_migration
Update "Notify On Start" Migration File

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2019-06-19 19:57:12 +00:00
softwarefactory-project-zuul[bot]
e6232957b4 Merge pull request #4079 from ryanpetrello/ldap-setting-flake
work around a unit test that's periodically flaky

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-19 18:55:24 +00:00
Jeff Bradberry
1a72ff4c47 Use the in operator to test against the Organization membership subquery
If more than one Organization were selected by this subquery, then
Postgres would complain with "more than one row returned by a subquery
used as an expression".  We needed to allow for that case.

Annoyingly SQLite3 doesn't seem to care, so writing a py.test test to
exercise this isn't feasible under our current development setup.
2019-06-19 14:49:02 -04:00
Jake McDermott
f33b343cd8 Merge pull request #274 from jakemcdermott/alias-top-level-imports
alias top-level imports
2019-06-19 13:09:26 -04:00
softwarefactory-project-zuul[bot]
c585c3d07d Merge pull request #4105 from rooftopcellist/fix_instance_counts
Fixes analytics & metrics instance specific job counts

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-19 16:49:09 +00:00
softwarefactory-project-zuul[bot]
1413c1be7b Merge pull request #4074 from ryanpetrello/whoopsie
fix a bug introduced in the inventory source detail API by v1 removal

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-19 15:52:47 +00:00
Jake McDermott
012852ec53 alias top-level imports 2019-06-19 11:45:57 -04:00
Michael Abashian
ee56e9ccfb Reorganize file locations/directory structure (#270)
Reorganize file locations
2019-06-19 11:41:14 -04:00
Christian Adams
a5c057cc18 Fixes analytics & metrics instance specific job counts 2019-06-19 11:32:05 -04:00
softwarefactory-project-zuul[bot]
9c06dc7106 Merge pull request #4106 from shanemcd/fix-offline-builds
Downgrade pip

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-18 23:17:48 +00:00
Shane McDonald
fe850dff38 Fix offline builds
pip 19 added support for something called `pyproject.toml`. Several packages have been setting the option `build-backend = "setuptools.build_meta”` (bcrypt, attrs, jaraco) which seems to be the root of the problem when building from source. Until the community sorts this out I’m inclined to avoid pip 19.
2019-06-18 18:48:54 -04:00
Keith Grant
e3cb8d0447 Add JSON/YAML components (#267)
Add CodeMirrorInput and VariablesField

Add components for syntax highlighting, YAML/JSON toggle
2019-06-18 12:32:22 -07:00
Marliana Lara
0b10ff7fe6 Merge pull request #268 from marshmalien/263-org-badge-count-styles
Group organization list user and member badges
2019-06-18 13:53:32 -04:00
beeankha
40840e3789 Update migration file to indicate there is no reverse function in case of a rollback 2019-06-18 12:57:50 -04:00
softwarefactory-project-zuul[bot]
e3750f541e Merge pull request #4096 from mabashian/4091-workflow-form
Fix field enablement on workflow form

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-18 16:15:57 +00:00
Marliana Lara
c9a4cb7696 Reduce gap between organization list count badges 2019-06-18 12:07:08 -04:00
softwarefactory-project-zuul[bot]
5d49fe2170 Merge pull request #4097 from shanemcd/five-dot-oh-dot-oh
Bump version to AWX 5.0.0

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-18 14:43:25 +00:00
softwarefactory-project-zuul[bot]
ca0e8102fd Merge pull request #3982 from beeankha/notify_on_start
Notification On Job Start

Reviewed-by: Bianca Henderson <beeankha@gmail.com>
             https://github.com/beeankha
2019-06-18 14:23:58 +00:00
mabashian
164d305b51 More canAddWorkflowJobTemplate cleanup 2019-06-18 09:16:19 -04:00
mabashian
4d33e484d0 Fix field enablement on workflow form 2019-06-18 09:10:49 -04:00
Michael Abashian
7a5cf4b81c Add support for deleting templates on templates list (#266)
Adds support for deleting templates from the templates list
2019-06-17 13:52:05 -04:00
Marliana Lara
4e45a3b365 Merge pull request #256 from marshmalien/skeleton-job-results
Skeleton job results
2019-06-17 11:48:14 -04:00
beeankha
69502bc133 Add functions in migration file for deleting and altering 'any' state notifications 2019-06-17 10:47:58 -04:00
beeankha
17c89ed412 Remove tests for 'any' notification state 2019-06-17 10:47:58 -04:00
beeankha
f5b6bd65cf More deletions of 'any' state 2019-06-17 10:47:58 -04:00
beeankha
c6f1806a23 Removing references to 'any' state notifications 2019-06-17 10:47:58 -04:00
beeankha
c65e6ba30b Update the logic for 'any' and 'started' notifications 2019-06-17 10:47:58 -04:00
beeankha
d511d63a5a Fixed typo 2019-06-17 10:47:58 -04:00
beeankha
30741e762a Add more notification tests 2019-06-17 10:47:58 -04:00
beeankha
7687eddf6d Add api test, edit AWX docs 2019-06-17 10:47:58 -04:00
beeankha
9cfed6f2a8 Add check for no-op case back, remove redundant on_commit code 2019-06-17 10:47:58 -04:00
beeankha
95896b1acd Edit wfj running notification trigger 2019-06-17 10:47:58 -04:00
beeankha
68fe23d8b7 Update Organization Notification Template subclass, move success/fail wfj notification trigger 2019-06-17 10:47:58 -04:00
beeankha
dd372548a9 Update swagger test 2019-06-17 10:47:57 -04:00
beeankha
8d6e1f0927 Trigger running notifications in WFJs and edit unit test 2019-06-17 10:47:57 -04:00
beeankha
98fa1fc813 Add migration file 2019-06-17 10:47:57 -04:00
beeankha
8ec97235e3 Add feature for notifications to trigger on job start 2019-06-17 10:47:57 -04:00
Ryan Kraus
468e79a754 Updated ovirt4 dynamic inventory script.
Pulling in the new ovirt4 dynamic inventory script that will be pulled in ansible/ansible#57824

Signed-off-by: Ryan Kraus <rmkraus@gmail.com>
2019-06-16 11:55:46 -04:00
Marliana Lara
096f5fb324 Fix lint errors and pull in new content error and loading handler 2019-06-14 15:34:55 -04:00
Marliana Lara
416d30a189 Add close button to job detail and test 2019-06-14 14:46:48 -04:00
Marliana Lara
cda5cc25b8 Add Job results skeleton tests 2019-06-14 14:46:48 -04:00
Marliana Lara
508d8311dd Add Job results skeleton 2019-06-14 14:46:48 -04:00
Marliana Lara
54f9dd5e98 Add Job API model 2019-06-14 14:46:48 -04:00
Marliana Lara
4fe558392a Update organization card header and tabs to use styled-components 2019-06-14 14:46:42 -04:00
Jake McDermott
a98be1443b Merge pull request #255 from jakemcdermott/update-content-loading-and-errors
update content loading and error handling
2019-06-14 13:29:16 -04:00
Jake McDermott
e35f7acd05 add test coverage for auth utils 2019-06-14 13:01:02 -04:00
Jake McDermott
4aa4490933 add test coverage for api notification mixin 2019-06-14 13:00:50 -04:00
Jake McDermott
e72f0bcfd4 update content loading and error handling
unwind error handling

use auth cookie as source of truth, fetch config only when authenticated
2019-06-14 13:00:37 -04:00
Jake McDermott
534418c81a Merge pull request #262 from catjones9/organizations
Added Max Hosts field on Organizations Add/Edit form
2019-06-14 12:39:10 -04:00
Ryan Petrello
d8bd72054d work around a unit test that's periodically flaky 2019-06-14 10:05:41 -04:00
catjones9
91b8aa90ff Added 'Max Hosts' field in the Add/Edit Organization view
* max hosts field is enabled is user is superuser, otherwise it is disabled and default is 0
 * OrganizationForm tests added for max hosts input
 * minMaxValue added in validators to validate user input for max hosts

Signed-off-by: catjones9 <catjones@redhat.com>
2019-06-13 18:43:34 -04:00
catjones9
5874becb00 Max Hosts shows up in Org Detail View
Signed-off-by: catjones9 <catjones@redhat.com>
2019-06-13 18:04:09 -04:00
Ryan Petrello
ae9032ce03 fix a bug introduced in the inventory source detail API by v1 removal
see: https://github.com/ansible/awx/issues/4059
2019-06-13 17:20:21 -04:00
Alex Corey
19b41743de 215 templates list skeleton (#251)
* adding package-lock.json

* deleted unsured file

* Removes and unused file

* Fixes errant styling change

* Fixes an error and uses a prop that PF recognizes

* Updates PR to use API Modules

*  Fixes PR Issues

* Addes tests to Templates

* Addresses PR Issues

* Revert package-lock.json
2019-06-13 11:08:05 -04:00
Michael Abashian
ffcb655038 Convert Tower logo/strings to AWX (#253)
Sets up awx logo and strings
2019-06-10 14:31:12 -04:00
Michael Abashian
2ae93261d1 api.js refactor using classes (#250)
Refactor api.js into an api module where endpoint specific models can be imported and used in components.
2019-06-07 15:48:09 -04:00
catjones9
a8c51670af Switched Selectable Card to styled components (#249)
* Switched Selectable Card to styled components
 * styles.scss in AddRole/ removed
 * styles.scss import in index.jsx removed

Signed-off-by: catjones9 <catjones@redhat.com>

* Addressed PR linter issues

Signed-off-by: catjones9 <catjones@redhat.com>

* Switched Indicator and Label to styled components

Signed-off-by: catjones9 <catjones@redhat.com>
2019-06-04 15:03:41 -04:00
kialam
5df424803f Merge pull request #211 from ansible/upgrade-node-v8-to-node-v10
Upgrade our packaging for NodeJS 10.
2019-06-04 10:54:24 -04:00
John Mitchell
241d7f57b7 Merge pull request #247 from jlmitch5/removeUnusedScssStyles
remove unused scss styles from app.scss
2019-06-04 10:30:44 -04:00
John Mitchell
9ba8feaec1 remove unused scss styles from app.scss 2019-06-03 10:20:13 -04:00
Alex Corey
886d29e111 Merge pull request #236 from AlexSCorey/SwitchToStyledComps
updates test issues caused by PF bump
2019-05-28 13:30:55 -04:00
Alex Corey
7452b82856 addresses PR issues 2019-05-28 13:13:42 -04:00
Alex Corey
b7b17b9176 updates test issues caused by PF bump 2019-05-28 11:42:17 -04:00
Keith Grant
29e17ac49e Standardize chip height (#213)
* make all chips the same size

* create DetailList, Detail components; clean up Chips, ChipGroup

* delete BasicChip in favor of <Chip isReadOnly>

* create our own ChipGroup to handle overflow
2019-05-28 08:49:03 -04:00
Keith Grant
189e12f8b3 Restore logo (#218)
* move tower logo svg into component

* switch to new logo in header & login screen
2019-05-23 13:47:41 -04:00
Keith Grant
cc2869d0c2 Merge pull request #214 from keithjgrant/200-trailing-slash-routing
Redirect to remove trailing slash from URL
2019-05-23 09:54:07 -04:00
Keith Grant
79d8b74221 redirect to remove trailing slash from URL 2019-05-23 08:29:08 -04:00
Jake McDermott
8d8d9292bc Merge pull request #212 from jakemcdermott/wait-for-element
add waitForElement helper
2019-05-22 10:52:14 -04:00
Jake McDermott
7965f94027 add waitForElement helper 2019-05-22 08:56:49 -04:00
Kia Lam
efc45ac1fa Upgrade our packaging for NodeJS 10.
- Update README.md
- Bump certain dependencies to fix vulnerabilities.
2019-05-20 16:07:33 -04:00
Keith Grant
6bfbcb35cd Merge pull request #208 from keithjgrant/toolbar-render-prop
use a render prop for PaginatedDataList toolbar
2019-05-20 06:16:48 -07:00
Keith Grant
8cd05679c2 extract out PaginatedDataListItem 2019-05-20 09:15:31 -04:00
Keith Grant
510d56b245 refactor PaginatedDataList to renderToolbar prop 2019-05-20 09:13:23 -04:00
Alex Corey
dc1bfaac3f Merge pull request #203 from AlexSCorey/178-AddOrgBtnV2
178 add org btn v2
2019-05-17 19:48:08 -04:00
Alex Corey
92d8948a83 updates tests 2019-05-17 15:32:04 -04:00
Alex Corey
d3cc1a8771 Adds AddOrgBtn to Orgs List empty state 2019-05-17 15:29:05 -04:00
Keith Grant
5df2b1f346 Merge pull request #207 from keithjgrant/126-pf-pagination
Convert to PF Pagination component
2019-05-17 11:01:03 -04:00
Keith Grant
7ff7517bdf change pagination drop direction to up 2019-05-17 07:47:17 -07:00
Keith Grant
957984d9e9 convert to PF Pagination component 2019-05-16 16:09:58 -04:00
John Mitchell
69a25bb092 Merge pull request #198 from jlmitch5/translationUpdate
utilize i18n correctly
2019-05-16 13:54:05 -04:00
John Mitchell
b45f3f6cab fix inadverdently added extra notification toggle from conflicts 2019-05-16 13:32:40 -04:00
John Mitchell
0f02daa64d run to generate po files 2019-05-16 12:53:56 -04:00
John Mitchell
001fc1293c fix lint error from removing api passing via props 2019-05-16 12:45:14 -04:00
John Mitchell
f4550900bb update tests based on i18n changes 2019-05-16 11:38:28 -04:00
John Mitchell
e2de8e4d5f update i18n contributing guidelines 2019-05-15 11:20:20 -04:00
John Mitchell
07664a05fd update awx-pf to use withI18n i18n._ and t exclusively 2019-05-15 11:20:00 -04:00
Keith Grant
4407aeac20 Add namespacing for query params (#205)
* use qs utils to namespace query params

* refactor Lookup and SelectResource Steps to use PaginatedDataList

* preserve query params when adding new ones

* require namespace for QS Configs
2019-05-15 10:06:14 -04:00
kialam
d59975c1ad Merge pull request #204 from ansible/use-styled-components
Use styled-components
2019-05-14 10:33:28 -04:00
Kia Lam
cc24d524ac Merge remote-tracking branch 'origin' into use-styled-components 2019-05-14 10:20:25 -04:00
Kia Lam
457c6287a2 General cleanup.
- Fix tests.
- Update snapshots.
- Remove old import statement.
- Add element ids for Sort and Search Components.
2019-05-13 18:42:26 -04:00
Kia Lam
3322123dd4 Remove defunct external stylesheet. 2019-05-13 18:42:26 -04:00
Kia Lam
a53509b359 Refactor DataListToolbar component. 2019-05-13 18:42:26 -04:00
Kia Lam
a87c6ddf1b Convert DataListToolbar to a styled-component. 2019-05-13 18:42:25 -04:00
Kia Lam
0ea4a4dedd Convert toolbar button components to styled-components. 2019-05-13 18:42:25 -04:00
Kia Lam
cc192246d9 Make Orgs List page responsive. 2019-05-13 18:42:08 -04:00
Marliana Lara
0b3245eab6 Merge pull request #201 from marshmalien/194-missing-header-dropdowns
Fix page header styles, search icon, and vertical separator
2019-05-13 16:23:48 -04:00
Marliana Lara
b640203f88 Fix page header styles, search icon, and vertical separator 2019-05-10 12:29:55 -04:00
Kia Lam
82c7052d6f Make Org Notifications page responsive. 2019-05-10 11:06:24 -04:00
Kia Lam
349a9c7cc2 Add styled-components library and its babel plugin. 💅 2019-05-10 11:03:16 -04:00
Keith Grant
e7ec1c6ef8 convert OrganizationList to use PaginatedDataList (#192)
* convert Org list to use PaginatedDataList

* add ToolbarAddButton, ToolbarDeleteButton

* pass full org into OrganizationListItem
2019-05-07 09:51:50 -04:00
Jake McDermott
a011896cc0 Update README.md 2019-05-06 11:11:27 -04:00
Alex Corey
a4899d4dbb Merge pull request #191 from AlexSCorey/175-BottomBorder
175 bottom border
2019-05-06 08:50:14 -04:00
Alex Corey
1200c23ebc addressing PR issues 2019-05-03 14:26:19 -04:00
Alex Corey
b8b2209335 add bottom border to org tabs 2019-05-03 10:27:48 -04:00
kialam
500765cea5 Merge pull request #186 from ansible/add-username-to-top-header-bar
Add logged in username to top level header bar.
2019-05-03 10:14:29 -04:00
Kia Lam
f14934f42c Translate tooltip block. 2019-05-03 09:59:10 -04:00
Alex Corey
a3fdb4aee3 add bottom border to tabs 2019-05-02 16:26:31 -04:00
Alex Corey
fed24ed6df Merge pull request #187 from AlexSCorey/177-UXImprovements
UX improvements
2019-05-02 16:22:13 -04:00
Alex Corey
c9c7d2c2a5 add tooltip proptype 2019-05-02 15:20:25 -04:00
Alex Corey
cc0b2bb5b4 added props to Proptypes 2019-05-02 15:12:04 -04:00
Alex Corey
e29710ebab Merge branch 'master' into 177-UXImprovements 2019-05-02 15:04:57 -04:00
Keith Grant
0ec274d13c Merge pull request #189 from keithjgrant/73-add-org-spacing
Adjust spacing for add/edit org form
2019-05-02 14:53:24 -04:00
Marliana Lara
0fc8179ca3 Merge pull request #190 from marshmalien/pf-base-css-import
Use recommended PatternFly Base CSS
2019-05-02 14:37:52 -04:00
Alex Corey
c6de6b8f25 added props to Proptypes 2019-05-02 14:34:17 -04:00
Marliana Lara
516aecf7de Use recommended PatternFly Base CSS 2019-05-02 11:43:13 -04:00
Keith Grant
eea3d72ffc add CardCloseButton tests 2019-05-02 10:02:45 -04:00
Keith Grant
1490235752 adjust spacing of org add/edit form, add CardCloseButton 2019-05-02 08:39:36 -04:00
Alex Corey
b136ce1e1d updating PR issues updated snapshot test 2019-05-01 15:48:08 -04:00
Alex Corey
f704f320b5 address pr issues 2019-05-01 14:42:59 -04:00
Alex Corey
c4a4275a89 updated snapshot of failing test 2019-05-01 14:42:00 -04:00
Alex Corey
64d4b71ec9 UX improvements 2019-05-01 14:42:00 -04:00
Keith Grant
1be496cfc1 Patternfly upgrade (#188)
* correct spacing after PF update

* update wizard layout/borders for PF upgrade
2019-05-01 13:50:00 -04:00
Alex Corey
420b19cfb9 Merge pull request #185 from AlexSCorey/AlexSCorey-deleteOrgsTest
Alex s corey delete orgs test
2019-04-30 13:22:35 -04:00
Kia Lam
5287af1b9f Add logged in username to top level header bar. 2019-04-30 11:05:08 -04:00
Alex Corey
f71421f60a removed orgsToDelete and fixed other tests 2019-04-30 10:22:25 -04:00
Alex Corey
f4da620c4d updating PR 2019-04-30 09:48:42 -04:00
Keith Grant
ffade973a9 upgrade to patternfly 2.x, pf/react-core 3.x (#184) 2019-04-30 08:19:19 -04:00
Alex Corey
1bae944b85 fix tests and function name changes 2019-04-29 17:29:40 -04:00
Alex Corey
33f7bf67e1 fix merge conflicts 2019-04-29 17:00:04 -04:00
Jake McDermott
6fe93f474f Merge pull request #181 from jakemcdermott/page-header-method-names
use 'handle' notation for header toolbar methods
2019-04-29 14:39:43 -04:00
Jake McDermott
bdad9ac8f9 use 'handle' notation for header toolbar methods
- 'handleFoo' is for methods defined on the component
- 'onFoo' is for naming function props that can be passed to the component from its parents
2019-04-29 14:32:56 -04:00
Jake McDermott
d74c3a09e5 Merge pull request #183 from jakemcdermott/test-fixup
fix unit and functional tests
2019-04-29 14:32:12 -04:00
Jake McDermott
ee5b4b072b fix unit and functional tests 2019-04-29 11:35:06 -04:00
Keith Grant
9d66b583b7 158 paginated data list (#180)
* working: rename OrganizationTeamsList to PaginatedDataList

* convert org notifications list fully to PaginatedDataList

* update NotificationList tests

* refactor org access to use PaginatedDataList

* update tests for org access refactor; fix pagination & sorting

* restore Add Role functionality to Org roles

* fix displayed text when list of items is empty

* preserve query params when navigating through pagination

* fix bugs after RBAC rebase

* fix lint errors, fix add org access button
2019-04-29 10:08:50 -04:00
Michael Abashian
3c06c97c32 Merge pull request #173 from mabashian/151-org-rbac
Add RBAC to org views (now with tests!)
2019-04-26 12:01:33 -04:00
mabashian
8cfe74a854 Code cleanup, renaming functions, use .all() on config promises 2019-04-26 11:02:16 -04:00
mabashian
e5dda696d7 Add new tests for rbac on some of the org pages 2019-04-24 10:10:14 -04:00
mabashian
82db7df6b3 Remove errant comment 2019-04-23 15:19:46 -04:00
mabashian
f57876b6d9 Fix existing test failures 2019-04-23 14:55:06 -04:00
mabashian
38bb4f3f3c Fix merge conflicts 2019-04-23 13:27:00 -04:00
mabashian
5ae7cbb43a Add RBAC to org views 2019-04-23 13:19:34 -04:00
Michael Abashian
1509ef3e80 Merge pull request #143 from mabashian/wizard-access-list
Add roles modal to org access list
2019-04-23 13:12:31 -04:00
mabashian
df87681e6d Fix linting errors 2019-04-23 12:20:08 -04:00
mabashian
621cc3f839 Fix rebase errors 2019-04-23 11:52:49 -04:00
mabashian
e8d73babaf Rebase and incorporates feedback 2019-04-23 10:01:03 -04:00
mabashian
9880f1e124 Removes the need to pass default search params to the select resource step 2019-04-23 10:01:03 -04:00
mabashian
a1002b03fa Add roles modal to org access list 2019-04-23 10:01:03 -04:00
Michael Abashian
47bdbddbeb Merge pull request #172 from jlmitch5/moveTestContext
PR for moving tests to using new mountWithContext helper
2019-04-23 09:58:15 -04:00
Michael Abashian
f7bd9af7a1 Merge branch 'master' into moveTestContext 2019-04-23 09:57:35 -04:00
John Mitchell
261980f18e update components tests to use mountWithContexts when relevant 2019-04-22 16:34:33 -04:00
John Mitchell
986641de9f Fix ORganizationTeams test 2019-04-22 16:33:12 -04:00
John Mitchell
6f789b661f Fix NotificationList tests 2019-04-22 15:43:47 -04:00
John Mitchell
667cbb0c20 update the rest of the organizations tests 2019-04-22 15:11:28 -04:00
Alex Corey
ec3be57539 Merge pull request #162 from AlexSCorey/128-UsePFTabs
Add PF's Tabs to Orgs Details page
2019-04-22 09:26:12 -04:00
John Mitchell
54499dbf69 update OrganizsationAccess and OrganizationAccessList w mountWithContexts 2019-04-18 17:18:19 -04:00
John Mitchell
a6f79c646d update organization add test to use mountWithContexts 2019-04-18 13:54:41 -04:00
John Mitchell
ce49cb9ba4 fix config context if value passed by props not getting overwritten 2019-04-18 13:53:05 -04:00
John Mitchell
5030eb35b6 migrate App.jsx to mountwithContext 2019-04-18 13:10:17 -04:00
Alex Corey
8fa9535b98 styling changes 2019-04-18 13:07:10 -04:00
Jake McDermott
db4734be85 Merge pull request #169 from ansible/jakemcdermott-only-coverage
don't use --watch by default when running tests
2019-04-18 11:29:54 -04:00
John Mitchell
e1333f5e00 move value by prop in providers to consistent interface 2019-04-18 10:52:35 -04:00
Keith Grant
ae72d8dce5 Context test tools (#168)
* add enzyme test helper with lingui provider

* add router context to enzyme test helper

* get 18n, router, & config contexts rendering together in enzyme helper

* add config context to enzyme helpers

* add network and dialog contexts to enzymeHelpers

* convert OrganizationForm tests to use new mountWithContexts helper

* default all context value keys to default unless provided

* document use of mountWithContexts()

* fix typo in CONTRIBUTING.md

* update Organizations to use mountWithContext
2019-04-18 10:03:06 -04:00
Alex Corey
2067718c0e fixed tests 2019-04-17 16:42:39 -04:00
Keith Grant
25db22e072 fix RoutedTabs tests
Signed-off-by: Alex Corey <alex.swansboro@gmail.com>
2019-04-17 16:20:24 -04:00
Alex Corey
ca6153c955 RoutedTabs is now a functional component 2019-04-17 13:51:09 -04:00
Alex Corey
76a7a76e81 refactoring and updating tests 2019-04-17 13:50:38 -04:00
Alex Corey
2daf202e52 addresses PR issues 2019-04-17 13:50:38 -04:00
Alex Corey
178d519f6e Remove unwanted committed file 2019-04-17 13:50:38 -04:00
Jake McDermott
a414c4e60e don't use --watch by default when running tests 2019-04-17 11:54:22 -04:00
Jake McDermott
7c2554be8c Merge pull request #165 from jakemcdermott/dependency-updates
update vulnerable dependencies
2019-04-16 09:40:28 -04:00
Jake McDermott
468a290ba6 update vulnerable dependencies 2019-04-16 09:14:14 -04:00
Michael Abashian
d6f91f8b2d Merge pull request #163 from mabashian/146-access-expand-collapse
Remove expand/collapse from org access list
2019-04-15 10:48:47 -04:00
mabashian
53f564068f Remove leftover isCompact references 2019-04-12 16:10:30 -04:00
mabashian
e11c2df6b6 Remove expand/collapse from org access list 2019-04-12 16:10:30 -04:00
John Mitchell
14c1b85127 Merge pull request #156 from jlmitch5/handleNetworkErrors
Handle network errors
2019-04-12 16:00:54 -04:00
John Mitchell
526b640329 fix translation marked org and org access list strings 2019-04-12 15:23:45 -04:00
John Mitchell
63894bf822 update Promise.all map functions to not be async 2019-04-12 14:35:35 -04:00
John Mitchell
b9e0b2e0ad update to correct grab handleHttpError from props instead of state 2019-04-12 14:35:18 -04:00
John Mitchell
83e6255ba4 update NotifyAndRedirect to function component 2019-04-11 17:16:42 -04:00
John Mitchell
09a950570e Update provider export syntax 2019-04-11 17:10:32 -04:00
John Mitchell
64aecb85fa move router setup to RootProvider 2019-04-11 17:07:46 -04:00
John Mitchell
85b9b4f896 add missing link to react docs about context 2019-04-11 16:18:08 -04:00
John Mitchell
a808462a3d remove test.only causing org access tests to skip 2019-04-11 12:40:27 -04:00
John Mitchell
b17fb8a596 Add handleHttpError prop to stop error from org detail test 2019-04-11 12:36:19 -04:00
John Mitchell
bab7095d67 Update qs path imports to include util 2019-04-11 12:00:39 -04:00
John Mitchell
e36320174c Add contrib docs based on context changes and move qs to util dir 2019-04-11 11:58:15 -04:00
John Mitchell
abc3733449 fix test after rebase of org teams update 2019-04-11 11:06:39 -04:00
John Mitchell
344713f938 fix unit tests for network handling 2019-04-11 10:42:33 -04:00
John Mitchell
ad0e409448 do 404 modal redirect on unknown routes 2019-04-11 10:42:00 -04:00
John Mitchell
81267c7212 update language and stylign for all warning/danger modals 2019-04-11 10:42:00 -04:00
John Mitchell
fa232a94bd update api calls to utilized network context 2019-04-11 10:41:59 -04:00
John Mitchell
722ae932ab update login modal to grab error from RootDialog 2019-04-11 10:38:54 -04:00
John Mitchell
aea4a04c66 add RootDialog and Network contexts, update app bootstrapping 2019-04-11 10:34:48 -04:00
John Mitchell
e20cf72dd6 add AlertModal component and update styling of delete confirmations 2019-04-11 10:34:48 -04:00
John Mitchell
af3419c2dd update eslint to allow short circuit ternary chains 2019-04-11 10:29:45 -04:00
Alex Corey
84f45d122d Merge pull request #160 from AlexSCorey/114-HeaderIcons
Adds tooltip to username and help icon
2019-04-10 16:39:20 -04:00
Alex Corey
c4ffc58228 addresses PR issues 2019-04-10 14:16:22 -04:00
Keith Grant
96906c2ece Merge pull request #157 from keithjgrant/145-org-teams-empty-state
Org teams empty state
2019-04-10 14:01:55 -04:00
Marliana Lara
0f2355f416 Merge pull request #159 from marshmalien/ux-org-list-links
Remove org list links and update label
2019-04-10 13:19:44 -04:00
Alex Corey
731da8049b Adds tooltip to username and help icon. 2019-04-10 10:48:56 -04:00
Keith Grant
909c5e77c4 rename all test files to *.test.js 2019-04-10 09:55:57 -04:00
Marliana Lara
2ab688932d Remove org list links 2019-04-09 11:37:43 -04:00
Keith Grant
70137dea5a fix tests for OrganizationTeams, OrganizationTeamsList 2019-04-08 10:59:26 -04:00
Marliana Lara
3d6790a419 Merge pull request #155 from marshmalien/ux-instance-groups-lookup-height
UX - Lookup static height
2019-04-08 10:40:20 -04:00
Marliana Lara
212d3d517d Replace lookup with patternfly's input group component and 'fix' the height 2019-04-05 15:39:14 -04:00
Alex Corey
09fd8e8106 Merge pull request #141 from AlexSCorey/48-deleteOrgs
Add alert for org. delete.
2019-04-05 12:39:38 -04:00
Alex Corey
c0b882d6fb fixes progress bar 2019-04-05 12:01:04 -04:00
Alex Corey
a42a1bfa17 Addresses PR feedback 2019-04-05 11:29:48 -04:00
Keith Grant
89ecddf662 refactor OrganizationTeams/OrganizationTeamsList 2019-04-05 10:52:52 -04:00
Alex Corey
de55ec1688 Add alert for org. delete. 2019-04-05 10:48:51 -04:00
Marliana Lara
2062124a92 Merge pull request #149 from marshmalien/org-details-ig-show-more-less
Update Org Details UX layout
2019-04-05 10:04:20 -04:00
Marliana Lara
868ad51158 Set static value to const variable 2019-04-05 09:58:19 -04:00
Keith Grant
c2a223bbb4 delete unused method 2019-04-04 09:17:33 -04:00
Marliana Lara
268d50a339 Update Org Details UX layout and add show more/less to instance groups field 2019-04-03 13:40:08 -04:00
Keith Grant
04bd4d973a Merge pull request #150 from keithjgrant/test-fix
update tests to match new ids
2019-04-03 13:38:01 -04:00
Keith Grant
8700f32ffc fix tests eslintrc 2019-04-03 13:29:25 -04:00
Keith Grant
9781c22c3f update tests to match new ids 2019-04-03 13:16:29 -04:00
Keith Grant
99b2350778 Merge pull request #144 from keithjgrant/120-add-org-form-cleanup
Refactor org add/edit forms with Formik
2019-04-03 09:15:03 -04:00
Keith Grant
0c63a57418 improve org form input ids 2019-04-03 09:13:26 -04:00
Keith Grant
3f2cc53992 fix tests eslintrc 2019-03-29 14:28:41 -04:00
Keith Grant
20f27f4062 make InstanceGroupsLookup tooltip customizable via prop 2019-03-29 14:22:09 -04:00
Keith Grant
40b88da9dd add FormRow component; rename unwrapped components with underscore 2019-03-29 13:50:17 -04:00
Keith Grant
2002d48bcc minor tweaks 2019-03-28 16:44:44 -04:00
Keith Grant
6353d5e410 update tests for org add/edit refactor 2019-03-28 13:02:04 -04:00
John Mitchell
cc0fd6beb6 fix openDeleteModal with button test 2019-03-28 10:42:17 -04:00
Alex Corey
f3a07753e6 Add alert for org. delete. 2019-03-28 10:29:55 -04:00
Keith Grant
64e933acb4 refactor out OrganizationForm; share between add & edit 2019-03-27 15:29:46 -04:00
Michael Abashian
77ab6ec044 Merge pull request #142 from mabashian/upgrade-pf-2.9.2
Upgrade pf react-core to 2.9.2
2019-03-27 13:49:39 -04:00
John Mitchell
4e80f05cdf Merge pull request #136 from jlmitch5/addOrgTeamsList
add org teams list
2019-03-27 11:30:59 -04:00
Alex Corey
ae622c4875 Merge pull request #139 from AlexSCorey/138-updateFunctionName
Fixes function naming
2019-03-27 11:05:18 -04:00
Keith Grant
40b2539626 rework org edit form to use Formik 2019-03-27 10:49:10 -04:00
Alex Corey
a430b5bf9a fixes function naming to match our naming convention in the org. notifications. 2019-03-26 18:08:09 -04:00
John Mitchell
aeed1d8ee9 one org teams rename spelling issue 2019-03-26 17:06:43 -04:00
John Mitchell
5419434daa rename org teams functions based on guide 2019-03-26 17:04:34 -04:00
mabashian
9b314a6f2f Upgrade pf react-core to 2.9.2 2019-03-26 11:49:41 -04:00
Keith Grant
02cd188c2f rename onX methods to handleX 2019-03-25 15:40:20 -04:00
Keith Grant
f3a6da20f6 create InstanceGroupsLookup for org add/edit forms 2019-03-25 11:59:14 -04:00
Keith Grant
f0c94c7e9c stub api in org add/edit tests 2019-03-25 11:56:29 -04:00
kialam
1cb2a95a47 Merge pull request #137 from ansible/document-naming-functions
Update contributing doc
2019-03-21 14:26:12 -04:00
John Mitchell
7e414ace5a add org teams list 2019-03-21 13:12:12 -04:00
Kia Lam
e3a6a20049 Update contributing doc to include:
- Method naming convention
- Initial Empty State convention
2019-03-21 12:51:23 -04:00
Michael Abashian
7bd8234edf Merge pull request #135 from mabashian/upgrade-pf
Upgrades pf deps to latest
2019-03-20 10:53:10 -04:00
mabashian
d30aed9231 Upgrades pf deps to latest 2019-03-19 16:41:26 -04:00
Michael Abashian
c288c5fcbe Merge pull request #134 from mabashian/toolbar-refactor-v2
Refactor of DataListToolbar v2
2019-03-19 14:16:04 -04:00
mabashian
fc80470e5d Normalize event callback function names in search and sort components 2019-03-19 14:01:39 -04:00
mabashian
3596d776fc Refactor of DataListToolbar. Creates a number of smaller components used by the toolbar. Adds support for passing in an add button node to the toolbar. 2019-03-19 14:01:39 -04:00
kialam
dbeef0a823 Merge pull request #123 from ansible/access-list-remove-role-functionality
Org Access List: add remove role functionality
2019-03-18 10:25:56 -04:00
Kia Lam
a4493cd02b Add empty initial states and adjust rendering logic. 2019-03-18 09:32:11 -04:00
Kia Lam
a5683fb354 Clear mocked methods after each test to prevent overlaps with other tests. 2019-03-14 10:41:28 -04:00
Kia Lam
518ecee53e Apply padding to Alert component. 2019-03-14 10:35:54 -04:00
Kia Lam
6bd5ee4201 Move test for AccessList. 2019-03-13 17:12:16 -04:00
Kia Lam
390832cc1a Rename AccessList to OrganizationAccessList and fix paths. 2019-03-13 16:46:50 -04:00
Kia Lam
c6d810621f Move AccessList out of components directory.
- The AccessList component is pretty specific to the Organization component, and given the structure and methods within it, is pretty context-specific and not a good candidate to be a re-useable component.
2019-03-13 16:37:03 -04:00
Alex Corey
0f6a40014e Merge pull request #129 from AlexSCorey/paginationTest
add pagination test
2019-03-13 16:21:01 -04:00
Alex Corey
91e4679311 adds test to ensure page size option dropdown is removed is no page size option is passed in. 2019-03-13 16:19:59 -04:00
Kia Lam
0495214f47 Address PR feedback. 2019-03-13 15:59:42 -04:00
Kia Lam
21156d1409 Merge remote-tracking branch 'origin' into access-list-remove-role-functionality 2019-03-13 15:43:30 -04:00
Kia Lam
198dfe7f2e Add unit test to check state when user tries to delete a role. 2019-03-13 14:44:12 -04:00
Keith Grant
e1ebcd51b0 Merge pull request #131 from keithjgrant/add-org-ux-improvements
UX improvements for Add Organization screen
2019-03-13 13:36:46 -04:00
Keith Grant
fe5821eb15 Merge pull request #132 from keithjgrant/org-notification-spacing
increase space next to organization notifications
2019-03-13 08:37:03 -04:00
Keith Grant
24f0fe2980 increase space next to organization notifications 2019-03-12 16:04:22 -04:00
Keith Grant
188eaede43 switch to PatternFly Tooltip everywhere 2019-03-12 15:24:36 -04:00
John Mitchell
bbb31eb478 fix pagination page input and componentDidUpdate tests 2019-03-12 15:03:21 -04:00
Alex Corey
d96b88e495 add pagination test 2019-03-12 12:28:42 -04:00
Keith Grant
601214f6d4 add close (x) button to Add Org screen 2019-03-12 11:48:29 -04:00
Keith Grant
5b3f5206c4 add tooltips to add organization form 2019-03-12 08:58:12 -04:00
Keith Grant
ecb7306c46 Adding organization: add inputs helper text 2019-03-11 14:41:46 -04:00
Kia Lam
3b65068258 Add remove role functionality. 2019-03-08 13:56:27 -05:00
Keith Grant
a3bea6d4a8 Merge pull request #122 from keithjgrant/fix-pagination-text
fix pagination text
2019-03-06 14:42:52 -05:00
Keith Grant
4d15df2b48 fix pagination text when items displayed matches number of items per page 2019-03-06 14:30:21 -05:00
kialam
e935776067 Merge pull request #121 from ansible/org-access-list
Organization Access List
2019-03-05 18:56:29 -05:00
Kia Lam
9f86fc2def Respond to PR feedback. 2019-03-05 12:01:06 -05:00
Kia Lam
35ecd83214 Some cosmetic changes.
- Reverse order of Expand/Compact icons in DataListToolbar to Compact/Expand.
- Make Expanded the default view for Access Lists.
- Make role badge styling closer to Chip component styling.
2019-03-04 14:38:58 -05:00
Kia Lam
86a92fefe7 Merge remote-tracking branch 'origin' into org-access-list 2019-03-01 10:37:44 -05:00
Kia Lam
bf7e6201a2 Refactor Access List.
- Derive Team Roles without making extra API call.
- Consistent variable naming convention use camelCase.
- More informative error display.
2019-03-01 10:12:36 -05:00
Kia Lam
a3a80bc23e Fix prop errors in unit tests. 2019-02-27 18:03:15 -05:00
Kia Lam
5659270d3e Add unit test for Access List component. 2019-02-27 17:30:02 -05:00
Marliana Lara
6f26383e06 Merge pull request #119 from marshmalien/org-edit
Add Org Edit View
2019-02-26 15:04:08 -05:00
Marliana Lara
053b21e832 Use ternary operator in Org Edit form 2019-02-26 14:21:27 -05:00
Kia Lam
1443625d89 Abstract out Access List as shared component. 2019-02-26 13:23:34 -05:00
Kia Lam
3cd54c45eb Add Access List to Orgs. 2019-02-26 08:39:13 -05:00
Marliana Lara
a7b51c526a Update Lookup chip test 2019-02-25 11:42:18 -05:00
Marliana Lara
ffefba9bf9 Fix bug where lookup parent state is not updated on toggleSelected 2019-02-25 11:05:42 -05:00
Marliana Lara
ff339e0eba Update org edit form layout and remove chip group component from lookup; 2019-02-25 09:15:21 -05:00
Marliana Lara
c3fc00c45a Add Organization Edit tests and fix Lookup unit tests 2019-02-22 14:53:47 -05:00
Marliana Lara
d2cf2c275b Add Organization Edit view 2019-02-22 14:53:17 -05:00
Marliana Lara
f1fefbf5f0 Add organization details patch and instance groups disassociate methods to api 2019-02-22 14:51:38 -05:00
Marliana Lara
b6eacbab86 Rename createInstanceGroups api method to associateInstanceGroup 2019-02-22 14:47:25 -05:00
Marliana Lara
92d3cb6dc4 Replace Lookup tags with pf-react Chip component 2019-02-22 14:35:58 -05:00
Michael Abashian
de3cc4637e Merge pull request #112 from mabashian/88-sort-filter-ig-modal
Adds sorting to IG lookup on org form
2019-02-20 15:53:47 -05:00
mabashian
e28776962d Fixes left margin on notifications tab 2019-02-20 14:52:11 -05:00
mabashian
87d9df5876 Fixes modal button margin and focus border on toolbar buttons 2019-02-20 13:28:06 -05:00
mabashian
56bd145f21 Adds sort to IG modal 2019-02-20 11:30:58 -05:00
mabashian
581ec8860b recompile strings to fix Foo being displayed instead of My View 2019-02-20 09:41:38 -05:00
Marliana Lara
1599d2c62c Merge pull request #110 from marshmalien/upgrade-patternfly
Upgrade @patternfly-next to @patternfly/patternfly
2019-02-20 09:29:07 -05:00
Marliana Lara
83982d5e2e Fix Modal footer button styles 2019-02-19 16:34:27 -05:00
Marliana Lara
8be8663665 Fix AnsibleSelect tests 2019-02-19 16:14:28 -05:00
Marliana Lara
740a9c1e61 Remove pf base css import and tweak styles 2019-02-19 16:10:50 -05:00
Marliana Lara
9229c8e724 Add translations to AnsibleSelect 2019-02-19 16:10:47 -05:00
Marliana Lara
7567a6b36a Fix Org Detail Action button margin 2019-02-19 16:05:47 -05:00
Marliana Lara
240d07b6d4 Refactor styles and remove patternfly utility classes 2019-02-19 16:05:45 -05:00
Marliana Lara
09107aef1f Amend LoginForm component to use updated helperText props for @patternfly/react-core 2.1.8 2019-02-19 16:04:48 -05:00
Marliana Lara
68225d191a Remove old BackgroundImageSrc tokens for @patternfly/react-core 2.1.8 2019-02-19 16:04:47 -05:00
Marliana Lara
58f273347c Remove heroImgSrc props for @patternfly/react-core 2.1.8 2019-02-19 16:04:47 -05:00
Marliana Lara
c4065a54bd Rename Select components to FormSelect for @patternfly/react-core 2.1.8 2019-02-19 16:04:45 -05:00
Marliana Lara
50ebf65178 Update @patternfly/patternfly-next references to @patternfly/patternfly 2019-02-19 16:00:11 -05:00
Marliana Lara
f5f67627db Update @patternfly/* dependencies
* Remove @patternfly/react-styles dependency
2019-02-19 16:00:11 -05:00
kialam
e0df011804 Merge pull request #109 from ansible/add-prop-checking
Add proptypes to shared components
2019-02-19 11:37:03 -05:00
kialam
f9d615fdee Fix unit tests. 2019-02-19 11:28:17 -05:00
kialam
da8c3f6c43 Enable submit button by default. 2019-02-19 10:24:26 -05:00
kialam
c3493b0539 Remove unused method. 2019-02-19 10:19:47 -05:00
kialam
bba1c4f5b6 Restore FormGroup to parent Add Org component for AnsibleSelect. 2019-02-19 10:18:03 -05:00
kialam
2a254ea538 Add typechecking to contributing guide. 2019-02-15 15:20:02 -05:00
kialam
b340d49cb7 Integrate proptypes for our shared components.
- Fix unit tests.
- Fix linter errors.
2019-02-15 15:08:52 -05:00
kialam
91f87b6d81 Merge pull request #106 from ansible/add-select-default-option
Add default option for AnsibleSelect dropdown.
2019-02-14 11:00:04 -05:00
kialam
7c009fc315 Update unit tests to use new props. 2019-02-14 10:53:53 -05:00
kialam
f09eb182c2 Merge remote-tracking branch 'origin/master' into add-select-default-option 2019-02-14 10:38:28 -05:00
John Mitchell
614116c90e Merge pull request #104 from jlmitch5/instanceGroupsPagination
add pagination to instance groups
2019-02-13 15:42:36 -05:00
John Mitchell
b4007c7e04 put FormGroup component in form instead of in AnsibleSelect component 2019-02-13 15:40:46 -05:00
kialam
1f07fc8494 Make default option selectable but return null value. 2019-02-13 15:39:29 -05:00
kialam
2b18cee9c0 Fix linter errors and add test to AnsibleSelect component. 2019-02-13 15:39:29 -05:00
kialam
97477b789a Add default option for AnsibleSelect dropdown. 2019-02-13 15:39:26 -05:00
John Mitchell
f2ab7f62b9 fix disabled of submit button 2019-02-13 15:09:14 -05:00
John Mitchell
35c94e9cd8 update selected to value in AnsibleSelect 2019-02-13 14:52:11 -05:00
John Mitchell
de658939c5 add default value to props destructure statement 2019-02-13 10:50:04 -05:00
John Mitchell
cbc1ae8875 fix tests based on AnsibleSelect fn name change 2019-02-13 10:34:32 -05:00
John Mitchell
c1381f7b98 incorporate feedback on instance groups pagination 2019-02-12 11:59:49 -05:00
John Mitchell
6431ec603f fix AnsibleSelect passing onChange callback 2019-02-12 11:53:22 -05:00
Marliana Lara
fb7ccdb726 Merge pull request #108 from marshmalien/remove-breadcrumb-text-style
Remove breadcrumb item capitalize text style
2019-02-12 11:32:14 -05:00
Marliana Lara
9619513017 Remove breadcrumb item capitalize text style 2019-02-12 11:18:28 -05:00
John Mitchell
c67088628f fix border color 2019-02-12 09:05:22 -05:00
John Mitchell
680d153a14 add pagination to instance groups lookup modal 2019-02-11 18:10:27 -05:00
Marliana Lara
cdc8b372f9 Merge pull request #105 from marshmalien/wrap-long-detail-descriptions
Wrap Org Details description field
2019-02-11 12:58:28 -05:00
Marliana Lara
0b7c643e75 Wrap Org Details description field 2019-02-11 12:21:34 -05:00
Marliana Lara
8e194baa66 Merge pull request #102 from marshmalien/style-tab-text
Update organization tab styles
2019-02-06 14:37:41 -05:00
Marliana Lara
df30a2e8d1 Update organization tab styles 2019-02-06 14:00:26 -05:00
Marliana Lara
241f8a8ac8 Merge pull request #100 from marshmalien/org-details
Add Organization Details view and tests
2019-02-06 12:04:46 -05:00
Marliana Lara
9d9b94c8c3 Increase label font-weight and vertically align labels and chips 2019-02-06 11:42:53 -05:00
John Mitchell
56c0ab97ed Merge pull request #99 from jlmitch5/addOrgEmptyListAndUpdateCSS
Add org empty list and update css
2019-02-05 11:52:36 -05:00
Marliana Lara
8846e1427e Add Organization Details view and test 2019-02-05 10:52:33 -05:00
John Mitchell
736f1e1775 update conditional showing of empty list component 2019-02-04 15:39:44 -05:00
John Mitchell
21bdd487e6 fix to tabs -- padding around and left most border 2019-01-30 16:32:42 -05:00
John Mitchell
4ce19a4b42 add empty list functionality to org list 2019-01-30 16:20:04 -05:00
John Mitchell
98cb8c6f6e update scss patternfly override file and add center empty list tweak 2019-01-30 16:20:04 -05:00
Michael Abashian
a2007b8e0c Merge pull request #98 from mabashian/selected-list
Adds selected list to lookup component
2019-01-30 15:58:14 -05:00
mabashian
0e9e17f957 Only update selected instance groups if the select button is clicked in the modal 2019-01-30 15:27:12 -05:00
mabashian
6ed36daef7 Fixes close button on tags in instance group form field 2019-01-30 12:59:22 -05:00
mabashian
5778c9cf05 Removes commented styles, use defined color variable in lockup 2019-01-30 12:46:00 -05:00
mabashian
2579e30ca1 Pulls in latest pf-react. Adds selected list component to org instance groups lookup 2019-01-30 12:46:00 -05:00
John Mitchell
701eb6afa5 Merge pull request #97 from jlmitch5/newPagination
New pagination
2019-01-30 12:16:21 -05:00
John Mitchell
e4d44efea2 reduce disabled background color to increase contrast w border 2019-01-30 12:14:48 -05:00
John Mitchell
3c0744629b update pagination component based on ux feedback 2019-01-29 12:50:29 -05:00
John Mitchell
990851aa3b wrap org list in Card for consistency between detail 2019-01-29 12:50:15 -05:00
Marliana Lara
65e369c0f3 Merge pull request #96 from marshmalien/refactor-url
Refactor Breadcrumbs, Tabs, routing
2019-01-28 12:02:23 -05:00
Marliana Lara
9048c34a7d Fix merge conflicts and linting errors 2019-01-25 16:49:46 -05:00
Marliana Lara
21298c8872 Add Breadcrumbs test 2019-01-25 16:42:09 -05:00
Marliana Lara
b820e411d3 Refactor breadcrumbs, tabs, routing.
* Cleanup previous params logic from Notificaitons list
* Add shared breadcrumbs and tabs components
* Structure Organization screens to render only cardBody content
* Add styles
* Fetch organization when location changes
2019-01-25 16:42:04 -05:00
John Mitchell
dd522c240e remove test debuggers 2019-01-25 16:17:58 -05:00
John Mitchell
54e79a93d9 Merge pull request #95 from jlmitch5/fixLinting
Fix linting
2019-01-25 16:16:55 -05:00
John Mitchell
02d7006ea4 fix tests 2019-01-25 15:22:32 -05:00
John Mitchell
7de89f6486 fix linting issues 2019-01-24 13:05:36 -05:00
John Mitchell
2588832629 remove debug flag from eslint 2019-01-24 12:08:39 -05:00
John Mitchell
f37bdba645 update eslint config and add eslint ignore 2019-01-24 11:36:18 -05:00
Michael Abashian
28b5d43e1f Merge pull request #93 from mabashian/63-org-notifications
Add notification list to org
2019-01-24 09:21:13 -05:00
mabashian
47719776f2 More cleanup based on pr feedback. Adds org notif list page and tests 2019-01-23 16:53:02 -05:00
mabashian
6c19d6ae4e Removes unnecessary fragment elements. Fixes vertical alignment on notif row item. Bind notification list functions to constructor 2019-01-23 14:13:51 -05:00
mabashian
c97dfeb725 Cleanup after change post... to create... 2019-01-21 15:46:11 -05:00
mabashian
2c19a5a1d7 Changed post to create in api.js. Removed capitalize text component in favor of css solution. Updates to empty list contents. Fixes padding on notifications list 2019-01-21 15:44:34 -05:00
mabashian
4f929c7052 Fix inadvertent merge conflict change 2019-01-21 13:30:15 -05:00
mabashian
58f99c8918 Adds notification list to orgs 2019-01-21 13:18:37 -05:00
kialam
3060abab1d Merge pull request #87 from ansible/lookup-form-component
Lookup form component
2019-01-16 13:32:28 -05:00
kialam
a70a0fa622 Bump Lookup component test coverage up. 2019-01-16 13:15:51 -05:00
kialam
7230b4bf8d Bump up unit test coverage for OrganizationAdd component. 2019-01-15 15:51:37 -05:00
kialam
fc32cf026f Address review feedback. 2019-01-15 15:15:17 -05:00
kialam
e8fe6fe33c Fix & Add unit tests. 2019-01-15 14:58:23 -05:00
kialam
215c23609c Hook up 'x' remove button; rename ListItem component. 2019-01-14 09:45:49 -05:00
kialam
c5cd659c83 Redirect user to org detail page after successful POST. 2019-01-08 16:09:30 -05:00
kialam
a1d1dc7a24 Style pop up modal 2019-01-08 15:56:37 -05:00
John Mitchell
a1419f0f20 Merge pull request #85 from jlmitch5/portalModeToMyView
update portal mode to my view and update translations
2019-01-08 14:00:54 -05:00
kialam
c085fc6751 Merge remote-tracking branch 'origin/master' into lookup-form-component 2019-01-08 13:47:06 -05:00
Marliana Lara
57b1c2c42c Merge pull request #86 from marshmalien/directory-structure
Move Organization screens and tests into new folder structure
2019-01-08 13:06:55 -05:00
kialam
395e30509b Fix linter and existing unit tests. 2019-01-07 17:17:22 -05:00
kialam
517ef8a2c9 Hook up add instance group functionality. 2019-01-07 16:56:39 -05:00
Marliana Lara
d040f063e9 Move Organization screens and tests into new folder structure 2019-01-07 15:33:27 -05:00
John Mitchell
e77efbfec2 update portal mode to my view and update translations 2019-01-07 15:23:31 -05:00
kialam
f34ec4be10 Merge remote-tracking branch 'origin/master' into lookup-form-component 2019-01-07 14:40:35 -05:00
Marliana Lara
f521fe5cbc Merge pull request #79 from marshmalien/org-breadcrumb-tabs
Org Breadcrumb and Tabs
2019-01-07 11:23:51 -05:00
Marliana Lara
2d3152ef41 Add translation and small css tweaks 2019-01-07 11:15:11 -05:00
kialam
c63896fbb6 Implement basic lookup modal component. 2019-01-07 10:09:35 -06:00
Marliana Lara
f76e9bddf9 Update org utils test 2019-01-07 10:52:50 -05:00
Marliana Lara
83e300636d Move Tab components out into component directory 2019-01-07 10:52:50 -05:00
Marliana Lara
913077c489 Update tab content and related badge links 2019-01-07 10:52:50 -05:00
Marliana Lara
e782be10b6 Add Tab styles 2019-01-07 10:52:50 -05:00
Marliana Lara
7406421d1b Add PF Breadcrumb components 2019-01-07 10:52:47 -05:00
Jake McDermott
976c490dc3 Merge pull request #84 from jakemcdermott/tests-fixup
add more unit and functional test coverage
2019-01-07 07:50:11 -05:00
Jake McDermott
a83e5e5675 add unit test coverage for DataListToolbar.jsx 2019-01-07 07:40:31 -05:00
Jake McDermott
8756da59fa add unit test coverage for TowerLogo.jsx 2019-01-07 07:40:25 -05:00
Jake McDermott
4936238344 add more unit test coverage for index.jsx 2019-01-07 07:40:19 -05:00
Jake McDermott
cb0367ac28 handle null error response 2019-01-07 07:40:12 -05:00
Jake McDermott
48e1fbfb38 add unit test coverage for AnsibleSelect.jsx 2019-01-07 07:40:06 -05:00
Jake McDermott
bbd94fa4f7 add functional test coverage for App.jsx 2019-01-07 07:39:59 -05:00
Jake McDermott
164464c595 add more test coverage for api client 2019-01-07 07:39:51 -05:00
Jake McDermott
5bff942110 pagination test fixup 2019-01-07 07:39:42 -05:00
Jake McDermott
6a7ba87a02 org-add fixup
re-adding a changeset I missed when resolving a merge conflict earlier
2019-01-07 07:39:31 -05:00
Jake McDermott
3f2e47b1b1 Merge pull request #82 from jakemcdermott/page-toolbar-tests
add some tests for page toolbar and background wrapper
2019-01-04 15:28:06 -05:00
Jake McDermott
df6877bb99 Merge pull request #83 from jakemcdermott/update-webpack-dev-server
update webpack-dev-server
2019-01-04 15:20:54 -05:00
Jake McDermott
b69522b5aa add basic test for background wrapper component 2019-01-04 15:20:32 -05:00
Jake McDermott
95861491cb add more tests for header toolbar 2019-01-04 15:20:22 -05:00
Jake McDermott
e07db0c05e update webpack-dev-server 2019-01-04 15:12:57 -05:00
Jake McDermott
8d62b7a2e3 Merge pull request #75 from ansible/contributing-guide
Add a contributing doc to our repo.
2019-01-03 22:24:31 -05:00
Jake McDermott
f6f6643622 Merge pull request #81 from jakemcdermott/update-and-refactor
wip - update to pf-react 1.43 and refactor some things
2019-01-03 19:37:16 -05:00
Jake McDermott
0d565eb3e3 add header toolbar test 2019-01-03 18:11:26 -05:00
Jake McDermott
23e34bcbbe remove config pass-through
removing this for the time being to giving the config Context a try
2019-01-03 18:00:20 -05:00
Jake McDermott
87101a487d use constructor bound methods for pagination 2019-01-03 17:54:07 -05:00
Jake McDermott
6446e45165 use constructor bound methods for org view 2019-01-03 17:54:04 -05:00
Jake McDermott
afcfd1640e use constructor bound methods for org list 2019-01-03 17:54:01 -05:00
Jake McDermott
e015558190 use constructor bound methods for data toolbar 2019-01-03 17:53:58 -05:00
Jake McDermott
e5cdea8daf use constructor bound methods for logo 2019-01-03 17:53:55 -05:00
Jake McDermott
5948ecce16 use constructor bound methods for nav group 2019-01-03 17:53:52 -05:00
Jake McDermott
24208197e8 use constructor bound methods for Login 2019-01-03 17:53:49 -05:00
Jake McDermott
dce50fe18b update route group params 2019-01-03 17:53:46 -05:00
Jake McDermott
3e201d3ca0 add config pass-through to inline render 2019-01-03 17:53:43 -05:00
Jake McDermott
4ccce4cc9e add header toolbar component and move About modal control to App 2019-01-03 17:53:40 -05:00
Jake McDermott
31d0347553 test fixup 2019-01-03 17:53:37 -05:00
Jake McDermott
8f4437e17e initialize and pass api client to subviews 2019-01-03 17:53:34 -05:00
Jake McDermott
a023df2c17 add inline rendering prop to app component 2019-01-03 17:53:31 -05:00
Jake McDermott
f2760ed91c use default patternfly breakpoint token name 2019-01-03 17:53:28 -05:00
Jake McDermott
9c6df68557 decouple App and Login components 2019-01-03 17:53:25 -05:00
Jake McDermott
6efd523db2 move wrapper / shared components out of App component 2019-01-03 17:53:21 -05:00
Jake McDermott
f975f9fa75 add background component 2019-01-03 17:53:18 -05:00
Jake McDermott
a2601d5f67 remove conditional redirect component 2019-01-03 17:53:08 -05:00
Jake McDermott
18505b35b8 add params for component routing 2019-01-03 17:53:05 -05:00
Jake McDermott
8bd85193ab fix login page test for @patternfly/react-core 1.43.5 2019-01-03 17:53:01 -05:00
Jake McDermott
70840841c1 update LoginPage param names for @patternfly/react-core 1.43.5 2019-01-03 17:52:58 -05:00
Jake McDermott
1c483a42c6 update @patternfly/react-core to 1.43.5 2019-01-03 17:52:53 -05:00
Jake McDermott
2254bdb0e1 make default dev server target overridable with env vars 2019-01-03 17:52:46 -05:00
Jake McDermott
23bb32b7ad Merge pull request #72 from ansible/react-context-api
Implement React Context API
2019-01-03 15:28:54 -05:00
kialam
e8924e8f6f Fix linter errors. 2019-01-03 15:20:46 -05:00
kialam
e77d81dd5b Lift config context one level higher.
- Refactor About component to use config context.
- Update About component unit tests.
2019-01-03 15:20:41 -05:00
kialam
a217a387c6 Use new lifecycle method to update component state.
- Use component state to handle rendering of Ansible Select dropdown based on the number of custom virtualenvs the API returns.
2019-01-03 15:20:35 -05:00
kialam
13680a436c Add unit tests for recent changes to App.jsx. 2019-01-03 15:20:30 -05:00
kialam
6c307726db Use setState instead of sessionStorage for config data. 2019-01-03 15:20:23 -05:00
kialam
9bc87b3e80 Implement React Context API
- Move API GET request to /v2/config out to the top level of our App.
- Store /v2/config response data in sessionStorage.
- Use Context API to pass down relevant data to Organizations component.
- Wrap our AnsibleSelect component as a context consumer and pass in the list of Ansible Environments of the logged in user.
- Clear sessionStorage object when user logs out.
- Update unit tests.
2019-01-03 15:20:08 -05:00
Jake McDermott
f678e158f8 Merge pull request #57 from jlmitch5/updateComponentTests
Update component tests and bump back up coverage
2019-01-03 13:52:28 -05:00
John Mitchell
11583dbff0 update pagination tests 2019-01-03 13:37:56 -05:00
John Mitchell
e48c734925 update datelisttoolbar test 2019-01-03 13:37:46 -05:00
John Mitchell
e25dcb2448 update app and towerlogo tests and remove stale code 2019-01-03 13:37:41 -05:00
John Mitchell
ebd09883fe update DataListToolbar component and tests 2019-01-03 13:37:31 -05:00
kialam
fefbb8fff8 Fix linter errors. 2019-01-02 09:19:11 -07:00
kialam
f5119e5d97 Lift config context one level higher.
- Refactor About component to use config context.
- Update About component unit tests.
2019-01-02 09:03:48 -07:00
kialam
5fcdd16f54 Use new lifecycle method to update component state.
- Use component state to handle rendering of Ansible Select dropdown based on the number of custom virtualenvs the API returns.
2018-12-22 09:03:44 -05:00
kialam
e30b198418 Remove duplicate REST call in add org component. 2018-12-21 11:56:39 -05:00
kialam
aaa9096b4e Add unit tests for recent changes to App.jsx. 2018-12-21 10:25:17 -05:00
kialam
4eb04b6f5c Use setState instead of sessionStorage for config data. 2018-12-21 10:20:07 -05:00
kialam
6dc11a926e Merge remote-tracking branch 'origin/master' into react-context-api 2018-12-21 10:16:50 -05:00
Michael Abashian
7f1c3c8c6a Update readme to fix display of unit test commands 2018-12-20 09:52:03 -05:00
kialam
fe857ad68b Merge remote-tracking branch 'origin/master' into react-context-api 2018-12-18 10:52:09 -05:00
kialam
fd513f704b Add a contributing doc to our repo. 2018-12-18 10:30:48 -05:00
kialam
46e9fcfda7 Merge pull request #53 from ansible/add-org-new
Basic Add Organization View
2018-12-17 17:14:05 -05:00
Michael Abashian
32378266bd Merge pull request #59 from mabashian/45-list-ux
Small ux changes on the org list based on feedback
2018-12-17 14:55:19 -05:00
kialam
ff0015e21d Hook up Cancel button
- Update unit tests.
- Add basic error handling for API requests in Add Orgs component.
2018-12-17 13:44:59 -05:00
mabashian
6ce88fdf4d Separates search dropdown items from sort dropdown items 2018-12-17 13:16:08 -05:00
mabashian
21cf1d85e3 Remove border-radius on add button 2018-12-17 12:40:20 -05:00
mabashian
d43f0cb2fc Removed extraneous style 2018-12-17 12:40:20 -05:00
mabashian
71ace1bc00 Small ux changes on the org list based on feedback 2018-12-17 12:40:20 -05:00
kialam
656e6d4f6a Add back missing style. 2018-12-17 12:39:41 -05:00
Jake McDermott
b375963165 Merge pull request #68 from ansible/refactor-nav
replace navitem generator with expandable navgroup component
2018-12-17 12:15:39 -05:00
kialam
b3b6e0515e Merge remote-tracking branch 'origin/add-org-new' into react-context-api 2018-12-17 11:59:46 -05:00
kialam
b8fc402d55 Implement React Context API
- Move API GET request to /v2/config out to the top level of our App.
- Store /v2/config response data in sessionStorage.
- Use Context API to pass down relevant data to Organizations component.
- Wrap our AnsibleSelect component as a context consumer and pass in the list of Ansible Environments of the logged in user.
- Clear sessionStorage object when user logs out.
- Update unit tests.
2018-12-17 11:44:11 -05:00
Michael Abashian
e58613b441 Merge pull request #70 from mabashian/69-hide-expand-collapse
Adds option to hide expand/collapse in toolbar and hides it for the org list
2018-12-17 11:40:24 -05:00
mabashian
14f1c4b652 Conditionally render rather than show expand/collapse 2018-12-17 11:28:34 -05:00
Jake McDermott
1bb86dbdf0 use beginning of location path name when checking for active items 2018-12-17 00:16:49 -05:00
Jake McDermott
3d730ef8d2 add basic unit test for expandable navgroup component 2018-12-17 00:16:31 -05:00
Jake McDermott
5d4aa56f4a refactor wrapped nav components to expandable nav group component 2018-12-16 23:40:54 -05:00
kialam
9292b21a41 Merge remote-tracking branch 'origin/master' into add-org-new 2018-12-14 10:14:36 -05:00
mabashian
4a8791693f Adds option to hide expand/collapse in toolbar and hides it for the org list 2018-12-14 09:55:59 -05:00
Jake McDermott
9114c16a97 refactor navitem factory function to wrapped router-hoc nav components 2018-12-14 04:05:29 -05:00
Michael Abashian
b2ba863569 Merge pull request #51 from mabashian/43-lingui
Add support for i18n using lingui
2018-12-13 16:56:16 -05:00
mabashian
ef9f9e902e Update readme with new npm command syntax 2018-12-12 13:17:07 -05:00
mabashian
ac8553df85 Pull messages from the correct location 2018-12-12 11:30:50 -05:00
mabashian
6adcac85a6 Moves locales out of src and into build dir. Changes npm commands from extract/compile to extract-strings/compile-strings 2018-12-12 11:28:29 -05:00
kialam
7ea5ea2ecd Merge pull request #55 from ansible/ansible-environment-dropdown
Basic Ansible Environment Select Component
2018-12-12 11:03:00 -05:00
kialam
44029c2191 Use object desctructuring. 2018-12-11 16:57:38 -05:00
kialam
9627a73978 Rename AnsibleEnvironmentSelect to AnsibleSelect
- Update references to the component.
2018-12-11 16:42:24 -05:00
kialam
9c7d449a4d Abstract out API get request to Add Org component.
- This makes it so we now have a generic select dropdown where we can pass data down as props.
2018-12-11 16:20:55 -05:00
kialam
d047bc876a Basic Ansible Environment Select Component
- Component conditionally renders based on # of virtual environments.
- User can add an Organization and associate it with a virtual environment.
2018-12-10 20:41:47 -05:00
kialam
27e13ca082 Add tests for Organization add view plus code refactoring. 2018-12-10 15:03:33 -05:00
kialam
9400bad990 Linter fixes. 2018-12-10 15:00:49 -05:00
kialam
1dd8175e11 Basic add organization functionality.
- Placeholders for Lookup Modal and Ansible Environment dropdown.
2018-12-10 15:00:16 -05:00
mabashian
356ad06d74 Add support for i18n using lingui 2018-12-10 10:17:00 -05:00
Marliana Lara
e736cfab36 Merge pull request #40 from marshmalien/side-nav-bug
Update active nav item based on url
2018-12-05 10:32:47 -05:00
Marliana Lara
a31ef24be6 Remove calling setState from render 2018-12-05 10:19:14 -05:00
John Mitchell
8f54ec681d Merge pull request #28 from jlmitch5/orgUrls
add routes and breadcrumbs for org detail/edit/related routes
2018-12-05 10:01:01 -05:00
John Mitchell
aaaf598ca1 remove commented out code in the data list toolbar 2018-12-05 09:57:11 -05:00
John Mitchell
00c9ae1376 update map function to be chained 2018-12-05 07:59:06 -05:00
John Mitchell
f83b59cb48 working commit of group and nav selection based on url 2018-12-05 07:59:06 -05:00
Marliana Lara
9341c4660c Update active nav item based on url 2018-12-05 07:58:59 -05:00
John Mitchell
e5320b6fa6 make current tab link replace instead of add new history item 2018-12-04 16:04:44 -05:00
John Mitchell
27542ea322 add tooltip test coverage 2018-12-04 15:27:43 -05:00
John Mitchell
3a8d95b03b working test commit 2018-12-04 14:46:18 -05:00
John Mitchell
aab6aa4ef9 working commit tests 2018-12-03 13:30:31 -05:00
John Mitchell
12c8267b12 update organizations structure and add unstyled sub routes and breadcrumbs 2018-12-03 13:30:30 -05:00
Michael Abashian
1e7ab9deed Merge pull request #30 from mabashian/update-pf-fix-login
Updates to login page after LoginPage and LoginForm components landed
2018-12-03 12:06:49 -05:00
mabashian
8f6b476388 Update sidebar override to ensure it is the same width as the masthead 2018-12-03 11:30:33 -05:00
mabashian
58d6e586cd Fixes login page after pf-react added LoginPage and LoginForm components 2018-11-29 16:50:56 -05:00
mabashian
7d2bc1c766 Bumps all patternfly versions to latest 2018-11-28 11:29:07 -05:00
Marliana Lara
07d2a1ed1e Merge pull request #23 from marshmalien/about-modal
Add help dropdown and about modal
2018-11-20 11:33:39 -05:00
Marliana Lara
6d315568d2 Add help dropdown and about modal 2018-11-19 22:53:05 -05:00
Jake McDermott
7fdf27eece Merge pull request #5 from ansible/pf4-table
basic pf4 data list, toolbar, pagination
2018-11-19 11:35:28 -05:00
Jake McDermott
4e6e715f1f add parametrized unit tests for querystring module 2018-11-18 22:50:21 -05:00
Jake McDermott
9979eddbcd add basic component test for pagination 2018-11-18 22:50:15 -05:00
Jake McDermott
de96f6cf8a check tooltip in organization functional test 2018-11-18 22:50:09 -05:00
Jake McDermott
9111948959 add basic component test for data list toolbar 2018-11-18 22:49:59 -05:00
Jake McDermott
e3a5f32b57 wip - pf4 data list and pagination 2018-11-18 22:49:50 -05:00
Jake McDermott
546d5d5587 Merge pull request #20 from ansible/async-await
Start using async-await
2018-11-13 13:38:26 -05:00
kialam
b0855ee33d Fix unhandled promise reject from jenkins. 2018-11-13 13:31:24 -05:00
kialam
03f6e52cf1 Address PR review comments. 2018-11-13 10:55:18 -05:00
kialam
44e9d3919d Update unit tests. 2018-11-13 09:46:43 -05:00
kialam
f520be71d6 Begin using async/await. 2018-11-12 13:24:17 -05:00
Jake McDermott
06470a0e65 Merge pull request #19 from jlmitch5/useCollapsedHeader
Use collapsed header
2018-11-09 21:28:18 -05:00
John Mitchell
5ea40efd3a update pages to utilize collapsed modifier for padding override 2018-11-09 17:31:40 -05:00
John Mitchell
4632383a33 update app component to utilize collapsing header and update style overrides 2018-11-09 17:30:48 -05:00
Jake McDermott
ea0f3a64b1 Merge pull request #16 from jlmitch5/indexJsxTestsAndRestructure
finish unit test coverage
2018-11-06 12:32:29 -05:00
John Mitchell
df57b144c4 fix logout in App.jsx and update test 2018-11-06 12:25:36 -05:00
John Mitchell
7b099578c8 update App.jsx and improve coverage
abstract LogoutButton to component
2018-11-02 17:47:59 -04:00
John Mitchell
08d2718f5e add about page tests 2018-11-02 17:46:43 -04:00
John Mitchell
96b8ab47c4 add TowerLogo tests 2018-11-02 16:34:02 -04:00
John Mitchell
07f6508402 move ConditionalRedirect test to components subfolder 2018-11-02 16:33:40 -04:00
John Mitchell
a670a73fd0 update file mock to return file name 2018-11-02 16:32:51 -04:00
John Mitchell
90d1ab88b1 and index.jsx tests 2018-11-02 13:45:11 -04:00
John Mitchell
19dcf5ed59 update unit test mocks and restructure test dir structure 2018-11-02 13:44:13 -04:00
Jake McDermott
90273247ac Merge pull request #14 from ansible/pagesTests
pages unit tests
2018-10-31 14:52:46 -04:00
John Mitchell
8a3b8823ee move login page test under pages and add tests for all pages stubs 2018-10-31 14:44:18 -04:00
John Mitchell
b40c81cc3d Merge pull request #10 from jlmitch5/loginPageTests
Add login page tests
2018-10-31 09:45:35 -07:00
John Mitchell
e53a6a91d6 remove setTimeout hack for testing api.login Login.jsx handlers 2018-10-31 12:04:59 -04:00
John Mitchell
55586b9b2a convert post-api.login code to using async/await for Login.jsx 2018-10-31 12:04:33 -04:00
John Mitchell
986d299961 move login back to using finally handler and update tests 2018-10-31 10:28:51 -04:00
John Mitchell
7c97989e84 add more login page tests 2018-10-31 09:56:35 -04:00
John Mitchell
ecd8427a51 fix eslint issues with app and conditional redirect tests 2018-10-31 09:56:28 -04:00
Jake McDermott
5c2e6244c6 Merge pull request #13 from jlmitch5/updateBuildSystem
Update build system
2018-10-30 17:34:07 -04:00
John Mitchell
fed7f51476 update build system
polyfill new js features before executing tests
move jest config to file, update transformation exclusion to be okay with axios module
rename enzyme.config.js to jest.setup.js
remove currently unused redux deps
update babel to 7, use env preset as opposed to deprecated stage preset
move .babelrc to newer, favored babel.config.js preset
update all babel preset and plugin packages to those name spaced under @babel
2018-10-30 17:25:29 -04:00
John Mitchell
3ccfc5905e Merge pull request #8 from jlmitch5/navUpdates
update navigation
2018-10-29 12:29:07 -07:00
John Mitchell
74d3e55908 bump patternfly dep versions 2018-10-29 13:58:56 -04:00
John Mitchell
557e619db6 update page navigation
fix issue with jerky close and expand of nav
update nav to use expandle headers
separate settings pages out into separate stup page components
2018-10-26 17:24:34 -04:00
John Mitchell
2dfbae79bd update patternfly style overrides 2018-10-26 17:23:37 -04:00
John Mitchell
fd28cff412 add additional patternfly react packages 2018-10-26 17:23:27 -04:00
Jake McDermott
ca0127d889 Merge pull request #7 from ansible/testing
add unit and functional testing to the app
2018-10-24 22:03:43 -04:00
John Mitchell
05d72ae8cf update webpack and package.json with index.jsx entrypoint 2018-10-24 21:55:59 -04:00
John Mitchell
1caa5b1c54 fix eslint errors 2018-10-24 21:51:35 -04:00
John Mitchell
2245d6a22e update LoginPage component and test pseudocode 2018-10-24 21:35:43 -04:00
John Mitchell
3e9a85a58b remove stale route redirection components 2018-10-24 21:35:14 -04:00
John Mitchell
51c58d5645 remove babel config.js to favor .babelrc file 2018-10-24 21:34:20 -04:00
John Mitchell
cfb89f1e31 working commit LoginPage.jsx tests 2018-10-24 21:16:24 -04:00
John Mitchell
fba1a5b71a fix App.jsx test misnamed variables 2018-10-24 21:15:08 -04:00
John Mitchell
79e68b1dbe add coverage report 2018-10-24 21:11:52 -04:00
John Mitchell
3938d49a1f refactor auth redirect and add ConditionalRedirect unit tests and App unit and functional tests 2018-10-24 16:53:16 -04:00
John Mitchell
0373058540 update api.js api client, and axios mock, and add api.js unit tests 2018-10-24 16:52:11 -04:00
John Mitchell
22112f3dd8 update package-lock.json with new jest and enzyme testing dependencies 2018-10-24 16:50:37 -04:00
John Mitchell
a76ac805f2 add jest and enzyme testing dependencies and update infrastructure configuration to make testing work 2018-10-24 16:50:08 -04:00
Jake McDermott
311346b77b Merge pull request #6 from ansible/nav-login-fixup
nav login fixup
2018-10-16 00:31:52 -04:00
Jake McDermott
05af4c7c53 nav login fixup 2018-10-16 00:30:14 -04:00
Jake McDermott
9f2b2b3456 adding pf assets / styles 2018-10-15 12:55:11 -04:00
Jake McDermott
0fbd0c941a Merge pull request #4 from ansible/nav-login-updates
Nav login updates
2018-10-15 12:49:27 -04:00
Jake McDermott
a54fb0e27d Nav and login updates 2018-10-15 12:44:29 -04:00
Jake McDermott
ff53a9c8ea move logo component to folder 2018-10-15 12:44:14 -04:00
Jake McDermott
070cec19df handle fonts and images differently in webpack config 2018-10-15 12:44:07 -04:00
Jake McDermott
f639f353ec update pf react version 2018-10-15 12:43:52 -04:00
Jake McDermott
ab94398889 Update README.md 2018-10-12 11:54:09 -04:00
Jake McDermott
13f6e63f75 Merge pull request #1 from ansible/nav
wip - one way of approaching nav
2018-10-12 11:23:03 -04:00
Jake McDermott
b31edef9b2 one way of approaching nav 2018-10-11 22:48:39 -04:00
Jake McDermott
b2ebbc6a0a use a few more pf-core components 2018-09-26 21:39:04 -04:00
Jake McDermott
d926378cf5 add .gitignore 2018-09-26 20:59:50 -04:00
Jake McDermott
f8a4b01da5 lint 2018-09-26 20:59:41 -04:00
Jake McDermott
0986ebef33 avoid port collision with other tooling 2018-09-26 18:11:29 -04:00
Jake McDermott
065813ebc0 make default configuration work with awx development api server 2018-09-26 18:06:30 -04:00
Jake McDermott
a73c1dd28e Update README.md 2018-09-26 14:50:15 -04:00
Jake McDermott
421aa09383 Update README.md 2018-09-26 14:31:28 -04:00
Jake McDermott
72af9c1405 Update README.md 2018-09-26 14:02:10 -04:00
Jake McDermott
1bfa8b19ff update readme 2018-09-26 13:57:10 -04:00
Jake McDermott
43f3b484f9 initial commit 2018-09-25 10:53:35 -04:00
508 changed files with 43844 additions and 1456 deletions

3
.gitignore vendored
View File

@@ -28,6 +28,9 @@ awx/ui/build_test
awx/ui/client/languages
awx/ui/templates/ui/index.html
awx/ui/templates/ui/installing.html
awx/ui_next/node_modules/
awx/ui_next/coverage/
awx/ui_next/build/locales/_build
/tower-license
/tower-license/**
tools/prometheus/data

View File

@@ -73,6 +73,9 @@ clean-ui:
rm -rf awx/ui/test/spec/reports/
rm -rf awx/ui/test/e2e/reports/
rm -rf awx/ui/client/languages/
rm -rf awx/ui_next/node_modules/
rm -rf awx/ui_next/coverage/
rm -rf awx/ui_next/build/locales/_build/
rm -f $(UI_DEPS_FLAG_FILE)
rm -f $(UI_RELEASE_DEPS_FLAG_FILE)
rm -f $(UI_RELEASE_FLAG_FILE)
@@ -98,7 +101,7 @@ clean: clean-ui clean-dist
rm -rf awx/job_status
rm -rf awx/job_output
rm -rf reports
rm -f awx/awx_test.sqlite3
rm -f awx/awx_test.sqlite3*
rm -rf requirements/vendor
rm -rf tmp
rm -rf $(I18N_FLAG_FILE)
@@ -124,8 +127,8 @@ virtualenv_ansible:
if [ ! -d "$(VENV_BASE)/ansible" ]; then \
virtualenv -p python --system-site-packages $(VENV_BASE)/ansible && \
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed six packaging appdirs && \
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed setuptools==41.0.1 && \
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed pip==19.1.1; \
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed setuptools==36.0.1 && \
$(VENV_BASE)/ansible/bin/pip install $(PIP_OPTIONS) --ignore-installed pip==9.0.1; \
fi; \
fi
@@ -515,6 +518,21 @@ jshint: $(UI_DEPS_FLAG_FILE)
# END UI TASKS
# --------------------------------------
# UI NEXT TASKS
# --------------------------------------
ui-next-lint:
$(NPM_BIN) --prefix awx/ui_next install
$(NPM_BIN) run --prefix awx/ui_next lint
$(NPM_BIN) run --prefix awx/ui_next prettier-check
ui-next-test:
$(NPM_BIN) --prefix awx/ui_next install
$(NPM_BIN) run --prefix awx/ui_next test
# END UI NEXT TASKS
# --------------------------------------
# Build a pip-installable package into dist/ with a timestamped version number.
dev_build:
$(PYTHON) setup.py dev_build

View File

@@ -1 +1 @@
5.0.0
6.1.0

View File

@@ -25,9 +25,8 @@ import hashlib
try:
import django
from django.utils.encoding import force_bytes
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.backends.base import schema
from django.db.backends.utils import names_digest
HAS_DJANGO = True
except ImportError:
HAS_DJANGO = False
@@ -37,30 +36,33 @@ if HAS_DJANGO is True:
# This line exists to make sure we don't regress on FIPS support if we
# upgrade Django; if you're upgrading Django and see this error,
# update the version check below, and confirm that FIPS still works.
if django.__version__ != '1.11.20':
raise RuntimeError("Django version other than 1.11.20 detected {}. \
Subclassing BaseDatabaseSchemaEditor is known to work for Django 1.11.20 \
and may not work in newer Django versions.".format(django.__version__))
# If operating in a FIPS environment, `hashlib.md5()` will raise a `ValueError`,
# but will support the `usedforsecurity` keyword on RHEL and Centos systems.
# Keep an eye on https://code.djangoproject.com/ticket/28401
target_version = '2.2.2'
if django.__version__ != target_version:
raise RuntimeError(
"Django version other than {target} detected: {current}. "
"Overriding `names_digest` is known to work for Django {target} "
"and may not work in other Django versions.".format(target=target_version,
current=django.__version__)
)
class FipsBaseDatabaseSchemaEditor(BaseDatabaseSchemaEditor):
@classmethod
def _digest(cls, *args):
try:
names_digest('foo', 'bar', 'baz', length=8)
except ValueError:
def names_digest(*args, length):
"""
Generates a 32-bit digest of a set of arguments that can be used to
shorten identifying names.
Generate a 32-bit digest of a set of arguments that can be used to shorten
identifying names. Support for use in FIPS environments.
"""
try:
h = hashlib.md5()
except ValueError:
h = hashlib.md5(usedforsecurity=False)
h = hashlib.md5(usedforsecurity=False)
for arg in args:
h.update(force_bytes(arg))
return h.hexdigest()[:8]
h.update(arg.encode())
return h.hexdigest()[:length]
schema.BaseDatabaseSchemaEditor = FipsBaseDatabaseSchemaEditor
schema.names_digest = names_digest
def find_commands(management_dir):

View File

@@ -401,21 +401,21 @@ class ListAPIView(generics.ListAPIView, GenericAPIView):
continue
if getattr(field, 'related_model', None):
fields.add('{}__search'.format(field.name))
for rel in self.model._meta.related_objects:
name = rel.related_name
if isinstance(rel, OneToOneRel) and self.model._meta.verbose_name.startswith('unified'):
for related in self.model._meta.related_objects:
name = related.related_name
if isinstance(related, OneToOneRel) and self.model._meta.verbose_name.startswith('unified'):
# Add underscores for polymorphic subclasses for user utility
name = rel.related_model._meta.verbose_name.replace(" ", "_")
name = related.related_model._meta.verbose_name.replace(" ", "_")
if skip_related_name(name) or name.endswith('+'):
continue
fields.add('{}__search'.format(name))
m2m_rel = []
m2m_rel += self.model._meta.local_many_to_many
m2m_related = []
m2m_related += self.model._meta.local_many_to_many
if issubclass(self.model, UnifiedJobTemplate) and self.model != UnifiedJobTemplate:
m2m_rel += UnifiedJobTemplate._meta.local_many_to_many
m2m_related += UnifiedJobTemplate._meta.local_many_to_many
if issubclass(self.model, UnifiedJob) and self.model != UnifiedJob:
m2m_rel += UnifiedJob._meta.local_many_to_many
for relationship in m2m_rel:
m2m_related += UnifiedJob._meta.local_many_to_many
for relationship in m2m_related:
if skip_related_name(relationship.name):
continue
if relationship.related_model._meta.app_label != 'main':

View File

@@ -95,7 +95,7 @@ class ModelAccessPermission(permissions.BasePermission):
'''
# Don't allow anonymous users. 401, not 403, hence no raised exception.
if not request.user or request.user.is_anonymous():
if not request.user or request.user.is_anonymous:
return False
# Always allow superusers

View File

@@ -1246,7 +1246,7 @@ class OrganizationSerializer(BaseSerializer):
applications = self.reverse('api:organization_applications_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:organization_activity_stream_list', kwargs={'pk': obj.pk}),
notification_templates = self.reverse('api:organization_notification_templates_list', kwargs={'pk': obj.pk}),
notification_templates_any = self.reverse('api:organization_notification_templates_any_list', kwargs={'pk': obj.pk}),
notification_templates_started = self.reverse('api:organization_notification_templates_started_list', kwargs={'pk': obj.pk}),
notification_templates_success = self.reverse('api:organization_notification_templates_success_list', kwargs={'pk': obj.pk}),
notification_templates_error = self.reverse('api:organization_notification_templates_error_list', kwargs={'pk': obj.pk}),
object_roles = self.reverse('api:organization_object_roles_list', kwargs={'pk': obj.pk}),
@@ -1352,7 +1352,7 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer):
scm_inventory_sources = self.reverse('api:project_scm_inventory_sources', kwargs={'pk': obj.pk}),
schedules = self.reverse('api:project_schedules_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:project_activity_stream_list', kwargs={'pk': obj.pk}),
notification_templates_any = self.reverse('api:project_notification_templates_any_list', kwargs={'pk': obj.pk}),
notification_templates_started = self.reverse('api:project_notification_templates_started_list', kwargs={'pk': obj.pk}),
notification_templates_success = self.reverse('api:project_notification_templates_success_list', kwargs={'pk': obj.pk}),
notification_templates_error = self.reverse('api:project_notification_templates_error_list', kwargs={'pk': obj.pk}),
access_list = self.reverse('api:project_access_list', kwargs={'pk': obj.pk}),
@@ -1943,6 +1943,25 @@ class InventorySourceOptionsSerializer(BaseSerializer):
return super(InventorySourceOptionsSerializer, self).validate(attrs)
# TODO: remove when old 'credential' fields are removed
def get_summary_fields(self, obj):
summary_fields = super(InventorySourceOptionsSerializer, self).get_summary_fields(obj)
all_creds = []
if 'credential' in summary_fields:
cred = obj.get_cloud_credential()
if cred:
summarized_cred = {
'id': cred.id, 'name': cred.name, 'description': cred.description,
'kind': cred.kind, 'cloud': True
}
summary_fields['credential'] = summarized_cred
all_creds.append(summarized_cred)
summary_fields['credential']['credential_type_id'] = cred.credential_type_id
else:
summary_fields.pop('credential')
summary_fields['credentials'] = all_creds
return summary_fields
class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOptionsSerializer):
@@ -1970,7 +1989,7 @@ class InventorySourceSerializer(UnifiedJobTemplateSerializer, InventorySourceOpt
activity_stream = self.reverse('api:inventory_source_activity_stream_list', kwargs={'pk': obj.pk}),
hosts = self.reverse('api:inventory_source_hosts_list', kwargs={'pk': obj.pk}),
groups = self.reverse('api:inventory_source_groups_list', kwargs={'pk': obj.pk}),
notification_templates_any = self.reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': obj.pk}),
notification_templates_started = self.reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': obj.pk}),
notification_templates_success = self.reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': obj.pk}),
notification_templates_error = self.reverse('api:inventory_source_notification_templates_error_list', kwargs={'pk': obj.pk}),
))
@@ -2541,7 +2560,7 @@ class CredentialSerializer(BaseSerializer):
def validate_credential_type(self, credential_type):
if self.instance and credential_type.pk != self.instance.credential_type.pk:
for rel in (
for related_objects in (
'ad_hoc_commands',
'insights_inventories',
'unifiedjobs',
@@ -2550,7 +2569,7 @@ class CredentialSerializer(BaseSerializer):
'projectupdates',
'workflowjobnodes'
):
if getattr(self.instance, rel).count() > 0:
if getattr(self.instance, related_objects).count() > 0:
raise ValidationError(
_('You cannot change the credential type of the credential, as it may break the functionality'
' of the resources using it.'),
@@ -2792,7 +2811,7 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
schedules = self.reverse('api:job_template_schedules_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:job_template_activity_stream_list', kwargs={'pk': obj.pk}),
launch = self.reverse('api:job_template_launch', kwargs={'pk': obj.pk}),
notification_templates_any = self.reverse('api:job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
notification_templates_started = self.reverse('api:job_template_notification_templates_started_list', kwargs={'pk': obj.pk}),
notification_templates_success = self.reverse('api:job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
notification_templates_error = self.reverse('api:job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
access_list = self.reverse('api:job_template_access_list', kwargs={'pk': obj.pk}),
@@ -3204,7 +3223,7 @@ class SystemJobTemplateSerializer(UnifiedJobTemplateSerializer):
jobs = self.reverse('api:system_job_template_jobs_list', kwargs={'pk': obj.pk}),
schedules = self.reverse('api:system_job_template_schedules_list', kwargs={'pk': obj.pk}),
launch = self.reverse('api:system_job_template_launch', kwargs={'pk': obj.pk}),
notification_templates_any = self.reverse('api:system_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
notification_templates_started = self.reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': obj.pk}),
notification_templates_success = self.reverse('api:system_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
notification_templates_error = self.reverse('api:system_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
@@ -3271,7 +3290,7 @@ class WorkflowJobTemplateSerializer(JobTemplateMixin, LabelsListMixin, UnifiedJo
workflow_nodes = self.reverse('api:workflow_job_template_workflow_nodes_list', kwargs={'pk': obj.pk}),
labels = self.reverse('api:workflow_job_template_label_list', kwargs={'pk': obj.pk}),
activity_stream = self.reverse('api:workflow_job_template_activity_stream_list', kwargs={'pk': obj.pk}),
notification_templates_any = self.reverse('api:workflow_job_template_notification_templates_any_list', kwargs={'pk': obj.pk}),
notification_templates_started = self.reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': obj.pk}),
notification_templates_success = self.reverse('api:workflow_job_template_notification_templates_success_list', kwargs={'pk': obj.pk}),
notification_templates_error = self.reverse('api:workflow_job_template_notification_templates_error_list', kwargs={'pk': obj.pk}),
access_list = self.reverse('api:workflow_job_template_access_list', kwargs={'pk': obj.pk}),
@@ -4621,37 +4640,37 @@ class ActivityStreamSerializer(BaseSerializer):
return ""
def get_related(self, obj):
rel = {}
data = {}
if obj.actor is not None:
rel['actor'] = self.reverse('api:user_detail', kwargs={'pk': obj.actor.pk})
data['actor'] = self.reverse('api:user_detail', kwargs={'pk': obj.actor.pk})
for fk, __ in self._local_summarizable_fk_fields:
if not hasattr(obj, fk):
continue
m2m_list = self._get_rel(obj, fk)
m2m_list = self._get_related_objects(obj, fk)
if m2m_list:
rel[fk] = []
data[fk] = []
id_list = []
for thisItem in m2m_list:
if getattr(thisItem, 'id', None) in id_list:
for item in m2m_list:
if getattr(item, 'id', None) in id_list:
continue
id_list.append(getattr(thisItem, 'id', None))
if hasattr(thisItem, 'get_absolute_url'):
rel_url = thisItem.get_absolute_url(self.context.get('request'))
id_list.append(getattr(item, 'id', None))
if hasattr(item, 'get_absolute_url'):
url = item.get_absolute_url(self.context.get('request'))
else:
view_name = fk + '_detail'
rel_url = self.reverse('api:' + view_name, kwargs={'pk': thisItem.id})
rel[fk].append(rel_url)
url = self.reverse('api:' + view_name, kwargs={'pk': item.id})
data[fk].append(url)
if fk == 'schedule':
rel['unified_job_template'] = thisItem.unified_job_template.get_absolute_url(self.context.get('request'))
data['unified_job_template'] = item.unified_job_template.get_absolute_url(self.context.get('request'))
if obj.setting and obj.setting.get('category', None):
rel['setting'] = self.reverse(
data['setting'] = self.reverse(
'api:setting_singleton_detail',
kwargs={'category_slug': obj.setting['category']}
)
return rel
return data
def _get_rel(self, obj, fk):
def _get_related_objects(self, obj, fk):
related_model = ActivityStream._meta.get_field(fk).related_model
related_manager = getattr(obj, fk)
if issubclass(related_model, PolymorphicModel) and hasattr(obj, '_prefetched_objects_cache'):
@@ -4661,43 +4680,34 @@ class ActivityStreamSerializer(BaseSerializer):
obj._prefetched_objects_cache[related_manager.prefetch_cache_name] = list(related_manager.all())
return related_manager.all()
def _summarize_parent_ujt(self, obj, fk, summary_fields):
summary_keys = {'job': 'job_template',
'workflow_job_template_node': 'workflow_job_template',
'schedule': 'unified_job_template'}
if fk not in summary_keys:
return
related_obj = getattr(obj, summary_keys[fk], None)
item = {}
fields = SUMMARIZABLE_FK_FIELDS[summary_keys[fk]]
if related_obj is not None:
summary_fields[get_type_for_model(related_obj)] = []
for field in fields:
fval = getattr(related_obj, field, None)
if fval is not None:
item[field] = fval
summary_fields[get_type_for_model(related_obj)].append(item)
def get_summary_fields(self, obj):
summary_fields = OrderedDict()
for fk, related_fields in self._local_summarizable_fk_fields:
try:
if not hasattr(obj, fk):
continue
m2m_list = self._get_rel(obj, fk)
m2m_list = self._get_related_objects(obj, fk)
if m2m_list:
summary_fields[fk] = []
for thisItem in m2m_list:
if fk == 'job':
summary_fields['job_template'] = []
job_template_item = {}
job_template_fields = SUMMARIZABLE_FK_FIELDS['job_template']
job_template = getattr(thisItem, 'job_template', None)
if job_template is not None:
for field in job_template_fields:
fval = getattr(job_template, field, None)
if fval is not None:
job_template_item[field] = fval
summary_fields['job_template'].append(job_template_item)
if fk == 'workflow_job_template_node':
summary_fields['workflow_job_template'] = []
workflow_job_template_item = {}
workflow_job_template_fields = SUMMARIZABLE_FK_FIELDS['workflow_job_template']
workflow_job_template = getattr(thisItem, 'workflow_job_template', None)
if workflow_job_template is not None:
for field in workflow_job_template_fields:
fval = getattr(workflow_job_template, field, None)
if fval is not None:
workflow_job_template_item[field] = fval
summary_fields['workflow_job_template'].append(workflow_job_template_item)
if fk == 'schedule':
unified_job_template = getattr(thisItem, 'unified_job_template', None)
if unified_job_template is not None:
summary_fields[get_type_for_model(unified_job_template)] = {'id': unified_job_template.id,
'name': unified_job_template.name}
self._summarize_parent_ujt(thisItem, fk, summary_fields)
thisItemDict = {}
for field in related_fields:
fval = getattr(thisItem, field, None)

View File

@@ -13,8 +13,8 @@ from awx.api.views import (
InventorySourceCredentialsList,
InventorySourceGroupsList,
InventorySourceHostsList,
InventorySourceNotificationTemplatesAnyList,
InventorySourceNotificationTemplatesErrorList,
InventorySourceNotificationTemplatesStartedList,
InventorySourceNotificationTemplatesSuccessList,
)
@@ -29,8 +29,8 @@ urls = [
url(r'^(?P<pk>[0-9]+)/credentials/$', InventorySourceCredentialsList.as_view(), name='inventory_source_credentials_list'),
url(r'^(?P<pk>[0-9]+)/groups/$', InventorySourceGroupsList.as_view(), name='inventory_source_groups_list'),
url(r'^(?P<pk>[0-9]+)/hosts/$', InventorySourceHostsList.as_view(), name='inventory_source_hosts_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', InventorySourceNotificationTemplatesAnyList.as_view(),
name='inventory_source_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', InventorySourceNotificationTemplatesStartedList.as_view(),
name='inventory_source_notification_templates_started_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', InventorySourceNotificationTemplatesErrorList.as_view(),
name='inventory_source_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', InventorySourceNotificationTemplatesSuccessList.as_view(),

View File

@@ -13,8 +13,8 @@ from awx.api.views import (
JobTemplateSchedulesList,
JobTemplateSurveySpec,
JobTemplateActivityStreamList,
JobTemplateNotificationTemplatesAnyList,
JobTemplateNotificationTemplatesErrorList,
JobTemplateNotificationTemplatesStartedList,
JobTemplateNotificationTemplatesSuccessList,
JobTemplateInstanceGroupsList,
JobTemplateAccessList,
@@ -34,8 +34,8 @@ urls = [
url(r'^(?P<pk>[0-9]+)/schedules/$', JobTemplateSchedulesList.as_view(), name='job_template_schedules_list'),
url(r'^(?P<pk>[0-9]+)/survey_spec/$', JobTemplateSurveySpec.as_view(), name='job_template_survey_spec'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', JobTemplateActivityStreamList.as_view(), name='job_template_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', JobTemplateNotificationTemplatesAnyList.as_view(),
name='job_template_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', JobTemplateNotificationTemplatesStartedList.as_view(),
name='job_template_notification_templates_started_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', JobTemplateNotificationTemplatesErrorList.as_view(),
name='job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', JobTemplateNotificationTemplatesSuccessList.as_view(),

View File

@@ -15,8 +15,8 @@ from awx.api.views import (
OrganizationCredentialList,
OrganizationActivityStreamList,
OrganizationNotificationTemplatesList,
OrganizationNotificationTemplatesAnyList,
OrganizationNotificationTemplatesErrorList,
OrganizationNotificationTemplatesStartedList,
OrganizationNotificationTemplatesSuccessList,
OrganizationInstanceGroupsList,
OrganizationObjectRolesList,
@@ -25,7 +25,7 @@ from awx.api.views import (
)
urls = [
urls = [
url(r'^$', OrganizationList.as_view(), name='organization_list'),
url(r'^(?P<pk>[0-9]+)/$', OrganizationDetail.as_view(), name='organization_detail'),
url(r'^(?P<pk>[0-9]+)/users/$', OrganizationUsersList.as_view(), name='organization_users_list'),
@@ -37,8 +37,8 @@ urls = [
url(r'^(?P<pk>[0-9]+)/credentials/$', OrganizationCredentialList.as_view(), name='organization_credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', OrganizationActivityStreamList.as_view(), name='organization_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates/$', OrganizationNotificationTemplatesList.as_view(), name='organization_notification_templates_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', OrganizationNotificationTemplatesAnyList.as_view(),
name='organization_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', OrganizationNotificationTemplatesStartedList.as_view(),
name='organization_notification_templates_started_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', OrganizationNotificationTemplatesErrorList.as_view(),
name='organization_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', OrganizationNotificationTemplatesSuccessList.as_view(),

View File

@@ -14,8 +14,8 @@ from awx.api.views import (
ProjectUpdatesList,
ProjectActivityStreamList,
ProjectSchedulesList,
ProjectNotificationTemplatesAnyList,
ProjectNotificationTemplatesErrorList,
ProjectNotificationTemplatesStartedList,
ProjectNotificationTemplatesSuccessList,
ProjectObjectRolesList,
ProjectAccessList,
@@ -34,10 +34,11 @@ urls = [
url(r'^(?P<pk>[0-9]+)/project_updates/$', ProjectUpdatesList.as_view(), name='project_updates_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', ProjectActivityStreamList.as_view(), name='project_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/schedules/$', ProjectSchedulesList.as_view(), name='project_schedules_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', ProjectNotificationTemplatesAnyList.as_view(), name='project_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', ProjectNotificationTemplatesErrorList.as_view(), name='project_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', ProjectNotificationTemplatesSuccessList.as_view(),
name='project_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', ProjectNotificationTemplatesStartedList.as_view(),
name='project_notification_templates_started_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', ProjectObjectRolesList.as_view(), name='project_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', ProjectAccessList.as_view(), name='project_access_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', ProjectCopy.as_view(), name='project_copy'),

View File

@@ -9,8 +9,8 @@ from awx.api.views import (
SystemJobTemplateLaunch,
SystemJobTemplateJobsList,
SystemJobTemplateSchedulesList,
SystemJobTemplateNotificationTemplatesAnyList,
SystemJobTemplateNotificationTemplatesErrorList,
SystemJobTemplateNotificationTemplatesStartedList,
SystemJobTemplateNotificationTemplatesSuccessList,
)
@@ -21,8 +21,8 @@ urls = [
url(r'^(?P<pk>[0-9]+)/launch/$', SystemJobTemplateLaunch.as_view(), name='system_job_template_launch'),
url(r'^(?P<pk>[0-9]+)/jobs/$', SystemJobTemplateJobsList.as_view(), name='system_job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/schedules/$', SystemJobTemplateSchedulesList.as_view(), name='system_job_template_schedules_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', SystemJobTemplateNotificationTemplatesAnyList.as_view(),
name='system_job_template_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', SystemJobTemplateNotificationTemplatesStartedList.as_view(),
name='system_job_template_notification_templates_started_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', SystemJobTemplateNotificationTemplatesErrorList.as_view(),
name='system_job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', SystemJobTemplateNotificationTemplatesSuccessList.as_view(),

View File

@@ -13,8 +13,8 @@ from awx.api.views import (
WorkflowJobTemplateSurveySpec,
WorkflowJobTemplateWorkflowNodesList,
WorkflowJobTemplateActivityStreamList,
WorkflowJobTemplateNotificationTemplatesAnyList,
WorkflowJobTemplateNotificationTemplatesErrorList,
WorkflowJobTemplateNotificationTemplatesStartedList,
WorkflowJobTemplateNotificationTemplatesSuccessList,
WorkflowJobTemplateAccessList,
WorkflowJobTemplateObjectRolesList,
@@ -32,8 +32,8 @@ urls = [
url(r'^(?P<pk>[0-9]+)/survey_spec/$', WorkflowJobTemplateSurveySpec.as_view(), name='workflow_job_template_survey_spec'),
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobTemplateWorkflowNodesList.as_view(), name='workflow_job_template_workflow_nodes_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', WorkflowJobTemplateNotificationTemplatesAnyList.as_view(),
name='workflow_job_template_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_started/$', WorkflowJobTemplateNotificationTemplatesStartedList.as_view(),
name='workflow_job_template_notification_templates_started_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', WorkflowJobTemplateNotificationTemplatesErrorList.as_view(),
name='workflow_job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(),

View File

@@ -116,6 +116,7 @@ from awx.api.views.organization import ( # noqa
OrganizationNotificationTemplatesList,
OrganizationNotificationTemplatesAnyList,
OrganizationNotificationTemplatesErrorList,
OrganizationNotificationTemplatesStartedList,
OrganizationNotificationTemplatesSuccessList,
OrganizationInstanceGroupsList,
OrganizationAccessList,
@@ -747,22 +748,20 @@ class ProjectNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.Project
relationship = 'notification_templates_any'
class ProjectNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
class ProjectNotificationTemplatesStartedList(ProjectNotificationTemplatesAnyList):
relationship = 'notification_templates_started'
class ProjectNotificationTemplatesErrorList(ProjectNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.Project
relationship = 'notification_templates_error'
class ProjectNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
class ProjectNotificationTemplatesSuccessList(ProjectNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.Project
relationship = 'notification_templates_success'
@@ -2102,7 +2101,6 @@ class InventorySourceNotificationTemplatesAnyList(SubListCreateAttachDetachAPIVi
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.InventorySource
relationship = 'notification_templates_any'
def post(self, request, *args, **kwargs):
parent = self.get_parent_object()
@@ -2113,6 +2111,11 @@ class InventorySourceNotificationTemplatesAnyList(SubListCreateAttachDetachAPIVi
return super(InventorySourceNotificationTemplatesAnyList, self).post(request, *args, **kwargs)
class InventorySourceNotificationTemplatesStartedList(InventorySourceNotificationTemplatesAnyList):
relationship = 'notification_templates_started'
class InventorySourceNotificationTemplatesErrorList(InventorySourceNotificationTemplatesAnyList):
relationship = 'notification_templates_error'
@@ -2626,22 +2629,20 @@ class JobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.JobTemplate
relationship = 'notification_templates_any'
class JobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
class JobTemplateNotificationTemplatesStartedList(JobTemplateNotificationTemplatesAnyList):
relationship = 'notification_templates_started'
class JobTemplateNotificationTemplatesErrorList(JobTemplateNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.JobTemplate
relationship = 'notification_templates_error'
class JobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
class JobTemplateNotificationTemplatesSuccessList(JobTemplateNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.JobTemplate
relationship = 'notification_templates_success'
@@ -2996,7 +2997,7 @@ class WorkflowJobTemplateNodeChildrenBaseList(EnforceParentRelationshipMixin, Su
relationships = ['success_nodes', 'failure_nodes', 'always_nodes']
relationships.remove(self.relationship)
qs = functools.reduce(lambda x, y: (x | y),
(Q(**{'{}__in'.format(rel): [sub.id]}) for rel in relationships))
(Q(**{'{}__in'.format(r): [sub.id]}) for r in relationships))
if models.WorkflowJobTemplateNode.objects.filter(Q(pk=parent.id) & qs).exists():
return {"Error": _("Relationship not allowed.")}
@@ -3234,22 +3235,20 @@ class WorkflowJobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachA
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.WorkflowJobTemplate
relationship = 'notification_templates_any'
class WorkflowJobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
class WorkflowJobTemplateNotificationTemplatesStartedList(WorkflowJobTemplateNotificationTemplatesAnyList):
relationship = 'notification_templates_started'
class WorkflowJobTemplateNotificationTemplatesErrorList(WorkflowJobTemplateNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.WorkflowJobTemplate
relationship = 'notification_templates_error'
class WorkflowJobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
class WorkflowJobTemplateNotificationTemplatesSuccessList(WorkflowJobTemplateNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.WorkflowJobTemplate
relationship = 'notification_templates_success'
@@ -3411,22 +3410,20 @@ class SystemJobTemplateNotificationTemplatesAnyList(SubListCreateAttachDetachAPI
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.SystemJobTemplate
relationship = 'notification_templates_any'
class SystemJobTemplateNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
class SystemJobTemplateNotificationTemplatesStartedList(SystemJobTemplateNotificationTemplatesAnyList):
relationship = 'notification_templates_started'
class SystemJobTemplateNotificationTemplatesErrorList(SystemJobTemplateNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.SystemJobTemplate
relationship = 'notification_templates_error'
class SystemJobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
class SystemJobTemplateNotificationTemplatesSuccessList(SystemJobTemplateNotificationTemplatesAnyList):
model = models.NotificationTemplate
serializer_class = serializers.NotificationTemplateSerializer
parent_model = models.SystemJobTemplate
relationship = 'notification_templates_success'

View File

@@ -178,22 +178,20 @@ class OrganizationNotificationTemplatesAnyList(SubListCreateAttachDetachAPIView)
model = NotificationTemplate
serializer_class = NotificationTemplateSerializer
parent_model = Organization
relationship = 'notification_templates_any'
class OrganizationNotificationTemplatesErrorList(SubListCreateAttachDetachAPIView):
class OrganizationNotificationTemplatesStartedList(OrganizationNotificationTemplatesAnyList):
relationship = 'notification_templates_started'
class OrganizationNotificationTemplatesErrorList(OrganizationNotificationTemplatesAnyList):
model = NotificationTemplate
serializer_class = NotificationTemplateSerializer
parent_model = Organization
relationship = 'notification_templates_error'
class OrganizationNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIView):
class OrganizationNotificationTemplatesSuccessList(OrganizationNotificationTemplatesAnyList):
model = NotificationTemplate
serializer_class = NotificationTemplateSerializer
parent_model = Organization
relationship = 'notification_templates_success'

View File

@@ -21,7 +21,8 @@ class Migration(migrations.Migration):
('modified', models.DateTimeField(default=None, editable=False)),
('key', models.CharField(max_length=255)),
('value', jsonfield.fields.JSONField(null=True)),
('user', models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('user', models.ForeignKey(related_name='settings', default=None, editable=False,
to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)),
],
options={
'abstract': False,

View File

@@ -8,6 +8,7 @@ from awx.main.utils.encryption import decrypt_field
from awx.conf import fields
from awx.conf.registry import settings_registry
from awx.conf.models import Setting
from awx.sso import fields as sso_fields
@pytest.fixture
@@ -137,7 +138,7 @@ def test_setting_signleton_retrieve_hierachy(api_request, dummy_setting):
@pytest.mark.django_db
def test_setting_signleton_retrieve_readonly(api_request, dummy_setting):
def test_setting_singleton_retrieve_readonly(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
@@ -183,6 +184,30 @@ def test_setting_singleton_update(api_request, dummy_setting):
assert response.data['FOO_BAR'] == 4
@pytest.mark.django_db
def test_setting_singleton_update_hybriddictfield_with_forbidden(api_request, dummy_setting):
# Some HybridDictField subclasses have a child of _Forbidden,
# indicating that only the defined fields can be filled in. Make
# sure that the _Forbidden validator doesn't get used for the
# fields. See also https://github.com/ansible/awx/issues/4099.
with dummy_setting(
'FOO_BAR',
field_class=sso_fields.SAMLOrgAttrField,
category='FooBar',
category_slug='foobar',
), mock.patch('awx.conf.views.handle_setting_changes'):
api_request(
'patch',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}),
data={'FOO_BAR': {'saml_admin_attr': 'Admins', 'saml_attr': 'Orgs'}}
)
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == {'saml_admin_attr': 'Admins', 'saml_attr': 'Orgs'}
@pytest.mark.django_db
def test_setting_singleton_update_dont_change_readonly_fields(api_request, dummy_setting):
with dummy_setting(
@@ -206,7 +231,7 @@ def test_setting_singleton_update_dont_change_readonly_fields(api_request, dummy
@pytest.mark.django_db
def test_setting_singleton_update_dont_change_encripted_mark(api_request, dummy_setting):
def test_setting_singleton_update_dont_change_encrypted_mark(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.CharField,

View File

@@ -1265,7 +1265,7 @@ class TeamAccess(BaseAccess):
(self.user.admin_of_organizations.exists() or self.user.auditor_of_organizations.exists()):
return self.model.objects.all()
return self.model.objects.filter(
Q(organization=Organization.accessible_pk_qs(self.user, 'member_role')) |
Q(organization__in=Organization.accessible_pk_qs(self.user, 'member_role')) |
Q(pk__in=self.model.accessible_pk_qs(self.user, 'read_role'))
)

View File

@@ -153,10 +153,16 @@ def projects_by_scm_type(since):
return counts
def _get_isolated_datetime(last_check):
if last_check:
return last_check.isoformat()
return last_check
@register('instance_info')
def instance_info(since):
info = {}
instances = models.Instance.objects.values_list('hostname').annotate().values(
instances = models.Instance.objects.values_list('hostname').values(
'uuid', 'version', 'capacity', 'cpu', 'memory', 'managed_by_policy', 'hostname', 'last_isolated_check', 'enabled')
for instance in instances:
instance_info = {
@@ -166,7 +172,7 @@ def instance_info(since):
'cpu': instance['cpu'],
'memory': instance['memory'],
'managed_by_policy': instance['managed_by_policy'],
'last_isolated_check': instance['last_isolated_check'],
'last_isolated_check': _get_isolated_datetime(instance['last_isolated_check']),
'enabled': instance['enabled']
}
info[instance['uuid']] = instance_info
@@ -187,12 +193,12 @@ def job_counts(since):
def job_instance_counts(since):
counts = {}
job_types = models.UnifiedJob.objects.exclude(launch_type='sync').values_list(
'execution_node', 'launch_type').annotate(job_launch_type=Count('launch_type'))
'execution_node', 'launch_type').annotate(job_launch_type=Count('launch_type')).order_by()
for job in job_types:
counts.setdefault(job[0], {}).setdefault('launch_type', {})[job[1]] = job[2]
job_statuses = models.UnifiedJob.objects.exclude(launch_type='sync').values_list(
'execution_node', 'status').annotate(job_status=Count('status'))
'execution_node', 'status').annotate(job_status=Count('status')).order_by()
for job in job_statuses:
counts.setdefault(job[0], {}).setdefault('status', {})[job[1]] = job[2]
return counts

View File

@@ -119,24 +119,28 @@ def ship(path):
"""
Ship gathered metrics via the Insights agent
"""
agent = 'insights-client'
if shutil.which(agent) is None:
logger.error('could not find {} on PATH'.format(agent))
return
logger.debug('shipping analytics file: {}'.format(path))
try:
cmd = [
agent, '--payload', path, '--content-type', settings.INSIGHTS_AGENT_MIME
]
output = smart_str(subprocess.check_output(cmd, timeout=60 * 5))
logger.debug(output)
# reset the `last_run` when data is shipped
run_now = now()
state = TowerAnalyticsState.get_solo()
state.last_run = run_now
state.save()
agent = 'insights-client'
if shutil.which(agent) is None:
logger.error('could not find {} on PATH'.format(agent))
return
logger.debug('shipping analytics file: {}'.format(path))
try:
cmd = [
agent, '--payload', path, '--content-type', settings.INSIGHTS_AGENT_MIME
]
output = smart_str(subprocess.check_output(cmd, timeout=60 * 5))
logger.debug(output)
# reset the `last_run` when data is shipped
run_now = now()
state = TowerAnalyticsState.get_solo()
state.last_run = run_now
state.save()
except subprocess.CalledProcessError:
logger.exception('{} failure:'.format(cmd))
except subprocess.TimeoutExpired:
logger.exception('{} timeout:'.format(cmd))
except subprocess.CalledProcessError:
logger.exception('{} failure:'.format(cmd))
except subprocess.TimeoutExpired:
logger.exception('{} timeout:'.format(cmd))
finally:
# cleanup tar.gz
os.remove(path)

View File

@@ -24,7 +24,7 @@ def ws_connect(message):
headers = dict(message.content.get('headers', ''))
message.reply_channel.send({"accept": True})
message.content['method'] = 'FAKE'
if message.user.is_authenticated():
if message.user.is_authenticated:
message.reply_channel.send(
{"text": json.dumps({"accept": True, "user": message.user.id})}
)

View File

@@ -1,14 +1,14 @@
from .plugin import CredentialPlugin
import os
import stat
import tempfile
import threading
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': [{
@@ -60,24 +60,6 @@ aim_inputs = {
}
def create_temporary_fifo(data):
"""Open fifo named pipe in a new thread using a temporary file path. The
thread blocks until data is read from the pipe.
Returns the path to the fifo.
:param data(bytes): Data to write to the pipe.
"""
path = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names()))
os.mkfifo(path, stat.S_IRUSR | stat.S_IWUSR)
threading.Thread(
target=lambda p, d: open(p, 'wb').write(d),
args=(path, data)
).start()
return path
def aim_backend(**kwargs):
url = kwargs['url']
client_cert = kwargs.get('client_cert', None)

View File

@@ -1,15 +1,16 @@
from .plugin import CredentialPlugin
import base64
import os
import stat
import tempfile
import threading
from urllib.parse import urljoin, quote_plus
from django.utils.translation import ugettext_lazy as _
import requests
# AWX
from awx.main.utils import (
create_temporary_fifo,
)
conjur_inputs = {
'fields': [{
@@ -51,24 +52,6 @@ conjur_inputs = {
}
def create_temporary_fifo(data):
"""Open fifo named pipe in a new thread using a temporary file path. The
thread blocks until data is read from the pipe.
Returns the path to the fifo.
:param data(bytes): Data to write to the pipe.
"""
path = os.path.join(tempfile.mkdtemp(), next(tempfile._get_candidate_names()))
os.mkfifo(path, stat.S_IRUSR | stat.S_IWUSR)
threading.Thread(
target=lambda p, d: open(p, 'wb').write(d),
args=(path, data)
).start()
return path
def conjur_backend(**kwargs):
url = kwargs['url']
api_key = kwargs['api_key']

View File

@@ -8,6 +8,10 @@ from .plugin import CredentialPlugin
import requests
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.main.utils import (
create_temporary_fifo,
)
base_inputs = {
'fields': [{
@@ -22,12 +26,18 @@ base_inputs = {
'type': 'string',
'secret': True,
'help_text': _('The access token used to authenticate to the Vault server'),
}, {
'id': 'cacert',
'label': _('CA Certificate'),
'type': 'string',
'multiline': True,
'help_text': _('The CA certificate used to verify the SSL certificate of the Vault server')
}],
'metadata': [{
'id': 'secret_path',
'label': _('Path to Secret'),
'type': 'string',
'help_text': _('The path to the secret e.g., /some-engine/some-secret/'),
'help_text': _('The path to the secret stored in the secret backend e.g, /some/secret/')
}],
'required': ['url', 'token', 'secret_path'],
}
@@ -40,7 +50,12 @@ hashi_kv_inputs['fields'].append({
'help_text': _('API v1 is for static key/value lookups. API v2 is for versioned key/value lookups.'),
'default': 'v1',
})
hashi_kv_inputs['metadata'].extend([{
hashi_kv_inputs['metadata'] = [{
'id': 'secret_backend',
'label': _('Name of Secret Backend'),
'type': 'string',
'help_text': _('The name of the kv secret backend (if left empty, the first segment of the secret path will be used).')
}] + hashi_kv_inputs['metadata'] + [{
'id': 'secret_key',
'label': _('Key Name'),
'type': 'string',
@@ -50,7 +65,7 @@ hashi_kv_inputs['metadata'].extend([{
'label': _('Secret Version (v2 only)'),
'type': 'string',
'help_text': _('Used to specify a specific secret version (if left empty, the latest version will be used).'),
}])
}]
hashi_kv_inputs['required'].extend(['api_version', 'secret_key'])
hashi_ssh_inputs = copy.deepcopy(base_inputs)
@@ -75,36 +90,46 @@ hashi_ssh_inputs['required'].extend(['public_key', 'role'])
def kv_backend(**kwargs):
token = kwargs['token']
url = urljoin(kwargs['url'], 'v1')
url = kwargs['url']
secret_path = kwargs['secret_path']
secret_backend = kwargs.get('secret_backend', None)
secret_key = kwargs.get('secret_key', None)
cacert = kwargs.get('cacert', None)
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)
if api_version == 'v2':
params = {}
if kwargs.get('secret_version'):
params['version'] = kwargs['secret_version']
try:
mount_point, *path = pathlib.Path(secret_path.lstrip(os.sep)).parts
'/'.join(*path)
except Exception:
mount_point, path = secret_path, []
# https://www.vaultproject.io/api/secret/kv/kv-v2.html#read-secret-version
response = sess.get(
'/'.join([url, mount_point, 'data'] + path).rstrip('/'),
params=params,
timeout=30
)
response.raise_for_status()
json = response.json()['data']
request_kwargs['params'] = {'version': kwargs['secret_version']}
if secret_backend:
path_segments = [secret_backend, 'data', secret_path]
else:
try:
mount_point, *path = pathlib.Path(secret_path.lstrip(os.sep)).parts
'/'.join(path)
except Exception:
mount_point, path = secret_path, []
# https://www.vaultproject.io/api/secret/kv/kv-v2.html#read-secret-version
path_segments = [mount_point, 'data'] + path
else:
# https://www.vaultproject.io/api/secret/kv/kv-v1.html#read-secret
response = sess.get('/'.join([url, secret_path]).rstrip('/'), timeout=30)
response.raise_for_status()
json = response.json()
if secret_backend:
path_segments = [secret_backend, secret_path]
else:
path_segments = [secret_path]
request_url = urljoin(url, '/'.join(['v1'] + path_segments)).rstrip('/')
response = sess.get(request_url, **request_kwargs)
response.raise_for_status()
json = response.json()
if api_version == 'v2':
json = json['data']
if secret_key:
try:
@@ -121,20 +146,22 @@ def ssh_backend(**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'):
request_kwargs['json']['valid_principals'] = kwargs['valid_principals']
sess = requests.Session()
sess.headers['Authorization'] = 'Bearer {}'.format(token)
json = {
'public_key': kwargs['public_key']
}
if kwargs.get('valid_principals'):
json['valid_principals'] = kwargs['valid_principals']
# https://www.vaultproject.io/api/secret/ssh/index.html#sign-ssh-key
resp = sess.post(
'/'.join([url, secret_path, 'sign', role]).rstrip('/'),
json=json,
timeout=30
)
request_url = '/'.join([url, secret_path, 'sign', role]).rstrip('/')
resp = sess.post(request_url, **request_kwargs)
resp.raise_for_status()
return resp.json()['data']['signed_key']

View File

@@ -11,8 +11,9 @@ from jinja2 import Environment, StrictUndefined
from jinja2.exceptions import UndefinedError, TemplateSyntaxError
# Django
import django
from django.contrib.postgres.fields import JSONField as upstream_JSONBField
from django.core import exceptions as django_exceptions
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models.signals import (
post_save,
post_delete,
@@ -37,7 +38,6 @@ import jsonschema.exceptions
# Django-JSONField
from jsonfield import JSONField as upstream_JSONField
from jsonbfield.fields import JSONField as upstream_JSONBField
# DRF
from rest_framework import serializers
@@ -76,10 +76,10 @@ class JSONField(upstream_JSONField):
def db_type(self, connection):
return 'text'
def from_db_value(self, value, expression, connection, context):
def from_db_value(self, value, expression, connection):
if value in {'', None} and not self.null:
return {}
return super(JSONField, self).from_db_value(value, expression, connection, context)
return super(JSONField, self).from_db_value(value, expression, connection)
class JSONBField(upstream_JSONBField):
@@ -91,12 +91,12 @@ class JSONBField(upstream_JSONBField):
def get_db_prep_value(self, value, connection, prepared=False):
if connection.vendor == 'sqlite':
# sqlite (which we use for tests) does not support jsonb;
return json.dumps(value)
return json.dumps(value, cls=DjangoJSONEncoder)
return super(JSONBField, self).get_db_prep_value(
value, connection, prepared
)
def from_db_value(self, value, expression, connection, context):
def from_db_value(self, value, expression, connection):
# Work around a bug in django-jsonfield
# https://bitbucket.org/schinckel/django-jsonfield/issues/57/cannot-use-in-the-same-project-as-djangos
if isinstance(value, str):
@@ -112,14 +112,9 @@ class AutoSingleRelatedObjectDescriptor(ReverseOneToOneDescriptor):
def __get__(self, instance, instance_type=None):
try:
return super(AutoSingleRelatedObjectDescriptor,
self).__get__(instance, instance_type)
return super(AutoSingleRelatedObjectDescriptor, self).__get__(instance, instance_type)
except self.related.related_model.DoesNotExist:
obj = self.related.related_model(**{self.related.field.name: instance})
if self.related.field.rel.parent_link:
raise NotImplementedError('not supported with polymorphic!')
for f in instance._meta.local_fields:
setattr(obj, f.name, getattr(instance, f.name))
obj.save()
return obj
@@ -453,21 +448,6 @@ class JSONSchemaField(JSONBField):
params={'value': value},
)
def get_db_prep_value(self, value, connection, prepared=False):
if connection.vendor == 'sqlite':
# sqlite (which we use for tests) does not support jsonb;
return json.dumps(value)
return super(JSONSchemaField, self).get_db_prep_value(
value, connection, prepared
)
def from_db_value(self, value, expression, connection, context):
# Work around a bug in django-jsonfield
# https://bitbucket.org/schinckel/django-jsonfield/issues/57/cannot-use-in-the-same-project-as-djangos
if isinstance(value, str):
return json.loads(value)
return value
@JSONSchemaField.format_checker.checks('vault_id')
def format_vault_id(value):
@@ -986,7 +966,7 @@ class OAuth2ClientSecretField(models.CharField):
encrypt_value(value), connection, prepared
)
def from_db_value(self, value, expression, connection, context):
def from_db_value(self, value, expression, connection):
if value and value.startswith('$encrypted$'):
return decrypt_value(get_encryption_key('value', pk=None), value)
return value
@@ -1022,38 +1002,6 @@ class OrderedManyToManyDescriptor(ManyToManyDescriptor):
'%s__position' % self.through._meta.model_name
)
def add(self, *objs):
# Django < 2 doesn't support this method on
# ManyToManyFields w/ an intermediary model
# We should be able to remove this code snippet when we
# upgrade Django.
# see: https://github.com/django/django/blob/stable/1.11.x/django/db/models/fields/related_descriptors.py#L926
if not django.__version__.startswith('1.'):
raise RuntimeError(
'This method is no longer necessary in Django>=2'
)
try:
self.through._meta.auto_created = True
super(OrderedManyRelatedManager, self).add(*objs)
finally:
self.through._meta.auto_created = False
def remove(self, *objs):
# Django < 2 doesn't support this method on
# ManyToManyFields w/ an intermediary model
# We should be able to remove this code snippet when we
# upgrade Django.
# see: https://github.com/django/django/blob/stable/1.11.x/django/db/models/fields/related_descriptors.py#L944
if not django.__version__.startswith('1.'):
raise RuntimeError(
'This method is no longer necessary in Django>=2'
)
try:
self.through._meta.auto_created = True
super(OrderedManyRelatedManager, self).remove(*objs)
finally:
self.through._meta.auto_created = False
return OrderedManyRelatedManager
return add_custom_queryset_to_many_related_manager(

View File

@@ -10,6 +10,7 @@ from django.core.management.base import BaseCommand
from django.db import connection as django_connection, connections
from kombu import Exchange, Queue
from awx.main.utils.handlers import AWXProxyHandler
from awx.main.dispatch import get_local_queuename, reaper
from awx.main.dispatch.control import Control
from awx.main.dispatch.kombu import Connection
@@ -121,6 +122,12 @@ class Command(BaseCommand):
reaper.reap()
consumer = None
# don't ship external logs inside the dispatcher's parent process
# this exists to work around a race condition + deadlock bug on fork
# in cpython itself:
# https://bugs.python.org/issue37429
AWXProxyHandler.disable()
with Connection(settings.BROKER_URL) as conn:
try:
bcast = 'tower_broadcast_all'

View File

@@ -73,7 +73,7 @@ class ActivityStreamMiddleware(threading.local, MiddlewareMixin):
super().__init__(get_response)
def process_request(self, request):
if hasattr(request, 'user') and hasattr(request.user, 'is_authenticated') and request.user.is_authenticated():
if hasattr(request, 'user') and request.user.is_authenticated:
user = request.user
else:
user = None

View File

@@ -44,7 +44,7 @@ class Migration(migrations.Migration):
('modified', models.DateTimeField(default=None, editable=False)),
('host_name', models.CharField(default='', max_length=1024, editable=False)),
('event', models.CharField(max_length=100, choices=[('runner_on_failed', 'Host Failed'), ('runner_on_ok', 'Host OK'), ('runner_on_unreachable', 'Host Unreachable'), ('runner_on_skipped', 'Host Skipped')])),
('event_data', jsonfield.fields.JSONField(default={}, blank=True)),
('event_data', jsonfield.fields.JSONField(default=dict, blank=True)),
('failed', models.BooleanField(default=False, editable=False)),
('changed', models.BooleanField(default=False, editable=False)),
('counter', models.PositiveIntegerField(default=0)),
@@ -62,7 +62,7 @@ class Migration(migrations.Migration):
('expires', models.DateTimeField(default=django.utils.timezone.now)),
('request_hash', models.CharField(default='', max_length=40, blank=True)),
('reason', models.CharField(default='', help_text='Reason the auth token was invalidated.', max_length=1024, blank=True)),
('user', models.ForeignKey(related_name='auth_tokens', to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(related_name='auth_tokens', on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@@ -198,7 +198,7 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(default=None, editable=False)),
('modified', models.DateTimeField(default=None, editable=False)),
('event', models.CharField(max_length=100, choices=[('runner_on_failed', 'Host Failed'), ('runner_on_ok', 'Host OK'), ('runner_on_error', 'Host Failure'), ('runner_on_skipped', 'Host Skipped'), ('runner_on_unreachable', 'Host Unreachable'), ('runner_on_no_hosts', 'No Hosts Remaining'), ('runner_on_async_poll', 'Host Polling'), ('runner_on_async_ok', 'Host Async OK'), ('runner_on_async_failed', 'Host Async Failure'), ('runner_on_file_diff', 'File Difference'), ('playbook_on_start', 'Playbook Started'), ('playbook_on_notify', 'Running Handlers'), ('playbook_on_no_hosts_matched', 'No Hosts Matched'), ('playbook_on_no_hosts_remaining', 'No Hosts Remaining'), ('playbook_on_task_start', 'Task Started'), ('playbook_on_vars_prompt', 'Variables Prompted'), ('playbook_on_setup', 'Gathering Facts'), ('playbook_on_import_for_host', 'internal: on Import for Host'), ('playbook_on_not_import_for_host', 'internal: on Not Import for Host'), ('playbook_on_play_start', 'Play Started'), ('playbook_on_stats', 'Playbook Complete')])),
('event_data', jsonfield.fields.JSONField(default={}, blank=True)),
('event_data', jsonfield.fields.JSONField(default=dict, blank=True)),
('failed', models.BooleanField(default=False, editable=False)),
('changed', models.BooleanField(default=False, editable=False)),
('host_name', models.CharField(default='', max_length=1024, editable=False)),
@@ -241,7 +241,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('instance', models.ForeignKey(to='main.Instance')),
('instance', models.ForeignKey(on_delete=models.CASCADE, to='main.Instance')),
],
),
migrations.CreateModel(
@@ -287,7 +287,7 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(default=None, editable=False)),
('modified', models.DateTimeField(default=None, editable=False)),
('ldap_dn', models.CharField(default='', max_length=1024)),
('user', awx.main.fields.AutoOneToOneField(related_name='profile', editable=False, to=settings.AUTH_USER_MODEL)),
('user', awx.main.fields.AutoOneToOneField(related_name='profile', editable=False, on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@@ -304,7 +304,7 @@ class Migration(migrations.Migration):
('dtend', models.DateTimeField(default=None, null=True, editable=False)),
('rrule', models.CharField(max_length=255)),
('next_run', models.DateTimeField(default=None, null=True, editable=False)),
('extra_data', jsonfield.fields.JSONField(default={}, blank=True)),
('extra_data', jsonfield.fields.JSONField(default=dict, blank=True)),
('created_by', models.ForeignKey(related_name="{u'class': 'schedule', u'app_label': 'main'}(class)s_created+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('modified_by', models.ForeignKey(related_name="{u'class': 'schedule', u'app_label': 'main'}(class)s_modified+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')),
@@ -343,7 +343,7 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=512)),
('old_pk', models.PositiveIntegerField(default=None, null=True, editable=False)),
('launch_type', models.CharField(default='manual', max_length=20, editable=False, choices=[('manual', 'Manual'), ('relaunch', 'Relaunch'), ('callback', 'Callback'), ('scheduled', 'Scheduled'), ('dependency', 'Dependency')])),
('cancel_flag', models.BooleanField(default=False, editable=False)),
('cancel_flag', models.BooleanField(blank=True, default=False, editable=False)),
('status', models.CharField(default='new', max_length=20, editable=False, choices=[('new', 'New'), ('pending', 'Pending'), ('waiting', 'Waiting'), ('running', 'Running'), ('successful', 'Successful'), ('failed', 'Failed'), ('error', 'Error'), ('canceled', 'Canceled')])),
('failed', models.BooleanField(default=False, editable=False)),
('started', models.DateTimeField(default=None, null=True, editable=False)),
@@ -351,7 +351,7 @@ class Migration(migrations.Migration):
('elapsed', models.DecimalField(editable=False, max_digits=12, decimal_places=3)),
('job_args', models.TextField(default='', editable=False, blank=True)),
('job_cwd', models.CharField(default='', max_length=1024, editable=False, blank=True)),
('job_env', jsonfield.fields.JSONField(default={}, editable=False, blank=True)),
('job_env', jsonfield.fields.JSONField(default=dict, editable=False, blank=True)),
('job_explanation', models.TextField(default='', editable=False, blank=True)),
('start_args', models.TextField(default='', editable=False, blank=True)),
('result_stdout_text', models.TextField(default='', editable=False, blank=True)),
@@ -380,7 +380,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='AdHocCommand',
fields=[
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJob')),
('job_type', models.CharField(default='run', max_length=64, choices=[('run', 'Run'), ('check', 'Check')])),
('limit', models.CharField(default='', max_length=1024, blank=True)),
('module_name', models.CharField(default='', max_length=1024, blank=True)),
@@ -394,7 +394,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='InventorySource',
fields=[
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJobTemplate')),
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJobTemplate')),
('source', models.CharField(default='', max_length=32, blank=True, choices=[('', 'Manual'), ('file', 'Local File, Directory or Script'), ('rax', 'Rackspace Cloud Servers'), ('ec2', 'Amazon EC2'), ('gce', 'Google Compute Engine'), ('azure', 'Microsoft Azure'), ('vmware', 'VMware vCenter'), ('openstack', 'OpenStack'), ('custom', 'Custom Script')])),
('source_path', models.CharField(default='', max_length=1024, editable=False, blank=True)),
('source_vars', models.TextField(default='', help_text='Inventory source variables in YAML or JSON format.', blank=True)),
@@ -411,7 +411,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='InventoryUpdate',
fields=[
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJob')),
('source', models.CharField(default='', max_length=32, blank=True, choices=[('', 'Manual'), ('file', 'Local File, Directory or Script'), ('rax', 'Rackspace Cloud Servers'), ('ec2', 'Amazon EC2'), ('gce', 'Google Compute Engine'), ('azure', 'Microsoft Azure'), ('vmware', 'VMware vCenter'), ('openstack', 'OpenStack'), ('custom', 'Custom Script')])),
('source_path', models.CharField(default='', max_length=1024, editable=False, blank=True)),
('source_vars', models.TextField(default='', help_text='Inventory source variables in YAML or JSON format.', blank=True)),
@@ -427,7 +427,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Job',
fields=[
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJob')),
('job_type', models.CharField(default='run', max_length=64, choices=[('run', 'Run'), ('check', 'Check'), ('scan', 'Scan')])),
('playbook', models.CharField(default='', max_length=1024, blank=True)),
('forks', models.PositiveIntegerField(default=0, blank=True)),
@@ -435,7 +435,7 @@ class Migration(migrations.Migration):
('verbosity', models.PositiveIntegerField(default=0, blank=True, choices=[(0, '0 (Normal)'), (1, '1 (Verbose)'), (2, '2 (More Verbose)'), (3, '3 (Debug)'), (4, '4 (Connection Debug)'), (5, '5 (WinRM Debug)')])),
('extra_vars', models.TextField(default='', blank=True)),
('job_tags', models.CharField(default='', max_length=1024, blank=True)),
('force_handlers', models.BooleanField(default=False)),
('force_handlers', models.BooleanField(blank=True, default=False)),
('skip_tags', models.CharField(default='', max_length=1024, blank=True)),
('start_at_task', models.CharField(default='', max_length=1024, blank=True)),
('become_enabled', models.BooleanField(default=False)),
@@ -448,7 +448,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='JobTemplate',
fields=[
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJobTemplate')),
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJobTemplate')),
('job_type', models.CharField(default='run', max_length=64, choices=[('run', 'Run'), ('check', 'Check'), ('scan', 'Scan')])),
('playbook', models.CharField(default='', max_length=1024, blank=True)),
('forks', models.PositiveIntegerField(default=0, blank=True)),
@@ -456,14 +456,14 @@ class Migration(migrations.Migration):
('verbosity', models.PositiveIntegerField(default=0, blank=True, choices=[(0, '0 (Normal)'), (1, '1 (Verbose)'), (2, '2 (More Verbose)'), (3, '3 (Debug)'), (4, '4 (Connection Debug)'), (5, '5 (WinRM Debug)')])),
('extra_vars', models.TextField(default='', blank=True)),
('job_tags', models.CharField(default='', max_length=1024, blank=True)),
('force_handlers', models.BooleanField(default=False)),
('force_handlers', models.BooleanField(blank=True, default=False)),
('skip_tags', models.CharField(default='', max_length=1024, blank=True)),
('start_at_task', models.CharField(default='', max_length=1024, blank=True)),
('become_enabled', models.BooleanField(default=False)),
('host_config_key', models.CharField(default='', max_length=1024, blank=True)),
('ask_variables_on_launch', models.BooleanField(default=False)),
('survey_enabled', models.BooleanField(default=False)),
('survey_spec', jsonfield.fields.JSONField(default={}, blank=True)),
('survey_spec', jsonfield.fields.JSONField(default=dict, blank=True)),
],
options={
'ordering': ('name',),
@@ -473,7 +473,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Project',
fields=[
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJobTemplate')),
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJobTemplate')),
('local_path', models.CharField(help_text='Local path (relative to PROJECTS_ROOT) containing playbooks and related files for this project.', max_length=1024, blank=True)),
('scm_type', models.CharField(default='', max_length=8, verbose_name='SCM Type', blank=True, choices=[('', 'Manual'), ('git', 'Git'), ('hg', 'Mercurial'), ('svn', 'Subversion')])),
('scm_url', models.CharField(default='', max_length=1024, verbose_name='SCM URL', blank=True)),
@@ -492,7 +492,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='ProjectUpdate',
fields=[
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJob')),
('local_path', models.CharField(help_text='Local path (relative to PROJECTS_ROOT) containing playbooks and related files for this project.', max_length=1024, blank=True)),
('scm_type', models.CharField(default='', max_length=8, verbose_name='SCM Type', blank=True, choices=[('', 'Manual'), ('git', 'Git'), ('hg', 'Mercurial'), ('svn', 'Subversion')])),
('scm_url', models.CharField(default='', max_length=1024, verbose_name='SCM URL', blank=True)),
@@ -505,7 +505,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='SystemJob',
fields=[
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJob')),
('job_type', models.CharField(default='', max_length=32, blank=True, choices=[('cleanup_jobs', 'Remove jobs older than a certain number of days'), ('cleanup_activitystream', 'Remove activity stream entries older than a certain number of days'), ('cleanup_deleted', 'Purge previously deleted items from the database'), ('cleanup_facts', 'Purge and/or reduce the granularity of system tracking data')])),
('extra_vars', models.TextField(default='', blank=True)),
],
@@ -517,7 +517,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='SystemJobTemplate',
fields=[
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJobTemplate')),
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=django.db.models.deletion.CASCADE, serialize=False, to='main.UnifiedJobTemplate')),
('job_type', models.CharField(default='', max_length=32, blank=True, choices=[('cleanup_jobs', 'Remove jobs older than a certain number of days'), ('cleanup_activitystream', 'Remove activity stream entries older than a certain number of days'), ('cleanup_deleted', 'Purge previously deleted items from the database'), ('cleanup_facts', 'Purge and/or reduce the granularity of system tracking data')])),
],
bases=('main.unifiedjobtemplate', models.Model),
@@ -550,7 +550,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='unifiedjobtemplate',
name='polymorphic_ctype',
field=models.ForeignKey(related_name='polymorphic_main.unifiedjobtemplate_set+', editable=False, to='contenttypes.ContentType', null=True),
field=models.ForeignKey(related_name='polymorphic_main.unifiedjobtemplate_set+', editable=False, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', null=True),
),
migrations.AddField(
model_name='unifiedjobtemplate',
@@ -575,7 +575,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='unifiedjob',
name='polymorphic_ctype',
field=models.ForeignKey(related_name='polymorphic_main.unifiedjob_set+', editable=False, to='contenttypes.ContentType', null=True),
field=models.ForeignKey(related_name='polymorphic_main.unifiedjob_set+', editable=False, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType', null=True),
),
migrations.AddField(
model_name='unifiedjob',
@@ -595,7 +595,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='schedule',
name='unified_job_template',
field=models.ForeignKey(related_name='schedules', to='main.UnifiedJobTemplate'),
field=models.ForeignKey(related_name='schedules', on_delete=django.db.models.deletion.CASCADE, to='main.UnifiedJobTemplate'),
),
migrations.AddField(
model_name='permission',
@@ -610,12 +610,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='joborigin',
name='unified_job',
field=models.OneToOneField(related_name='job_origin', to='main.UnifiedJob'),
field=models.OneToOneField(related_name='job_origin', on_delete=django.db.models.deletion.CASCADE, to='main.UnifiedJob'),
),
migrations.AddField(
model_name='inventory',
name='organization',
field=models.ForeignKey(related_name='inventories', to='main.Organization', help_text='Organization containing this inventory.'),
field=models.ForeignKey(related_name='inventories', on_delete=django.db.models.deletion.CASCADE, to='main.Organization', help_text='Organization containing this inventory.'),
),
migrations.AddField(
model_name='inventory',
@@ -625,7 +625,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='host',
name='inventory',
field=models.ForeignKey(related_name='hosts', to='main.Inventory'),
field=models.ForeignKey(related_name='hosts', on_delete=django.db.models.deletion.CASCADE, to='main.Inventory'),
),
migrations.AddField(
model_name='host',
@@ -650,7 +650,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='group',
name='inventory',
field=models.ForeignKey(related_name='groups', to='main.Inventory'),
field=models.ForeignKey(related_name='groups', on_delete=django.db.models.deletion.CASCADE, to='main.Inventory'),
),
migrations.AddField(
model_name='group',
@@ -680,12 +680,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='credential',
name='team',
field=models.ForeignKey(related_name='credentials', default=None, blank=True, to='main.Team', null=True),
field=models.ForeignKey(related_name='credentials', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Team', null=True),
),
migrations.AddField(
model_name='credential',
name='user',
field=models.ForeignKey(related_name='credentials', default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True),
field=models.ForeignKey(related_name='credentials', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AddField(
model_name='adhoccommandevent',
@@ -774,7 +774,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='projectupdate',
name='project',
field=models.ForeignKey(related_name='project_updates', editable=False, to='main.Project'),
field=models.ForeignKey(related_name='project_updates', on_delete=django.db.models.deletion.CASCADE, editable=False, to='main.Project'),
),
migrations.AddField(
model_name='project',
@@ -814,12 +814,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='jobhostsummary',
name='job',
field=models.ForeignKey(related_name='job_host_summaries', editable=False, to='main.Job'),
field=models.ForeignKey(related_name='job_host_summaries', on_delete=django.db.models.deletion.CASCADE, editable=False, to='main.Job'),
),
migrations.AddField(
model_name='jobevent',
name='job',
field=models.ForeignKey(related_name='job_events', editable=False, to='main.Job'),
field=models.ForeignKey(related_name='job_events', on_delete=django.db.models.deletion.CASCADE, editable=False, to='main.Job'),
),
migrations.AddField(
model_name='job',
@@ -859,7 +859,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='inventoryupdate',
name='inventory_source',
field=models.ForeignKey(related_name='inventory_updates', editable=False, to='main.InventorySource'),
field=models.ForeignKey(related_name='inventory_updates', on_delete=django.db.models.deletion.CASCADE, editable=False, to='main.InventorySource'),
),
migrations.AddField(
model_name='inventoryupdate',
@@ -874,12 +874,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='inventorysource',
name='group',
field=awx.main.fields.AutoOneToOneField(related_name='inventory_source', null=True, default=None, editable=False, to='main.Group'),
field=awx.main.fields.AutoOneToOneField(related_name='inventory_source', on_delete=django.db.models.deletion.SET_NULL, null=True, default=None, editable=False, to='main.Group'),
),
migrations.AddField(
model_name='inventorysource',
name='inventory',
field=models.ForeignKey(related_name='inventory_sources', default=None, editable=False, to='main.Inventory', null=True),
field=models.ForeignKey(related_name='inventory_sources', on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to='main.Inventory', null=True),
),
migrations.AddField(
model_name='inventorysource',
@@ -916,7 +916,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='adhoccommandevent',
name='ad_hoc_command',
field=models.ForeignKey(related_name='ad_hoc_command_events', editable=False, to='main.AdHocCommand'),
field=models.ForeignKey(related_name='ad_hoc_command_events', on_delete=django.db.models.deletion.CASCADE, editable=False, to='main.AdHocCommand'),
),
migrations.AddField(
model_name='adhoccommand',

View File

@@ -13,7 +13,6 @@ from django.conf import settings
from django.utils.timezone import now
import jsonfield.fields
import jsonbfield.fields
import taggit.managers
@@ -144,7 +143,7 @@ class Migration(migrations.Migration):
('category', models.CharField(max_length=128)),
('value', models.TextField(blank=True)),
('value_type', models.CharField(max_length=12, choices=[('string', 'String'), ('int', 'Integer'), ('float', 'Decimal'), ('json', 'JSON'), ('bool', 'Boolean'), ('password', 'Password'), ('list', 'List')])),
('user', models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('user', models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)),
],
),
# Notification changes
@@ -185,7 +184,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='notification',
name='notification_template',
field=models.ForeignKey(related_name='notifications', editable=False, to='main.NotificationTemplate'),
field=models.ForeignKey(related_name='notifications', editable=False, on_delete=models.CASCADE, to='main.NotificationTemplate'),
),
migrations.AddField(
model_name='activitystream',
@@ -239,8 +238,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('timestamp', models.DateTimeField(default=None, help_text='Date and time of the corresponding fact scan gathering time.', editable=False)),
('module', models.CharField(max_length=128)),
('facts', jsonbfield.fields.JSONField(default={}, help_text='Arbitrary JSON structure of module facts captured at timestamp for a single host.', blank=True)),
('host', models.ForeignKey(related_name='facts', to='main.Host', help_text='Host for the facts that the fact scan captured.')),
('facts', awx.main.fields.JSONBField(default=dict, help_text='Arbitrary JSON structure of module facts captured at timestamp for a single host.', blank=True)),
('host', models.ForeignKey(related_name='facts', to='main.Host', on_delete=models.CASCADE, help_text='Host for the facts that the fact scan captured.')),
],
),
migrations.AlterIndexTogether(
@@ -318,7 +317,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='project',
name='organization',
field=models.ForeignKey(related_name='projects', to='main.Organization', blank=True, null=True),
field=models.ForeignKey(related_name='projects', to='main.Organization', on_delete=models.CASCADE, blank=True, null=True),
),
migrations.AlterField(
model_name='team',
@@ -367,7 +366,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='credential',
name='organization',
field=models.ForeignKey(related_name='credentials', default=None, blank=True, to='main.Organization', null=True),
field=models.ForeignKey(related_name='credentials', on_delete=models.CASCADE, default=None, blank=True, to='main.Organization', null=True),
),
#
@@ -382,7 +381,7 @@ class Migration(migrations.Migration):
('members', models.ManyToManyField(related_name='roles', to=settings.AUTH_USER_MODEL)),
('parents', models.ManyToManyField(related_name='children', to='main.Role')),
('implicit_parents', models.TextField(default='[]')),
('content_type', models.ForeignKey(default=None, to='contenttypes.ContentType', null=True)),
('content_type', models.ForeignKey(default=None, to='contenttypes.ContentType', on_delete=models.CASCADE, null=True)),
('object_id', models.PositiveIntegerField(default=None, null=True)),
],
@@ -398,8 +397,8 @@ class Migration(migrations.Migration):
('role_field', models.TextField()),
('content_type_id', models.PositiveIntegerField()),
('object_id', models.PositiveIntegerField()),
('ancestor', models.ForeignKey(related_name='+', to='main.Role')),
('descendent', models.ForeignKey(related_name='+', to='main.Role')),
('ancestor', models.ForeignKey(on_delete=models.CASCADE, related_name='+', to='main.Role')),
('descendent', models.ForeignKey(on_delete=models.CASCADE, related_name='+', to='main.Role')),
],
options={
'db_table': 'main_rbac_role_ancestors',
@@ -569,7 +568,7 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=512)),
('created_by', models.ForeignKey(related_name="{u'class': 'label', u'app_label': 'main'}(class)s_created+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('modified_by', models.ForeignKey(related_name="{u'class': 'label', u'app_label': 'main'}(class)s_modified+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('organization', models.ForeignKey(related_name='labels', to='main.Organization', help_text='Organization this label belongs to.')),
('organization', models.ForeignKey(related_name='labels', on_delete=django.db.models.deletion.CASCADE, to='main.Organization', help_text='Organization this label belongs to.')),
('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')),
],
options={
@@ -599,12 +598,12 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='label',
name='organization',
field=models.ForeignKey(related_name='labels', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Organization', help_text='Organization this label belongs to.', null=True),
field=models.ForeignKey(related_name='labels', on_delete=django.db.models.deletion.CASCADE, default=None, blank=True, to='main.Organization', help_text='Organization this label belongs to.', null=True),
),
migrations.AlterField(
model_name='label',
name='organization',
field=models.ForeignKey(related_name='labels', to='main.Organization', help_text='Organization this label belongs to.'),
field=models.ForeignKey(related_name='labels', on_delete=django.db.models.deletion.CASCADE, to='main.Organization', help_text='Organization this label belongs to.'),
),
# InventorySource Credential
migrations.AddField(
@@ -630,12 +629,12 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='credential',
name='deprecated_team',
field=models.ForeignKey(related_name='deprecated_credentials', default=None, blank=True, to='main.Team', null=True),
field=models.ForeignKey(related_name='deprecated_credentials', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.Team', null=True),
),
migrations.AlterField(
model_name='credential',
name='deprecated_user',
field=models.ForeignKey(related_name='deprecated_credentials', default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True),
field=models.ForeignKey(related_name='deprecated_credentials', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AlterField(
model_name='credential',

View File

@@ -116,7 +116,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='team',
name='organization',
field=models.ForeignKey(related_name='teams', to='main.Organization'),
field=models.ForeignKey(related_name='teams', on_delete=models.CASCADE, to='main.Organization'),
preserve_default=False,
),
] + _squashed.operations(SQUASHED_30, applied=True)

View File

@@ -74,7 +74,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='WorkflowJob',
fields=[
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJob')),
('unifiedjob_ptr', models.OneToOneField(parent_link=True, auto_created=True, on_delete=models.CASCADE, primary_key=True, serialize=False, to='main.UnifiedJob')),
('extra_vars', models.TextField(default='', blank=True)),
],
options={
@@ -100,7 +100,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='WorkflowJobTemplate',
fields=[
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='main.UnifiedJobTemplate')),
('unifiedjobtemplate_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, on_delete=models.CASCADE, serialize=False, to='main.UnifiedJobTemplate')),
('extra_vars', models.TextField(default='', blank=True)),
('admin_role', awx.main.fields.ImplicitRoleField(related_name='+', parent_role='singleton:system_administrator', to='main.Role', null='True')),
],
@@ -116,7 +116,7 @@ class Migration(migrations.Migration):
('failure_nodes', models.ManyToManyField(related_name='workflowjobtemplatenodes_failure', to='main.WorkflowJobTemplateNode', blank=True)),
('success_nodes', models.ManyToManyField(related_name='workflowjobtemplatenodes_success', to='main.WorkflowJobTemplateNode', blank=True)),
('unified_job_template', models.ForeignKey(related_name='workflowjobtemplatenodes', on_delete=django.db.models.deletion.SET_NULL, default=None, blank=True, to='main.UnifiedJobTemplate', null=True)),
('workflow_job_template', models.ForeignKey(related_name='workflow_job_template_nodes', default=None, blank=True, to='main.WorkflowJobTemplate', null=True)),
('workflow_job_template', models.ForeignKey(related_name='workflow_job_template_nodes', on_delete=models.SET_NULL, default=None, blank=True, to='main.WorkflowJobTemplate', null=True)),
],
options={
'abstract': False,
@@ -161,7 +161,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjobnode',
name='char_prompts',
field=jsonfield.fields.JSONField(default={}, blank=True),
field=jsonfield.fields.JSONField(default=dict, blank=True),
),
migrations.AddField(
model_name='workflowjobnode',
@@ -191,7 +191,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjobtemplatenode',
name='char_prompts',
field=jsonfield.fields.JSONField(default={}, blank=True),
field=jsonfield.fields.JSONField(default=dict, blank=True),
),
migrations.AddField(
model_name='workflowjobtemplatenode',
@@ -211,7 +211,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='workflowjobnode',
name='workflow_job',
field=models.ForeignKey(related_name='workflow_job_nodes', default=None, blank=True, to='main.WorkflowJob', null=True),
field=models.ForeignKey(related_name='workflow_job_nodes', on_delete=django.db.models.deletion.CASCADE, default=None, blank=True, to='main.WorkflowJob', null=True),
),
migrations.AlterField(
model_name='workflowjobtemplate',
@@ -227,12 +227,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='job',
name='artifacts',
field=jsonfield.fields.JSONField(default={}, editable=False, blank=True),
field=jsonfield.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AddField(
model_name='workflowjobnode',
name='ancestor_artifacts',
field=jsonfield.fields.JSONField(default={}, editable=False, blank=True),
field=jsonfield.fields.JSONField(default=dict, editable=False, blank=True),
),
# Job timeout settings
migrations.AddField(
@@ -397,7 +397,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjob',
name='survey_passwords',
field=jsonfield.fields.JSONField(default={}, editable=False, blank=True),
field=jsonfield.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AddField(
model_name='workflowjobtemplate',
@@ -407,33 +407,33 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjobtemplate',
name='survey_spec',
field=jsonfield.fields.JSONField(default={}, blank=True),
field=jsonfield.fields.JSONField(default=dict, blank=True),
),
# JSON field changes
migrations.AlterField(
model_name='adhoccommandevent',
name='event_data',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AlterField(
model_name='job',
name='artifacts',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AlterField(
model_name='job',
name='survey_passwords',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AlterField(
model_name='jobevent',
name='event_data',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AlterField(
model_name='jobtemplate',
name='survey_spec',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AlterField(
model_name='notification',
@@ -453,37 +453,37 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='schedule',
name='extra_data',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AlterField(
model_name='unifiedjob',
name='job_env',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AlterField(
model_name='workflowjob',
name='survey_passwords',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AlterField(
model_name='workflowjobnode',
name='ancestor_artifacts',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AlterField(
model_name='workflowjobnode',
name='char_prompts',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AlterField(
model_name='workflowjobtemplate',
name='survey_spec',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AlterField(
model_name='workflowjobtemplatenode',
name='char_prompts',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
# Job Project Update
migrations.AddField(

View File

@@ -55,12 +55,12 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='inventorysource',
name='deprecated_group',
field=models.OneToOneField(related_name='deprecated_inventory_source', null=True, default=None, to='main.Group'),
field=models.OneToOneField(related_name='deprecated_inventory_source', on_delete=models.CASCADE, null=True, default=None, to='main.Group'),
),
migrations.AlterField(
model_name='inventorysource',
name='inventory',
field=models.ForeignKey(related_name='inventory_sources', default=None, to='main.Inventory', null=True),
field=models.ForeignKey(related_name='inventory_sources', default=None, to='main.Inventory', on_delete=models.CASCADE, null=True),
),
# Smart Inventory
@@ -78,13 +78,13 @@ class Migration(migrations.Migration):
name='SmartInventoryMembership',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('host', models.ForeignKey(related_name='+', to='main.Host')),
('host', models.ForeignKey(related_name='+', on_delete=models.CASCADE, to='main.Host')),
],
),
migrations.AddField(
model_name='smartinventorymembership',
name='inventory',
field=models.ForeignKey(related_name='+', to='main.Inventory'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='+', to='main.Inventory'),
),
migrations.AddField(
model_name='host',
@@ -105,19 +105,19 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='inventory',
name='organization',
field=models.ForeignKey(related_name='inventories', on_delete=models.deletion.SET_NULL, to='main.Organization', help_text='Organization containing this inventory.', null=True),
field=models.ForeignKey(related_name='inventories', on_delete=models.SET_NULL, to='main.Organization', help_text='Organization containing this inventory.', null=True),
),
# Facts
migrations.AlterField(
model_name='fact',
name='facts',
field=awx.main.fields.JSONBField(default={}, help_text='Arbitrary JSON structure of module facts captured at timestamp for a single host.', blank=True),
field=awx.main.fields.JSONBField(default=dict, help_text='Arbitrary JSON structure of module facts captured at timestamp for a single host.', blank=True),
),
migrations.AddField(
model_name='host',
name='ansible_facts',
field=awx.main.fields.JSONBField(default={}, help_text='Arbitrary JSON structure of most recent ansible_facts, per-host.', blank=True),
field=awx.main.fields.JSONBField(default=dict, help_text='Arbitrary JSON structure of most recent ansible_facts, per-host.', blank=True),
),
migrations.AddField(
model_name='host',
@@ -148,12 +148,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='inventorysource',
name='source_project',
field=models.ForeignKey(related_name='scm_inventory_sources', default=None, blank=True, to='main.Project', help_text='Project containing inventory file used as source.', null=True),
field=models.ForeignKey(related_name='scm_inventory_sources', on_delete=models.CASCADE, default=None, blank=True, to='main.Project', help_text='Project containing inventory file used as source.', null=True),
),
migrations.AddField(
model_name='inventoryupdate',
name='source_project_update',
field=models.ForeignKey(related_name='scm_inventory_updates', default=None, blank=True, to='main.ProjectUpdate', help_text='Inventory files from this Project Update were used for the inventory update.', null=True),
field=models.ForeignKey(related_name='scm_inventory_updates', on_delete=models.CASCADE, default=None, blank=True, to='main.ProjectUpdate', help_text='Inventory files from this Project Update were used for the inventory update.', null=True),
),
migrations.AddField(
model_name='project',
@@ -200,7 +200,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='notificationtemplate',
name='organization',
field=models.ForeignKey(related_name='notification_templates', to='main.Organization', null=True),
field=models.ForeignKey(related_name='notification_templates', on_delete=models.CASCADE, to='main.Organization', null=True),
),
migrations.AlterUniqueTogether(
name='notificationtemplate',
@@ -312,7 +312,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='inventory',
name='insights_credential',
field=models.ForeignKey(related_name='insights_inventories', on_delete=models.deletion.SET_NULL, default=None, blank=True, to='main.Credential', help_text='Credentials to be used by hosts belonging to this inventory when accessing Red Hat Insights API.', null=True),
field=models.ForeignKey(related_name='insights_inventories', on_delete=models.SET_NULL, default=None, blank=True, to='main.Credential', help_text='Credentials to be used by hosts belonging to this inventory when accessing Red Hat Insights API.', null=True),
),
migrations.AlterField(
model_name='inventory',
@@ -382,10 +382,10 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=512)),
('kind', models.CharField(max_length=32, choices=[('ssh', 'Machine'), ('vault', 'Vault'), ('net', 'Network'), ('scm', 'Source Control'), ('cloud', 'Cloud'), ('insights', 'Insights')])),
('managed_by_tower', models.BooleanField(default=False, editable=False)),
('inputs', awx.main.fields.CredentialTypeInputField(default={}, blank=True, help_text='Enter inputs using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.')),
('injectors', awx.main.fields.CredentialTypeInjectorField(default={}, blank=True, help_text='Enter injectors using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.')),
('created_by', models.ForeignKey(related_name="{u'class': 'credentialtype', u'app_label': 'main'}(class)s_created+", on_delete=models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('modified_by', models.ForeignKey(related_name="{u'class': 'credentialtype', u'app_label': 'main'}(class)s_modified+", on_delete=models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('inputs', awx.main.fields.CredentialTypeInputField(default=dict, blank=True, help_text='Enter inputs using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.')),
('injectors', awx.main.fields.CredentialTypeInjectorField(default=dict, blank=True, help_text='Enter injectors using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.')),
('created_by', models.ForeignKey(related_name="{u'class': 'credentialtype', u'app_label': 'main'}(class)s_created+", on_delete=models.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('modified_by', models.ForeignKey(related_name="{u'class': 'credentialtype', u'app_label': 'main'}(class)s_modified+", on_delete=models.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')),
],
options={
@@ -399,23 +399,23 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='credential',
name='inputs',
field=awx.main.fields.CredentialInputField(default={}, blank=True),
field=awx.main.fields.CredentialInputField(default=dict, blank=True),
),
migrations.AddField(
model_name='credential',
name='credential_type',
field=models.ForeignKey(related_name='credentials', to='main.CredentialType', null=True),
field=models.ForeignKey(related_name='credentials', on_delete=models.CASCADE, to='main.CredentialType', null=True),
preserve_default=False,
),
migrations.AddField(
model_name='job',
name='vault_credential',
field=models.ForeignKey(related_name='jobs_as_vault_credential+', on_delete=models.deletion.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
field=models.ForeignKey(related_name='jobs_as_vault_credential+', on_delete=models.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
),
migrations.AddField(
model_name='jobtemplate',
name='vault_credential',
field=models.ForeignKey(related_name='jobtemplates_as_vault_credential+', on_delete=models.deletion.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
field=models.ForeignKey(related_name='jobtemplates_as_vault_credential+', on_delete=models.SET_NULL, default=None, blank=True, to='main.Credential', null=True),
),
migrations.AddField(
model_name='job',
@@ -452,7 +452,7 @@ class Migration(migrations.Migration):
('name', models.CharField(unique=True, max_length=250)),
('created', models.DateTimeField(auto_now_add=True)),
('modified', models.DateTimeField(auto_now=True)),
('controller', models.ForeignKey(related_name='controlled_groups', default=None, editable=False, to='main.InstanceGroup', help_text='Instance Group to remotely control this group.', null=True)),
('controller', models.ForeignKey(related_name='controlled_groups', on_delete=models.CASCADE, default=None, editable=False, to='main.InstanceGroup', help_text='Instance Group to remotely control this group.', null=True)),
('instances', models.ManyToManyField(help_text='Instances that are members of this InstanceGroup', related_name='rampart_groups', editable=False, to='main.Instance')),
],
),
@@ -464,7 +464,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='unifiedjob',
name='instance_group',
field=models.ForeignKey(on_delete=models.deletion.SET_NULL, default=None, blank=True, to='main.InstanceGroup', help_text='The Rampart/Instance group the job was run under', null=True),
field=models.ForeignKey(on_delete=models.SET_NULL, default=None, blank=True, to='main.InstanceGroup', help_text='The Rampart/Instance group the job was run under', null=True),
),
migrations.AddField(
model_name='unifiedjobtemplate',

View File

@@ -103,12 +103,12 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='credential',
name='credential_type',
field=models.ForeignKey(related_name='credentials', to='main.CredentialType', null=False, help_text='Specify the type of credential you want to create. Refer to the Ansible Tower documentation for details on each type.')
field=models.ForeignKey(related_name='credentials', to='main.CredentialType', on_delete=models.CASCADE, null=False, help_text='Specify the type of credential you want to create. Refer to the Ansible Tower documentation for details on each type.')
),
migrations.AlterField(
model_name='credential',
name='inputs',
field=awx.main.fields.CredentialInputField(default={}, help_text='Enter inputs using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.', blank=True),
field=awx.main.fields.CredentialInputField(default=dict, help_text='Enter inputs using either JSON or YAML syntax. Use the radio button to toggle between the two. Refer to the Ansible Tower documentation for example syntax.', blank=True),
),
migrations.RemoveField(
model_name='job',

View File

@@ -20,7 +20,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='schedule',
name='char_prompts',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AddField(
model_name='schedule',
@@ -35,7 +35,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='schedule',
name='survey_passwords',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AddField(
model_name='workflowjobnode',
@@ -45,12 +45,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjobnode',
name='extra_data',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AddField(
model_name='workflowjobnode',
name='survey_passwords',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
migrations.AddField(
model_name='workflowjobtemplatenode',
@@ -60,12 +60,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjobtemplatenode',
name='extra_data',
field=awx.main.fields.JSONField(default={}, blank=True),
field=awx.main.fields.JSONField(default=dict, blank=True),
),
migrations.AddField(
model_name='workflowjobtemplatenode',
name='survey_passwords',
field=awx.main.fields.JSONField(default={}, editable=False, blank=True),
field=awx.main.fields.JSONField(default=dict, editable=False, blank=True),
),
# Run data migration before removing the old credential field
migrations.RunPython(migration_utils.set_current_apps_for_migrations, migrations.RunPython.noop),
@@ -83,9 +83,9 @@ class Migration(migrations.Migration):
name='JobLaunchConfig',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('extra_data', awx.main.fields.JSONField(blank=True, default={})),
('survey_passwords', awx.main.fields.JSONField(blank=True, default={}, editable=False)),
('char_prompts', awx.main.fields.JSONField(blank=True, default={})),
('extra_data', awx.main.fields.JSONField(blank=True, default=dict)),
('survey_passwords', awx.main.fields.JSONField(blank=True, default=dict, editable=False)),
('char_prompts', awx.main.fields.JSONField(blank=True, default=dict)),
('credentials', models.ManyToManyField(related_name='joblaunchconfigs', to='main.Credential')),
('inventory', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='joblaunchconfigs', to='main.Inventory')),
('job', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='launch_config', to='main.UnifiedJob')),
@@ -94,51 +94,51 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjobtemplate',
name='ask_variables_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_credential_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_diff_mode_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_inventory_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_job_type_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_limit_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_skip_tags_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_tags_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_variables_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AlterField(
model_name='jobtemplate',
name='ask_verbosity_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
]

View File

@@ -20,7 +20,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=None, editable=False)),
('modified', models.DateTimeField(default=None, editable=False)),
('event_data', awx.main.fields.JSONField(blank=True, default={})),
('event_data', awx.main.fields.JSONField(blank=True, default=dict)),
('uuid', models.CharField(default='', editable=False, max_length=1024)),
('counter', models.PositiveIntegerField(default=0, editable=False)),
('stdout', models.TextField(default='', editable=False)),
@@ -40,7 +40,7 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(default=None, editable=False)),
('modified', models.DateTimeField(default=None, editable=False)),
('event', models.CharField(choices=[('runner_on_failed', 'Host Failed'), ('runner_on_ok', 'Host OK'), ('runner_on_error', 'Host Failure'), ('runner_on_skipped', 'Host Skipped'), ('runner_on_unreachable', 'Host Unreachable'), ('runner_on_no_hosts', 'No Hosts Remaining'), ('runner_on_async_poll', 'Host Polling'), ('runner_on_async_ok', 'Host Async OK'), ('runner_on_async_failed', 'Host Async Failure'), ('runner_item_on_ok', 'Item OK'), ('runner_item_on_failed', 'Item Failed'), ('runner_item_on_skipped', 'Item Skipped'), ('runner_retry', 'Host Retry'), ('runner_on_file_diff', 'File Difference'), ('playbook_on_start', 'Playbook Started'), ('playbook_on_notify', 'Running Handlers'), ('playbook_on_include', 'Including File'), ('playbook_on_no_hosts_matched', 'No Hosts Matched'), ('playbook_on_no_hosts_remaining', 'No Hosts Remaining'), ('playbook_on_task_start', 'Task Started'), ('playbook_on_vars_prompt', 'Variables Prompted'), ('playbook_on_setup', 'Gathering Facts'), ('playbook_on_import_for_host', 'internal: on Import for Host'), ('playbook_on_not_import_for_host', 'internal: on Not Import for Host'), ('playbook_on_play_start', 'Play Started'), ('playbook_on_stats', 'Playbook Complete'), ('debug', 'Debug'), ('verbose', 'Verbose'), ('deprecated', 'Deprecated'), ('warning', 'Warning'), ('system_warning', 'System Warning'), ('error', 'Error')], max_length=100)),
('event_data', awx.main.fields.JSONField(blank=True, default={})),
('event_data', awx.main.fields.JSONField(blank=True, default=dict)),
('failed', models.BooleanField(default=False, editable=False)),
('changed', models.BooleanField(default=False, editable=False)),
('uuid', models.CharField(default='', editable=False, max_length=1024)),
@@ -65,7 +65,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=None, editable=False)),
('modified', models.DateTimeField(default=None, editable=False)),
('event_data', awx.main.fields.JSONField(blank=True, default={})),
('event_data', awx.main.fields.JSONField(blank=True, default=dict)),
('uuid', models.CharField(default='', editable=False, max_length=1024)),
('counter', models.PositiveIntegerField(default=0, editable=False)),
('stdout', models.TextField(default='', editable=False)),

View File

@@ -17,7 +17,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjob',
name='char_prompts',
field=awx.main.fields.JSONField(blank=True, default={}),
field=awx.main.fields.JSONField(blank=True, default=dict),
),
migrations.AddField(
model_name='workflowjob',
@@ -27,7 +27,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workflowjobtemplate',
name='ask_inventory_on_launch',
field=awx.main.fields.AskForField(default=False),
field=awx.main.fields.AskForField(blank=True, default=False),
),
migrations.AddField(
model_name='workflowjobtemplate',

View File

@@ -34,7 +34,7 @@ class Migration(migrations.Migration):
('modified', models.DateTimeField(default=None, editable=False)),
('description', models.TextField(blank=True, default='')),
('input_field_name', models.CharField(max_length=1024)),
('metadata', awx.main.fields.DynamicCredentialInputField(blank=True, default={})),
('metadata', awx.main.fields.DynamicCredentialInputField(blank=True, default=dict)),
('created_by', models.ForeignKey(default=None, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="{'class': 'credentialinputsource', 'model_name': 'credentialinputsource', 'app_label': 'main'}(class)s_created+", to=settings.AUTH_USER_MODEL)),
('modified_by', models.ForeignKey(default=None, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="{'class': 'credentialinputsource', 'model_name': 'credentialinputsource', 'app_label': 'main'}(class)s_modified+", to=settings.AUTH_USER_MODEL)),
('source_credential', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='target_input_sources', to='main.Credential')),

View File

@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-30 20:35
from __future__ import unicode_literals
from django.db import migrations, models
def forwards_split_unified_job_template_any(apps, schema_editor):
UnifiedJobTemplate = apps.get_model('main', 'unifiedjobtemplate')
for ujt in UnifiedJobTemplate.objects.all():
for ujt_notification in ujt.notification_templates_any.all():
ujt.notification_templates_success.add(ujt_notification)
ujt.notification_templates_error.add(ujt_notification)
def forwards_split_organization_any(apps, schema_editor):
Organization = apps.get_model('main', 'organization')
for org in Organization.objects.all():
for org_notification in org.notification_templates_any.all():
org.notification_templates_success.add(org_notification)
org.notification_templates_error.add(org_notification)
class Migration(migrations.Migration):
dependencies = [
('main', '0080_v360_replace_job_origin'),
]
operations = [
migrations.AddField(
model_name='organization',
name='notification_templates_started',
field=models.ManyToManyField(blank=True, related_name='organization_notification_templates_for_started', to='main.NotificationTemplate'),
),
migrations.AddField(
model_name='unifiedjobtemplate',
name='notification_templates_started',
field=models.ManyToManyField(blank=True, related_name='unifiedjobtemplate_notification_templates_for_started', to='main.NotificationTemplate'),
),
# Separate out "any" notifications into "success" and "error" before the "any" state gets deleted.
migrations.RunPython(forwards_split_unified_job_template_any, None),
migrations.RunPython(forwards_split_organization_any, None),
migrations.RemoveField(
model_name='organization',
name='notification_templates_any',
),
migrations.RemoveField(
model_name='unifiedjobtemplate',
name='notification_templates_any',
),
]

View File

@@ -1,17 +1,11 @@
import logging
from time import time
from django.utils.encoding import smart_text
from django.db import transaction
from django.db.models import Q
from django.db.utils import IntegrityError
from collections import defaultdict
from awx.main.utils import getattrd
from awx.main.models.rbac import Role, batch_role_ancestor_rebuilding
logger = logging.getLogger('rbac_migrations')
def create_roles(apps, schema_editor):
'''
Implicit role creation happens in our post_save hook for all of our
@@ -41,465 +35,19 @@ def create_roles(apps, schema_editor):
obj.save()
def migrate_users(apps, schema_editor):
User = apps.get_model('auth', "User")
Role = apps.get_model('main', "Role")
ContentType = apps.get_model('contenttypes', "ContentType")
user_content_type = ContentType.objects.get_for_model(User)
for user in User.objects.iterator():
user.save()
try:
Role.objects.get(content_type=user_content_type, object_id=user.id)
logger.info(smart_text(u"found existing role for user: {}".format(user.username)))
except Role.DoesNotExist:
role = Role.objects.create(
role_field='admin_role',
content_type = user_content_type,
object_id = user.id
)
role.members.add(user)
logger.info(smart_text(u"migrating to new role for user: {}".format(user.username)))
if user.is_superuser:
if Role.objects.filter(singleton_name='system_administrator').exists():
sa_role = Role.objects.get(singleton_name='system_administrator')
else:
sa_role = Role.objects.create(
singleton_name='system_administrator',
role_field='system_administrator'
)
sa_role.members.add(user)
logger.warning(smart_text(u"added superuser: {}".format(user.username)))
def migrate_organization(apps, schema_editor):
Organization = apps.get_model('main', "Organization")
for org in Organization.objects.iterator():
for admin in org.deprecated_admins.all():
org.admin_role.members.add(admin)
logger.info(smart_text(u"added admin: {}, {}".format(org.name, admin.username)))
for user in org.deprecated_users.all():
org.member_role.members.add(user)
logger.info(smart_text(u"added member: {}, {}".format(org.name, user.username)))
def migrate_team(apps, schema_editor):
Team = apps.get_model('main', 'Team')
for t in Team.objects.iterator():
for user in t.deprecated_users.all():
t.member_role.members.add(user)
logger.info(smart_text(u"team: {}, added user: {}".format(t.name, user.username)))
def attrfunc(attr_path):
'''attrfunc returns a function that will
attempt to use the attr_path to access the attribute
of an instance that is passed in to the returned function.
Example:
get_org = attrfunc('inventory.organization')
org = get_org(JobTemplateInstance)
'''
def attr(inst):
return getattrd(inst, attr_path)
return attr
def _update_credential_parents(org, cred):
cred.organization = org
cred.save()
def _discover_credentials(instances, cred, orgfunc):
'''_discover_credentials will find shared credentials across
organizations. If a shared credential is found, it will duplicate
the credential, ensure the proper role permissions are added to the new
credential, and update any references from the old to the newly created
credential.
instances is a list of all objects that were matched when filtered
with cred.
orgfunc is a function that when called with an instance from instances
will produce an Organization object.
'''
orgs = defaultdict(list)
for inst in instances:
try:
orgs[orgfunc(inst)].append(inst)
except AttributeError:
# JobTemplate.inventory can be NULL sometimes, eg when an inventory
# has been deleted. This protects against that.
pass
if len(orgs) == 1:
try:
_update_credential_parents(orgfunc(instances[0]), cred)
except AttributeError:
# JobTemplate.inventory can be NULL sometimes, eg when an inventory
# has been deleted. This protects against that.
pass
else:
for pos, org in enumerate(orgs):
if pos == 0:
_update_credential_parents(org, cred)
else:
# Create a new credential
cred.pk = None
cred.organization = None
cred.save()
cred.admin_role, cred.use_role = None, None
for i in orgs[org]:
i.credential = cred
i.save()
_update_credential_parents(org, cred)
def migrate_credential(apps, schema_editor):
Credential = apps.get_model('main', "Credential")
JobTemplate = apps.get_model('main', 'JobTemplate')
Project = apps.get_model('main', 'Project')
InventorySource = apps.get_model('main', 'InventorySource')
for cred in Credential.objects.iterator():
results = [x for x in JobTemplate.objects.filter(Q(credential=cred) | Q(cloud_credential=cred), inventory__isnull=False).all()] + \
[x for x in InventorySource.objects.filter(credential=cred).all()]
if cred.deprecated_team is not None and results:
if len(results) == 1:
_update_credential_parents(results[0].inventory.organization, cred)
else:
_discover_credentials(results, cred, attrfunc('inventory.organization'))
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at organization level".format(cred.name, cred.kind, cred.host)))
projs = Project.objects.filter(credential=cred).all()
if cred.deprecated_team is not None and projs:
if len(projs) == 1:
_update_credential_parents(projs[0].organization, cred)
else:
_discover_credentials(projs, cred, attrfunc('organization'))
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at organization level".format(cred.name, cred.kind, cred.host)))
if cred.deprecated_team is not None:
cred.deprecated_team.admin_role.children.add(cred.admin_role)
cred.deprecated_team.member_role.children.add(cred.use_role)
cred.save()
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at user level".format(cred.name, cred.kind, cred.host)))
elif cred.deprecated_user is not None:
cred.admin_role.members.add(cred.deprecated_user)
cred.save()
logger.info(smart_text(u"added Credential(name={}, kind={}, host={}) at user level".format(cred.name, cred.kind, cred.host, )))
else:
logger.warning(smart_text(u"orphaned credential found Credential(name={}, kind={}, host={}), superuser only".format(cred.name, cred.kind, cred.host, )))
def migrate_inventory(apps, schema_editor):
Inventory = apps.get_model('main', 'Inventory')
Permission = apps.get_model('main', 'Permission')
def role_from_permission(perm):
if perm.permission_type == 'admin':
return inventory.admin_role
elif perm.permission_type == 'read':
return inventory.read_role
elif perm.permission_type == 'write':
return inventory.update_role
elif perm.permission_type == 'check' or perm.permission_type == 'run' or perm.permission_type == 'create':
# These permission types are handled differntly in RBAC now, nothing to migrate.
return False
else:
return None
for inventory in Inventory.objects.iterator():
for perm in Permission.objects.filter(inventory=inventory):
role = None
execrole = None
role = role_from_permission(perm)
if role is None:
raise Exception(smart_text(u'Unhandled permission type for inventory: {}'.format( perm.permission_type)))
if perm.run_ad_hoc_commands:
execrole = inventory.use_role
if perm.team:
if role:
perm.team.member_role.children.add(role)
if execrole:
perm.team.member_role.children.add(execrole)
logger.info(smart_text(u'added Team({}) access to Inventory({})'.format(perm.team.name, inventory.name)))
if perm.user:
if role:
role.members.add(perm.user)
if execrole:
execrole.members.add(perm.user)
logger.info(smart_text(u'added User({}) access to Inventory({})'.format(perm.user.username, inventory.name)))
def migrate_projects(apps, schema_editor):
'''
I can see projects when:
X I am a superuser.
X I am an admin in an organization associated with the project.
X I am a user in an organization associated with the project.
X I am on a team associated with the project.
X I have been explicitly granted permission to run/check jobs using the
project.
X I created the project but it isn't associated with an organization
I can change/delete when:
X I am a superuser.
X I am an admin in an organization associated with the project.
X I created the project but it isn't associated with an organization
'''
Project = apps.get_model('main', 'Project')
Permission = apps.get_model('main', 'Permission')
JobTemplate = apps.get_model('main', 'JobTemplate')
# Migrate projects to single organizations, duplicating as necessary
for project in Project.objects.iterator():
original_project_name = project.name
project_orgs = project.deprecated_organizations.distinct().all()
if len(project_orgs) >= 1:
first_org = None
for org in project_orgs:
if first_org is None:
# For the first org, re-use our existing Project object, so don't do the below duplication effort
first_org = org
if len(project_orgs) > 1:
project.name = smart_text(u'{} - {}'.format(first_org.name, original_project_name))
project.organization = first_org
project.save()
else:
new_prj = Project.objects.create(
created = project.created,
modified = project.modified,
polymorphic_ctype_id = project.polymorphic_ctype_id,
description = project.description,
name = smart_text(u'{} - {}'.format(org.name, original_project_name)),
old_pk = project.old_pk,
created_by_id = project.created_by_id,
modified_by_id = project.modified_by_id,
scm_type = project.scm_type,
scm_url = project.scm_url,
scm_branch = project.scm_branch,
scm_clean = project.scm_clean,
scm_delete_on_update = project.scm_delete_on_update,
scm_delete_on_next_update = project.scm_delete_on_next_update,
scm_update_on_launch = project.scm_update_on_launch,
scm_update_cache_timeout = project.scm_update_cache_timeout,
credential = project.credential,
organization = org
)
if project.scm_type == "":
new_prj.local_path = project.local_path
new_prj.save()
for team in project.deprecated_teams.iterator():
new_prj.deprecated_teams.add(team)
logger.warning(smart_text(u'cloning Project({}) onto {} as Project({})'.format(original_project_name, org, new_prj)))
job_templates = JobTemplate.objects.filter(project=project, inventory__organization=org).all()
for jt in job_templates:
jt.project = new_prj
jt.save()
for perm in Permission.objects.filter(project=project):
Permission.objects.create(
created = perm.created,
modified = perm.modified,
created_by = perm.created_by,
modified_by = perm.modified_by,
description = perm.description,
name = perm.name,
user = perm.user,
team = perm.team,
project = new_prj,
inventory = perm.inventory,
permission_type = perm.permission_type,
run_ad_hoc_commands = perm.run_ad_hoc_commands,
)
# Migrate permissions
for project in Project.objects.iterator():
if project.organization is None and project.created_by is not None:
project.admin_role.members.add(project.created_by)
logger.warn(smart_text(u'adding Project({}) admin: {}'.format(project.name, project.created_by.username)))
for team in project.deprecated_teams.all():
team.member_role.children.add(project.read_role)
logger.info(smart_text(u'adding Team({}) access for Project({})'.format(team.name, project.name)))
for perm in Permission.objects.filter(project=project):
if perm.permission_type == 'create':
role = project.use_role
else:
role = project.read_role
if perm.team:
perm.team.member_role.children.add(role)
logger.info(smart_text(u'adding Team({}) access for Project({})'.format(perm.team.name, project.name)))
if perm.user:
role.members.add(perm.user)
logger.info(smart_text(u'adding User({}) access for Project({})'.format(perm.user.username, project.name)))
if project.organization is not None:
for user in project.organization.deprecated_users.all():
if not (project.use_role.members.filter(pk=user.id).exists() or project.admin_role.members.filter(pk=user.id).exists()):
project.read_role.members.add(user)
logger.info(smart_text(u'adding Organization({}) member access to Project({})'.format(project.organization.name, project.name)))
def migrate_job_templates(apps, schema_editor):
'''
NOTE: This must be run after orgs, inventory, projects, credential, and
users have been migrated
'''
'''
I can see job templates when:
X I am a superuser.
- I can read the inventory, project and credential (which means I am an
org admin or member of a team with access to all of the above).
- I have permission explicitly granted to check/deploy with the inventory
and project.
#This does not mean I would be able to launch a job from the template or
#edit the template.
- access.py can_read for JobTemplate enforces that you can only
see it if you can launch it, so the above imply launch too
'''
'''
Tower administrators, organization administrators, and project
administrators, within a project under their purview, may create and modify
new job templates for that project.
When editing a job template, they may select among the inventory groups and
credentials in the organization for which they have usage permissions, or
they may leave either blank to be selected at runtime.
Additionally, they may specify one or more users/teams that have execution
permission for that job template, among the users/teams that are a member
of that project.
That execution permission is valid irrespective of any explicit permissions
the user has or has not been granted to the inventory group or credential
specified in the job template.
'''
User = apps.get_model('auth', 'User')
JobTemplate = apps.get_model('main', 'JobTemplate')
Team = apps.get_model('main', 'Team')
Permission = apps.get_model('main', 'Permission')
Credential = apps.get_model('main', 'Credential')
jt_queryset = JobTemplate.objects.select_related('inventory', 'project', 'inventory__organization', 'execute_role')
for jt in jt_queryset.iterator():
if jt.inventory is None:
# If inventory is None, then only system admins and org admins can
# do anything with the JT in 2.4
continue
jt_permission_qs = Permission.objects.filter(
inventory=jt.inventory,
project=jt.project,
)
inventory_permission_qs = Permission.objects.filter(
inventory=jt.inventory,
project__isnull=True,
)
team_create_permissions = set(
jt_permission_qs
.filter(permission_type__in=['create'])
.values_list('team__id', flat=True)
)
team_run_permissions = set(
jt_permission_qs
.filter(permission_type__in=['check', 'run'] if jt.job_type == 'check' else ['run'])
.values_list('team__id', flat=True)
)
user_create_permissions = set(
jt_permission_qs
.filter(permission_type__in=['create'])
.values_list('user__id', flat=True)
)
user_run_permissions = set(
jt_permission_qs
.filter(permission_type__in=['check', 'run'] if jt.job_type == 'check' else ['run'])
.values_list('user__id', flat=True)
)
team_inv_permissions = defaultdict(set)
user_inv_permissions = defaultdict(set)
for user_id, team_id, inventory_id in inventory_permission_qs.values_list('user_id', 'team_id', 'inventory_id'):
if user_id:
user_inv_permissions[user_id].add(inventory_id)
if team_id:
team_inv_permissions[team_id].add(inventory_id)
for team in Team.objects.filter(id__in=team_create_permissions).iterator():
if jt.inventory.id in team_inv_permissions[team.id] and \
((not jt.credential and not jt.cloud_credential) or
Credential.objects.filter(deprecated_team=team, jobtemplates=jt).exists()):
team.member_role.children.add(jt.admin_role)
logger.info(smart_text(u'transfering admin access on JobTemplate({}) to Team({})'.format(jt.name, team.name)))
for team in Team.objects.filter(id__in=team_run_permissions).iterator():
if jt.inventory.id in team_inv_permissions[team.id] and \
((not jt.credential and not jt.cloud_credential) or
Credential.objects.filter(deprecated_team=team, jobtemplates=jt).exists()):
team.member_role.children.add(jt.execute_role)
logger.info(smart_text(u'transfering execute access on JobTemplate({}) to Team({})'.format(jt.name, team.name)))
for user in User.objects.filter(id__in=user_create_permissions).iterator():
cred = jt.credential or jt.cloud_credential
if (jt.inventory.id in user_inv_permissions[user.id] or
any([jt.inventory.id in team_inv_permissions[team.id] for team in user.deprecated_teams.all()])) and \
(not cred or cred.deprecated_user == user or
(cred.deprecated_team and cred.deprecated_team.deprecated_users.filter(pk=user.id).exists())):
jt.admin_role.members.add(user)
logger.info(smart_text(u'transfering admin access on JobTemplate({}) to User({})'.format(jt.name, user.username)))
for user in User.objects.filter(id__in=user_run_permissions).iterator():
cred = jt.credential or jt.cloud_credential
if (jt.inventory.id in user_inv_permissions[user.id] or
any([jt.inventory.id in team_inv_permissions[team.id] for team in user.deprecated_teams.all()])) and \
(not cred or cred.deprecated_user == user or
(cred.deprecated_team and cred.deprecated_team.deprecated_users.filter(pk=user.id).exists())):
jt.execute_role.members.add(user)
logger.info(smart_text(u'transfering execute access on JobTemplate({}) to User({})'.format(jt.name, user.username)))
def rebuild_role_hierarchy(apps, schema_editor):
logger.info('Computing role roots..')
start = time()
roots = Role.objects \
.all() \
.values_list('id', flat=True)
stop = time()
logger.info('Found %d roots in %f seconds, rebuilding ancestry map' % (len(roots), stop - start))
start = time()
Role.rebuild_role_ancestor_list(roots, [])
stop = time()
logger.info('Rebuild completed in %f seconds' % (stop - start))
logger.info('Done.')
def infer_credential_org_from_team(apps, schema_editor):
Credential = apps.get_model('main', "Credential")
for cred in Credential.objects.exclude(deprecated_team__isnull=True):
try:
with transaction.atomic():
_update_credential_parents(cred.deprecated_team.organization, cred)
except IntegrityError:
logger.info("Organization<{}> credential for old Team<{}> credential already created".format(cred.deprecated_team.organization.pk, cred.pk))
logger.info('Computing role roots..')
start = time()
roots = Role.objects \
.all() \
.values_list('id', flat=True)
stop = time()
logger.info('Found %d roots in %f seconds, rebuilding ancestry map' % (len(roots), stop - start))
start = time()
Role.rebuild_role_ancestor_list(roots, [])
stop = time()
logger.info('Rebuild completed in %f seconds' % (stop - start))
logger.info('Done.')
def delete_all_user_roles(apps, schema_editor):

View File

@@ -30,7 +30,7 @@ SQUASHED_30 = {
migrations.AddField(
model_name='job',
name='survey_passwords',
field=jsonfield.fields.JSONField(default={}, editable=False, blank=True),
field=jsonfield.fields.JSONField(default=dict, editable=False, blank=True),
),
],
'0031_v302_migrate_survey_passwords': [

View File

@@ -62,24 +62,6 @@ from awx.main.models.oauth import ( # noqa
from oauth2_provider.models import Grant, RefreshToken # noqa -- needed django-oauth-toolkit model migrations
# Monkeypatch Django serializer to ignore django-taggit fields (which break
# the dumpdata command; see https://github.com/alex/django-taggit/issues/155).
from django.core.serializers.python import Serializer as _PythonSerializer
_original_handle_m2m_field = _PythonSerializer.handle_m2m_field
def _new_handle_m2m_field(self, obj, field):
try:
field.rel.through._meta
except AttributeError:
return
return _original_handle_m2m_field(self, obj, field)
_PythonSerializer.handle_m2m_field = _new_handle_m2m_field
# Add custom methods to User model for permissions checks.
from django.contrib.auth.models import User # noqa
from awx.main.access import ( # noqa
@@ -158,7 +140,7 @@ User.add_to_class('is_system_auditor', user_is_system_auditor)
def user_is_in_enterprise_category(user, category):
ret = (category,) in user.enterprise_auth.all().values_list('provider') and not user.has_usable_password()
ret = (category,) in user.enterprise_auth.values_list('provider') and not user.has_usable_password()
# NOTE: this if-else block ensures existing enterprise users are still able to
# log in. Remove it in a future release
if category == 'radius':

View File

@@ -163,18 +163,18 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
all_orgs.add(h.inventory.organization)
active_templates = dict(error=set(),
success=set(),
any=set())
started=set())
base_notification_templates = NotificationTemplate.objects
for org in all_orgs:
for templ in base_notification_templates.filter(organization_notification_templates_for_errors=org):
active_templates['error'].add(templ)
for templ in base_notification_templates.filter(organization_notification_templates_for_success=org):
active_templates['success'].add(templ)
for templ in base_notification_templates.filter(organization_notification_templates_for_any=org):
active_templates['any'].add(templ)
for templ in base_notification_templates.filter(organization_notification_templates_for_started=org):
active_templates['started'].add(templ)
active_templates['error'] = list(active_templates['error'])
active_templates['any'] = list(active_templates['any'])
active_templates['success'] = list(active_templates['success'])
active_templates['started'] = list(active_templates['started'])
return active_templates
def get_passwords_needed_to_start(self):

View File

@@ -386,14 +386,13 @@ class NotificationFieldsModel(BaseModel):
related_name='%(class)s_notification_templates_for_success'
)
notification_templates_any = models.ManyToManyField(
notification_templates_started = models.ManyToManyField(
"NotificationTemplate",
blank=True,
related_name='%(class)s_notification_templates_for_any'
related_name='%(class)s_notification_templates_for_started'
)
def prevent_search(relation):
"""
Used to mark a model field or relation as "restricted from filtering"

View File

@@ -105,7 +105,7 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
)
inputs = CredentialInputField(
blank=True,
default={},
default=dict,
help_text=_('Enter inputs using either JSON or YAML syntax. Use the '
'radio button to toggle between the two. Refer to the '
'Ansible Tower documentation for example syntax.')
@@ -343,14 +343,14 @@ class CredentialType(CommonModelNameNotUnique):
)
inputs = CredentialTypeInputField(
blank=True,
default={},
default=dict,
help_text=_('Enter inputs using either JSON or YAML syntax. Use the '
'radio button to toggle between the two. Refer to the '
'Ansible Tower documentation for example syntax.')
)
injectors = CredentialTypeInjectorField(
blank=True,
default={},
default=dict,
help_text=_('Enter injectors using either JSON or YAML syntax. Use the '
'radio button to toggle between the two. Refer to the '
'Ansible Tower documentation for example syntax.')
@@ -1117,7 +1117,7 @@ class CredentialInputSource(PrimordialModel):
)
metadata = DynamicCredentialInputField(
blank=True,
default={}
default=dict
)
def clean_target_credential(self):

View File

@@ -39,6 +39,14 @@ def gce(cred, env, private_data_dir):
f.close()
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
env['GCE_CREDENTIALS_FILE_PATH'] = path
env['GCP_SERVICE_ACCOUNT_FILE'] = path
# Handle env variables for new module types.
# This includes gcp_compute inventory plugin and
# all new gcp_* modules.
env['GCP_AUTH_KIND'] = 'serviceaccount'
env['GCP_PROJECT'] = project
env['GCP_ENV_TYPE'] = 'tower'
return path

View File

@@ -149,7 +149,7 @@ class BasePlaybookEvent(CreatedModifiedModel):
)
event_data = JSONField(
blank=True,
default={},
default=dict,
)
failed = models.BooleanField(
default=False,
@@ -567,7 +567,7 @@ class BaseCommandEvent(CreatedModifiedModel):
event_data = JSONField(
blank=True,
default={},
default=dict,
)
uuid = models.CharField(
max_length=1024,

View File

@@ -650,7 +650,7 @@ class Host(CommonModelNameNotUnique, RelatedJobsMixin):
)
ansible_facts = JSONBField(
blank=True,
default={},
default=dict,
help_text=_('Arbitrary JSON structure of most recent ansible_facts, per-host.'),
)
ansible_facts_modified = models.DateTimeField(
@@ -1619,20 +1619,20 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, CustomVirtualE
base_notification_templates = NotificationTemplate.objects
error_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_errors__in=[self]))
started_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_started__in=[self]))
success_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_success__in=[self]))
any_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_any__in=[self]))
if self.inventory.organization is not None:
error_notification_templates = set(error_notification_templates + list(base_notification_templates
.filter(organization_notification_templates_for_errors=self.inventory.organization)))
started_notification_templates = set(started_notification_templates + list(base_notification_templates
.filter(organization_notification_templates_for_started=self.inventory.organization)))
success_notification_templates = set(success_notification_templates + list(base_notification_templates
.filter(organization_notification_templates_for_success=self.inventory.organization)))
any_notification_templates = set(any_notification_templates + list(base_notification_templates
.filter(organization_notification_templates_for_any=self.inventory.organization)))
return dict(error=list(error_notification_templates),
success=list(success_notification_templates),
any=list(any_notification_templates))
started=list(started_notification_templates),
success=list(success_notification_templates))
def clean_source(self): # TODO: remove in 3.3
source = self.source
@@ -1991,6 +1991,8 @@ class azure_rm(PluginFileInjector):
source_vars = inventory_update.source_vars_dict
ret['fail_on_template_errors'] = False
group_by_hostvar = {
'location': {'prefix': '', 'separator': '', 'key': 'location'},
'tag': {'prefix': '', 'separator': '', 'key': 'tags.keys() | list if tags else []'},

View File

@@ -435,19 +435,21 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
base_notification_templates = NotificationTemplate.objects
error_notification_templates = list(base_notification_templates.filter(
unifiedjobtemplate_notification_templates_for_errors__in=[self, self.project]))
started_notification_templates = list(base_notification_templates.filter(
unifiedjobtemplate_notification_templates_for_started__in=[self, self.project]))
success_notification_templates = list(base_notification_templates.filter(
unifiedjobtemplate_notification_templates_for_success__in=[self, self.project]))
any_notification_templates = list(base_notification_templates.filter(
unifiedjobtemplate_notification_templates_for_any__in=[self, self.project]))
# Get Organization NotificationTemplates
if self.project is not None and self.project.organization is not None:
error_notification_templates = set(error_notification_templates + list(base_notification_templates.filter(
organization_notification_templates_for_errors=self.project.organization)))
started_notification_templates = set(started_notification_templates + list(base_notification_templates.filter(
organization_notification_templates_for_started=self.project.organization)))
success_notification_templates = set(success_notification_templates + list(base_notification_templates.filter(
organization_notification_templates_for_success=self.project.organization)))
any_notification_templates = set(any_notification_templates + list(base_notification_templates.filter(
organization_notification_templates_for_any=self.project.organization)))
return dict(error=list(error_notification_templates), success=list(success_notification_templates), any=list(any_notification_templates))
return dict(error=list(error_notification_templates),
started=list(started_notification_templates),
success=list(success_notification_templates))
'''
RelatedJobsMixin
@@ -483,7 +485,7 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
)
artifacts = JSONField(
blank=True,
default={},
default=dict,
editable=False,
)
scm_revision = models.CharField(
@@ -845,7 +847,7 @@ class LaunchTimeConfigBase(BaseModel):
# This is a solution to the nullable CharField problem, specific to prompting
char_prompts = JSONField(
blank=True,
default={}
default=dict
)
def prompts_dict(self, display=False):
@@ -925,11 +927,11 @@ class LaunchTimeConfig(LaunchTimeConfigBase):
# Special case prompting fields, even more special than the other ones
extra_data = JSONField(
blank=True,
default={}
default=dict
)
survey_passwords = prevent_search(JSONField(
blank=True,
default={},
default=dict,
editable=False,
))
# Credentials needed for non-unified job / unified JT models
@@ -1133,13 +1135,13 @@ class SystemJobTemplate(UnifiedJobTemplate, SystemJobOptions):
base_notification_templates = NotificationTemplate.objects.all()
error_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_errors__in=[self]))
started_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_started__in=[self]))
success_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_success__in=[self]))
any_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_any__in=[self]))
return dict(error=list(error_notification_templates),
success=list(success_notification_templates),
any=list(any_notification_templates))
started=list(started_notification_templates),
success=list(success_notification_templates))
def _accept_or_ignore_job_kwargs(self, _exclude_errors=None, **kwargs):
extra_data = kwargs.pop('extra_vars', {})

View File

@@ -100,7 +100,7 @@ class SurveyJobTemplateMixin(models.Model):
)
survey_spec = prevent_search(JSONField(
blank=True,
default={},
default=dict,
))
ask_variables_on_launch = AskForField(
blank=True,
@@ -360,7 +360,7 @@ class SurveyJobMixin(models.Model):
survey_passwords = prevent_search(JSONField(
blank=True,
default={},
default=dict,
editable=False,
))

View File

@@ -7,6 +7,7 @@ import logging
from django.db import models
from django.conf import settings
from django.core.mail.message import EmailMessage
from django.db import connection
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_str, force_text
@@ -129,7 +130,7 @@ class NotificationTemplate(CommonModelNameNotUnique):
if field not in notification_configuration:
if 'default' in params:
notification_configuration[field] = params['default']
backend_obj = self.notification_class(**notification_configuration)
backend_obj = self.notification_class(**notification_configuration)
notification_obj = EmailMessage(subject, backend_obj.format_body(body), sender, recipients)
with set_environ(**settings.AWX_TASK_ENV):
return backend_obj.send_messages([notification_obj])
@@ -221,10 +222,13 @@ class JobNotificationMixin(object):
def build_notification_failed_message(self):
return self._build_notification_message('failed')
def build_notification_running_message(self):
return self._build_notification_message('running')
def send_notification_templates(self, status_str):
from awx.main.tasks import send_notifications # avoid circular import
if status_str not in ['succeeded', 'failed']:
raise ValueError(_("status_str must be either succeeded or failed"))
if status_str not in ['succeeded', 'failed', 'running']:
raise ValueError(_("status_str must be either running, succeeded or failed"))
try:
notification_templates = self.get_notification_templates()
except Exception:
@@ -233,14 +237,19 @@ class JobNotificationMixin(object):
if notification_templates:
if status_str == 'succeeded':
notification_template_type = 'success'
elif status_str == 'running':
notification_template_type = 'started'
else:
notification_template_type = 'error'
all_notification_templates = set(notification_templates.get(notification_template_type, []) + notification_templates.get('any', []))
all_notification_templates = set(notification_templates.get(notification_template_type, []))
if len(all_notification_templates):
try:
(notification_subject, notification_body) = getattr(self, 'build_notification_%s_message' % status_str)()
except AttributeError:
raise NotImplementedError("build_notification_%s_message() does not exist" % status_str)
send_notifications.delay([n.generate_notification(notification_subject, notification_body).id
for n in all_notification_templates],
job_id=self.id)
def send_it():
send_notifications.delay([n.generate_notification(notification_subject, notification_body).id
for n in all_notification_templates],
job_id=self.id)
connection.on_commit(send_it)

View File

@@ -411,24 +411,24 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEn
base_notification_templates = NotificationTemplate.objects
error_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_errors=self))
started_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_started=self))
success_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_success=self))
any_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_any=self))
# Get Organization NotificationTemplates
if self.organization is not None:
error_notification_templates = set(error_notification_templates +
list(base_notification_templates
.filter(organization_notification_templates_for_errors=self.organization)))
started_notification_templates = set(started_notification_templates +
list(base_notification_templates
.filter(organization_notification_templates_for_started=self.organization)))
success_notification_templates = set(success_notification_templates +
list(base_notification_templates
.filter(organization_notification_templates_for_success=self.organization)))
any_notification_templates = set(any_notification_templates +
list(base_notification_templates
.filter(organization_notification_templates_for_any=self.organization)))
return dict(error=list(error_notification_templates),
success=list(success_notification_templates),
any=list(any_notification_templates))
started=list(started_notification_templates),
success=list(success_notification_templates))
def get_absolute_url(self, request=None):
return reverse('api:project_detail', kwargs={'pk': self.pk}, request=request)
@@ -567,5 +567,3 @@ class ProjectUpdate(UnifiedJob, ProjectOptions, JobNotificationMixin, TaskManage
if not selected_groups:
return self.global_instance_groups
return selected_groups

View File

@@ -641,7 +641,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
)
job_env = prevent_search(JSONField(
blank=True,
default={},
default=dict,
editable=False,
))
job_explanation = models.TextField(
@@ -1397,6 +1397,13 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
r['{}_user_email'.format(name)] = created_by.email
r['{}_user_first_name'.format(name)] = created_by.first_name
r['{}_user_last_name'.format(name)] = created_by.last_name
inventory = getattr_dne(self, 'inventory')
if inventory:
for name in ('awx', 'tower'):
r['{}_inventory_id'.format(name)] = inventory.pk
r['{}_inventory_name'.format(name)] = inventory.name
return r
def get_queue_name(self):

View File

@@ -180,7 +180,7 @@ class WorkflowJobNode(WorkflowNodeBase):
)
ancestor_artifacts = JSONField(
blank=True,
default={},
default=dict,
editable=False,
)
do_not_run = models.BooleanField(
@@ -419,13 +419,13 @@ class WorkflowJobTemplate(UnifiedJobTemplate, WorkflowJobOptions, SurveyJobTempl
base_notification_templates = NotificationTemplate.objects.all()
error_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_errors__in=[self]))
started_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_started__in=[self]))
success_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_success__in=[self]))
any_notification_templates = list(base_notification_templates
.filter(unifiedjobtemplate_notification_templates_for_any__in=[self]))
return dict(error=list(error_notification_templates),
success=list(success_notification_templates),
any=list(any_notification_templates))
started=list(started_notification_templates),
success=list(success_notification_templates))
def create_unified_job(self, **kwargs):
workflow_job = super(WorkflowJobTemplate, self).create_unified_job(**kwargs)

View File

@@ -193,6 +193,8 @@ class TaskManager():
status_changed = True
if status_changed:
workflow_job.websocket_emit_status(workflow_job.status)
# Operations whose queries rely on modifications made during the atomic scheduling session
workflow_job.send_notification_templates('succeeded' if workflow_job.status == 'successful' else 'failed')
if workflow_job.spawned_by_workflow:
schedule_task_manager()
return result
@@ -233,6 +235,7 @@ class TaskManager():
else:
if type(task) is WorkflowJob:
task.status = 'running'
task.send_notification_templates('running')
logger.debug('Transitioning %s to running status.', task.log_format)
schedule_task_manager()
elif not task.supports_isolation() and rampart_group.controller_id:
@@ -581,10 +584,5 @@ class TaskManager():
logger.debug("Not running scheduler, another task holds lock")
return
logger.debug("Starting Scheduler")
with task_manager_bulk_reschedule():
finished_wfjs = self._schedule()
# Operations whose queries rely on modifications made during the atomic scheduling session
for wfj in WorkflowJob.objects.filter(id__in=finished_wfjs):
wfj.send_notification_templates('succeeded' if wfj.status == 'successful' else 'failed')
self._schedule()

View File

@@ -602,25 +602,26 @@ def update_inventory_computed_fields(inventory_id, should_update_hosts=True):
def update_smart_memberships_for_inventory(smart_inventory):
current = set(SmartInventoryMembership.objects.filter(inventory=smart_inventory).values_list('host_id', flat=True))
new = set(smart_inventory.hosts.values_list('id', flat=True))
additions = new - current
removals = current - new
if additions or removals:
with transaction.atomic():
if removals:
SmartInventoryMembership.objects.filter(inventory=smart_inventory, host_id__in=removals).delete()
if additions:
add_for_inventory = [
SmartInventoryMembership(inventory_id=smart_inventory.id, host_id=host_id)
for host_id in additions
]
SmartInventoryMembership.objects.bulk_create(add_for_inventory)
logger.debug('Smart host membership cached for {}, {} additions, {} removals, {} total count.'.format(
smart_inventory.pk, len(additions), len(removals), len(new)
))
return True # changed
return False
with advisory_lock('update_smart_memberships_for_inventory-{}'.format(smart_inventory.id)):
current = set(SmartInventoryMembership.objects.filter(inventory=smart_inventory).values_list('host_id', flat=True))
new = set(smart_inventory.hosts.values_list('id', flat=True))
additions = new - current
removals = current - new
if additions or removals:
with transaction.atomic():
if removals:
SmartInventoryMembership.objects.filter(inventory=smart_inventory, host_id__in=removals).delete()
if additions:
add_for_inventory = [
SmartInventoryMembership(inventory_id=smart_inventory.id, host_id=host_id)
for host_id in additions
]
SmartInventoryMembership.objects.bulk_create(add_for_inventory)
logger.debug('Smart host membership cached for {}, {} additions, {} removals, {} total count.'.format(
smart_inventory.pk, len(additions), len(removals), len(new)
))
return True # changed
return False
@task()
@@ -827,8 +828,10 @@ class BaseTask(object):
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
private_data_files['credentials'][credential] = path
for credential, data in private_data.get('certificates', {}).items():
name = 'credential_%d-cert.pub' % credential.pk
path = os.path.join(private_data_dir, name)
artifact_dir = os.path.join(private_data_dir, 'artifacts', str(self.instance.id))
if not os.path.exists(artifact_dir):
os.makedirs(artifact_dir, mode=0o700)
path = os.path.join(artifact_dir, 'ssh_key_data-cert.pub')
with open(path, 'w') as f:
f.write(data)
f.close()
@@ -856,10 +859,16 @@ class BaseTask(object):
'''
process_isolation_params = dict()
if self.should_use_proot(instance):
show_paths = self.proot_show_paths + [private_data_dir, cwd] + \
settings.AWX_PROOT_SHOW_PATHS
# Help the user out by including the collections path inside the bubblewrap environment
if getattr(settings, 'AWX_ANSIBLE_COLLECTIONS_PATHS', []):
show_paths.extend(settings.AWX_ANSIBLE_COLLECTIONS_PATHS)
process_isolation_params = {
'process_isolation': True,
'process_isolation_path': settings.AWX_PROOT_BASE_PATH,
'process_isolation_show_paths': self.proot_show_paths + [private_data_dir, cwd] + settings.AWX_PROOT_SHOW_PATHS,
'process_isolation_show_paths': show_paths,
'process_isolation_hide_paths': [
settings.AWX_PROOT_BASE_PATH,
'/etc/tower',
@@ -933,6 +942,11 @@ class BaseTask(object):
if self.should_use_proot(instance):
env['PROOT_TMP_DIR'] = settings.AWX_PROOT_BASE_PATH
env['AWX_PRIVATE_DATA_DIR'] = private_data_dir
if 'ANSIBLE_COLLECTIONS_PATHS' in env:
env['ANSIBLE_COLLECTIONS_PATHS'] += os.pathsep + os.pathsep.join(settings.AWX_ANSIBLE_COLLECTIONS_PATHS)
else:
env['ANSIBLE_COLLECTIONS_PATHS'] = os.pathsep.join(settings.AWX_ANSIBLE_COLLECTIONS_PATHS)
return env
def should_use_proot(self, instance):
@@ -1131,6 +1145,7 @@ class BaseTask(object):
try:
isolated = self.instance.is_isolated()
self.instance.send_notification_templates("running")
self.pre_run_hook(self.instance)
if self.instance.cancel_flag:
self.instance = self.update_model(self.instance.pk, status='canceled')

View File

@@ -1,9 +1,9 @@
{
"AZURE_SUBSCRIPTION_ID": "fooo",
"AZURE_CLIENT_ID": "fooo",
"AZURE_TENANT": "fooo",
"AZURE_SECRET": "fooo",
"AZURE_CLOUD_ENVIRONMENT": "fooo",
"ANSIBLE_JINJA2_NATIVE": "True",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"AZURE_CLIENT_ID": "fooo",
"AZURE_CLOUD_ENVIRONMENT": "fooo",
"AZURE_SECRET": "fooo",
"AZURE_SUBSCRIPTION_ID": "fooo",
"AZURE_TENANT": "fooo"
}

View File

@@ -4,6 +4,7 @@ default_host_filters: []
exclude_host_filters:
- resource_group not in ['foo_resources', 'bar_resources']
- location not in ['southcentralus', 'westus']
fail_on_template_errors: false
hostvar_expressions:
ansible_host: private_ipv4_addresses[0]
computer_name: name

View File

@@ -1,7 +1,7 @@
{
"ANSIBLE_JINJA2_NATIVE": "True",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"AWS_ACCESS_KEY_ID": "fooo",
"AWS_SECRET_ACCESS_KEY": "fooo",
"AWS_SECURITY_TOKEN": "fooo",
"ANSIBLE_JINJA2_NATIVE": "True",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"AWS_SECURITY_TOKEN": "fooo"
}

View File

@@ -1,4 +1,8 @@
{
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"GCE_CREDENTIALS_FILE_PATH": "{{ file_reference }}"
"GCE_CREDENTIALS_FILE_PATH": "{{ file_reference }}",
"GCP_AUTH_KIND": "serviceaccount",
"GCP_ENV_TYPE": "tower",
"GCP_PROJECT": "fooo",
"GCP_SERVICE_ACCOUNT_FILE": "{{ file_reference }}"
}

View File

@@ -1,6 +1,6 @@
{
"FOREMAN_SERVER": "https://foo.invalid",
"FOREMAN_USER": "fooo",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"FOREMAN_PASSWORD": "fooo",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"FOREMAN_SERVER": "https://foo.invalid",
"FOREMAN_USER": "fooo"
}

View File

@@ -1,7 +1,7 @@
{
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"TOWER_HOST": "https://foo.invalid",
"TOWER_USERNAME": "fooo",
"TOWER_PASSWORD": "fooo",
"TOWER_VERIFY_SSL": "False",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"TOWER_USERNAME": "fooo",
"TOWER_VERIFY_SSL": "False"
}

View File

@@ -1,9 +1,9 @@
{
"AZURE_SUBSCRIPTION_ID": "fooo",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"AZURE_CLIENT_ID": "fooo",
"AZURE_TENANT": "fooo",
"AZURE_SECRET": "fooo",
"AZURE_CLOUD_ENVIRONMENT": "fooo",
"AZURE_INI_PATH": "{{ file_reference }}",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"AZURE_SECRET": "fooo",
"AZURE_SUBSCRIPTION_ID": "fooo",
"AZURE_TENANT": "fooo"
}

View File

@@ -1,4 +1,4 @@
{
"CLOUDFORMS_INI_PATH": "{{ file_reference }}",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"CLOUDFORMS_INI_PATH": "{{ file_reference }}"
}

View File

@@ -1,7 +1,7 @@
{
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"AWS_ACCESS_KEY_ID": "fooo",
"AWS_SECRET_ACCESS_KEY": "fooo",
"AWS_SECURITY_TOKEN": "fooo",
"EC2_INI_PATH": "{{ file_reference }}",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"EC2_INI_PATH": "{{ file_reference }}"
}

View File

@@ -1,8 +1,12 @@
{
"GCE_EMAIL": "fooo",
"GCE_PROJECT": "fooo",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"GCE_CREDENTIALS_FILE_PATH": "{{ file_reference }}",
"GCE_EMAIL": "fooo",
"GCE_INI_PATH": "{{ file_reference_0 }}",
"GCE_PROJECT": "fooo",
"GCE_ZONE": "us-east4-a,us-west1-b",
"GCE_INI_PATH": "{{ file_reference }}",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"GCP_AUTH_KIND": "serviceaccount",
"GCP_ENV_TYPE": "tower",
"GCP_PROJECT": "fooo",
"GCP_SERVICE_ACCOUNT_FILE": "{{ file_reference }}"
}

View File

@@ -1,4 +1,4 @@
{
"OS_CLIENT_CONFIG_FILE": "{{ file_reference }}",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"OS_CLIENT_CONFIG_FILE": "{{ file_reference }}"
}

View File

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

View File

@@ -1,4 +1,4 @@
{
"FOREMAN_INI_PATH": "{{ file_reference }}",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"FOREMAN_INI_PATH": "{{ file_reference }}"
}

View File

@@ -1,9 +1,9 @@
{
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never",
"TOWER_HOST": "https://foo.invalid",
"TOWER_USERNAME": "fooo",
"TOWER_PASSWORD": "fooo",
"TOWER_VERIFY_SSL": "False",
"TOWER_INVENTORY": "42",
"TOWER_LICENSE_TYPE": "open",
"ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never"
"TOWER_PASSWORD": "fooo",
"TOWER_USERNAME": "fooo",
"TOWER_VERIFY_SSL": "False"
}

View File

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

View File

@@ -91,7 +91,7 @@ class TestSwaggerGeneration():
# The number of API endpoints changes over time, but let's just check
# for a reasonable number here; if this test starts failing, raise/lower the bounds
paths = JSON['paths']
assert 250 < len(paths) < 300
assert 250 < len(paths) < 350
assert list(paths['/api/'].keys()) == ['get']
assert list(paths['/api/v2/'].keys()) == ['get']
assert list(sorted(

View File

@@ -101,7 +101,7 @@ def test_instance_group_is_isolated(instance_group, isolated_instance_group):
assert not instance_group.is_isolated
assert isolated_instance_group.is_isolated
isolated_instance_group.instances = []
isolated_instance_group.instances.set([])
assert isolated_instance_group.is_isolated

View File

@@ -42,10 +42,6 @@ def test_inventory_source_notification_on_cloud_only(get, post, inventory_source
not_is = inventory_source_factory("not_ec2")
url = reverse('api:inventory_source_notification_templates_any_list', kwargs={'pk': cloud_is.id})
response = post(url, dict(id=notification_template.id), u)
assert response.status_code == 204
url = reverse('api:inventory_source_notification_templates_success_list', kwargs={'pk': not_is.id})
response = post(url, dict(id=notification_template.id), u)
assert response.status_code == 400

View File

@@ -0,0 +1,129 @@
import pytest
from awx.api.versioning import reverse
@pytest.mark.django_db
def test_get_org_running_notification(get, admin, organization):
url = reverse('api:organization_notification_templates_started_list', kwargs={'pk': organization.pk})
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 0
@pytest.mark.django_db
def test_post_org_running_notification(get, post, admin, notification_template, organization):
url = reverse('api:organization_notification_templates_started_list', kwargs={'pk': organization.pk})
response = post(url,
dict(id=notification_template.id,
associate=True),
admin)
assert response.status_code == 204
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 1
@pytest.mark.django_db
def test_get_project_running_notification(get, admin, project):
url = reverse('api:project_notification_templates_started_list', kwargs={'pk': project.pk})
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 0
@pytest.mark.django_db
def test_post_project_running_notification(get, post, admin, notification_template, project):
url = reverse('api:project_notification_templates_started_list', kwargs={'pk': project.pk})
response = post(url,
dict(id=notification_template.id,
associate=True),
admin)
assert response.status_code == 204
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 1
@pytest.mark.django_db
def test_get_inv_src_running_notification(get, admin, inventory_source):
url = reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': inventory_source.pk})
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 0
@pytest.mark.django_db
def test_post_inv_src_running_notification(get, post, admin, notification_template, inventory_source):
url = reverse('api:inventory_source_notification_templates_started_list', kwargs={'pk': inventory_source.pk})
response = post(url,
dict(id=notification_template.id,
associate=True),
admin)
assert response.status_code == 204
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 1
@pytest.mark.django_db
def test_get_jt_running_notification(get, admin, job_template):
url = reverse('api:job_template_notification_templates_started_list', kwargs={'pk': job_template.pk})
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 0
@pytest.mark.django_db
def test_post_jt_running_notification(get, post, admin, notification_template, job_template):
url = reverse('api:job_template_notification_templates_started_list', kwargs={'pk': job_template.pk})
response = post(url,
dict(id=notification_template.id,
associate=True),
admin)
assert response.status_code == 204
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 1
@pytest.mark.django_db
def test_get_sys_jt_running_notification(get, admin, system_job_template):
url = reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': system_job_template.pk})
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 0
@pytest.mark.django_db
def test_post_sys_jt_running_notification(get, post, admin, notification_template, system_job_template):
url = reverse('api:system_job_template_notification_templates_started_list', kwargs={'pk': system_job_template.pk})
response = post(url,
dict(id=notification_template.id,
associate=True),
admin)
assert response.status_code == 204
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 1
@pytest.mark.django_db
def test_get_wfjt_running_notification(get, admin, workflow_job_template):
url = reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': workflow_job_template.pk})
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 0
@pytest.mark.django_db
def test_post_wfjt_running_notification(get, post, admin, notification_template, workflow_job_template):
url = reverse('api:workflow_job_template_notification_templates_started_list', kwargs={'pk': workflow_job_template.pk})
response = post(url,
dict(id=notification_template.id,
associate=True),
admin)
assert response.status_code == 204
response = get(url, admin)
assert response.status_code == 200
assert len(response.data['results']) == 1

View File

@@ -12,7 +12,6 @@ def run_command(name, *args, **options):
command_runner = options.pop('command_runner', call_command)
stdin_fileobj = options.pop('stdin_fileobj', None)
options.setdefault('verbosity', 1)
options.setdefault('interactive', False)
original_stdin = sys.stdin
original_stdout = sys.stdout
original_stderr = sys.stderr

View File

@@ -11,9 +11,9 @@ from django.urls import resolve
from django.contrib.auth.models import User
from django.core.serializers.json import DjangoJSONEncoder
from django.db.backends.sqlite3.base import SQLiteCursorWrapper
from jsonbfield.fields import JSONField
# AWX
from awx.main.fields import JSONBField
from awx.main.models.projects import Project
from awx.main.models.ha import Instance
@@ -737,7 +737,7 @@ def get_db_prep_save(self, value, connection, **kwargs):
@pytest.fixture
def monkeypatch_jsonbfield_get_db_prep_save(mocker):
JSONField.get_db_prep_save = get_db_prep_save
JSONBField.get_db_prep_save = get_db_prep_save
@pytest.fixture

View File

@@ -457,4 +457,4 @@ def test_duplicate_name_within_template(job_template):
with pytest.raises(IntegrityError) as ierror:
s2.save()
assert str(ierror.value) == "columns unified_job_template_id, name are not unique"
assert str(ierror.value) == "UNIQUE constraint failed: main_schedule.unified_job_template_id, main_schedule.name"

View File

@@ -20,7 +20,6 @@ from django.test import TransactionTestCase
from django.core.exceptions import ValidationError
@pytest.mark.django_db
class TestWorkflowDAGFunctional(TransactionTestCase):
def workflow_job(self, states=['new', 'new', 'new', 'new', 'new']):
"""

View File

@@ -1,5 +1,3 @@
import pytest
from django.test import TransactionTestCase
from awx.main.models import (
@@ -8,7 +6,6 @@ from awx.main.models import (
)
@pytest.mark.django_db
class TestCapacityMapping(TransactionTestCase):
def sample_cluster(self):

View File

@@ -129,6 +129,7 @@ def read_content(private_data_dir, raw_env, inventory_update):
return a dictionary `content` with file contents, keyed off environment variable
that references the file
"""
# build dict env as a mapping of environment variables to file names
# Filter out environment variables which come from runtime environment
env = {}
exclude_keys = set(('PATH', 'INVENTORY_SOURCE_ID', 'INVENTORY_UPDATE_ID'))
@@ -142,71 +143,74 @@ def read_content(private_data_dir, raw_env, inventory_update):
env[k] = v
inverse_env = {}
for key, value in env.items():
inverse_env[value] = key
inverse_env.setdefault(value, []).append(key)
cache_file_regex = re.compile(r'/tmp/awx_{0}_[a-zA-Z0-9_]+/{1}_cache[a-zA-Z0-9_]+'.format(
inventory_update.id, inventory_update.source)
)
private_key_regex = re.compile(r'-----BEGIN ENCRYPTED PRIVATE KEY-----.*-----END ENCRYPTED PRIVATE KEY-----')
# read directory content
# build a mapping of the file paths to aliases which will be constant accross runs
dir_contents = {}
references = {}
for filename in os.listdir(private_data_dir):
referenced_paths = set()
file_aliases = {}
filename_list = sorted(os.listdir(private_data_dir), key=lambda fn: inverse_env.get(os.path.join(private_data_dir, fn), [fn])[0])
for filename in filename_list:
if filename in ('args', 'project'):
continue # Ansible runner
abs_file_path = os.path.join(private_data_dir, filename)
file_aliases[abs_file_path] = filename
if abs_file_path in inverse_env:
env_key = inverse_env[abs_file_path]
references[abs_file_path] = env_key
env[env_key] = '{{ file_reference }}'
referenced_paths.add(abs_file_path)
alias = 'file_reference'
for i in range(10):
if alias not in file_aliases.values():
break
alias = 'file_reference_{}'.format(i)
else:
raise RuntimeError('Test not able to cope with >10 references by env vars. '
'Something probably went very wrong.')
file_aliases[abs_file_path] = alias
for env_key in inverse_env[abs_file_path]:
env[env_key] = '{{{{ {} }}}}'.format(alias)
try:
with open(abs_file_path, 'r') as f:
dir_contents[abs_file_path] = f.read()
# Declare a reference to inventory plugin file if it exists
if abs_file_path.endswith('.yml') and 'plugin: ' in dir_contents[abs_file_path]:
references[abs_file_path] = filename # plugin filenames are universal
referenced_paths.add(abs_file_path) # used as inventory file
elif cache_file_regex.match(abs_file_path):
file_aliases[abs_file_path] = 'cache_file'
except IsADirectoryError:
dir_contents[abs_file_path] = '<directory>'
if cache_file_regex.match(abs_file_path):
file_aliases[abs_file_path] = 'cache_dir'
# Declare cross-file references, also use special keywords if it is the cache
cache_referenced = False
cache_present = False
# Substitute in aliases for cross-file references
for abs_file_path, file_content in dir_contents.copy().items():
if cache_file_regex.match(file_content):
cache_referenced = True
if 'cache_dir' not in file_aliases.values() and 'cache_file' not in file_aliases in file_aliases.values():
raise AssertionError(
'A cache file was referenced but never created, files:\n{}'.format(
json.dumps(dir_contents, indent=4)))
# if another files path appears in this file, replace it with its alias
for target_path in dir_contents.keys():
other_alias = file_aliases[target_path]
if target_path in file_content:
if target_path in references:
raise AssertionError(
'File {} is referenced by env var or other file as well as file {}:\n{}\n{}'.format(
target_path, abs_file_path, json.dumps(env, indent=4), json.dumps(dir_contents, indent=4)))
else:
if cache_file_regex.match(target_path):
cache_present = True
if os.path.isdir(target_path):
keyword = 'cache_dir'
else:
keyword = 'cache_file'
references[target_path] = keyword
new_file_content = cache_file_regex.sub('{{ ' + keyword + ' }}', file_content)
else:
references[target_path] = 'file_reference'
new_file_content = file_content.replace(target_path, '{{ file_reference }}')
dir_contents[abs_file_path] = new_file_content
if cache_referenced and not cache_present:
raise AssertionError(
'A cache file was referenced but never created, files:\n{}'.format(
json.dumps(dir_contents, indent=4)))
referenced_paths.add(target_path)
dir_contents[abs_file_path] = file_content.replace(target_path, '{{ ' + other_alias + ' }}')
# build dict content which is the directory contents keyed off the file aliases
content = {}
for abs_file_path, file_content in dir_contents.items():
if abs_file_path not in references:
# assert that all files laid down are used
if abs_file_path not in referenced_paths:
raise AssertionError(
"File {} is not referenced. References and files:\n{}\n{}".format(
abs_file_path, json.dumps(references, indent=4), json.dumps(dir_contents, indent=4)))
reference_key = references[abs_file_path]
abs_file_path, json.dumps(env, indent=4), json.dumps(dir_contents, indent=4)))
file_content = private_key_regex.sub('{{private_key}}', file_content)
content[reference_key] = file_content
content[file_aliases[abs_file_path]] = file_content
return (env, content)
@@ -223,7 +227,7 @@ def create_reference_data(source_dir, env, content):
f.write(content)
if env:
with open(os.path.join(source_dir, 'env.json'), 'w') as f:
f.write(json.dumps(env, indent=4))
json.dump(env, f, indent=4, sort_keys=True)
@pytest.mark.django_db
@@ -258,6 +262,7 @@ def test_inventory_update_injected_content(this_kind, script_or_plugin, inventor
"""
private_data_dir = envvars.pop('AWX_PRIVATE_DATA_DIR')
assert envvars.pop('ANSIBLE_INVENTORY_ENABLED') == ('auto' if use_plugin else 'script')
assert envvars.pop('ANSIBLE_COLLECTIONS_PATHS') == os.pathsep.join(settings.AWX_ANSIBLE_COLLECTIONS_PATHS)
set_files = bool(os.getenv("MAKE_INVENTORY_REFERENCE_FILES", 'false').lower()[0] not in ['f', '0'])
env, content = read_content(private_data_dir, envvars, inventory_update)
base_dir = os.path.join(DATA, script_or_plugin)
@@ -283,7 +288,7 @@ def test_inventory_update_injected_content(this_kind, script_or_plugin, inventor
for f_name in expected_file_list:
with open(os.path.join(files_dir, f_name), 'r') as f:
ref_content = f.read()
assert ref_content == content[f_name]
assert ref_content == content[f_name], f_name
try:
with open(os.path.join(source_dir, 'env.json'), 'r') as f:
ref_env_text = f.read()

View File

@@ -42,7 +42,7 @@ def test_job_notification_data(inventory, machine_credential, project):
survey_passwords={"SSN": encrypted_str},
project=project,
)
job.credentials = [machine_credential]
job.credentials.set([machine_credential])
notification_data = job.notification_data(block=0)
assert json.loads(notification_data['extra_vars'])['SSN'] == encrypted_str

View File

@@ -92,27 +92,7 @@ def test_inherited_notification_templates(get, post, user, organization, project
isrc.save()
jt = JobTemplate.objects.create(name='test', inventory=i, project=project, playbook='debug.yml')
jt.save()
url = reverse('api:organization_notification_templates_any_list', kwargs={'pk': organization.id})
response = post(url, dict(id=notification_templates[0]), u)
assert response.status_code == 204
url = reverse('api:project_notification_templates_any_list', kwargs={'pk': project.id})
response = post(url, dict(id=notification_templates[1]), u)
assert response.status_code == 204
url = reverse('api:job_template_notification_templates_any_list', kwargs={'pk': jt.id})
response = post(url, dict(id=notification_templates[2]), u)
assert response.status_code == 204
assert len(jt.notification_templates['any']) == 3
assert len(project.notification_templates['any']) == 2
assert len(isrc.notification_templates['any']) == 1
@pytest.mark.django_db
def test_notification_template_merging(get, post, user, organization, project, notification_template):
user('admin-poster', True)
organization.notification_templates_any.add(notification_template)
project.notification_templates_any.add(notification_template)
assert len(project.notification_templates['any']) == 1
@pytest.mark.django_db
def test_notification_template_simple_patch(patch, notification_template, admin):

View File

@@ -7,7 +7,6 @@ from awx.main.access import UserAccess, RoleAccess, TeamAccess
from awx.main.models import User, Organization, Inventory
@pytest.mark.django_db
class TestSysAuditorTransactional(TransactionTestCase):
def rando(self):
return User.objects.create(username='rando', password='rando', email='rando@com.com')

View File

@@ -71,7 +71,7 @@ class TestInventorySourceSerializerGetRelated(object):
'activity_stream',
'notification_templates_error',
'notification_templates_success',
'notification_templates_any',
'notification_templates_started',
'inventory_updates',
'update',
'hosts',

View File

@@ -50,7 +50,7 @@ class TestJobTemplateSerializerGetRelated():
'schedules',
'activity_stream',
'launch',
'notification_templates_any',
'notification_templates_started',
'notification_templates_success',
'notification_templates_error',
'survey_spec',

View File

@@ -186,11 +186,8 @@ class TestResourceAccessList:
def mock_request(self):
return mock.MagicMock(
user=mock.MagicMock(
is_anonymous=mock.MagicMock(return_value=False),
is_superuser=False
), method='GET')
user=mock.MagicMock(is_anonymous=False, is_superuser=False),
method='GET')
def mock_view(self, parent=None):
view = ResourceAccessList()
@@ -200,7 +197,6 @@ class TestResourceAccessList:
view.get_parent_object = lambda: parent
return view
def test_parent_access_check_failed(self, mocker, mock_organization):
mock_access = mocker.MagicMock(__name__='for logger', return_value=False)
with mocker.patch('awx.main.access.BaseAccess.can_read', mock_access):
@@ -208,7 +204,6 @@ class TestResourceAccessList:
self.mock_view(parent=mock_organization).check_permissions(self.mock_request())
mock_access.assert_called_once_with(mock_organization)
def test_parent_access_check_worked(self, mocker, mock_organization):
mock_access = mocker.MagicMock(__name__='for logger', return_value=True)
with mocker.patch('awx.main.access.BaseAccess.can_read', mock_access):

View File

@@ -6,7 +6,7 @@ from unittest.mock import PropertyMock
from awx.api.urls import urlpatterns as api_patterns
# Django
from django.urls import RegexURLResolver, RegexURLPattern
from django.urls import URLResolver, URLPattern
@pytest.fixture(autouse=True)
@@ -20,24 +20,24 @@ def all_views():
'''
returns a set of all views in the app
'''
patterns = set([])
url_views = set([])
patterns = set()
url_views = set()
# Add recursive URL patterns
unprocessed = set(api_patterns)
while unprocessed:
to_process = unprocessed.copy()
unprocessed = set([])
unprocessed = set()
for pattern in to_process:
if hasattr(pattern, 'lookup_str') and not pattern.lookup_str.startswith('awx.api'):
continue
patterns.add(pattern)
if isinstance(pattern, RegexURLResolver):
if isinstance(pattern, URLResolver):
for sub_pattern in pattern.url_patterns:
if sub_pattern not in patterns:
unprocessed.add(sub_pattern)
# Get view classes
for pattern in patterns:
if isinstance(pattern, RegexURLPattern) and hasattr(pattern.callback, 'view_class'):
if isinstance(pattern, URLPattern) and hasattr(pattern.callback, 'view_class'):
url_views.add(pattern.callback.view_class)
return url_views

View File

@@ -57,5 +57,5 @@ def test_really_long_event_fields(field):
})
manager.create.assert_called_with(**{
'job_id': 123,
'event_data': {field: 'X' * 1021 + '...'}
'event_data': {field: 'X' * 1023 + ''}
})

View File

@@ -9,7 +9,8 @@ from awx.main.models import (
Job,
User,
Project,
JobTemplate
JobTemplate,
Inventory
)
@@ -81,11 +82,13 @@ class TestMetaVars:
def test_job_metavars(self):
maker = User(username='joe', pk=47, id=47)
inv = Inventory(name='example-inv', id=45)
assert Job(
name='fake-job',
pk=42, id=42,
launch_type='manual',
created_by=maker
created_by=maker,
inventory=inv
).awx_meta_vars() == {
'tower_job_id': 42,
'awx_job_id': 42,
@@ -100,7 +103,11 @@ class TestMetaVars:
'awx_user_last_name': '',
'tower_user_last_name': '',
'awx_user_id': 47,
'tower_user_id': 47
'tower_user_id': 47,
'tower_inventory_id': 45,
'awx_inventory_id': 45,
'tower_inventory_name': 'example-inv',
'awx_inventory_name': 'example-inv'
}
def test_project_update_metavars(self):

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