Compare commits

..

1552 Commits
4.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
Shane McDonald
08aff9bd2c AWX 5.0.0 2019-06-18 10:12:42 -04: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
softwarefactory-project-zuul[bot]
1897b18a6e Merge pull request #4090 from Spredzy/bump_pip
Makefile: align pip and setuptools bump

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-17 20:52:44 +00:00
Yanis Guenane
ec92abf014 Makefile: align pip and setuptools bump
Signed-off-by: Yanis Guenane <yanis@guenane.org>
2019-06-17 21:58:42 +02:00
softwarefactory-project-zuul[bot]
5ed7db8cc2 Merge pull request #4085 from mabashian/4082-inv_obj
Ensure inventory_obj is on scope before checking it

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-17 18:08:43 +00: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
mabashian
863d962ec2 Ensure inventory_obj is on scope before checking it 2019-06-17 07:40:08 -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
softwarefactory-project-zuul[bot]
049b3a2e87 Merge pull request #4080 from AlanCoding/no_more_v1
Remove code used defunct jobs list POST

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-15 01:02:24 +00: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
AlanCoding
196b6572b2 remove code used defunct jobs list POST 2019-06-14 13:13:37 -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
softwarefactory-project-zuul[bot]
37cb912367 Merge pull request #4075 from ryanpetrello/old-migration-cleanup
delete a few really old migration utility files

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-14 14:27:47 +00:00
Ryan Petrello
d8bd72054d work around a unit test that's periodically flaky 2019-06-14 10:05:41 -04:00
softwarefactory-project-zuul[bot]
9958f382d7 Merge pull request #4043 from mabashian/4029-inv-refresh
Fixes bug where the delete inventory event would wipe or reset inventory form fields

Reviewed-by: Michael Abashian
             https://github.com/mabashian
2019-06-14 14:04:59 +00:00
softwarefactory-project-zuul[bot]
1d767a15d8 Merge pull request #4044 from mabashian/read-only-codemirrors
Read-only codemirror cleanup

Reviewed-by: Michael Abashian
             https://github.com/mabashian
2019-06-14 13:58:51 +00:00
softwarefactory-project-zuul[bot]
612373c849 Merge pull request #4041 from mabashian/wf-execute-unsaved
Fixes bug where save changes modal was shown to user with execute permissions

Reviewed-by: Michael Abashian
             https://github.com/mabashian
2019-06-14 13:45:33 +00:00
mabashian
3ea6171b54 Fixes bug where the delete inventory event would wipe or reset inventory form fields 2019-06-14 09:38:27 -04:00
mabashian
302d8589c9 Make extra vars read-only for users without edit role on some forms. Fixes console error thrown in launch modal if survey tab missing. 2019-06-14 09:37:37 -04:00
mabashian
01f51219a6 Fix linting errors 2019-06-14 09:22:16 -04:00
mabashian
38ea82bf3d Fixes bug where save changes modal was shown to user with execute permissions 2019-06-14 09:22:16 -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
softwarefactory-project-zuul[bot]
d4ad674899 Merge pull request #4064 from mabashian/3829-new-list-links
Fixes links in various lists to maintain query params while navigating to edit form

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-13 21:56:34 +00:00
softwarefactory-project-zuul[bot]
9d3aca5e1b Merge pull request #4060 from mabashian/3830-host-filter-search
Always show search bar in smart inventory host filter modal

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-13 21:44:02 +00: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
Ryan Petrello
a454102e77 delete a few really old migration utility files 2019-06-13 17:19:43 -04:00
softwarefactory-project-zuul[bot]
e1d60ff4f1 Merge pull request #4052 from gamuniz/enabled_value_fix
Enabled value fix to be case insensitive(GCE API)

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-13 20:08:30 +00:00
Gabe Muniz
bd93d97a60 fix so enabled value is case insensitive 2019-06-13 15:36:54 -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
softwarefactory-project-zuul[bot]
793e78d9c0 Merge pull request #4046 from AlanCoding/setuptools
Upgrade pip and setuptools

Reviewed-by: Alan Rominger <arominge@redhat.com>
             https://github.com/AlanCoding
2019-06-13 14:13:28 +00:00
AlanCoding
76ebcf914b upgrade pip and setuptools 2019-06-13 09:45:18 -04:00
mabashian
effe7151eb Adds missing semi-colon 2019-06-12 22:13:45 -04:00
mabashian
0023591bb0 Removes unnecessary variable 2019-06-12 22:13:45 -04:00
mabashian
9c50609776 Always show search bar in smart inventory host filter modal 2019-06-12 22:13:45 -04:00
softwarefactory-project-zuul[bot]
28cc08f215 Merge pull request #4033 from mabashian/bootstrap-whitelist-table
Whitelist table elements for use in bootstrap popovers

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-12 21:12:37 +00:00
mabashian
b83cef6ed7 Fixes links in various lists to maintain query params while navigating to edit form 2019-06-12 16:12:08 -04:00
mabashian
c729b698dd Whitelist table elements for use in bootstrap popovers 2019-06-12 15:32:08 -04:00
softwarefactory-project-zuul[bot]
e70c7ab458 Merge pull request #3967 from jbradberry/upgrade-drf-3.9.4
Upgrade DRF to 3.9.4

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-12 18:41:05 +00:00
Jeff Bradberry
aa548442ce Ensure the request is on the Metadata object
in order to correctly populate the default for the TOWER_URL_BASE
field, which is specific to the host and preferred scheme.
2019-06-12 14:12:59 -04:00
Jeff Bradberry
ab587e7e6c Update get_view_description to conform to changes in DRF's version
related encode/django-rest-framework#5605
2019-06-12 14:12:59 -04:00
Jeff Bradberry
3f5c018c8a Replace the load of the staticfiles template library with static
The staticfiles library will be going away before too long.
2019-06-12 14:12:59 -04:00
Jeff Bradberry
12e3d0aebf Remove rest_framework/base.html 2019-06-12 14:12:59 -04:00
Jeff Bradberry
ba4ad191fc Add the csrf token to window.drf
In the same manner as the current version of base.html from DRF.  This
is part 2 of the removal of base.html.
2019-06-12 14:12:59 -04:00
Jeff Bradberry
34d76422d6 Move the endpoint deprecation warning out of base.html
This is part 1 of the removal of awx/templates/rest_framework/base.html.
2019-06-12 14:12:59 -04:00
Jeff Bradberry
2a81643308 Refactor the SSO serializer fields to follow the DRF idioms more closely
and fix the tests to handle the newer nested validation checks properly.
2019-06-12 14:12:59 -04:00
Jeff Bradberry
76d4de24df Handle a change in the error message for BooleanField
related encode/django-rest-framework#5881
2019-06-12 14:12:59 -04:00
Jeff Bradberry
ed7a7e5f7b Support parse_requirements out of pip < 10 and >= 10 2019-06-12 14:12:59 -04:00
Jeff Bradberry
f94959d120 Remove the custom get_view_name function
It appeared to not be doing anything that we were making use of that
couldn't already be done, slightly differently, using DRF's built-in
one.
2019-06-12 14:12:59 -04:00
Jeff Bradberry
b5728fc548 Bump Django Rest Framework from 3.7.7 to 3.9.4 2019-06-12 14:12:59 -04:00
softwarefactory-project-zuul[bot]
4a19da650d Merge pull request #4056 from ansible/capitalization
updated e2e to work with new capitalization

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-12 17:36:29 +00:00
Daniel Sami
8db27611ca updated e2e to work with new capitalization 2019-06-12 13:05:11 -04:00
softwarefactory-project-zuul[bot]
7161f28d26 Merge pull request #4053 from AlanCoding/apps_management
Correctly manage current apps for the action_node addition

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-12 15:59:55 +00:00
softwarefactory-project-zuul[bot]
290c242221 Merge pull request #4054 from ansible/unpin-vault-plugin-container-image
unpin vault plugin development container image

Reviewed-by: awxbot
             https://github.com/awxbot
2019-06-12 15:00:23 +00:00
Jake McDermott
90fb7c6769 unpin vault plugin development container image 2019-06-12 10:23:01 -04:00
AlanCoding
f8c69aadcb Correctly manage current apps for the action_node addition 2019-06-12 10:13:45 -04:00
softwarefactory-project-zuul[bot]
c7b38bc9b9 Merge pull request #4050 from Spredzy/capitalize
User: Ensure First Name is not capitalized

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2019-06-12 13:23:21 +00:00
Yanis Guenane
cc1ef50729 User: Ensure First Name is not capitalized
When creating a new user, the Last Name is not capitalized but First
Name is. Make the behavior being consistent.

Signed-off-by: Yanis Guenane <yguenane@redhat.com>
2019-06-12 14:40:44 +02:00
softwarefactory-project-zuul[bot]
42b3aa45c5 Merge pull request #4045 from ansible/quick-chrome75-workaround
Chrome75 workaround for e2e tests

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-12 11:52:09 +00:00
John Hill
1e91e4e531 set to json protocol 2019-06-11 15:51:02 -04:00
softwarefactory-project-zuul[bot]
b3979eb2b9 Merge pull request #4042 from shanemcd/cache-me-outside
Always consider devel tag as a cache source

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-11 18:34:25 +00:00
Shane McDonald
75ef30d21b Always consider devel tag as a cache source
When you do `make docker-compose-build` on your branch without any changes, this will use the devel tag as a cache source. This will speed things up if you havent made any local changes to the Makefile or requirements files.
2019-06-11 14:01:35 -04:00
softwarefactory-project-zuul[bot]
31b78cc00f Merge pull request #4036 from AlanCoding/event_query
Cache smart inventory memberships to avoid slow query

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-11 15:55:55 +00:00
softwarefactory-project-zuul[bot]
a510f9f2c7 Merge pull request #4038 from jakemcdermott/update-v1-cred-delete-prompt-queries
update credential deletion prompt queries

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-11 15:26:49 +00:00
AlanCoding
05aab5da4c cache smart inventory memberships to avoid slow query 2019-06-11 11:06:35 -04:00
softwarefactory-project-zuul[bot]
3054fbc61c Merge pull request #4040 from ryanpetrello/ldap-py3-bug
fix a py3 compat problem in an LDAP migration

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-11 14:47:12 +00:00
Ryan Petrello
be8a30b9d9 fix a py3 compat problem in an LDAP migration 2019-06-11 10:25:15 -04:00
Jake McDermott
d4301bd9bd update v1 credential deletion prompt queries 2019-06-11 09:45:15 -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
softwarefactory-project-zuul[bot]
adb768bed3 Merge pull request #3413 from ryanpetrello/bye-bye-v1
remove /api/v1 and deprecated credential fields

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-10 17:31:28 +00: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
softwarefactory-project-zuul[bot]
9253ab28c8 Merge pull request #4021 from ryanpetrello/dotted-vault-id
support vault IDs that include dot characters

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-06 18:34:24 +00:00
softwarefactory-project-zuul[bot]
31d4e8362e Merge pull request #4003 from keithjgrant/3574-survey-tab-required-fields
Don't allow Enter to proceed to next step if survey fields invalid

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-06 18:33:29 +00:00
Ryan Petrello
329b40fd69 support vault IDs that include dot characters
see: https://github.com/ansible/awx/issues/4009
2019-06-06 12:42:31 -04:00
Jake McDermott
6bc5c4da74 include credential in inventory update detail summary 2019-06-06 12:23:17 -04:00
Jake McDermott
51d7de296f remove dead code related to v1 kind field
Currently, the credentials list doesn't seem to be returning
any options data for 'kind' so this code wasn't being reached. In
the future api updates, we'll also be removing the 'kind' field from
credentials in general.
2019-06-06 12:23:11 -04:00
Jake McDermott
5987aafb82 update shared client code for api v2 2019-06-06 12:23:09 -04:00
Jake McDermott
7a0a2fb54c update adhoc command queries for api v2 2019-06-06 12:23:06 -04:00
Jake McDermott
2f57a1ea93 update inventory source credential lookup queries for api v2 2019-06-06 12:23:03 -04:00
Ryan Petrello
6da445f7c0 remove /api/v1 and deprecated credential fields 2019-06-06 12:23:00 -04:00
softwarefactory-project-zuul[bot]
176f8632e5 Merge pull request #4017 from ryanpetrello/swagger-action-node
make activity stream action_node deterministic for Swagger docs

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-06 16:13:17 +00:00
softwarefactory-project-zuul[bot]
958c192ff7 Merge pull request #4000 from rooftopcellist/order_job_counts
fix analytics job counts by ordering query

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-06 15:16:42 +00:00
softwarefactory-project-zuul[bot]
7e8990dff9 Merge pull request #4011 from shanemcd/devel
Clean up related to isolated env

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-06 14:48:49 +00:00
Christian Adams
a727de184b Fix analytics job counts by ordering query
- More Info: https://github.com/ansible/awx/issues/4014
2019-06-06 10:45:26 -04:00
Ryan Petrello
6d1ba411e6 make activity stream action_node deterministic for Swagger docs 2019-06-06 10:36:34 -04:00
Shane McDonald
b00979792e Clean up related to isolated env
- Made  make target names consistent with our other commands
- Found some unnecessary code, deleted it
2019-06-06 10:15:11 -04:00
softwarefactory-project-zuul[bot]
8be0b01c33 Merge pull request #4013 from ansible/docker-container-tag-updates
Updated docker tags in container setup

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-05 20:17:03 +00:00
Daniel Sami
62a3e0df98 Updated docker tags in container setup
Use env variable for selenium docker tag
2019-06-05 15:10:06 -04:00
softwarefactory-project-zuul[bot]
c7f49c1193 Merge pull request #3992 from marshmalien/isolated-badge
Add isolated badge to isolated instance groups

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-05 16:58:20 +00:00
softwarefactory-project-zuul[bot]
3fcf3b20c4 Merge pull request #4005 from shanemcd/sdist-builder-node
Update node in AWX installer sdist builder

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-05 11:48:30 +00:00
softwarefactory-project-zuul[bot]
5db3a8e7dc Merge pull request #4007 from git4anand/devel
Multiple installation of same dependency

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-05 11:39:46 +00:00
Anand kumar
3d7bd8579b Multiple installation of same dependency
python-pip is being installed multiple times.
2019-06-05 12:38:52 +05:30
Shane McDonald
99704af302 Fix some ansible warnings 2019-06-04 20:37:03 -04:00
Shane McDonald
a13b733191 Update node in sdist builder image 2019-06-04 20:36:39 -04:00
Keith Grant
4a7cd56e4a do allow Enter to proceed to next step if survey fields invalid 2019-06-04 16:08:23 -07:00
softwarefactory-project-zuul[bot]
839f49c6ed Merge pull request #3997 from ryanpetrello/libcloud
unpin apache-libcloud now that a version is out without PyCrypto

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-04 19:59:06 +00: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
Ryan Petrello
c6afd98500 unpin apache-libcloud now that a version is out without PyCrypto
see: https://github.com/ansible/awx/pull/3466
see: https://github.com/ansible/awx/issues/3822
2019-06-04 09:26:27 -04:00
softwarefactory-project-zuul[bot]
67fb898a9d Merge pull request #3993 from shanemcd/fix-isolated-dev-env
Fix isolated dev env

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-03 21:43:31 +00:00
Shane McDonald
f18f9ec0ef Bring isolated dev env current
There was quite a bit of drift between the main Dockerfile and this one since we last touched it. It’s heavier than it needs to be, but by using the main development image as the base here, we have less duplicated and outdated code overall.
2019-06-03 16:48:45 -04:00
Shane McDonald
ef22986aa0 Install latest tini from RPM 2019-06-03 16:03:51 -04:00
softwarefactory-project-zuul[bot]
1829017ad4 Merge pull request #3991 from shanemcd/downgrade-ptyprocess
Downgrade ptyprocess

Reviewed-by: awxbot
             https://github.com/awxbot
2019-06-03 18:19:15 +00:00
Shane McDonald
be3d095067 Downgrade ptyprocess
See 8be490695d (diff-522adf759addbd3b193c74ca85243f7d) for more info
2019-06-03 13:42:45 -04:00
softwarefactory-project-zuul[bot]
112b9e7381 Merge pull request #3984 from jpmens/patch-1
Emphasize a recent version of Docker

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-03 17:42:24 +00:00
softwarefactory-project-zuul[bot]
87bd3c2f93 Merge pull request #3987 from Spredzy/quote_password
Installer: quote password where it applies

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-03 17:38:49 +00:00
Marliana Lara
abb37299cb Add isolated badge to instance groups list 2019-06-03 13:20:23 -04:00
softwarefactory-project-zuul[bot]
724ca9cd57 Merge pull request #3979 from elyezer/resize-window-e2e
e2e resize window on some specific tests

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-06-03 14:21:43 +00:00
John Mitchell
9ba8feaec1 remove unused scss styles from app.scss 2019-06-03 10:20:13 -04:00
Elyézer Rezende
39fb0d1679 e2e resize window on some specific tests 2019-06-03 08:50:37 -04:00
Yanis Guenane
11630a8803 Installer: quote password where it applies
Prior to this change, password having shell interpretable character
would break the installer (e.g '&', '(', etc... )

This commits rely on the `quote` filter from ansible to ensure those
password are properly quoted where it applies

Fixes: https://github.com/ansible/awx/issues/3943
Signed-off-by: Yanis Guenane <yguenane@redhat.com>
2019-06-03 11:50:52 +02:00
JP Mens
a7b96d5aec Emphasize a recent version of Docker
I had 1.13 installed as part of Centos Extras and spent hours attempting to install AWX 4.0.0; the attempts all threw masses of permission denied errors.

Uninstalling that version and replacing with a current docker-ce then worked.
2019-06-01 16:29:10 +02:00
softwarefactory-project-zuul[bot]
d8a80f9f3e Merge pull request #3981 from jakemcdermott/test-debug-helpers
add some debug helpers for tests

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-31 16:19:20 +00:00
Jake McDermott
1dcb1eda7c add some debug helpers for tests
Signed-off-by: Jake McDermott <yo@jakemcdermott.me>
2019-05-31 11:51:36 -04:00
softwarefactory-project-zuul[bot]
f64e31735c Merge pull request #3980 from wenottingham/following-in-finns-footsteps
Remove some things that are not first-order dependencies from requirements.in

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-31 15:14:43 +00:00
softwarefactory-project-zuul[bot]
d7c33a7246 Merge pull request #3893 from AlanCoding/replace_job_origin
Replace JobOrigin model with ActivityStream.action_node field

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-31 11:59:09 +00:00
AlanCoding
fedd1cf22f Replace JobOrigin with ActivityStream.action_node 2019-05-31 07:10:07 -04:00
Bill Nottingham
12ff7a481c Remove some things that are not first-order dependencies.
This includes a few things where the version specifiers resolve properly now.
2019-05-30 22:42:37 -04:00
softwarefactory-project-zuul[bot]
9b5494a6cc Merge pull request #3976 from Spredzy/fix_quote
openshift: Ensure char in password are not interpreted

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-31 01:27:38 +00:00
Yanis Guenane
99296cf5f1 openshift: Ensure char in password are not interpreted
If password contains ';' (and potentially any shell interpretable chars)
it won't be interpreted properly as the openshift password.

Signed-off-by: Yanis Guenane <yguenane@redhat.com>
2019-05-31 03:00:13 +02:00
softwarefactory-project-zuul[bot]
e6b78292ec Merge pull request #3974 from ryanpetrello/downstream-i18n
Fix python3 fallout in translations management script

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-30 19:06:26 +00:00
Shane McDonald
49b54f2d60 Fix python3 fallout in translations management script 2019-05-30 14:41:03 -04:00
softwarefactory-project-zuul[bot]
0a256a98be Merge pull request #3965 from AlexSCorey/2866-JTForksToolTip
Updates text of tooltip for Forks in JT.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-30 17:09:49 +00:00
softwarefactory-project-zuul[bot]
5756151568 Merge pull request #3921 from joseorpa/devel3004proxy
#3004 Add proxy support to postgresql, memcached and rabbitmq images

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-30 14:33:17 +00:00
softwarefactory-project-zuul[bot]
6606fd7461 Merge pull request #3930 from kialam/upgrade-node-v8-to-node-v10
Upgrade our UI packaging for NodeJS 10.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-30 14:29:52 +00:00
Jose OrPa
84b6866875 #3004 Add proxy support to postgresql, memcached and rabbitmq images 2019-05-30 10:04:17 -04:00
Kia Lam
4b9024bcb0 Revert puppeteer upgrade to fix failing UI unit tests in Zuul. 2019-05-30 09:51:19 -04:00
softwarefactory-project-zuul[bot]
4b1fc7894d Merge pull request #3961 from rooftopcellist/rm_implicit
remove implicit grant type for OAuth 2 apps

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-29 20:27:11 +00:00
Alex Corey
a5a6fdf1d6 Updates text of tooltip for Forks in JT. 2019-05-29 14:27:16 -04:00
Kia Lam
15c699de7c Update dockerfile to build using node v10.15.0. 2019-05-29 13:00:06 -04:00
Kia Lam
515d4fe20f Update INSTALL.md with new node version. 2019-05-29 12:21:54 -04:00
Kia Lam
75380b9576 Upgrade our packaging for NodeJS 10.
- Update README.md
- Bump certain dependencies to fix vulnerabilities. Exclude dependency bumps that would cause breaking changes.
2019-05-29 12:21:54 -04:00
Christian Adams
cb279843d2 remove implicit grant type for OAuth 2 apps 2019-05-29 02:28:37 -04:00
softwarefactory-project-zuul[bot]
41f2b83ae2 Merge pull request #3947 from ryanpetrello/transient-queues
RFC: add the ability to disable RabbitMQ queue durability

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-28 20:15:26 +00:00
Ryan Petrello
40b1e89b67 add the ability to disable RabbitMQ queue durability 2019-05-28 15:49:32 -04:00
softwarefactory-project-zuul[bot]
8c56d1d3a7 Merge pull request #3932 from shanemcd/zuul_k8s
Changes to enable tests in k8s

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-28 19:34:58 +00: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
Shane McDonald
2f77c67a62 Changes to enable tests in k8s 2019-05-28 13:22:15 -04:00
Alex Corey
7452b82856 addresses PR issues 2019-05-28 13:13:42 -04:00
softwarefactory-project-zuul[bot]
5a502f8709 Merge pull request #3925 from AlanCoding/gce_contract
Restore old use pattern for gce_ modules, update token_uri URL

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-28 17:03:32 +00:00
softwarefactory-project-zuul[bot]
873ff3de78 Merge pull request #3928 from wenottingham/waka-flocka
Use lockf, not flock.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-28 16:29:23 +00:00
Alex Corey
b7b17b9176 updates test issues caused by PF bump 2019-05-28 11:42:17 -04:00
softwarefactory-project-zuul[bot]
eb3ef809e0 Merge pull request #3873 from shanemcd/faster-boots
Avoid DNS timeout in non-Docker for Mac installs

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-28 14:30:45 +00:00
softwarefactory-project-zuul[bot]
9c90694f12 Merge pull request #3604 from athenahealth/complete-ssl-support
Update SSL support for docker-compose install

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-28 13:51:43 +00: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
softwarefactory-project-zuul[bot]
ca3735ee73 Merge pull request #3941 from elyezer/window-size-e2e
Set window size globally on e2e

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-24 20:23:45 +00:00
softwarefactory-project-zuul[bot]
380f122456 Merge pull request #3804 from AlanCoding/more_optimizations
Apply optimizations via standard methods

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-24 19:38:46 +00:00
Elyézer Rezende
0aa8c7427d Set window size globally on e2e 2019-05-24 14:05:39 -04:00
AlanCoding
dbc65baa43 apply optimizations via standard method
This addresses the top-level resources in the v2
root view, focusing in order of priority,
reflecting use by the UI.

In several cases get_queryset logic from the view
is moved into the access class.

Most other cases involve adding a straightforward
select_related or prefetch_related entry.

All additional confirmed to be effective with the
django debug toolbar.
2019-05-24 13:09:55 -04:00
softwarefactory-project-zuul[bot]
1ce587025e Merge pull request #3948 from rooftopcellist/fix_analytics_log_msg
fix analytics logging msg

Reviewed-by: awxbot
             https://github.com/awxbot
2019-05-23 18:55:55 +00:00
Christian Adams
45458b3265 fix analytics logging msg 2019-05-23 14:26: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
softwarefactory-project-zuul[bot]
874465a2d4 Merge pull request #3865 from chrismeyersfsu/fix-enabled_still_online
disabled instance does not mean offline instance

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-23 16:55:09 +00:00
softwarefactory-project-zuul[bot]
34c3aaee3d Merge pull request #3682 from AlanCoding/depgrades
General upgrade of dependencies

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-23 15:15:20 +00: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
softwarefactory-project-zuul[bot]
13ff5ffdf2 Merge pull request #3900 from AlanCoding/fewer_type_methods
Remove duplicated type methods and old Django logic

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-23 12:50:35 +00:00
softwarefactory-project-zuul[bot]
a606fdc958 Merge pull request #3933 from AlanCoding/schedule_no_op
More precise handling of schedule computed fields no-ops

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-23 12:39:58 +00:00
Keith Grant
79d8b74221 redirect to remove trailing slash from URL 2019-05-23 08:29:08 -04:00
AlanCoding
b11995e638 Remove duplicated type methods and old Django logic 2019-05-23 08:24:24 -04:00
AlanCoding
40f9d0b512 More precise handling of schedule computed fields no-ops
Do not set a next_run value for disabled schedules
Bail if no fields are changed
Do not update related template if its fields did not change

Change call pattern to schedule.update_computed_fields()
in doing so, fix bug where template does not pick up schedule
  due to schedules next_run not being saved

Handle the case (also a bug) where template was not updated
  when schedule was deleted
2019-05-23 08:13:37 -04:00
softwarefactory-project-zuul[bot]
9a1b205e06 Merge pull request #3944 from AlanCoding/move_to_filter
Move dynamic log level logic to filter

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-22 23:45:36 +00:00
softwarefactory-project-zuul[bot]
98c923a715 Merge pull request #3856 from rooftopcellist/cleanup_sessions_refactor
Cleanup Sessions & Tokens System Jobs

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-22 20:50:48 +00:00
softwarefactory-project-zuul[bot]
1d328134fd Merge pull request #3931 from wenottingham/be-bold
Update notification radio button styling to match schedule radiobuttons.

Reviewed-by: Bill Nottingham
             https://github.com/wenottingham
2019-05-22 18:58:43 +00:00
AlanCoding
d3f047d731 Move dynamic log level logic to filter 2019-05-22 14:00:39 -04:00
Christian Adams
8ca0c1b992 Add clearsessions and cleartokens system jobs
* add system job for gathering insights analytics
* enforce schedule enablement with analytics setting
* remove celery beat analytics job
* keep analytics schedule & setting enablement in sync in API
* handles updating schedules for multiple sys job schedules
* add analytics setting & schedule test
* rm ui modal from collection sys job
2019-05-22 13:11:48 -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
softwarefactory-project-zuul[bot]
4a711ec2dc Merge pull request #3914 from itdependsnetworks/var_port_numbers
Update the ports for memcache and rabbitmq to be variablized

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-22 14:08:41 +00:00
Jake McDermott
7965f94027 add waitForElement helper 2019-05-22 08:56:49 -04:00
softwarefactory-project-zuul[bot]
75fe801efb Merge pull request #3913 from marshmalien/3886-instance-group-breadcrumb-label
Dynamically show instance group name in breadcrumb

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-21 14:28:55 +00:00
Marliana Lara
56df930b99 Sanitize instance group breadcrumb name 2019-05-21 09:55:35 -04:00
Bill Nottingham
f48713f4ae Use lockf, not flock.
This performs more reliably on certain filesystems in Linux.
2019-05-20 16:56:16 -04:00
Bill Nottingham
bb009f0d12 Update notification radio button styling to match schedule radiobuttons. 2019-05-20 16:46:10 -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
softwarefactory-project-zuul[bot]
dc1bf3ef07 Merge pull request #3910 from AlanCoding/no_user_get
Avoid unnecessary user get expiring session memberships

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-20 17:20:36 +00:00
softwarefactory-project-zuul[bot]
9d4cfa7400 Merge pull request #3890 from AlanCoding/fix_debug_toolbar
Fix Django debug toolbar after its upgrade

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-20 16:41:13 +00:00
AlanCoding
06be3a29b9 fix Django debug toolbar after its upgrade 2019-05-20 12:17:57 -04:00
softwarefactory-project-zuul[bot]
2addf20907 Merge pull request #3918 from jbradberry/middleware-ordering
Fix the middleware ordering

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-20 15:43:06 +00:00
softwarefactory-project-zuul[bot]
29bbecb6bf Merge pull request #3820 from AlanCoding/default_ordering
Resolve default ordering warnings from tests

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-20 15:31:36 +00:00
AlanCoding
f4c18843a3 Resolve default ordering warnings from tests 2019-05-20 10:58:36 -04:00
AlanCoding
bda838f723 Add note for docutils, unpin runner dependency 2019-05-20 10:24:43 -04:00
AlanCoding
2bec5ddb41 General upgrade of dependencies
Update licenses for new versions after dependency upgrades

pin pycurl to version that does not break on install

implement new workflow for py2/3 requirements management

require twisted tls extras, resolve service-identity version

Upgrade celery to resolve importlib DeprecationWarning

use flags to resolve the unsafe and cache problems
2019-05-20 10:24:39 -04:00
AlanCoding
74643520c7 GCE contract update, do not use token_uri in job runs 2019-05-20 09:27:45 -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
Jeff Bradberry
44907b33dc Fix the middleware ordering 2019-05-17 14:40:33 -04:00
softwarefactory-project-zuul[bot]
f174902bb2 Merge pull request #3874 from jbradberry/expose-role-type
Expose the content type associated with roles for ActivityStream objects in the API

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-17 18:06:38 +00:00
AlanCoding
1223148116 Avoid unnecessary user get expiring session memberships 2019-05-17 14:05:17 -04:00
softwarefactory-project-zuul[bot]
ab1e45d6c4 Merge pull request #3875 from rooftopcellist/swifty_operation
reorder migrations to avoid session error

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-17 15:41:26 +00:00
softwarefactory-project-zuul[bot]
bd50e5d6a8 Merge pull request #3896 from rooftopcellist/collection_no_reset
collect events based on last ship, not collection

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-17 15:32:48 +00: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
itdependsnetworks
f085b828e4 Update the ports for memcache and rabbitmq to be variablized 2019-05-16 19:59:57 -04:00
Marliana Lara
e95339ba6e Add instance group name to breadcrumb 2019-05-16 16:46:53 -04:00
softwarefactory-project-zuul[bot]
d353daebc5 Merge pull request #3911 from rooftopcellist/rm_extra_error
rm extra collection error line

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-16 20:11:41 +00:00
Keith Grant
957984d9e9 convert to PF Pagination component 2019-05-16 16:09:58 -04:00
softwarefactory-project-zuul[bot]
6681cd918c Merge pull request #3906 from heavenly999/devel
Increasing requests-credssp ver to 1.0.2

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-16 20:00:07 +00:00
Christian Adams
2b327935de reorder migrations to avoid session error 2019-05-16 15:13:47 -04:00
Christian Adams
0c4925afe8 rm extra collection error line 2019-05-16 14:48:41 -04:00
softwarefactory-project-zuul[bot]
e0062484d0 Merge pull request #3908 from rverchere/fr_fix
Correct fr translation for Cancel message

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-16 18:46:19 +00:00
softwarefactory-project-zuul[bot]
faa353521a Merge pull request #3909 from marshmalien/3884-dropdown-alignment
Fix styling bug in Sort Dropdown

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-16 18:03:07 +00: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
softwarefactory-project-zuul[bot]
ff7e244a84 Merge pull request #3905 from NickBusey/patch-1
Update INSTALL.md

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-16 17:02:07 +00: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
Marliana Lara
17f71600df Add styles to grow dropdown width based on content 2019-05-16 12:23:47 -04:00
Rémi VERCHERE
9120a69006 Correct fr translation for Cancel message 2019-05-16 17:42:13 +02:00
John Mitchell
f4550900bb update tests based on i18n changes 2019-05-16 11:38:28 -04:00
softwarefactory-project-zuul[bot]
d9965cfe7e Merge pull request #3882 from ryanpetrello/debug-log
add the ability to toggle DEBUG logging on dynamically

Reviewed-by: Shane McDonald <me@shanemcd.com>
             https://github.com/shanemcd
2019-05-16 15:12:01 +00:00
Adam Nagy
c38ee06642 Increasing requests-credssp ver to 1.0.2
Signed-off-by: Adam Nagy <anagy@netsuite.com>
2019-05-16 15:56:35 +02:00
Ryan Petrello
b1d75327e3 add the ability to toggle DEBUG logging on dynamically 2019-05-16 07:58:31 -04:00
softwarefactory-project-zuul[bot]
8981c7d59a Merge pull request #3904 from wenottingham/new-year-new-you
Bump date.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-16 03:35:31 +00:00
Nick Busey
b10f06201d Update INSTALL.md 2019-05-15 16:34:27 -06:00
Bill Nottingham
681fe4865c Some more dates. 2019-05-15 17:01:33 -04:00
Bill Nottingham
faae55d085 Bump date. 2019-05-15 16:58:59 -04:00
softwarefactory-project-zuul[bot]
efddd9f679 Merge pull request #3854 from beeankha/add_debug_toolbar
Update Custom Middleware to New Style

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-15 18:38:24 +00:00
beeankha
6fb173da8a Remove redundant methods from SocialAuthMiddleware class 2019-05-15 12:54:00 -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
beeankha
64e8b76a10 Remove redundant middleware 2019-05-15 10:16:20 -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
Christian Adams
d0e160a037 collect events based on last ship, not collection 2019-05-14 17:14:44 -04:00
beeankha
20e5d8200e Subclass more middlware with deprecation mixin 2019-05-14 13:37:34 -04:00
beeankha
a6d3c0fd32 Remove redundant code and update URLModificationMiddleware 2019-05-14 13:37:34 -04:00
beeankha
318e0631b7 Add super() call 2019-05-14 13:37:34 -04:00
beeankha
da4153d653 Add mixin to ActivityStreamMiddleware class 2019-05-14 13:37:34 -04:00
beeankha
26e9dd307e Fix missing argument error 2019-05-14 13:37:34 -04:00
beeankha
6a2d59963f Update wsgi file to be compatible with new style of middleware 2019-05-14 13:37:34 -04:00
beeankha
68800d0e8e Make custom middleware use new style vs old 2019-05-14 13:37:34 -04:00
beeankha
97dc77ea63 Add debug_toolbar.middleware.DebugToolbarMiddleware to MIDDLEWARE classes in development.py 2019-05-14 13:37:34 -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
softwarefactory-project-zuul[bot]
6bc1856658 Merge pull request #3861 from beeankha/awx_doc_edits
Update/Edit AWX Docs

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-13 20:41:14 +00: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
beeankha
9ea3ec24ca Address comments/suggested changes 2019-05-13 15:46:24 -04:00
beeankha
7466873f69 Make more edits/grammatical changes 2019-05-13 15:27:54 -04:00
beeankha
07fa533b6f Make edits to Notification doc 2019-05-13 11:47:04 -04:00
chris meyers
8aa28092ff disabled instance does not mean offline instance
* Disabling an instance is used to stop and instance from being the
target of new jobs to run.
* The instance should still perform it's heartbeat so that it isn't
considered offline.
* If the instance was allowed to go offline on an openshift cluster it
would be deleted from the database.
2019-05-13 11:44:47 -04:00
Jeff Bradberry
3579584ffc i18n 2019-05-13 11:20:15 -04:00
Jeff Bradberry
05cae23180 Add help text to the ActivityStreamSerializer m2m relationship fields 2019-05-13 11:10:33 -04:00
Jeff Bradberry
d6e89092d3 Instead of exposing Role.content_type, create a new serializer field
called `object_type`, which is constructed based on manipulating the
string value of ActivityStream.object_relationship_type.  Since that
field does have the full class name, this manipulation should match
the manipulation that is done to construct the values of object1 and
object2 when ActivityStream is created.
2019-05-10 17:31:33 -04:00
beeankha
fe344038b5 Edit Clustering doc 2019-05-10 14:54:20 -04:00
Jeff Bradberry
250484339b Expose the role's content_type field and reorder the objects in the UI
when the resource was stored on ActivityStream as object1 instead of object2.

related #3841
2019-05-10 14:15:05 -04:00
Shane McDonald
5ca0cdb124 Avoid DNS timeout in non-Docker for Mac installs
Shaves 20 seconds off of rebooting the dev environment on Linux.
2019-05-10 12:31:08 -04:00
Marliana Lara
b640203f88 Fix page header styles, search icon, and vertical separator 2019-05-10 12:29:55 -04:00
softwarefactory-project-zuul[bot]
0d3f1f4ac2 Merge pull request #3871 from ryanpetrello/devel
merge in downstream changes

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-10 16:21:39 +00: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
softwarefactory-project-zuul[bot]
18c69fa391 Merge pull request #3870 from shanemcd/gimme-root
Ensure that a root user is always present in development environment

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-10 14:57:58 +00:00
softwarefactory-project-zuul[bot]
6d6eae571e Merge pull request #3868 from jakemcdermott/ig-order-docstring
add docstring and test for instance group service

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-10 14:54:52 +00:00
Shane McDonald
7d8a910be7 Improve dev environment init process
This ensures that /etc/passwd is always written, regardless of how the container starts.
2019-05-10 10:14:51 -04:00
Jake McDermott
df04660cdd add test for instance groups service 2019-05-10 10:05:05 -04:00
softwarefactory-project-zuul[bot]
9d1ed837f9 Merge pull request #3869 from AlanCoding/dev_supervisor_fix
Fix bug in dev supervisor reparenting processes

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-10 13:45:30 +00:00
Ryan Petrello
be4705ef8b Merge branch 'downstream' into devel 2019-05-10 09:18:07 -04:00
Shane McDonald
015234287c Ensure that a root user is always present in development environment
@AlanCoding was seeing errors in the development container when trying to run some commands as root. This fixes that.
2019-05-10 09:16:28 -04:00
AlanCoding
677a8b34ba Fix bug in dev supervisor reparenting processes 2019-05-10 07:46:53 -04:00
Jake McDermott
232c706b75 add docstring for instance group service 2019-05-10 07:16:50 -04:00
softwarefactory-project-zuul[bot]
8725d3e539 Merge pull request #3842 from ryanpetrello/instance-group-order
enforce a stable list order when attaching/detaching instance groups

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 21:04:29 +00:00
softwarefactory-project-zuul[bot]
e7290e6452 Merge pull request #3864 from rooftopcellist/more_verbose_instance_msg
more verbose list_instance messaging

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 19:31:24 +00:00
Christian Adams
21105b836e more verbose list_instance messaging 2019-05-09 15:08:56 -04:00
softwarefactory-project-zuul[bot]
99dc84c275 Merge pull request #3863 from ryanpetrello/makefile-supervisor
use make targets for dev supervisor commands

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 18:07:39 +00:00
Ryan Petrello
adfdfcdd0a use make targets for dev supervisor commands 2019-05-09 13:45:49 -04:00
softwarefactory-project-zuul[bot]
6feb58f76d Merge pull request #3853 from AlanCoding/variable_data_permission
Put variable data permission in its own class

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 16:48:11 +00:00
softwarefactory-project-zuul[bot]
2910a9dfff Merge pull request #3858 from shanemcd/unsquash
Remove --squash option from awx-devel-build

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 14:19:59 +00:00
beeankha
371966613f Update AWX docs 2019-05-09 10:03:57 -04:00
softwarefactory-project-zuul[bot]
91968a09c8 Merge pull request #3849 from AlanCoding/password_madness
Reduce passing around of passwords dictionary

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 13:34:43 +00:00
softwarefactory-project-zuul[bot]
190098bbd5 Merge pull request #3848 from AlanCoding/standard_injector
Move outlier gce cache logic to standard place

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 12:56:11 +00:00
AlanCoding
2585c5030b move outlier gce cache logic to standard place 2019-05-09 08:24:57 -04:00
Shane McDonald
22858f0044 Remove --squash option from awx-devel-build
This was intended to save us CI time if / when we switch away from static nodes for Zuul. After merging this in I discovered that this option does not work with `docker build --cache-from`, which will be more benefical in terms of speed improvements anyway.
2019-05-08 22:22:38 -04:00
AlanCoding
7e6a73f892 fix bug with null credential 2019-05-08 21:18:34 -04:00
AlanCoding
1874e8bb4c Reduce passing around of passwords dictionary 2019-05-08 21:18:34 -04:00
softwarefactory-project-zuul[bot]
83c286580b Merge pull request #3852 from shanemcd/dockerfiled
Refactor Dockerfiles

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-09 01:08:49 +00:00
Shane McDonald
0be8fe521a Refactor Dockerfiles
This commit does a few things:

- Add the `--squash` option to the `awx-devel-build` make target. This reduces the resulting image size from 2.12 GB to 1.37 GB. I think we can get this down even more by inspecting the image contents.
- Reorganize commands so that the cache expires less often. Before this commit, any changes to the Makefile would essentially cause the entire image to rebuild.
- Break yum dependencies up into multiple lines. This makes it easier to see what changes in a diff.
- Use `n` to install our required version of node (rather `curl node | bash`). I’ve found this to be easier to maintain / more portable when working with other Dockerfiles.
- General organizational changes to make things easier to parse visually.
2019-05-08 20:36:41 -04:00
softwarefactory-project-zuul[bot]
186ec88581 Merge pull request #3839 from zicklam/webhook_disable_ssl_verify
Add "Disable SSL Verification" checkbox to webhook notification

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-08 19:44:11 +00:00
softwarefactory-project-zuul[bot]
6407ab58ff Merge pull request #3855 from ryanpetrello/improved-dev-code-reload
remove honcho in the dev environment (just use foregrounded supervisor)

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-08 19:25:57 +00:00
Michael Abashian
466e965047 Merge pull request #3549 from mabashian/host_filter_or
Fixes basic host filter searches
2019-05-08 15:16:43 -04:00
mabashian
e1de0a528d Adds some test coverage for host_filter queries 2019-05-08 14:59:04 -04:00
Ryan Petrello
766a5c0c3f remove honcho in the dev environment (just use foregrounded supervisor)
using supervisor gives us the ability to restart entire processes on
code change (like the dispatcher and callback receiver)
2019-05-08 14:44:07 -04:00
AlanCoding
231abf865b put variable data permission in its own class 2019-05-08 13:43:13 -04:00
softwarefactory-project-zuul[bot]
70972f7ea1 Merge pull request #3850 from jbradberry/reload-dispatcher-on-code-change
Make the uwsgi autoreloader reload the dispatcher every time

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-08 16:11:04 +00:00
Ryan Petrello
993b0a889d add API tests for InstanceGroup order persistence 2019-05-08 11:56:30 -04:00
Jake McDermott
205f2c33c1 wait for instance group requests on template save 2019-05-08 11:56:19 -04:00
Jake McDermott
1e77053bbf handle re-ordering of instance groups 2019-05-08 11:56:05 -04:00
Jeff Bradberry
ae25717700 Make the uwsgi autoreloader reload the dispatcher every time
not just the first time uwsgi is brought up.

related #3846
2019-05-08 11:15:54 -04:00
mabashian
11244f85a4 Adds missing semicolon 2019-05-08 10:05:02 -04:00
softwarefactory-project-zuul[bot]
e05c6e67b6 Merge pull request #3837 from saito-hideki/issue/2891
Add credential info in expanded list view of inventory update

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-08 13:37:34 +00:00
zicklam
42f30e72b5 False is not false 2019-05-08 08:35:26 +02:00
zicklam
0fb3851a2b webhook_notification set default for var 'disable_ssl_verification' 2019-05-08 08:21:04 +02:00
Ryan Petrello
e4a50f3595 enforce a stable list order when attaching/detaching instance groups 2019-05-07 14:53:00 -04:00
mabashian
f524c94bad Fixes basic host filter searches 2019-05-07 14:43:53 -04:00
softwarefactory-project-zuul[bot]
c7fe840868 Merge pull request #3810 from vismay-golwala/restrict_copy_jt
Raise meaningful error when permission denied to copy JT

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-07 13:52:04 +00: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
Vismay Golwala
0154d80f19 Raise meaningful error when permission denied to copy JT
When a user doesn't have access to all the credentials of a job
template, they cannot copy the JT. However, currently we raise a
default `PermissionDenied`, which doesn't give the user insight
into what's wrong. So, this PR just adds a custom message indicating
that access to credentials is missing.

Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-05-06 15:02:36 -04:00
zicklam
08d60d0b78 Update test_notification Template for webhooks
- rename webhook_no_verify_ssl to disable_ssl_verification
2019-05-06 19:20:00 +02:00
softwarefactory-project-zuul[bot]
6908558acd Merge pull request #3833 from ryanpetrello/iso-mem-cpu
properly record Instance.cpu and Instance.memory for isolated nodes

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-06 16:14:18 +00:00
softwarefactory-project-zuul[bot]
4dc7178f3c Merge pull request #3785 from AlanCoding/no_output_replacements
Remove unused output_replacements logic

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-06 16:11:51 +00:00
Michael Abashian
b85cc716a4 Merge pull request #3542 from mabashian/3540-groups-layout
Fix display bug on host groups list
2019-05-06 11:16:30 -04:00
Jake McDermott
a011896cc0 Update README.md 2019-05-06 11:11:27 -04:00
Hideki Saito
418521f4a3 Add credential info in expanded list view of inventory update
- Fixed issue #2891

Signed-off-by: Hideki Saito <saito@fgrep.org>
2019-05-06 13:28:47 +00:00
Alex Corey
a4899d4dbb Merge pull request #191 from AlexSCorey/175-BottomBorder
175 bottom border
2019-05-06 08:50:14 -04:00
zicklam
5b8fba58e8 Add "Disable SSL Verification" checkbox to webhook notification
This commit will add a checkbox which will disable SSL verification on
the generic webhook notification type. This is required when using
self-signed certificates.
2019-05-06 13:12:41 +02:00
Michael Abashian
842d48810c Merge pull request #3545 from elyezer/fix-joblist-sorting-options
Fix job list sorting options grouping
2019-05-03 19:50:13 -04:00
Elyézer Rezende
70e513a3cf Fix job list sorting options grouping
Ensure that the sorting options are grouped just like every other
sorting options list.
2019-05-03 16:20:01 -04:00
Ryan Petrello
c6c14d4fb9 properly record Instance.cpu and Instance.memory for isolated nodes 2019-05-03 15:30:41 -04:00
Alex Corey
1200c23ebc addressing PR issues 2019-05-03 14:26:19 -04:00
Ryan Petrello
a874ed0424 Merge pull request #3543 from AlanCoding/migration_schmigration
Fix server error for in-flight migration
2019-05-03 11:59:02 -04:00
softwarefactory-project-zuul[bot]
cf6a103207 Merge pull request #3818 from ryanpetrello/devel
merge in downstream changes

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-03 14:36:56 +00:00
Alex Corey
b8b2209335 add bottom border to org tabs 2019-05-03 10:27:48 -04:00
AlanCoding
d2e67aea19 Fix server error for in-flight migration 2019-05-03 10:20:31 -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
softwarefactory-project-zuul[bot]
e5cf5be18d Merge pull request #3815 from pmoravec/awx-pmoravec-tower-sos-plugin-improvements
sosreport plugin improvements

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-03 12:47:39 +00:00
softwarefactory-project-zuul[bot]
f26ae8ef13 Merge pull request #3714 from vismay-golwala/org_member_count
Show only member users for organization

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-03 12:36:29 +00:00
softwarefactory-project-zuul[bot]
755c3e89e2 Merge pull request #3801 from vismay-golwala/copy_credential
Copy credential bug - add owner too

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2019-05-03 12:31:59 +00:00
softwarefactory-project-zuul[bot]
2800e89fd2 Merge pull request #3783 from AlanCoding/passwords_and_relaunching
Allow relaunching other user jobs with public vars

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-03 12:03:26 +00:00
Ryan Petrello
8d75fc5f56 Merge branch 'downstream' into devel 2019-05-03 07:58:25 -04:00
softwarefactory-project-zuul[bot]
17d2efde95 Merge pull request #3789 from AlanCoding/rm_fields
Remove job ask_ fields that reference JT

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-03 11:42:19 +00:00
Pavel Moravec
8909a8a8e4 sosreport plugin to stick on sos >= 3.0 API only
As sosreport 3.0 was released 5 years ago, older sos versions can
be ignored / not further supported.

Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
2019-05-03 10:38:34 +02:00
mabashian
90a86f53ba Fix display bug on host groups list 2019-05-02 17:13:17 -04:00
Michael Abashian
4be05f1bf6 Merge pull request #3535 from mabashian/job-events-collapse
Fix inert event expand/collapse on refreshed job results
2019-05-02 16:41:13 -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
Pavel Moravec
29822ee140 don't collect data from other sosreport plugins
Tower plugin shouldn't collect data that other sosreport plugins collect.

Further, few code optimizations in calling sos API are made.

Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
2019-05-02 21:45:09 +02: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
Ryan Petrello
7fc13b8bb5 Merge pull request #3538 from ryanpetrello/valid-netloc
require a valid netloc for Credential Type inputs w/ format=url
2019-05-02 15:08:48 -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
Ryan Petrello
e560dccd36 require a valid netloc for Credential Type inputs w/ format=url 2019-05-02 14:49:02 -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
Ryan Petrello
de56e20f11 Merge pull request #3536 from ryanpetrello/urllib3-1.24.3
pin urllib3 to 1.24.3 to address CVE-2019-9740
2019-05-02 14:27:10 -04:00
Michael Abashian
d4cc595630 Merge pull request #3510 from mabashian/3506-sort-more-fields
Add more sort options to new lists
2019-05-02 14:17:36 -04:00
mabashian
b754e0dbba Fix template sorting by project 2019-05-02 13:55:20 -04:00
softwarefactory-project-zuul[bot]
72fe6e400e Merge pull request #3802 from AlanCoding/playbook_search
Include playbook as a default search field

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-02 16:54:21 +00:00
Ryan Petrello
6bb9902588 pin urllib3 to 1.24.3 to address CVE-2019-9740 2019-05-02 11:59:01 -04:00
Marliana Lara
516aecf7de Use recommended PatternFly Base CSS 2019-05-02 11:43:13 -04:00
mabashian
04d22a930d Fix inert event expand/collapse on refreshed job results 2019-05-02 10:43:56 -04:00
Keith Grant
eea3d72ffc add CardCloseButton tests 2019-05-02 10:02:45 -04:00
softwarefactory-project-zuul[bot]
fe3a2d1a4e Merge pull request #3803 from ryanpetrello/matter-of-fact
remove references to the (now defunct) fact receiver

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-02 13:34:12 +00:00
Keith Grant
1490235752 adjust spacing of org add/edit form, add CardCloseButton 2019-05-02 08:39:36 -04:00
Ryan Petrello
50f9c70afd remove references to the (now defunct) fact receiver 2019-05-01 23:48:05 -04:00
softwarefactory-project-zuul[bot]
5ab7f888f1 Merge pull request #3800 from AlanCoding/event_children_list
Populate event children list via parent_uuid

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-02 00:37:03 +00:00
AlanCoding
7d692d08f9 include playbook as a default search field 2019-05-01 16:15:00 -04:00
softwarefactory-project-zuul[bot]
f3c023a11f Merge pull request #3765 from beeankha/task_doc_update
Add Task Overview Details to tasks.md

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-01 20:02:15 +00:00
Alex Corey
b136ce1e1d updating PR issues updated snapshot test 2019-05-01 15:48:08 -04:00
beeankha
a87c87b7c9 Add more runner-related details 2019-05-01 15:40:15 -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
AlanCoding
5f1aeb0f4e remove ask_vars from job_start endpoint 2019-05-01 13:39:25 -04:00
Vismay Golwala
cc001c9892 Copy credential bug - add owner too
While copying a credentials, we should set the new owner to person
who copies it. There was a bug while trying to do so and this PR
tries to address it.

Link: #3750

Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-05-01 13:15:16 -04:00
softwarefactory-project-zuul[bot]
a68ab19e16 Merge pull request #3791 from AlanCoding/clean_up_test_tasks
Make test_tasks.py durable to changing Ansible versions

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-05-01 17:14:11 +00:00
AlanCoding
530a7ba51d populate event children list via parent_uuid 2019-05-01 11:55:53 -04:00
beeankha
383fe278f5 Address a few more comments 2019-05-01 11:35:26 -04:00
Ryan Petrello
c41da766fb Merge pull request #3530 from ryanpetrello/you're-not-by-real-dad
fix a bug that caused parent_uuid not to be persisted
2019-05-01 10:21:35 -04:00
Ryan Petrello
46795cc71e fix a bug that caused parent_uuid not to be persisted 2019-05-01 10:13:59 -04:00
Ryan Petrello
4fac608890 Merge pull request #3528 from jakemcdermott/fix-3507
require url scheme for external credential type url inputs
2019-05-01 09:32:42 -04:00
Jake McDermott
84b21620b2 raise url string parsing error as validation error 2019-05-01 09:17:52 -04:00
mabashian
eaaad89a8c Removed inventory sorting from jobs list. Changed Last Run to Last Used in project sort filters. 2019-05-01 09:17:15 -04:00
Michael Abashian
6f309bd2d2 Merge pull request #3526 from jakemcdermott/fix-3524
use test callback from test form save hooks
2019-05-01 08:57:29 -04:00
Ryan Petrello
6e00038d35 Merge pull request #3516 from jakemcdermott/fix-3511
hide dashboard tips on graph teardown event
2019-04-30 23:01:25 -04:00
Ryan Petrello
ad4e413a36 Merge pull request #3515 from jakemcdermott/fix-3513
fix error on template prompt initialization when credential has prompt
2019-04-30 15:47:39 -04:00
beeankha
27ca5e1fd5 Add more details for several of the listed tasks 2019-04-30 15:32:52 -04:00
AlanCoding
4191b21052 make test_tasks.py durable to changing Ansible versions 2019-04-30 14:00:51 -04:00
Jake McDermott
9737ab620c require url scheme for credential type url inputs
This adds a url formatting type for credential input string fields
The validator for this formatting type will throw an error if the
provided url string doesn't have a url schema.
2019-04-30 13:41:07 -04:00
AlanCoding
81f0662161 remove job ask_ fields that reference JT 2019-04-30 13:35:58 -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
Jake McDermott
d1dc6007fd use test callback from test form save hooks
Enter key and other form submits are handled generically from the built-in
save hooks on the form controller. This adds implementations for those hooks
on the plugin test forms to make sure the expected handlers are always called.
2019-04-30 12:31:30 -04:00
Kia Lam
5287af1b9f Add logged in username to top level header bar. 2019-04-30 11:05:08 -04:00
Ryan Petrello
52276ebbab Merge pull request #3523 from wenottingham/failure-event-handling-is-an-option
Use AWX python interpreter for failure-event-handler.
2019-04-30 10:41:54 -04:00
Alex Corey
f71421f60a removed orgsToDelete and fixed other tests 2019-04-30 10:22:25 -04:00
AlanCoding
d204f12184 remove unneeded update_model call 2019-04-30 10:15:08 -04:00
AlanCoding
42dd3c5cf5 Remove unused output_replacements logic 2019-04-30 10:11:03 -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
AlanCoding
5720601a2e allow relaunching other user jobs with public vars 2019-04-30 08:07:45 -04:00
Bill Nottingham
5d1346b956 Use AWX python interpreter for failure-event-handler.
python3 isn't in the normal path when using SCLs.
2019-04-29 20:32:50 -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
Vismay Golwala
30d0130e79 Show only member users for organization
Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-04-29 14:20:57 -04:00
Jake McDermott
ee5b4b072b fix unit and functional tests 2019-04-29 11:35:06 -04:00
beeankha
4baecef866 Clean up references to Tower 2019-04-29 10:51:25 -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
softwarefactory-project-zuul[bot]
aaeb2d6fb9 Merge pull request #3740 from wenottingham/lets-re-compose-ourselves
Sync docker-compose dockerfile with the actual production image build.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-26 19:05:43 +00:00
softwarefactory-project-zuul[bot]
c707e60bde Merge pull request #3664 from vismay-golwala/pagination_cap_api
Cap page_size in pagination urls

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-26 17:55:51 +00:00
mabashian
b7e26b3507 Fix linting error 2019-04-26 13:15:37 -04:00
softwarefactory-project-zuul[bot]
44fcf2e0e4 Merge pull request #3766 from ryanpetrello/devel
merge in downstream changes

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-26 17:09:48 +00: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
3cd8d4f7e6 Adds more sort options to lists 2019-04-26 11:52:07 -04:00
softwarefactory-project-zuul[bot]
ddde669083 Merge pull request #3767 from ryanpetrello/cors-lite
document CORS middleware

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-26 15:32:35 +00:00
Jake McDermott
36e384e8ab hide dashboard tips on graph teardown event 2019-04-26 11:18:39 -04:00
mabashian
8cfe74a854 Code cleanup, renaming functions, use .all() on config promises 2019-04-26 11:02:16 -04:00
Ryan Petrello
586c3e4583 document CORS middleware 2019-04-26 11:00:33 -04:00
Jake McDermott
14045c1017 fix undefined prop in template credential prompt initialization
The prompt initialization code had a reference to an undefined
prop. This updates the code to use the expected prop.
2019-04-26 10:34:00 -04:00
Ryan Petrello
d11dfd0a2b Merge branch 'downstream' into devel 2019-04-26 08:02:04 -04:00
beeankha
cb7914dfa4 Make edits per first round of reviews. 2019-04-25 17:16:39 -04:00
beeankha
639e01e884 Remove unnecessary line 2019-04-25 16:26:58 -04:00
beeankha
e4d6d51cf5 Add further details/overview of AWX and Tower tasks into documentation 2019-04-25 16:14:49 -04:00
mabashian
7f452ee8d1 Add more sort options to new lists 2019-04-25 15:32:25 -04:00
Ryan Petrello
27d74528c0 Merge pull request #3494 from rooftopcellist/analytics_csv
analytics table copies formatted as csv now
2019-04-25 14:48:59 -04:00
Ryan Petrello
0ada1e965f Merge pull request #3508 from ryanpetrello/runner-134
pin runner 1.3.4
2019-04-25 10:16:05 -04:00
Ryan Petrello
2808a852eb pin runner 1.3.4 2019-04-25 09:49:03 -04:00
Ryan Petrello
80393e9194 Merge pull request #3504 from wenottingham/im-not-going-to-be-ignored-dan
Kill the rabbitmq sos collection from our plugin.
2019-04-24 14:51:01 -04:00
Bill Nottingham
aa52e41c02 Kill the rabbitmq sos collection from our plugin.
It exists in upstream sosreport, and this can cause conflicts.
2019-04-24 14:15:17 -04:00
Ryan Petrello
d7cdec37f2 Merge pull request #3502 from ryanpetrello/metrics-license-counts
fix a few issues with license counts in /api/v2/metrics/
2019-04-24 12:37:03 -04:00
softwarefactory-project-zuul[bot]
f60857013e Merge pull request #3754 from AlanCoding/gce_env_var
Simplify gce inventory plugin injector

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-24 16:25:09 +00:00
Ryan Petrello
c9424f9af8 fix a few issues with license counts in /api/v2/metrics/
- switched these to gauges so people can track them over time
- fixed a typo that caused `free_instances` to always be zero
2019-04-24 12:23:07 -04:00
Ryan Petrello
66f883befe Merge pull request #3485 from wenottingham/aaaaaaaaaaaaaaaaaaaaaaazure
Update Azure requirements for Ansible stable-2.8 branch.
2019-04-24 12:05:58 -04:00
softwarefactory-project-zuul[bot]
fad0274373 Merge pull request #3686 from vismay-golwala/instance_group_delete
[WIP] Disallow deleting controller or isolated instance groups

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-24 15:19:19 +00:00
mabashian
e5dda696d7 Add new tests for rbac on some of the org pages 2019-04-24 10:10:14 -04:00
Michael Abashian
8c715fc6e1 Merge pull request #3497 from dsesami/e2e_backport_3.5.0
E2E testing: compatibility edit to work with diff versions of node
2019-04-24 10:03:53 -04:00
Daniel Sami
870ebb4b43 fix to work with diff versions of node 2019-04-24 09:44:41 -04:00
softwarefactory-project-zuul[bot]
e78ef82385 Merge pull request #3758 from ryanpetrello/dot-files
clean up some old dotfiles

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-24 13:06:20 +00:00
Matthew Jones
1eb565543c Merge pull request #3495 from ansible/markerfiletest
Adding a markerfile for e2e runs
2019-04-24 09:06:03 -04:00
John Hill
082a819160 removing hyphen 2019-04-24 08:22:07 -04:00
Ryan Petrello
519d2eebcb remove unnecessary dotfiles 2019-04-23 17:23:15 -04:00
Michael Abashian
f2ea9003a3 Merge pull request #3493 from dsesami/e2e_backport_3.5.0
E2E backport 3.5.0
2019-04-23 16:51:34 -04:00
Christian Adams
64ae7a6e45 analytics table copies formatted as csv now 2019-04-23 16:26:14 -04:00
softwarefactory-project-zuul[bot]
b47be3c8c7 Merge pull request #3749 from AlanCoding/simple_openstack
Use common method for openstack OS_CLIENT_CONFIG_FILE injection

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-23 20:23:05 +00:00
John Hill
2f7ec6ff13 adding a markerfile for e2e runs 2019-04-23 16:01:45 -04:00
Daniel Sami
75065b6407 e2e stability backport for 3.5 2019-04-23 15:45:27 -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
softwarefactory-project-zuul[bot]
2cb6104fe4 Merge pull request #3696 from AlanCoding/django2_warnings
Fix Django 2.0 deprecation warnings

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-23 18:09:58 +00:00
softwarefactory-project-zuul[bot]
f90f8ba9a8 Merge pull request #3755 from ansible/noretry
Adding an option to run all the tests without a retry statement

Reviewed-by: awxbot
             https://github.com/awxbot
2019-04-23 17:48:52 +00: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
John Hill
9733fde560 Adding an option to run all the tests without a retry statement 2019-04-23 13:18: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
Ryan Petrello
231c76c9cb Merge pull request #3490 from jakemcdermott/fix-3487
handle insights credential lookups for projects
2019-04-23 12:08:43 -04:00
mabashian
621cc3f839 Fix rebase errors 2019-04-23 11:52:49 -04:00
Jake McDermott
311daf10b8 handle insights credential lookups for projects
Although most scm types correspond to an scm credential lookup, insights uses its own
credential type.
2019-04-23 11:44:03 -04:00
Bill Nottingham
4ca4563a19 Update Azure requirements for Ansible stable-2.8 branch. 2019-04-23 10:50:00 -04:00
Ryan Petrello
96183cf9c4 Merge pull request #3484 from ansible/insights-integration
Insights integration
2019-04-23 10:05:00 -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
Jeff Bradberry
0b555e938a Fix typo in the Insights inventory url 2019-04-23 09:39:08 -04:00
AlanCoding
c36dbb3448 Simplify gce inventory plugin injector
This consumes the change made in Ansible core
https://github.com/ansible/ansible/pull/54407
which is in Ansible 2.8, allowing the plugin
injection logic to share the script logic and
to be simplified
2019-04-23 09:33:17 -04:00
AlanCoding
adfce6edf1 Unify openstack inventory injection logic
Remove logic specific to job runs to create a "clouds" file
  for openstack credential type

Move that logic into the collection of managed_by_tower
  injector methods, so it will be used by all job types

Modify inventory openstack injector logic to use this
  data as a base for its logic building the clouds file
2019-04-23 07:59:47 -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
AlanCoding
140394fe1f Change credential pattern for openstack inventory plugin
See upstream docs https://github.com/ansible/ansible/pull/54532
Previously it was thought that the entry in the inventory config
file was necessary, but the upstream docs change allows us to
use the same pattern that we used to for the script.
2019-04-22 14:32:00 -04:00
Jeff Bradberry
6ff539e6ee Update the front-end Insights urls 2019-04-22 14:17:47 -04:00
Jeff Bradberry
49ba6c6b3d Appease flake8 2019-04-22 14:17:47 -04:00
Jeff Bradberry
e2861c6c39 Fix the tests to conform to the new Insights results 2019-04-22 14:17:47 -04:00
Jeff Bradberry
6dae4a1d6d Add the host in as a parameter to the _get_insights call 2019-04-22 14:17:47 -04:00
Jeff Bradberry
e66f9241a9 Remove the platform_id from the call to _get_insights
since it is now acquired within _get_insights.
2019-04-22 14:17:47 -04:00
Jeff Bradberry
72da961550 Conform to the new output of the Insights system reports endpoint 2019-04-22 14:17:47 -04:00
Jeff Bradberry
4c86c5065c Fix a typo in the per-system remediations api call 2019-04-22 14:17:47 -04:00
Jeff Bradberry
80a855c57a Do some basic slugification of the remediation playbook name 2019-04-22 14:17:47 -04:00
Jeff Bradberry
11b85250e8 Update more urls 2019-04-22 14:17:47 -04:00
Jeff Bradberry
10cfac2f0e Update the error message when we can't discover the platform ID 2019-04-22 14:17:47 -04:00
Jeff Bradberry
355a83441a Guard against the case where Insights fails to find the system ID 2019-04-22 14:17:47 -04:00
Jeff Bradberry
e25adca233 Replace the old unit tests with new functional tests 2019-04-22 14:17:47 -04:00
Jeff Bradberry
7c743904b0 Removed some no longer needed imports 2019-04-22 14:17:47 -04:00
Jeff Bradberry
a97865de0c Refactor HostInsights
for better reuse of the error handling of the Insights API calls.
2019-04-22 14:17:47 -04:00
Jeff Bradberry
596a5173ce Modify filter_insights_api_response to take in the separate remediations
since it is accumulated via a different API call.
2019-04-22 14:17:47 -04:00
Jeff Bradberry
63209197dd Iterate over the pages of remediations available 2019-04-22 14:17:47 -04:00
Jeff Bradberry
af2484cd97 Update the Insights API urls to use the new url structure 2019-04-22 14:17:47 -04:00
Jeff Bradberry
f01a936202 Update the test for filter_insights_api_response()
and fix the data nesting issue that it uncovered.
2019-04-22 14:17:47 -04:00
Jeff Bradberry
05f670a6d9 Update the filter_insights_api_response() utility function
in order to conform the output of the new Insights Advisor report
endpoint to our expections.
2019-04-22 14:17:47 -04:00
Jeff Bradberry
f4b0910e98 Call out to the Insights API to get the Platform ID for a host
Since the new reports endpoint requires that, rather than the Insights
system ID that we've been using (and storing on the Host model).
2019-04-22 14:17:47 -04:00
Jeff Bradberry
95b17892ee Factor out the response handling boilerplate from HostInsights.get_insights
We'll want to reuse it for the API call to /hosts as well.
2019-04-22 14:17:47 -04:00
Jeff Bradberry
8fdc53cb21 Update the Insights API endpoint for getting the reports for a host 2019-04-22 14:17:47 -04:00
Jeff Bradberry
04521f5c5c Update the Insights action plugin to make calls against the new API 2019-04-22 14:17:47 -04:00
AlanCoding
8c2b3e9b84 Fix Django 2.0 deprecation warnings 2019-04-22 14:17:14 -04:00
softwarefactory-project-zuul[bot]
864fef4f29 Merge pull request #3748 from ryanpetrello/pin-runner-133
pin runner to 1.3.3

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-22 17:28:16 +00:00
Ryan Petrello
787e369bcf pin runner to 1.3.3 2019-04-22 12:57:55 -04:00
softwarefactory-project-zuul[bot]
805a0c7a9a Merge pull request #3730 from jbradberry/manage-org-resource-roles
Adjust the access logic for settings.MANAGE_ORGANIZATION_AUTH = False

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-22 16:44:05 +00:00
softwarefactory-project-zuul[bot]
c80a5e2164 Merge pull request #3747 from ryanpetrello/d-d-d-danger-zone
add a loud warning about perf regressions to tasks.py

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-22 15:25:46 +00:00
Ryan Petrello
eb0463890c add a loud warning about perf regressions to tasks.py 2019-04-22 10:26:58 -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
softwarefactory-project-zuul[bot]
f6076052bd Merge pull request #3737 from wenottingham/computing-is-deprecated--tell-your-friends
Deprecate a bunch of inventory computed fields.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 21:11:50 +00:00
Bill Nottingham
0d18d46ccc Sync docker-compose dockerfile with image build dockerfile.
It was installing an IUS repo, rabbitmq-server, and other unneeded things.
2019-04-18 16:50:38 -04:00
softwarefactory-project-zuul[bot]
23ea419aa9 Merge pull request #3724 from ansible/spinnycheck
prevent flake for user e2e

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 20:47:00 +00:00
Daniel Sami
b084622c9e prevent flake for user e2e 2019-04-18 16:25:35 -04:00
Bill Nottingham
ef7e1afa34 Add migrations for field names. 2019-04-18 15:39:47 -04:00
softwarefactory-project-zuul[bot]
be86086134 Merge pull request #3739 from elyezer/update-jobs-portal-e2e
Update jobs portal list actions e2e

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 19:30:56 +00:00
Elyézer Rezende
a06d2946b6 Update jobs portal list actions e2e 2019-04-18 15:09:29 -04:00
Jeff Bradberry
0ba87c9729 Add more test checks for the alternate code path to the role checks 2019-04-18 14:53: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
Jeff Bradberry
41b476544d Improve test coverage of attaching a user to an organization 2019-04-18 13:35:35 -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
softwarefactory-project-zuul[bot]
97a6255531 Merge pull request #3736 from ryanpetrello/red-means-loud-on-the-internet
make deprecation warnings at /api/ much more obvious

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 17:05:33 +00:00
Ryan Petrello
4159a9b6af make deprecation warnings at /api/ much more obvious 2019-04-18 12:32:49 -04:00
softwarefactory-project-zuul[bot]
798bc4b8de Merge pull request #3734 from wenottingham/sqlitis-is-bad
remove sqlite db, add it to .gitignore

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 16:28:40 +00:00
Bill Nottingham
6adf4ca2c1 Deprecate a bunch of inventory computed fields.
Cribbed from https://github.com/ansible/awx/pull/3281/
2019-04-18 12:12:50 -04:00
softwarefactory-project-zuul[bot]
8cc18f501e Merge pull request #3733 from ryanpetrello/dashboard-deprecation
deprecate /api/v2/dashboard in favor of /api/v2/metrics

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 16:09:19 +00:00
Bill Nottingham
63049fe99d remove sqlite db, add it to .gitignore 2019-04-18 12:03:04 -04:00
Ryan Petrello
d6ecb486d2 deprecate /api/v2/dashboard in favor of /api/v2/metrics 2019-04-18 11:45:37 -04:00
Vismay Golwala
f4dc4d5849 Cap page_size in pagination urls
Currently, even with a `max_page_size` of n, we can see urls
formed in pagination with `page_size` > n. API still caps the
number of results it returns, but the URL remain invalid there.
This is a bit messy solution to make string replacement in URL
if the query param exceeds `max_page_size`

Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-04-18 11:39:22 -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
softwarefactory-project-zuul[bot]
87d55b13bc Merge pull request #3549 from vismay-golwala/verify_venv_on_launch
Validate virtual environment while running a job/inventory update

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 12:31:25 +00:00
Vismay Golwala
5d570a017a Validate virtual environment while running a job/inventory update
Currently we only check the custom virtual environment path when
it's created. However, to tackle with the case when the venv might
have been changed/deleted afterward, we need to validate it at
run-time too.

Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-04-18 08:09:49 -04:00
softwarefactory-project-zuul[bot]
6d5897f371 Merge pull request #3728 from chrismeyersfsu/speed_boost
instantiate dispatcher once per job run

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-18 11:14:32 +00:00
softwarefactory-project-zuul[bot]
e14f19468b Merge pull request #3729 from rooftopcellist/rename_analytics_setting
rename analytics setting

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-17 22:55:43 +00:00
Jeff Bradberry
8ad0b3f787 Check the permissions for adding users to orgs/teams in the other direction 2019-04-17 17:45:20 -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
Jeff Bradberry
70b0679a0c Adjust the access logic for settings.MANAGE_ORGANIZATION_AUTH = False
so that changing the membership of Organizations and Teams are
disallowed unless you are a superuser, but granting resource
privileges is still permitted.
2019-04-17 15:37:02 -04:00
Christian Adams
add8673d7c rename analytics setting 2019-04-17 15:28:15 -04:00
chris meyers
84c09a19d1 instantiate dispatcher once per job run
* Instantiating the callback dispatch queue on each job event callback
is expensive. Instead, instantiate it only once. Note, we do not need to
instantiate the callback queue in the iso case so we do not.
2019-04-17 14:03:00 -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
softwarefactory-project-zuul[bot]
fbc7d1a9f2 Merge pull request #3711 from AlanCoding/conservative_upgrades3
Apply critical dependency upgrades (try 2)

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-17 13:04:24 +00:00
softwarefactory-project-zuul[bot]
daeeb31590 Merge pull request #3715 from ryanpetrello/local-python
properly set ansible_python_interpreter for local task execution

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-17 12:44:39 +00:00
softwarefactory-project-zuul[bot]
66886fb57a Merge pull request #3721 from AlanCoding/org_members_read_teams
Use querset special case to let org members see teams

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-17 12:24:49 +00:00
AlanCoding
1ddb675fa2 Use querset special case to let org members see teams 2019-04-17 07:05:25 -04:00
softwarefactory-project-zuul[bot]
4fd04e095f Merge pull request #2860 from AlanCoding/auditor_association
Show entry for system auditor associations

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-17 10:48:37 +00:00
Ryan Petrello
9d000a76de properly set ansible_python_interpreter for local task execution
this works a limitation in ansible for connection: local and makes it so
that you can run connection: local playbooks with a /usr/bin/python that
is Python3 and an Ansible virtualenv that is Python2

see: https://github.com/ansible/awx/issues/3267
2019-04-16 21:24:23 -04:00
softwarefactory-project-zuul[bot]
7f5227809f Merge pull request #3723 from ryanpetrello/django-works-in-mysterious-ways
fix a bug that breaks the isolated heartbeat

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-16 20:46:14 +00:00
Ryan Petrello
f1d87bf392 fix a bug that breaks the isolated heartbeat 2019-04-16 16:24:40 -04:00
AlanCoding
941009bf6d Apply critical dependency upgrades
fix PyYAML warnings in unit tests
update paramiko source file for license
2019-04-16 16:00:09 -04:00
AlanCoding
9c71204435 show activity stream entry for system auditor association 2019-04-16 15:59:04 -04:00
softwarefactory-project-zuul[bot]
15ef095366 Merge pull request #3720 from shanemcd/memcache-config
Fix memcached configuration in local Docker installs

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-16 19:53:23 +00:00
softwarefactory-project-zuul[bot]
c2daccade7 Merge pull request #3667 from chrismeyersfsu/delete-system-tracking
remove system tracking

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-16 17:24:03 +00:00
Shane McDonald
3bfb54d2fd Fix memcached configuration in local Docker installs
Related: https://github.com/ansible/awx/issues/3719
Signed-off-by: Shane McDonald <me@shanemcd.com>
2019-04-16 12:51:28 -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
softwarefactory-project-zuul[bot]
a5d31e56d6 Merge pull request #3709 from AlanCoding/piparoo
Apply same pip and setuptools to AWX and Ansible venv

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-15 21:05:49 +00:00
softwarefactory-project-zuul[bot]
d222bed932 Merge pull request #3712 from jladdjr/iso_node_healthcheck_should_not_reset_capacity
Do not reset capacity of iso nodes when disabled

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-15 20:40:01 +00:00
softwarefactory-project-zuul[bot]
45cc8f1cc9 Merge pull request #3703 from mabashian/upgrade-bootstrap-yay
Bumps Bootstrap to 4.3.1

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-15 20:35:03 +00:00
Vismay Golwala
e0c4fd4b3a Disallow deleting controller or isolated instance groups
Added two new properties to the InstanceGroup model - `is_controller`
and `is_isolated`. Used these properties to hide the trash icon for
instance groups that are either controller or isolated.

Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-04-15 16:08:27 -04:00
Jim Ladd
6ef3b18803 Do not reset capacity of iso nodes when disabled 2019-04-15 12:36:15 -07:00
softwarefactory-project-zuul[bot]
f23b4e7b9a Merge pull request #3708 from rooftopcellist/update_prom_docs
add url to prom docs

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-15 18:23:19 +00:00
softwarefactory-project-zuul[bot]
1d4773545e Merge pull request #3707 from ryanpetrello/report-ansible-runner-crashes
if runner crashes, attempt to record why

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-15 18:16:09 +00:00
AlanCoding
e40c6da552 Apply same pip and setuptools to AWX and Ansible venv 2019-04-15 13:54:25 -04:00
Christian Adams
8ef81065b7 add url to prom docs 2019-04-15 13:39:55 -04:00
mabashian
08fcdf0e25 Bumps Bootstrap to 4.3.1 2019-04-15 13:20:00 -04:00
Ryan Petrello
387682ed8d if runner crashes, attempt to record why
this attempts to surface the underlying runner exception for tracebacks
like this one:

FileNotFoundError: [Errno 2] No such file or directory:
'/tmp/awx_41_93gtgv25/artifacts/41/status'
2019-04-15 13:17:45 -04:00
softwarefactory-project-zuul[bot]
707c3883a8 Merge pull request #3702 from AlanCoding/revert_upgrades
Revert "Merge pull request #3697 from AlanCoding/conservative_upgrades"

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-15 16:54:36 +00:00
softwarefactory-project-zuul[bot]
47b0a96e96 Merge pull request #3704 from rooftopcellist/cleanup_prom_files
add prometheus data to gitignore

Reviewed-by: awxbot
             https://github.com/awxbot
2019-04-15 15:17:07 +00: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
Christian Adams
fb4495b1b5 add prometheus data to gitignore 2019-04-15 10:43:28 -04:00
AlanCoding
5dbc269de1 Revert "Merge pull request #3697 from AlanCoding/conservative_upgrades"
This reverts commit 890de400e2, reversing
changes made to e8de7bc845.
2019-04-15 10:39:56 -04:00
softwarefactory-project-zuul[bot]
5c7939a6ac Merge pull request #3676 from keithjgrant/3604-search-tag-line-wrap
fix tag word wrapping for firefox

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-15 13:56:40 +00:00
softwarefactory-project-zuul[bot]
890de400e2 Merge pull request #3697 from AlanCoding/conservative_upgrades
Apply critical dependency upgrades

Reviewed-by: Alan Rominger <arominge@redhat.com>
             https://github.com/AlanCoding
2019-04-15 13:24:25 +00:00
softwarefactory-project-zuul[bot]
e8de7bc845 Merge pull request #3673 from rooftopcellist/metrics_uuids
add uuids to ping and metrics

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-13 11:45:47 +00:00
Christian Adams
40393e201f add uuids to ping and metrics 2019-04-12 18:37:40 -04:00
softwarefactory-project-zuul[bot]
97e2137d07 Merge pull request #3694 from ryanpetrello/gbye-callback-plugins
remove the old callback plugin import paths

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-12 21:01:34 +00:00
softwarefactory-project-zuul[bot]
29c3927a16 Merge pull request #3695 from wenottingham/words-are-hard
Update wording.

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2019-04-12 20:35:46 +00:00
Ryan Petrello
17a803f49c remove the old callback plugin import paths and callback-specific tests 2019-04-12 16:11:23 -04:00
softwarefactory-project-zuul[bot]
d0c3882d9d Merge pull request #3698 from ansible/bumpse
Adding selenium stability fix and unpinning se images

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-12 20:10:57 +00: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
Bill Nottingham
9da5cc9c23 Update wording. 2019-04-12 16:09:30 -04:00
John Mitchell
14c1b85127 Merge pull request #156 from jlmitch5/handleNetworkErrors
Handle network errors
2019-04-12 16:00:54 -04:00
softwarefactory-project-zuul[bot]
7913247eaa Merge pull request #3678 from jlmitch5/showRevAndIgForJobResults
subscribe to updates for scm revision and and instance group for job …

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-12 19:53:01 +00:00
AlanCoding
569cd3b34e update paramiko source file 2019-04-12 15:52:35 -04:00
AlanCoding
2c67bec3cb fix PyYAML warnings in unit tests 2019-04-12 15:48:08 -04:00
John Hill
77e587babe Adding selenium stability fix and unpinning se images 2019-04-12 15:43:37 -04:00
AlanCoding
235011f5e9 Apply critical dependency upgrades 2019-04-12 15:26:48 -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
chris meyers
0c6a522813 remove system tracking
* Leave the artisanal handcrafted migration from vendored fact scan to
external fact gathering.
2019-04-12 14:30:29 -04:00
softwarefactory-project-zuul[bot]
dc833bbaa7 Merge pull request #3683 from mabashian/3565-workflow-template-popover
Leverages awPopOverWatch to generate popover dynamically on workflow node templates help

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-12 16:54:54 +00:00
mabashian
9b0329021c Leverages awPopOverWatch to generate popover dynamically on workflow node templates help 2019-04-12 12:29:50 -04:00
softwarefactory-project-zuul[bot]
3611f3491b Merge pull request #3581 from beeankha/basic_license_feature
Update Basic License Feature Access

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-12 15:57:18 +00:00
softwarefactory-project-zuul[bot]
213a0c3cef Merge pull request #3692 from ansible/spinnycheck
Fixing flake and waits for spinny that don't need to be there.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-12 15:45:44 +00:00
beeankha
0cc640403a Resolve initial login error 2019-04-12 11:28:27 -04:00
Ryan Petrello
85898fd708 remove more unnecessary feature flagging for AUTHENTICATION_BACKENDS 2019-04-12 11:28:27 -04:00
beeankha
14d4d624e4 Restore button for adding notifications 2019-04-12 11:28:27 -04:00
beeankha
de34a64115 Basic License feature gating changes 2019-04-12 11:28:27 -04:00
Daniel Sami
d67a336e2f drop spinny
flake fixes

adjust
2019-04-12 10:57:35 -04:00
softwarefactory-project-zuul[bot]
58966d7368 Merge pull request #3625 from ryanpetrello/iso-forks
WIP: specify --forks on isolated health check calls

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-11 21:41:37 +00: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
softwarefactory-project-zuul[bot]
fc5322b2a4 Merge pull request #3675 from mabashian/as-mgmt-jobs
Check to make sure the activity stream button should be shown after refresh

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-11 17:54:24 +00:00
softwarefactory-project-zuul[bot]
817b350de9 Merge pull request #3685 from ryanpetrello/runner-132
pin ansible runner to 1.3.2

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-11 17:27:51 +00:00
Ryan Petrello
0c4ed78bee pin ansible runner to 1.3.2 2019-04-11 12:57:07 -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
softwarefactory-project-zuul[bot]
0252af0d30 Merge pull request #3674 from ansible/splits
added ws and pending to user e2e

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-11 16:04:34 +00: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
Daniel Sami
f56f6c11f7 added ws and pending to user e2e
lint
2019-04-11 09:41:51 -04:00
John Mitchell
ef84bfc1c2 subscribe to updates for scm revision and and instance group for job results 2019-04-10 17:00:35 -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
softwarefactory-project-zuul[bot]
8383568e3c Merge pull request #3672 from rooftopcellist/metrics_content_types
remove invalid json renderer from metrics endpoint

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 20:36:42 +00:00
Christian Adams
fd5d9c45d7 remove invalid json renderer from metrics endpoint 2019-04-10 16:14:54 -04:00
softwarefactory-project-zuul[bot]
23d0f6022c Merge pull request #3671 from athenahealth/fix-awx-logos-inventory-comments
Fix comment on awx branding inventory var

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 20:05:16 +00:00
mabashian
9e98058290 Check to make sure the activity stream button should be shown after refresh 2019-04-10 15:56:19 -04:00
Keith Grant
e073b5e017 fix tag word wrapping for firefox 2019-04-10 15:51:56 -04:00
softwarefactory-project-zuul[bot]
21bec83a4e Merge pull request #3669 from mabashian/workflow-node-save
Ensures extra vars are converted to yaml before being passed along to prompt steps

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 19:50:39 +00:00
softwarefactory-project-zuul[bot]
cd966f2669 Merge pull request #3670 from mabashian/root-all-groups-responsive
Make root/all groups action bar a bit more responsive

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 19:50:33 +00:00
softwarefactory-project-zuul[bot]
1830da4268 Merge pull request #3656 from elyezer/applications-e2e
Add applications to e2e

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 18:57:22 +00:00
Jeff Byrnes
98ec5c8250 Fix comment on awx branding inventory var
Fix a conflict with the “AWX Branding” in INSTALL.md, which
has the correct instructions.
2019-04-10 14:49:37 -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
mabashian
0caf1e8a3d Make root/all groups action bar a bit more responsive 2019-04-10 12:06:47 -04:00
softwarefactory-project-zuul[bot]
ae7b173e17 Merge pull request #3661 from AlanCoding/stdout_cleanup
Remove stdout wrapper classes that moved to runner

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 15:05:32 +00:00
softwarefactory-project-zuul[bot]
c326b186a6 Merge pull request #3629 from AlanCoding/nt_read_enable
Fix RBAC bugs with notification attachment

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 14:56:37 +00:00
mabashian
4f2443e7bb Ensures extra vars are converted to yaml before being passed along to prompt steps 2019-04-10 10:51:27 -04:00
Elyézer Rezende
213a70b98a Add applications to e2e 2019-04-10 10:50:49 -04:00
Alex Corey
731da8049b Adds tooltip to username and help icon. 2019-04-10 10:48:56 -04:00
mabashian
c91cd606ed Corresponding UI changes for notifications tab and toggle permissions 2019-04-10 10:31:31 -04:00
AlanCoding
4eab362318 fix RBAC bugs with notification attachment
Allow notification_admin_role users to attach
  NTs from that organization
Require either read_role or auditor_role to the
  object which the NT is being attached to
2019-04-10 10:29:54 -04:00
softwarefactory-project-zuul[bot]
df81eb7533 Merge pull request #3659 from rooftopcellist/prom_test
add prom permissions test

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 14:24:42 +00:00
Keith Grant
909c5e77c4 rename all test files to *.test.js 2019-04-10 09:55:57 -04:00
softwarefactory-project-zuul[bot]
1bb5d560bd Merge pull request #3663 from kialam/fix-3414-job-output-live-updates-disabled
Fix job output name in websocket service.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-10 13:52:08 +00:00
softwarefactory-project-zuul[bot]
652281b6fa Merge pull request #3645 from AlexSCorey/2281-HostEventToolTip
Add tool tip to Host Event lines.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 21:17:08 +00:00
Kia Lam
b978a28f8b Fix job output name in websocket service. 2019-04-09 17:04:30 -04:00
softwarefactory-project-zuul[bot]
4664d9556d Merge pull request #3620 from AlanCoding/gce_instance_id
Add instance_id for gce imported hosts

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 20:49:06 +00:00
softwarefactory-project-zuul[bot]
7f935084df Merge pull request #3653 from AlanCoding/instance_token_management2
Fix 403 bug using write PAT and view.always_allow_superuser=True

Reviewed-by: Alan Rominger <arominge@redhat.com>
             https://github.com/AlanCoding
2019-04-09 20:37:05 +00:00
AlanCoding
988438f119 Remove stdout wrapper classes that moved to runner 2019-04-09 16:28:30 -04:00
softwarefactory-project-zuul[bot]
20a023e243 Merge pull request #3658 from keithjgrant/2526-fix-workflow-results-layout
Fix workflow results layout when extra vars has long line

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 19:40:26 +00:00
Christian Adams
f49532090b add prom permissions test 2019-04-09 15:12:04 -04:00
Alex Corey
75a1c69ea2 address concerns in PR 2019-04-09 14:55:34 -04:00
softwarefactory-project-zuul[bot]
7f6659f767 Merge pull request #3657 from ryanpetrello/issue-template-remove-component
remove COMPONENT NAME from our issue templates

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 17:50:30 +00:00
Keith Grant
8f05482f8f fix workflow results layout when extra vars has long line 2019-04-09 13:48:25 -04:00
Ryan Petrello
01a79dd23e remove COMPONENT NAME from our issue templates
this is a remnant from our closed sourced days; upstream bug reporters
only fill this out correctly like 50% of the time, and it's often
difficult to know without knowing how AWX actually works
2019-04-09 12:49:11 -04:00
softwarefactory-project-zuul[bot]
3d308cc2a3 Merge pull request #3636 from ansible/prometheus
Prometheus Metrics

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 15:51:27 +00:00
Marliana Lara
2ab688932d Remove org list links 2019-04-09 11:37:43 -04:00
Alex Corey
4f55ffe4a0 Add tool tip to Host Event lines. 2019-04-09 10:58:23 -04:00
softwarefactory-project-zuul[bot]
6ce972a2a4 Merge pull request #3652 from keithjgrant/3639-codemirror-popout-bug
Don't obscure modal buttons when code mirror modal throws error

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 14:20:21 +00:00
softwarefactory-project-zuul[bot]
57b3565f42 Merge pull request #3631 from mabashian/reload-on-pendo-change
Refresh the page after pendo flag changes to make change effective immediately

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 14:13:00 +00:00
Wayne Witzel III
1abb0b2c35 restrict metrics to superuser and system auditor 2019-04-09 10:07:38 -04:00
AlanCoding
809fcac738 fix 403 bug using write PAT and view.always_allow_superuser=True 2019-04-09 09:54:52 -04:00
Keith Grant
fa665e81e4 don't obscure modal buttons when code mirror modal throws error 2019-04-09 09:30:58 -04:00
AlanCoding
c4b41a174b add instance_id for gce imported hosts 2019-04-09 08:20:26 -04:00
softwarefactory-project-zuul[bot]
ce65fdd26c Merge pull request #3647 from ryanpetrello/cred-namespace-api
expose CredentialType.namespace in the API

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-09 11:50:01 +00:00
Ryan Petrello
aa0179690d expose CredentialType.namespace in the API
see: https://github.com/ansible/awx/issues/3644
2019-04-08 19:02:10 -04:00
softwarefactory-project-zuul[bot]
67aeecdee5 Merge pull request #3637 from ryanpetrello/install-uuid
add a unique UUID for identifying an AWX installation

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-08 20:17:19 +00:00
softwarefactory-project-zuul[bot]
d14b71ccee Merge pull request #3643 from AlanCoding/cloudforms_py3
Backport fix to run cloudforms script in py3

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-08 18:06:49 +00:00
AlanCoding
47a3ee7d76 backport fix to run cloudforms script in py3 2019-04-08 13:40:44 -04:00
softwarefactory-project-zuul[bot]
a2bfb0f65c Merge pull request #3633 from AlanCoding/slice_of_one
Avoid slicing if the inventory only has 1 host

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-08 16:57:51 +00:00
Ryan Petrello
fc9da002d2 add an example config file and make target for starting a prometheus 2019-04-08 12:01:46 -04:00
Christian Adams
e1c6057b4c add insights setting to metrics 2019-04-08 11:49:41 -04:00
Wayne Witzel III
520cbd2015 update prometheus run example 2019-04-08 11:47:10 -04:00
Christian Adams
e2039b7d3f add insights setting to metrics 2019-04-08 11:34:38 -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
softwarefactory-project-zuul[bot]
9125313ed3 Merge pull request #3640 from konkolorado/devel
Removes failing symlink to /usr/bin/python3 during the image build

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-08 14:30:49 +00:00
Wayne Witzel III
2c8900568b add prometheus-client license details 2019-04-08 10:21:05 -04:00
Wayne Witzel III
5c1d2a6f0b flake8 cleanup 2019-04-08 09:35:46 -04:00
Wayne Witzel III
bb5c7a98f3 test prometheus metrics output 2019-04-08 09:28:57 -04:00
Christian Adams
3fb3079264 fix job status metric 2019-04-08 02:47:56 -04:00
Wayne Witzel III
c3812de3d6 initial prometheus commit
Co-authored-by: Wayne Witzel III <wayne@riotousliving.com>
Co-authored-by: Christian Adams <rooftopcellist@gmail.com>
2019-04-08 02:47:56 -04:00
Uriel Mandujano
4821a94944 Removes failing symlink to /usr/bin/python3 during the image build
Installing the latest python36-setuptools automatically creates the symlink from python3 -> python3.6 and from python36 -> /usr/bin/python3.6. Building the images fails when the symlink is created explicitly in the AWX installer.

Signed-off-by: Uriel Mandujano <uriel.mandujano14@gmail.com>
2019-04-06 11:13:41 -05:00
Uriel Mandujano
97e030dd1f Revert "Removes failing symlink to /usr/bin/python3 because that file already exists"
This reverts commit 13fadd3838.
2019-04-06 11:10:35 -05:00
Ryan Petrello
dfd4cb55e5 add a unique UUID for identifying an AWX installation 2019-04-05 20:10:55 -04:00
Uriel Mandujano
13fadd3838 Removes failing symlink to /usr/bin/python3 because that file already exists 2019-04-05 16:53:20 -05:00
Jeff Byrnes
7b636a7566 Set up HTTPS w/ proper port & HTTP redirect
HTTPS is, by default, expected to be on port 443.

Also, with HSTS set, we need to be sure that users attempting to arrive
via HTTP are properly redirected to HTTPS.

This does so by:

* Setting up a 301 redirect for any URL to its HTTPS version
* Adjusting the internal port for HTTPS traffic to 8053
* Setting docker-compose to share port 443 → 8053
    - This is configurable via an inventory variable
2019-04-05 16:13:23 -04:00
Jeff Byrnes
28e3c63562 Add optional SSL cert to docker-compose install
In #3322, this mount was added, but only to the standalone
Docker install setup:

github.com/ansible/awx/pull/3322/files#diff-596e32ab54a52bfed763f8a639499fe0

This ensures that the SSL cert is loaded when using docker-compose,
which is the only Docker-based method available as of v4.0.0
2019-04-05 16:13:23 -04:00
AlanCoding
cca9de9a3e set default slice ct for special cases 2019-04-05 16:12:40 -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
AlanCoding
880341ac05 avoid slicing if the inventory only has 1 host 2019-04-05 15:28:29 -04:00
softwarefactory-project-zuul[bot]
e9f2fddc7f Merge pull request #3635 from ryanpetrello/i-am-so-smrt
fix a typo

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 18:57:16 +00:00
Ryan Petrello
a9a479a51b fix a typo 2019-04-05 14:28:39 -04:00
softwarefactory-project-zuul[bot]
ddcb7d4881 Merge pull request #3634 from ryanpetrello/dashboard-confessionals
fix a small bug related to failed inventory counts in the dashboard API

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 18:24:39 +00:00
Ryan Petrello
cd90ad2497 fix a small bug related to failed inventory counts in the dashboard API 2019-04-05 14:02:19 -04:00
softwarefactory-project-zuul[bot]
e3dfc6c796 Merge pull request #3596 from jbradberry/capture-isolated-command
Updated IsolatedManager to take a callback that captures the remote command

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 17:15:11 +00: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
softwarefactory-project-zuul[bot]
1a151ad63a Merge pull request #3587 from chrismeyersfsu/fix-pickup_insights_id_from_ansible_facts
pickup insights system_id from ansible facts

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 16:07:21 +00:00
Alex Corey
c0b882d6fb fixes progress bar 2019-04-05 12:01:04 -04:00
softwarefactory-project-zuul[bot]
4095a6c9d4 Merge pull request #3632 from ryanpetrello/duplicate-playbook-stdout
don't write playbook stdout to sys.stdout (it's duplicated in log files)

Reviewed-by: awxbot
             https://github.com/awxbot
2019-04-05 15:50:17 +00:00
softwarefactory-project-zuul[bot]
161fd9cde0 Merge pull request #3460 from vismay-golwala/project_admin_issue
Project admin manual SCM Type creation bug fix

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 15:43:49 +00:00
softwarefactory-project-zuul[bot]
dc77ddbc5b Merge pull request #3617 from mabashian/jt-enter-toggle
Prevent on/off toggles from getting inadvertently trigged by enter key presses

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 15:31:02 +00:00
Alex Corey
a42a1bfa17 Addresses PR feedback 2019-04-05 11:29:48 -04:00
Ryan Petrello
81fe923577 don't write playbook stdout to sys.stdout (it's duplicated in log files)
this instructs runner to _not_ write to stdout when we invoke
runner.interface.run(); AWX consumes/ingests this strictly as events
2019-04-05 11:20:34 -04:00
softwarefactory-project-zuul[bot]
3521c56baf Merge pull request #3608 from mabashian/host-filter-quotes
Prevents replacing encoded quotes while searching against host filter

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 15:14:29 +00:00
softwarefactory-project-zuul[bot]
dd609b8a7c Merge pull request #3622 from wenottingham/roleing-roleing-roleing
Adjust descriptions of RBAC roles for clarity.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 15:09:42 +00:00
softwarefactory-project-zuul[bot]
ef1a5c09b6 Merge pull request #3510 from jbradberry/errors-on-change-password
Use Django's own logic to invalidate sessions of users when changing passwords

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 14:54:20 +00:00
Keith Grant
89ecddf662 refactor OrganizationTeams/OrganizationTeamsList 2019-04-05 10:52:52 -04:00
mabashian
fa3a41f25b Refresh the page after pendo flag changes to make change effective immediately 2019-04-05 10:48:53 -04:00
Alex Corey
de55ec1688 Add alert for org. delete. 2019-04-05 10:48:51 -04:00
softwarefactory-project-zuul[bot]
50c7807483 Merge pull request #3628 from marshmalien/fix-org-user-linkout
Fix Organization User badge linkout

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 14:37:53 +00:00
chris meyers
531d97d3b3 pickup insights system_id from ansible facts
* Continue to pick up facts from scan_insights.py
* This PR adds the ability to pickup facts from
/etc/ansible/facts.d/insights.facts
* Log what transport the insights system_id was found via
2019-04-05 10:35:56 -04:00
softwarefactory-project-zuul[bot]
d4c69429db Merge pull request #3624 from ryanpetrello/iso-cleanup-path-changes
update periodic isolated cleanup to match the new paths post-runner

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-05 14:25:18 +00: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
Ryan Petrello
79d580d5b9 update periodic isolated cleanup to match the new paths post-runner 2019-04-05 09:43:27 -04:00
Marliana Lara
8302992a35 Fix Organization User badge linkout 2019-04-05 08:44:12 -04:00
softwarefactory-project-zuul[bot]
4f8b197b55 Merge pull request #3615 from ryanpetrello/platform-metrics
add some additional analytics metrics

Reviewed-by: Ryan Petrello
             https://github.com/ryanpetrello
2019-04-05 00:50:04 +00:00
Ryan Petrello
5a4a812c73 specify --forks on isolated health check calls
this requires ansible-runner 1.3.2
2019-04-04 20:12:14 -04:00
Ryan Petrello
5c5173956d add some additional analytics metrics 2019-04-04 20:10:54 -04:00
softwarefactory-project-zuul[bot]
2423d9df44 Merge pull request #3626 from ryanpetrello/no_ln_py3
fix busted CI

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-04 23:15:42 +00:00
Ryan Petrello
ce2fc1a9dd fix more py3 centos7 issues 2019-04-04 18:35:59 -04:00
Matthew Jones
fd3a423b07 The python 3.6 package seems to already make this symlink 2019-04-04 18:35:56 -04:00
Jeff Bradberry
c6643946c5 Capture the redacted credential env vars separately
and then make use of them specifically to make safe the env vars
coming back from an isolated node.  This will allow us to capture the
safed versions of custom credential values, but without potentially
clobbering normal env var values that vary between the controller and
the node.
2019-04-04 15:22:27 -04:00
softwarefactory-project-zuul[bot]
6b422d3bb7 Merge pull request #3619 from ansible/headless
headless option added

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-04 18:46:32 +00:00
Jeff Bradberry
3f6d3506c6 Change the artifact file convention for isolated nodes to 'command'
since that's what landed in the ansible-runner PR.
2019-04-04 14:25:50 -04:00
Daniel Sami
ac11b3782b headless profile 2019-04-04 14:17:53 -04:00
Bill Nottingham
cfdecd7297 Adjust descriptions of RBAC roles for clarity. 2019-04-04 14:08:30 -04:00
softwarefactory-project-zuul[bot]
5debfdf5e8 Merge pull request #3545 from chrismeyersfsu/fix-tower_header_on_insights_playbook_fetches
include tower header to insights on plan fetch

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-04 15:51:06 +00:00
softwarefactory-project-zuul[bot]
3f9fd3a3a8 Merge pull request #3618 from rooftopcellist/dashboard_sync_jobs
don't show implicit update jobs in dashboard

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-04 15:43:39 +00:00
Christian Adams
2493374d44 don't show implicit update jobs in dashboard 2019-04-04 11:04:27 -04:00
mabashian
7722f0ca08 Prevent on/off toggles from getting inadvertently trigged by enter key presses 2019-04-04 10:16:39 -04:00
softwarefactory-project-zuul[bot]
e3f10ebd65 Merge pull request #3501 from beeankha/timeout_upgrade
Upgrade Old Email Timeout Notifications

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-04 13:23:43 +00:00
Keith Grant
c2a223bbb4 delete unused method 2019-04-04 09:17:33 -04:00
softwarefactory-project-zuul[bot]
713b2c1bf2 Merge pull request #3603 from athenahealth/fix-some-docker-standalone-bits
Fix some docker standalone bits

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-04 13:11:44 +00:00
softwarefactory-project-zuul[bot]
00a9ae0e72 Merge pull request #3614 from AlexSCorey/2220-AdminBtnRBAC
Removes Add Organization Admin Button

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-04 13:03:43 +00:00
Alex Corey
6bcb471584 Removes Add Organization Admin Button 2019-04-04 08:13:40 -04:00
beeankha
f5ea595763 Enable timeout feature to remain functional after upgrade
Have the UI spinner fill with a default upon notification type change or
upgrade.
2019-04-03 19:06:11 -04:00
softwarefactory-project-zuul[bot]
1f1cb2bdac Merge pull request #3598 from rooftopcellist/index_event_expiry
add index for jobevent created

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 20:56:57 +00:00
mabashian
d9d3c5d15f Adds comment explaining logic following the split on empty string in splitFilterIntoTerms 2019-04-03 16:56:36 -04:00
mabashian
47d6e5c028 Prevents replacing encoded quotes while searching against host filter 2019-04-03 16:50:45 -04:00
Jeff Bradberry
467700e4bb Bring the check_callback back into the loop
but try to process it only once.
2019-04-03 16:04:07 -04:00
softwarefactory-project-zuul[bot]
cfa2eabb57 Merge pull request #3576 from marshmalien/feat-toolbar-sort-template-list
Add sort toolbar to template lists

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 19:32:38 +00:00
Jeff Bradberry
b4e508f72a Bring the check_callback call out of the loop
We shouldn't need to call it multiple times.
2019-04-03 15:12:29 -04:00
softwarefactory-project-zuul[bot]
2bda81661e Merge pull request #3592 from keithjgrant/code-mirror-fixes
Code Mirror: prevent console errors when CM parses invalid syntax

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 18:57:54 +00:00
Jeff Bradberry
b0f6d2214c Fix a typo: there is no method called check_callback on BaseTask 2019-04-03 14:57:02 -04:00
softwarefactory-project-zuul[bot]
c9bac0b51c Merge pull request #3594 from keithjgrant/407-job-launch-keyboard-nav
Job launch keyboard navigation improvements

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 18:51:24 +00:00
softwarefactory-project-zuul[bot]
487473f0d1 Merge pull request #3586 from AlanCoding/update_verbosity
Set ansible-inventory verbosity for Ansible 2.8

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 18:51:09 +00:00
Jeff Bradberry
4364e00117 Do the env vars redaction for isolated nodes on this side 2019-04-03 14:34:09 -04:00
Christian Adams
e033eb5aef add index for jobevent created 2019-04-03 14:27:22 -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
softwarefactory-project-zuul[bot]
bc169fe1cc Merge pull request #3572 from ansible/pagination-stuff
add pagination to user e2e

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 17:34:33 +00: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
softwarefactory-project-zuul[bot]
c15502e581 Merge pull request #3601 from ryanpetrello/isolated-newline-strip
fix a bug in isolated OpenSSH key syncing

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 16:18:33 +00:00
Daniel Sami
45d5999bc2 add pagination to user e2e
lint
2019-04-03 12:11:28 -04:00
Ryan Petrello
78cd1abbb2 fix a bug in isolated OpenSSH key syncing
OpenSSH keys _must_ end with a \n to be accepted by ssh-add; enforce
a newline if there isn't one
2019-04-03 11:53:45 -04:00
Jeff Byrnes
e0861fee3a Update INSTALL docs re: docker-compose prereqs
As it turns out, the docker-compose Python module is
required, and docker-py doesn’t cut it.

Even more confusing, docker-compose Python module installs
the docker Python module, which conflicts with docker-py. To
avoid this, there are additional docs to call this out.
2019-04-03 11:52:10 -04:00
Jeff Byrnes
cb806b1699 Set docker_compose_dir like other inventory vars
When docker-compose become the sole method for using
Docker directly, some of this was shifted around in ways that
are inconsistent with other elements.

This adjusts it so that:

* The inventory variable default is set like the others, and
is less confusing
* We no longer mention the Standalone Docker in inventory
* We format our INSTALL docs w/r/t this var
2019-04-03 11:52:10 -04:00
softwarefactory-project-zuul[bot]
15b80cdb1a Merge pull request #3574 from AlexSCorey/265-JTLaunchResponsivness
Wraps launch template buttons

Reviewed-by: Alex Corey <Alex.swansboro@gmail.com>
             https://github.com/AlexSCorey
2019-04-03 15:41:43 +00:00
softwarefactory-project-zuul[bot]
bf0f1f1496 Merge pull request #3546 from jlmitch5/fixLaunchButtonPositioning
move wf and jt form launch buttons to the left instead of the right

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 14:49:13 +00: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
dbe4417ac3 fix lint error 2019-04-03 08:59:14 -04:00
Alex Corey
c76e97cecf Wraps launch template buttons 2019-04-03 08:30:51 -04:00
softwarefactory-project-zuul[bot]
ce4e34eb28 Merge pull request #3597 from wenottingham/how-many-crypto-libs-does-one-cloud-stack-need
Don't use the `rsa` python lib.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-03 00:22:27 +00:00
Jeff Bradberry
32286a9d49 Change the artifact to also capture the actual envvars data 2019-04-02 17:10:26 -04:00
Bill Nottingham
ed0bb127e8 Don't use the rsa python lib. 2019-04-02 15:48:30 -04:00
Jeff Bradberry
cac48e7cfb Updated IsolatedManager to take a callback that captures the remote command 2019-04-02 15:40:56 -04:00
softwarefactory-project-zuul[bot]
96bd0f9d9e Merge pull request #3573 from AlanCoding/custom_empty_default
Change default to allow empty groups from custom sources

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-02 17:54:54 +00:00
Keith Grant
bc7472f3f1 remove unused parameter 2019-04-02 13:54:26 -04:00
Keith Grant
5b2f00b978 make Enter key navigate to next tab in launch modal 2019-04-02 13:26:31 -04:00
softwarefactory-project-zuul[bot]
3f73176ef2 Merge pull request #3098 from ansible/credential_plugins
Credential Plugins

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-02 16:19:00 +00:00
Jake McDermott
d987c6e3f7 mention usage with custom credential types in credential plugins doc 2019-04-02 11:24:59 -04:00
Jake McDermott
5d11400f6c replace unlinked fields before updating input sources
With credential type changes for linked credentials disabled, we can
update the unlinked credential fields first. If an error occurs when
updating the unlinked fields, no input sources will be changed.
2019-04-02 11:24:55 -04:00
Jake McDermott
6f43f223b2 update e2e credential checks 2019-04-02 11:24:52 -04:00
Jake McDermott
6b87241099 render non-editable linked credentials
We still want to show linked credentials even when a field is
non-editable.
2019-04-02 11:24:48 -04:00
Jake McDermott
0f6615d9cd make linked fields look disabled when disabled 2019-04-02 11:24:44 -04:00
Jake McDermott
9b55fa61de fix required field entry for object_query 2019-04-02 11:24:41 -04:00
Jake McDermott
165405ad3f include externally sourced input fields for injection 2019-04-02 11:24:36 -04:00
Jake McDermott
7ca92e4c1e prevent input source changes without use role on source cred
To update an input source, the user must have admin access
to the target credential and at least use role on the source
credential.
2019-04-02 11:24:32 -04:00
Jake McDermott
8c107a5fa8 prevent overflow in plugin test notifications 2019-04-02 11:24:14 -04:00
Jake McDermott
8b35ac89fc add timeouts to plugin backends 2019-04-02 11:24:11 -04:00
Jake McDermott
b90f9ac401 remove linked fields from validation loop
All linked fields are initially valid. All unlinked fields
are initially valid.
2019-04-02 11:24:07 -04:00
Jake McDermott
7a093de9fd add workaround for null cloud credential kind summary fields
job details summary field credentials have `null` for the
`kind` field so we can't map it to icon names. To work around
this, we now check the value of the `cloud` field when generating
the icon to use.
2019-04-02 11:24:04 -04:00
Jake McDermott
259fcdc5df don't initialize linked textarea fields as invalid 2019-04-02 11:24:00 -04:00
Jake McDermott
aa4575c92e update validation when input source is set 2019-04-02 11:23:57 -04:00
Jake McDermott
f0f4f487fb disable input source lookups when they can't be changed
If a user doesn't have permission to change an input field, we disable
the input field.
2019-04-02 11:23:53 -04:00
Jake McDermott
c4a79a778f add delete to input source user_capabilities 2019-04-02 11:23:50 -04:00
Jake McDermott
f611d4275f add use to credential user_capabilities 2019-04-02 11:23:46 -04:00
Jake McDermott
8c3dfe8655 remove input value arg from plugin example
The plugin backends no longer expect an input value as an argument
so we're removing it from the documented examples.
2019-04-02 11:23:42 -04:00
Jake McDermott
f9e081046c add object query fields 2019-04-02 11:23:39 -04:00
Jake McDermott
da9abc087e don't ignore choices param in input config
We always want to use choices if they're available in the input config
from the api. An input can sometimes have no type. Usually we'd throw an
error but we can still load a component if it defines a set of choices
to use instead of a type.
2019-04-02 11:23:35 -04:00
Jake McDermott
956f588fd8 generalize secret textarea hint 2019-04-02 11:23:28 -04:00
Jake McDermott
cb238c1f24 read cert from memory
Certificate data lives in the db. We're using a fifo here so we can avoid writing
it to disk when making the http request.
2019-04-02 11:23:24 -04:00
Jake McDermott
3dee9f0512 add plugin for cyberark aim 2019-04-02 11:23:20 -04:00
Jake McDermott
261a635005 remove non-matches from input source arrays 2019-04-02 11:23:17 -04:00
Jake McDermott
4f13592430 hide drag-and-drop textarea hints when showing input value as tag
You can't drag and drop or enter text when a text area is displaying its value
as a tag, so we hide the hint to avoid incorrectly suggesting that you can.
2019-04-02 11:23:13 -04:00
Jake McDermott
73c9d1b7a9 remove bootstrap fade from dialog component
This was breaking the fixed positioning of help popovers for form inputs
nested within the dialog so I'm replacing it.
2019-04-02 11:23:10 -04:00
Jake McDermott
8180a2060a rename at-easy-modal to at-dialog 2019-04-02 11:23:06 -04:00
Jake McDermott
dfaf19cdf3 use default action button class when fill and color props aren't given 2019-04-02 11:23:02 -04:00
Jake McDermott
ea9ed31f9d refactor metadata conversion function to use reduce 2019-04-02 11:22:59 -04:00
Jake McDermott
05226333ff move tag max height declaration to input tag wrapper
We don't want to apply max height to all tags, just the ones we embed
within text/textarea input fields.
2019-04-02 11:22:55 -04:00
Jake McDermott
5b79843390 use a shared variable for layout declarations 2019-04-02 11:22:51 -04:00
Jake McDermott
1eda939ce2 add tips for secret controls 2019-04-02 11:22:48 -04:00
Jake McDermott
43456d13c4 don't replace input source unless changed 2019-04-02 11:22:44 -04:00
Jake McDermott
215c3c87e5 enable input source linking for secret textarea fields 2019-04-02 11:22:41 -04:00
Jake McDermott
957804e22a enable input source linking for textarea fields 2019-04-02 11:22:37 -04:00
Jake McDermott
e14f17687c disable prompt-on-launch when input source is set 2019-04-02 11:22:34 -04:00
Jake McDermott
e0d61cfb8e enable input source linking for password fields 2019-04-02 11:22:30 -04:00
Jake McDermott
1344706095 add wrapper for text input tags 2019-04-02 11:22:27 -04:00
Jake McDermott
5c855b5bd1 add selected credential tray to input source lookup 2019-04-02 11:22:23 -04:00
Jake McDermott
6d0f2948aa don't show lookup until data is fetched 2019-04-02 11:22:20 -04:00
Jake McDermott
736bd2ed67 add validation for required values and metadata fields 2019-04-02 11:22:16 -04:00
Jake McDermott
47f31b41fb combine add and edit controllers 2019-04-02 11:22:12 -04:00
Jake McDermott
61eeb630f8 move org edit permission check to route resolve 2019-04-02 11:22:08 -04:00
Jake McDermott
7f55a1da0d move input value initialization to models 2019-04-02 11:22:05 -04:00
Jake McDermott
ceef7f57af add input source creation ui 2019-04-02 11:21:59 -04:00
Jake McDermott
393ad6b2f4 add cyberark conjur to tested credential types 2019-04-02 11:21:51 -04:00
Ryan Petrello
0768c6ac1d store the public key for HashiVault signing in the plugin metadata 2019-04-02 11:21:47 -04:00
Ryan Petrello
2824616ba6 add support for CyberArk Conjur (API v5) 2019-04-02 11:21:44 -04:00
Jake McDermott
c436dcf875 add input source prompting and plugin testing 2019-04-02 11:21:40 -04:00
Jake McDermott
0de8a89293 support input source metadata in plugin test apis 2019-04-02 11:21:36 -04:00
Ryan Petrello
81a509424a prefetch related source credentials in tasks.py 2019-04-02 11:21:33 -04:00
Ryan Petrello
42f4956a7f enforce required credential fields at job start time rather than on save
this is necessary for credential plugins support so that you can (in two
requests):

1.  Save a Credential with _no_ input values defined
2.  Create/associate one (or more) CredentialInputSource records to the
    new Credential
2019-04-02 11:21:29 -04:00
Jake McDermott
e2d474ddd2 document restriction of external-external credential source linking 2019-04-02 11:21:25 -04:00
Ryan Petrello
011d7eb892 clean up access to various CredentialInputSource fields (#3336) 2019-04-02 11:21:21 -04:00
Ryan Petrello
018ff91620 add related and summary fields to the CredentialInputSource endpoint 2019-04-02 11:21:17 -04:00
Ryan Petrello
368d933799 remove association behavior from /api/v2/credentials/input_sources/ 2019-04-02 11:21:14 -04:00
Jake McDermott
e9532dea8e cache dynamic input fields
Query dynamic input fields once on attribute access and then cache it for future use.
2019-04-02 11:21:10 -04:00
Ryan Petrello
b911f8bf77 allow creation at /api/v2/credential_input_sources 2019-04-02 11:21:06 -04:00
Ryan Petrello
e727909a61 rename the CredentialInputSource related_names so they're plural 2019-04-02 11:21:02 -04:00
Ryan Petrello
13366c1e75 Encrypt machine.ssh_public_key_data (in case users paste in signed data) 2019-04-02 11:20:58 -04:00
Ryan Petrello
ca6d124417 add API examples for supported credential plugins 2019-04-02 11:20:55 -04:00
Ryan Petrello
35cca68f04 add RBAC definitions for CredentialInputSource 2019-04-02 11:20:51 -04:00
Ryan Petrello
dcf17683e2 mark cred plugin strings for translation 2019-04-02 11:20:48 -04:00
Ryan Petrello
b851e2be4a don't add hvac as a dependency for hashicorp vault integration
hvac is just based on requests anyways, and it doesn't support half of
what we need (like the SSH secrets engine API)
2019-04-02 11:20:44 -04:00
Ryan Petrello
69368d874e move path parameterization to the CredentialInputSource model 2019-04-02 11:20:36 -04:00
Jake McDermott
0ee223f799 add api for testing credential plugins 2019-04-02 11:20:33 -04:00
Ryan Petrello
7a43f00a5d add support for HashiCorp signed SSH certificates 2019-04-02 11:20:29 -04:00
Ryan Petrello
4ed5bca5e3 add credential plugin support for Azure Key Vault 2019-04-02 11:20:26 -04:00
Ryan Petrello
0a87469225 give credential plugins an explicit namespace 2019-04-02 11:20:22 -04:00
Ryan Petrello
63997838cd support HashiCorp Vault versioned secrets (API v2) 2019-04-02 11:20:19 -04:00
Ryan Petrello
89b731a0cb Improve the HashiCorp Vault KV name and field labels/help_text 2019-04-02 11:20:15 -04:00
Ryan Petrello
9036ba492c switch CredentialInput creation to use the associate/disassociate view 2019-04-02 11:20:10 -04:00
Jake McDermott
d87144c4a7 add api for managing credential input sources 2019-04-02 11:19:56 -04:00
Jake McDermott
c209955400 add credential plugin system and minimal working hashivault 2019-04-02 11:19:26 -04:00
Keith Grant
e5f48bfa62 set focus on first input in modal when launching jt 2019-04-02 11:10:02 -04:00
softwarefactory-project-zuul[bot]
6e2c04e16c Merge pull request #3579 from ansible/revert-3575-update_preload_data
Revert "Add scm_branch while preloading data"

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-02 13:02:19 +00:00
softwarefactory-project-zuul[bot]
8f096d11b6 Merge pull request #3569 from ansible/inv_src_venv
Use inventory source model, as opposed to organization, for update custom virtualenv

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-02 12:16:50 +00:00
softwarefactory-project-zuul[bot]
b98bac0ee9 Merge pull request #3580 from ryanpetrello/py3-insights-error
fix a py3 compat issue in the insights action plugin

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-01 21:35:07 +00:00
Ryan Petrello
52a2ed2786 fix a py3 compat issue in the insights action plugin 2019-04-01 17:07:37 -04:00
Vismay Golwala
9710015a2f Revert "Add scm_branch while preloading data" 2019-04-01 16:56:19 -04:00
softwarefactory-project-zuul[bot]
b70c354dfc Merge pull request #3575 from vismay-golwala/update_preload_data
Add scm_branch while preloading data

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-01 20:39:46 +00:00
Keith Grant
e943ae59b7 auto-focus first input in jt launch modal 2019-04-01 15:49:41 -04:00
softwarefactory-project-zuul[bot]
6e8809fe72 Merge pull request #3528 from elyezer/e2e-users
Add auditor and admin params to user e2e

Reviewed-by: Elyézer Rezende
             https://github.com/elyezer
2019-04-01 19:30:39 +00:00
Elyézer Rezende
d2d1074e8b Add auditor and admin params to user e2e 2019-04-01 14:48:33 -04:00
softwarefactory-project-zuul[bot]
1bcda0a4cb Merge pull request #3529 from chrismeyersfsu/fix-inventory_update_deadlock
fixes inventory update deadlock

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-01 18:05:36 +00:00
Marliana Lara
4e4afb4a98 Add sorting to all occurrences of the Template list 2019-04-01 13:44:24 -04:00
AlanCoding
750c8d8a6d Set ansible-inventory verbosity for Ansible 2.8 2019-04-01 13:39:20 -04:00
Vismay Golwala
74e264a6a5 Add scm_branch while preloading data
Currently, the SCM url for default project is not able to
fetch playbooks as branch is not specified. So, adding the
scm_branch value resolves this issue.

Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-04-01 11:53:34 -04:00
softwarefactory-project-zuul[bot]
c508dc7d83 Merge pull request #3564 from wenottingham/paranormal-activity-stream
Management jobs don't produce activity stream entries; don't try and show them

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-04-01 15:23:35 +00:00
AlanCoding
ea355f6f8f change default to allow empty groups from custom sources 2019-04-01 10:53:06 -04:00
Keith Grant
95f5315fa3 prevent console errors when code mirror parses invalid syntax 2019-04-01 08:16:19 -04:00
mabashian
e99e97bcb8 Adds support for custom_virutalenv on inventory sources in the UI 2019-03-31 13:45:24 -04:00
softwarefactory-project-zuul[bot]
7b16931658 Merge pull request #2736 from AlanCoding/logstash_removal
Remove python-logstash dependency

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-31 02:35:45 +00:00
softwarefactory-project-zuul[bot]
e395b87a1b Merge pull request #3559 from chrismeyersfsu/fix-isolated_fact_cache
process host facts for iso runs

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 20:44:04 +00:00
chris meyers
71fcb1a82c process host facts for iso runs
* Move isolated clean to our final run hook
* ISO and non-iso code path now share the post-fact-processing code
2019-03-29 16:16:22 -04:00
softwarefactory-project-zuul[bot]
21e5179a84 Merge pull request #3563 from shanemcd/secret-secret
Move secret key from configmap to secret

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 19:47:26 +00:00
Shane McDonald
298eaa0b32 Move secret key from configmap to secret 2019-03-29 15:24:50 -04:00
Bill Nottingham
17c0293065 Management jobs don't produce activity stream entries; don't try and show them. 2019-03-29 15:21:22 -04:00
AlanCoding
6f150f0362 Set inv src custom virtualenv directly on model 2019-03-29 14:37:28 -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
softwarefactory-project-zuul[bot]
71718ee2eb Merge pull request #3558 from ryanpetrello/index-job-status
index unified_job.status

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 18:14:53 +00:00
Keith Grant
40b88da9dd add FormRow component; rename unwrapped components with underscore 2019-03-29 13:50:17 -04:00
Ryan Petrello
7ef68a03c6 index unified_job.status
this is a fairly importantj column that we join on for a number of
queries throughout AWX, particularly the task scheduler and analytics
2019-03-29 12:59:43 -04:00
softwarefactory-project-zuul[bot]
bf3473d394 Merge pull request #3552 from ryanpetrello/final-isolated-cleanup
move awx.main.expect to awx.main.isolated

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 16:57:02 +00:00
softwarefactory-project-zuul[bot]
eab9ee5128 Merge pull request #3514 from AlanCoding/azure_huzzah
Enable azure_rm inventory plugin

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 16:41:16 +00:00
Ryan Petrello
563a0cc2a4 move awx.main.expect to awx.main.isolated 2019-03-29 12:14:40 -04:00
softwarefactory-project-zuul[bot]
3007b9c66a Merge pull request #3518 from jbradberry/isolated-heartbeat
Make use of user-defined settings for defining the isolated nodes heartbeat

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 15:15:49 +00:00
softwarefactory-project-zuul[bot]
a4ec149344 Merge pull request #3555 from ryanpetrello/even-more-iso-fixes
fix a variety of bugs in isolated support

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 15:13:23 +00:00
Ryan Petrello
a59bc33280 slightly refactor isolated event consumption 2019-03-29 10:48:42 -04:00
Ryan Petrello
8f089c02a5 fix some faulty logic in isolated syncs that caused SSH keys to not work 2019-03-29 10:32:24 -04:00
Ryan Petrello
d663d397f8 clean up some isolated adhoc code
if it's adhoc, there's not project directory to copy
2019-03-29 10:31:56 -04:00
Ryan Petrello
546281d435 work around a bug where runner doesn't provide atomic event writes 2019-03-29 10:31:12 -04:00
softwarefactory-project-zuul[bot]
4e01b11577 Merge pull request #3503 from kialam/fix-3421-wf-viz-popover
Format jt details for popover use.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 13:59:07 +00:00
Kia Lam
d25f1d1357 Format jt details for popover use. 2019-03-29 09:22:15 -04:00
softwarefactory-project-zuul[bot]
2ab290ff2d Merge pull request #3534 from ryanpetrello/iso-pexpect-cleanup
replace our usage of pexpect in IsolatedManager with ansible-runner

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-29 13:17:05 +00:00
softwarefactory-project-zuul[bot]
ef88507d23 Merge pull request #3543 from AlanCoding/do_not_transform
Set Ansible name transform setting for built-in sources

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-28 23:47:56 +00:00
softwarefactory-project-zuul[bot]
df9a012013 Merge pull request #3284 from ansible/analytics
Analytics

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-28 22:40:18 +00:00
Ryan Petrello
9160d91278 clean up old usage of idle_timeout
cmeyers and I looked at this and can't tell where/why/how you'd actually
set this setting - it looks like really old ~2014-2015 Tower history
that probably isn't actually in use
2019-03-28 17:31:32 -04:00
Ryan Petrello
ab11f18957 send an EOF event if isolated dispatch fails 2019-03-28 16:48:52 -04:00
Keith Grant
2002d48bcc minor tweaks 2019-03-28 16:44:44 -04:00
Ryan Petrello
ea30547754 remove main.expect tests (this functionality exists in runner now) 2019-03-28 16:13:14 -04:00
Christian Adams
4a0778a3d5 exclude implicit project updates 2019-03-28 16:12:30 -04:00
softwarefactory-project-zuul[bot]
1270949909 Merge pull request #3539 from AlanCoding/gce_huzzah
Use option to add back in gce_image hostvar

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
2019-03-28 18:37:59 +00:00
AlanCoding
180396b5df Use option to add back in gce_image hostvar
construct groups from this gce image hostvar
2019-03-28 14:14:44 -04:00
softwarefactory-project-zuul[bot]
504b17b474 Merge pull request #3540 from ansible/ci-repairs
ci adjustments

Reviewed-by: Jake McDermott <yo@jakemcdermott.me>
             https://github.com/jakemcdermott
2019-03-28 17:52:02 +00:00
Keith Grant
6353d5e410 update tests for org add/edit refactor 2019-03-28 13:02:04 -04:00
Ryan Petrello
dd81f59d9a set PYTHONPATH properly for isolated usage of runner 2019-03-28 12:40:21 -04:00
Ryan Petrello
99478f5d25 replace our usage of pexpect in IsolatedManager with ansible-runner 2019-03-28 12:40:21 -04:00
John Mitchell
b3ad12f31a move wf and jt form launch buttons to the left instead of the right 2019-03-28 11:32:12 -04:00
chris meyers
926d6a6525 include tower header to insights on plan fetch
* We include a special header value in the user agent when tower proxies
requests to get per-host rules.
* This extends that header logic to when we fetch plans (playbooks)
2019-03-28 10:56:56 -04:00
John Mitchell
cc0fd6beb6 fix openDeleteModal with button test 2019-03-28 10:42:17 -04:00
AlanCoding
e84642b4a1 Set Ansible name transform setting for built-in sources
This is the current default but will change in the future
for these sources, we do not want behavior change
2019-03-28 10:37:36 -04:00
Alex Corey
f3a07753e6 Add alert for org. delete. 2019-03-28 10:29:55 -04:00
Daniel Sami
ef3c0cfb38 ci adjustments
lint
2019-03-28 09:52:43 -04:00
Christian Adams
9a4439e731 collect jt table for analytics 2019-03-28 00:58:18 -04:00
Christian Adams
c481919a49 check for open license 2019-03-27 19:54:25 -04:00
Christian Adams
58f0e42bd6 update setting wording & add instance-enabled field 2019-03-27 19:54:25 -04:00
John Mitchell
70af2dd66b add ui for insights enablement 2019-03-27 19:54:25 -04:00
Christian Adams
40dbe70854 update setting wording & add instance-enabled field 2019-03-27 19:53:00 -04:00
Christian Adams
a7368cec43 add copy events table and remove events queries
add copy unifiedjob table, futher optimization, rm since from job_instance queries
2019-03-27 19:53:00 -04:00
Christian Adams
636153d92c add insights setting, optimize and consolidate queries 2019-03-27 19:53:00 -04:00
Christian Adams
ae9377e0e4 add basic job & JT analytics 2019-03-27 19:53:00 -04:00
Ryan Petrello
c586fa9821 add a minimal framework for generating analytics/metrics
annotate queries & add license analytics
2019-03-27 19:53:00 -04:00
chris meyers
cb4d55b47a fixes inventory update deadlock
* all inventory updates continue to occur in parallel up to the point
that they update the database with their results.
* the "funnel" is achieved by using a global per-inventory postgres
named lock
2019-03-27 16:52:07 -04:00
Keith Grant
64e933acb4 refactor out OrganizationForm; share between add & edit 2019-03-27 15:29:46 -04:00
Jeff Bradberry
e398a0ac5e Remove the isolated_heartbeat setup from settings/defaults.py 2019-03-27 14:12:42 -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
Jeff Bradberry
bc6df9cab8 Make use of user-defined settings for defining the isolated nodes heartbeat
Just in case the user has created custom settings files which set
AWX_ISOLATED_PERIODIC_CHECK.
2019-03-27 10:47:38 -04:00
Jeff Bradberry
efb4fb6fd0 Remove some no longer used imports 2019-03-27 10:06:13 -04:00
Jeff Bradberry
f2be4de544 Use Django's own logic to invalidate sessions of users when changing passwords
The key is django.contrib.auth.update_session_auth_hash(), which knows
how to inject a recalculated session hash back into the session if the
requesting user is changing their own password, in order to keep that
user logged in.
2019-03-27 10:06:13 -04:00
AlanCoding
73f16b2bee Enable azure_rm inventory plugin 2019-03-27 09:27: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
mabashian
b394766075 Show manual project path when available 2019-03-21 10:45:16 -04:00
Vismay Golwala
df11a7fd3d Project admin manual SCM Type creation bug fix
There was a bug in tower where project admin was not allowed to create
a project with manual SCM type. This was because, the project base dir
was only set from `settings.PROJECTS_ROOT`, if the user role was either
admin or auditor. This has been updated by also allowing it to set when
user is a project admin.

Signed-off-by: Vismay Golwala <vgolwala@redhat.com>
2019-03-20 16:01:33 -04:00
AlanCoding
1ae4ed4922 migrate python-logstash license 2019-03-20 15:29:06 -04:00
AlanCoding
8a72a4d39d Prune the python2 specific logic from log formatter 2019-03-20 15:29:06 -04:00
AlanCoding
127495b53d remove things from base class that were never used 2019-03-20 15:29:05 -04:00
AlanCoding
017d367749 Remove dependency and insert class 2019-03-20 15:29:05 -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
976 changed files with 56556 additions and 13114 deletions

View File

@@ -1,6 +0,0 @@
[mini_dinstall]
fqdn = localhost
method = local
incoming = FIXME/deb-repo/mini-dinstall/incoming
run_dinstall = 0
post_upload_command = mini-dinstall -b -v

View File

@@ -1,20 +0,0 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[Makefile]
indent_style = tab
[**.py]
indent_style = space
indent_size = 4
[**.{js,less,html}]
indent_style = space
indent_size = 4
[**.{json}]
indent_style = space
indent_size = 2

1
.env
View File

@@ -1,2 +1,3 @@
PYTHONUNBUFFERED=true
SELENIUM_DOCKER_TAG=latest

View File

@@ -7,12 +7,6 @@ about: Create a report to help us improve
##### ISSUE TYPE
- Bug Report
##### COMPONENT NAME
<!-- Pick the area of AWX for this issue, you can have multiple, delete the rest: -->
- API
- UI
- Installer
##### SUMMARY
<!-- Briefly describe the problem. -->

View File

@@ -7,16 +7,5 @@ about: Suggest an idea for this project
##### ISSUE TYPE
- Feature Idea
##### COMPONENT NAME
<!-- Pick the area of AWX for this issue, you can have multiple, delete the rest: -->
- API
- UI
- Installer
##### SUMMARY
<!-- Briefly describe the problem or desired enhancement. -->
##### ADDITIONAL INFORMATION
<!-- Include any links to sosreport, database dumps, screenshots or other
information. -->

5
.gitignore vendored
View File

@@ -8,6 +8,7 @@ reference-schema.json
.tags1
# Tower
awx-dev
awx/settings/local_*.py*
awx/*.sqlite3
awx/*.sqlite3_*
@@ -27,8 +28,12 @@ awx/ui/build_test
awx/ui/client/languages
awx/ui/templates/ui/index.html
awx/ui/templates/ui/installing.html
awx/ui_next/node_modules/
awx/ui_next/coverage/
awx/ui_next/build/locales/_build
/tower-license
/tower-license/**
tools/prometheus/data
# Tower setup playbook testing
setup/test/roles/postgresql

View File

@@ -1,16 +0,0 @@
[DEFAULT]
archivedir = FIXME/deb-repo
mail_to =
verify_sigs = false
architectures = all, amd64
archive_style = flat
generate_release = true
mail_on_success = false
release_codename = ansible-tower
release_description = Ansible Tower
release_label = ansible-tower
release_origin = ansible-tower
[trusty]
[precise]

View File

@@ -1,6 +0,0 @@
[MASTER]
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=site-packages,ui,migrations,data

View File

@@ -59,10 +59,13 @@ Before you can run a deployment, you'll need the following installed in your loc
- [Ansible](http://docs.ansible.com/ansible/latest/intro_installation.html) Requires Version 2.4+
- [Docker](https://docs.docker.com/engine/installation/)
- [docker-py](https://github.com/docker/docker-py) Python module
+ A recent version
- [docker](https://pypi.org/project/docker/) Python module
+ This is incompatible with `docker-py`. If you have previously installed `docker-py`, please uninstall it.
+ We use this module instead of `docker-py` because it is what the `docker-compose` Python module requires.
- [GNU Make](https://www.gnu.org/software/make/)
- [Git](https://git-scm.com/) Requires Version 1.8.4+
- [Node 8.x LTS version](https://nodejs.org/en/download/)
- [Node 10.x LTS version](https://nodejs.org/en/download/)
- [NPM 6.x LTS](https://docs.npmjs.com/)
### System Requirements
@@ -81,7 +84,7 @@ The system that runs the AWX service will need to satisfy the following requirem
### Choose a deployment platform
We currently support running AWX as a containerized application using Docker images deployed to either an OpenShift cluster or docker-compose. The remainder of this document will walk you through the process of building the images, and deploying them to either platform.
We currently support running AWX as a containerized application using Docker images deployed to either an OpenShift cluster, a Kubernetes cluster, or docker-compose. The remainder of this document will walk you through the process of building the images, and deploying them to either platform.
The [installer](./installer) directory contains an [inventory](./installer/inventory) file, and a playbook, [install.yml](./installer/install.yml). You'll begin by setting variables in the inventory file according to the platform you wish to use, and then you'll start the image build and deployment process by running the playbook.
@@ -396,7 +399,8 @@ Unlike Openshift's `Route` the Kubernetes `Ingress` doesn't yet handle SSL termi
### Prerequisites
- [Docker](https://docs.docker.com/engine/installation/) on the host where AWX will be deployed. After installing Docker, the Docker service must be started (depending on your OS, you may have to add the local user that uses Docker to the ``docker`` group, refer to the documentation for details)
- [docker-py](https://github.com/docker/docker-py) Python module.
- [docker-compose](https://pypi.org/project/docker-compose/) Python module.
+ This also installs the `docker` Python module, which is incompatible with `docker-py`. If you have previously installed `docker-py`, please uninstall it.
- [Docker Compose](https://docs.docker.com/compose/install/).
### Pre-build steps
@@ -440,13 +444,17 @@ Before starting the build process, review the [inventory](./installer/inventory)
> Provide a port number that can be mapped from the Docker daemon host to the web server running inside the AWX container. Defaults to *80*.
*host_port_ssl*
> Provide a port number that can be mapped from the Docker daemon host to the web server running inside the AWX container for SSL support. Defaults to *443*, only works if you also set `ssl_certificate` (see below).
*ssl_certificate*
> Optionally, provide the path to a file that contains a certificate and its private key.
*docker_compose_dir*
When using docker-compose, the `docker-compose.yml` file will be created there (default `/tmp/awxcompose`).
> When using docker-compose, the `docker-compose.yml` file will be created there (default `/tmp/awxcompose`).
*ca_trust_dir*

View File

@@ -60,7 +60,7 @@ I18N_FLAG_FILE = .i18n_built
.PHONY: awx-link clean clean-tmp clean-venv requirements requirements_dev \
develop refresh adduser migrate dbchange dbshell runserver \
receiver test test_unit test_ansible test_coverage coverage_html \
receiver test test_unit test_coverage coverage_html \
dev_build release_build release_clean sdist \
ui-docker-machine ui-docker ui-release ui-devel \
ui-test ui-deps ui-test-ci VERSION
@@ -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)
@@ -218,7 +221,7 @@ init:
if [ "$(AWX_GROUP_QUEUES)" == "tower,thepentagon" ]; then \
$(MANAGEMENT_COMMAND) provision_instance --hostname=isolated; \
$(MANAGEMENT_COMMAND) register_queue --queuename='thepentagon' --hostnames=isolated --controller=tower; \
$(MANAGEMENT_COMMAND) generate_isolated_key > /awx_devel/awx/main/expect/authorized_keys; \
$(MANAGEMENT_COMMAND) generate_isolated_key > /awx_devel/awx/main/isolated/authorized_keys; \
fi;
# Refresh development environment after pulling new code.
@@ -269,15 +272,7 @@ supervisor:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
supervisord --pidfile=/tmp/supervisor_pid
# Alternate approach to tmux to run all development tasks specified in
# Procfile.
honcho:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
honcho start -f tools/docker-compose/Procfile
supervisord --pidfile=/tmp/supervisor_pid -n
collectstatic:
@if [ "$(VENV_BASE)" ]; then \
@@ -289,7 +284,7 @@ uwsgi: collectstatic
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
uwsgi -b 32768 --socket 127.0.0.1:8050 --module=awx.wsgi:application --home=/venv/awx --chdir=/awx_devel/ --vacuum --processes=5 --harakiri=120 --master --no-orphans --py-autoreload 1 --max-requests=1000 --stats /tmp/stats.socket --lazy-apps --logformat "%(addr) %(method) %(uri) - %(proto) %(status)" --hook-accepting1-once="exec:awx-manage run_dispatcher --reload"
uwsgi -b 32768 --socket 127.0.0.1:8050 --module=awx.wsgi:application --home=/venv/awx --chdir=/awx_devel/ --vacuum --processes=5 --harakiri=120 --master --no-orphans --py-autoreload 1 --max-requests=1000 --stats /tmp/stats.socket --lazy-apps --logformat "%(addr) %(method) %(uri) - %(proto) %(status)" --hook-accepting1="exec:supervisorctl restart tower-processes:awx-dispatcher tower-processes:awx-receiver"
daphne:
@if [ "$(VENV_BASE)" ]; then \
@@ -353,7 +348,8 @@ pylint: reports
@(set -o pipefail && $@ | reports/$@.report)
genschema: reports
$(MAKE) swagger PYTEST_ARGS="--genschema"
$(MAKE) swagger PYTEST_ARGS="--genschema --create-db "
mv swagger.json schema.json
swagger: reports
@if [ "$(VENV_BASE)" ]; then \
@@ -378,20 +374,12 @@ test:
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS)
awx-manage check_migrations --dry-run --check -n 'vNNN_missing_migration_file'
test_combined: test_ansible test
test_unit:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
py.test awx/main/tests/unit awx/conf/tests/unit awx/sso/tests/unit
test_ansible:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/ansible/bin/activate; \
fi; \
py.test awx/lib/tests -c awx/lib/tests/pytest.ini
# Run all API unit tests with coverage enabled.
test_coverage:
@if [ "$(VENV_BASE)" ]; then \
@@ -512,6 +500,10 @@ ui-devel: $(UI_DEPS_FLAG_FILE)
ui-test: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run test
ui-lint: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) run --prefix awx/ui jshint
$(NPM_BIN) run --prefix awx/ui lint
# A standard go-to target for API developers to use building the frontend
ui: clean-ui ui-devel
@@ -526,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
@@ -562,21 +569,22 @@ docker-auth:
fi;
# Docker isolated rampart
docker-isolated:
TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml -f tools/docker-isolated-override.yml create
docker start tools_awx_1
docker start tools_isolated_1
docker-compose-isolated:
CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml -f tools/docker-isolated-override.yml up
# Docker Compose Development environment
docker-compose: docker-auth
CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml up --no-recreate awx
CURRENT_UID=$(shell id -u) OS="$(shell docker info | grep 'Operating System')" TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml up --no-recreate awx
docker-compose-cluster: docker-auth
CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose-cluster.yml up
docker-compose-credential-plugins: docker-auth
echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m"
CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose.yml -f tools/docker-credential-plugins-override.yml up --no-recreate awx
docker-compose-test: docker-auth
cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /bin/bash
cd tools && CURRENT_UID=$(shell id -u) OS="$(shell docker info | grep 'Operating System')" TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /bin/bash
docker-compose-runtest:
cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /start_tests.sh
@@ -584,12 +592,7 @@ docker-compose-runtest:
docker-compose-build-swagger:
cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /start_tests.sh swagger
docker-compose-genschema:
cd tools && CURRENT_UID=$(shell id -u) TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose run --rm --service-ports awx /start_tests.sh genschema
mv swagger.json schema.json
docker-compose-detect-schema-change:
$(MAKE) docker-compose-genschema
detect-schema-change: genschema
curl https://s3.amazonaws.com/awx-public-ci-files/schema.json -o reference-schema.json
# Ignore differences in whitespace with -b
diff -u -b reference-schema.json schema.json
@@ -602,12 +605,14 @@ docker-compose-build: awx-devel-build
# Base development image build
awx-devel-build:
docker build -t ansible/awx_devel -f tools/docker-compose/Dockerfile .
docker build -t ansible/awx_devel -f tools/docker-compose/Dockerfile \
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:devel \
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) .
docker tag ansible/awx_devel $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
#docker push $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
# For use when developing on "isolated" AWX deployments
awx-isolated-build:
docker-compose-isolated-build: awx-devel-build
docker build -t ansible/awx_isolated -f tools/docker-isolated/Dockerfile .
docker tag ansible/awx_isolated $(DEV_DOCKER_TAG_BASE)/awx_isolated:$(COMPOSE_TAG)
#docker push $(DEV_DOCKER_TAG_BASE)/awx_isolated:$(COMPOSE_TAG)
@@ -627,6 +632,9 @@ docker-compose-elk: docker-auth
docker-compose-cluster-elk: docker-auth
TAG=$(COMPOSE_TAG) DEV_DOCKER_TAG_BASE=$(DEV_DOCKER_TAG_BASE) docker-compose -f tools/docker-compose-cluster.yml -f tools/elastic/docker-compose.logstash-link-cluster.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
prometheus:
docker run -u0 --net=tools_default --link=`docker ps | egrep -o "tools_awx(_run)?_([^ ]+)?"`:awxweb --volume `pwd`/tools/prometheus:/prometheus --name prometheus -d -p 0.0.0.0:9090:9090 prom/prometheus --web.enable-lifecycle --config.file=/prometheus/prometheus.yml
minishift-dev:
ansible-playbook -i localhost, -e devtree_directory=$(CURDIR) tools/clusterdevel/start_minishift_dev.yml

View File

@@ -1 +1 @@
4.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.16':
raise RuntimeError("Django version other than 1.11.16 detected {}. \
Subclassing BaseDatabaseSchemaEditor is known to work for Django 1.11.16 \
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

@@ -24,20 +24,6 @@ from rest_framework.filters import BaseFilterBackend
# AWX
from awx.main.utils import get_type_for_model, to_python_boolean
from awx.main.utils.db import get_all_field_names
from awx.main.models.credential import CredentialType
class V1CredentialFilterBackend(BaseFilterBackend):
'''
For /api/v1/ requests, filter out v2 (custom) credentials
'''
def filter_queryset(self, request, queryset, view):
# TODO: remove in 3.3
from awx.api.versioning import get_request_version
if get_request_version(request) == 1:
queryset = queryset.filter(credential_type__managed_by_tower=True)
return queryset
class TypeFilterBackend(BaseFilterBackend):
@@ -223,7 +209,7 @@ class FieldLookupBackend(BaseFilterBackend):
raise ValueError('%s is not searchable' % new_lookup[:-8])
new_lookups = []
for rm_field in related_model._meta.fields:
if rm_field.name in ('username', 'first_name', 'last_name', 'email', 'name', 'description'):
if rm_field.name in ('username', 'first_name', 'last_name', 'email', 'name', 'description', 'playbook'):
new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name))
return value, new_lookups
else:
@@ -292,39 +278,6 @@ class FieldLookupBackend(BaseFilterBackend):
key = key[5:]
q_not = True
# Make legacy v1 Job/Template fields work for backwards compatability
# TODO: remove after API v1 deprecation period
if queryset.model._meta.object_name in ('JobTemplate', 'Job') and key in (
'credential', 'vault_credential', 'cloud_credential', 'network_credential'
) or queryset.model._meta.object_name in ('InventorySource', 'InventoryUpdate') and key == 'credential':
key = 'credentials'
# Make legacy v1 Credential fields work for backwards compatability
# TODO: remove after API v1 deprecation period
#
# convert v1 `Credential.kind` queries to `Credential.credential_type__pk`
if queryset.model._meta.object_name == 'Credential' and key == 'kind':
key = key.replace('kind', 'credential_type')
if 'ssh' in values:
# In 3.2, SSH and Vault became separate credential types, but in the v1 API,
# they're both still "kind=ssh"
# under the hood, convert `/api/v1/credentials/?kind=ssh` to
# `/api/v1/credentials/?or__credential_type=<ssh_pk>&or__credential_type=<vault_pk>`
values = set(values)
values.add('vault')
values = list(values)
q_or = True
for i, kind in enumerate(values):
if kind == 'vault':
type_ = CredentialType.objects.get(kind=kind)
else:
type_ = CredentialType.from_v1_kind(kind)
if type_ is None:
raise ParseError(_('cannot filter on kind %s') % kind)
values[i] = type_.pk
# Convert value(s) to python and add to the appropriate list.
for value in values:
if q_int:
@@ -402,6 +355,8 @@ class OrderByBackend(BaseFilterBackend):
order_by = value.split(',')
else:
order_by = (value,)
if order_by is None:
order_by = self.get_default_ordering(view)
if order_by:
order_by = self._validate_ordering_fields(queryset.model, order_by)
@@ -428,6 +383,12 @@ class OrderByBackend(BaseFilterBackend):
# Return a 400 for invalid field names.
raise ParseError(*e.args)
def get_default_ordering(self, view):
ordering = getattr(view, 'ordering', None)
if isinstance(ordering, str):
return (ordering,)
return ordering
def _validate_ordering_fields(self, model, order_by):
for field_name in order_by:
# strip off the negation prefix `-` if it exists

View File

@@ -34,7 +34,7 @@ from rest_framework.negotiation import DefaultContentNegotiation
# AWX
from awx.api.filters import FieldLookupBackend
from awx.main.models import (
UnifiedJob, UnifiedJobTemplate, User, Role
UnifiedJob, UnifiedJobTemplate, User, Role, Credential
)
from awx.main.access import access_registry
from awx.main.utils import (
@@ -46,7 +46,7 @@ from awx.main.utils import (
)
from awx.main.utils.db import get_all_field_names
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
from awx.api.versioning import URLPathVersioning, get_request_version
from awx.api.versioning import URLPathVersioning
from awx.api.metadata import SublistAttachDetatchMetadata, Metadata
__all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
@@ -119,39 +119,12 @@ class LoggedLogoutView(auth_views.LogoutView):
return ret
def get_view_name(cls, suffix=None):
'''
Wrapper around REST framework get_view_name() to support get_name() method
and view_name property on a view class.
'''
name = ''
if hasattr(cls, 'get_name') and callable(cls.get_name):
name = cls().get_name()
elif hasattr(cls, 'view_name'):
if callable(cls.view_name):
name = cls.view_name()
else:
name = cls.view_name
if name:
return ('%s %s' % (name, suffix)) if suffix else name
return views.get_view_name(cls, suffix=None)
def get_view_description(view, html=False):
'''Wrapper around REST framework get_view_description() to continue
to support our historical div.
def get_view_description(cls, request, html=False):
'''
Wrapper around REST framework get_view_description() to support
get_description() method and view_description property on a view class.
'''
if hasattr(cls, 'get_description') and callable(cls.get_description):
desc = cls().get_description(request, html=html)
cls = type(cls.__name__, (object,), {'__doc__': desc})
elif hasattr(cls, 'view_description'):
if callable(cls.view_description):
view_desc = cls.view_description()
else:
view_desc = cls.view_description
cls = type(cls.__name__, (object,), {'__doc__': view_desc})
desc = views.get_view_description(cls, html=html)
desc = views.get_view_description(view, html=html)
if html:
desc = '<div class="description">%s</div>' % desc
return mark_safe(desc)
@@ -264,14 +237,6 @@ class APIView(views.APIView):
# `curl https://user:pass@tower.example.org/api/v2/job_templates/N/launch/`
return 'Bearer realm=api authorization_url=/api/o/authorize/'
def get_view_description(self, html=False):
"""
Return some descriptive text for the view, as used in OPTIONS responses
and in the browsable API.
"""
func = self.settings.VIEW_DESCRIPTION_FUNCTION
return func(self.__class__, getattr(self, '_request', None), html)
def get_description_context(self):
return {
'view': self,
@@ -280,20 +245,14 @@ class APIView(views.APIView):
'swagger_method': getattr(self.request, 'swagger_method', None),
}
def get_description(self, request, html=False):
self.request = request
@property
def description(self):
template_list = []
for klass in inspect.getmro(type(self)):
template_basename = camelcase_to_underscore(klass.__name__)
template_list.append('api/%s.md' % template_basename)
context = self.get_description_context()
# "v2" -> 2
default_version = int(settings.REST_FRAMEWORK['DEFAULT_VERSION'].lstrip('v'))
request_version = get_request_version(self.request)
if request_version is not None and request_version < default_version:
context['deprecated'] = True
description = render_to_string(template_list, context)
if context.get('deprecated') and context.get('swagger_method') is None:
# render deprecation messages at the very top
@@ -389,12 +348,14 @@ class GenericAPIView(generics.GenericAPIView, APIView):
'model_verbose_name_plural': smart_text(self.model._meta.verbose_name_plural),
})
serializer = self.get_serializer()
metadata = self.metadata_class()
metadata.request = self.request
for method, key in [
('GET', 'serializer_fields'),
('POST', 'serializer_create_fields'),
('PUT', 'serializer_update_fields')
]:
d[key] = self.metadata_class().get_serializer_info(serializer, method=method)
d[key] = metadata.get_serializer_info(serializer, method=method)
d['settings'] = settings
return d
@@ -440,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':
@@ -815,6 +776,7 @@ class RetrieveUpdateDestroyAPIView(RetrieveUpdateAPIView, DestroyAPIView):
class ResourceAccessList(ParentMixin, ListAPIView):
serializer_class = ResourceAccessListElementSerializer
ordering = ('username',)
def get_queryset(self):
obj = self.get_parent_object()
@@ -841,10 +803,6 @@ class CopyAPIView(GenericAPIView):
new_in_330 = True
new_in_api_v2 = True
def v1_not_allowed(self):
return Response({'detail': 'Action only possible starting with v2 API.'},
status=status.HTTP_404_NOT_FOUND)
def _get_copy_return_serializer(self, *args, **kwargs):
if not self.copy_return_serializer_class:
return self.get_serializer(*args, **kwargs)
@@ -858,15 +816,15 @@ class CopyAPIView(GenericAPIView):
def _decrypt_model_field_if_needed(obj, field_name, field_val):
if field_name in getattr(type(obj), 'REENCRYPTION_BLACKLIST_AT_COPY', []):
return field_val
if isinstance(field_val, dict):
if isinstance(obj, Credential) and field_name == 'inputs':
for secret in obj.credential_type.secret_fields:
if secret in field_val:
field_val[secret] = decrypt_field(obj, secret)
elif isinstance(field_val, dict):
for sub_field in field_val:
if isinstance(sub_field, str) \
and isinstance(field_val[sub_field], str):
try:
field_val[sub_field] = decrypt_field(obj, field_name, sub_field)
except AttributeError:
# Catching the corner case with v1 credential fields
field_val[sub_field] = decrypt_field(obj, sub_field)
field_val[sub_field] = decrypt_field(obj, field_name, sub_field)
elif isinstance(field_val, str):
try:
field_val = decrypt_field(obj, field_name)
@@ -951,21 +909,20 @@ class CopyAPIView(GenericAPIView):
return ret
def get(self, request, *args, **kwargs):
if get_request_version(request) < 2:
return self.v1_not_allowed()
obj = self.get_object()
if not request.user.can_access(obj.__class__, 'read', obj):
raise PermissionDenied()
create_kwargs = self._build_create_dict(obj)
for key in create_kwargs:
create_kwargs[key] = getattr(create_kwargs[key], 'pk', None) or create_kwargs[key]
can_copy = request.user.can_access(self.model, 'add', create_kwargs) and \
request.user.can_access(self.model, 'copy_related', obj)
try:
can_copy = request.user.can_access(self.model, 'add', create_kwargs) and \
request.user.can_access(self.model, 'copy_related', obj)
except PermissionDenied:
return Response({'can_copy': False})
return Response({'can_copy': can_copy})
def post(self, request, *args, **kwargs):
if get_request_version(request) < 2:
return self.v1_not_allowed()
obj = self.get_object()
create_kwargs = self._build_create_dict(obj)
create_kwargs_check = {}
@@ -982,7 +939,7 @@ class CopyAPIView(GenericAPIView):
None, None, self.model, obj, request.user, create_kwargs=create_kwargs,
copy_name=serializer.validated_data.get('name', '')
)
if hasattr(new_obj, 'admin_role') and request.user not in new_obj.admin_role:
if hasattr(new_obj, 'admin_role') and request.user not in new_obj.admin_role.members.all():
new_obj.admin_role.members.add(request.user)
if sub_objs:
permission_check_func = None

View File

@@ -232,19 +232,6 @@ class RoleMetadata(Metadata):
return metadata
# TODO: Tower 3.3 remove class and all uses in views.py when API v1 is removed
class JobTypeMetadata(Metadata):
def get_field_info(self, field):
res = super(JobTypeMetadata, self).get_field_info(field)
if field.field_name == 'job_type':
res['choices'] = [
choice for choice in res['choices']
if choice[0] != 'scan'
]
return res
class SublistAttachDetatchMetadata(Metadata):
def determine_actions(self, request, view):

15
awx/api/metrics.py Normal file
View File

@@ -0,0 +1,15 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
MetricsView
)
urls = [
url(r'^$', MetricsView.as_view(), name='metrics_view'),
]
__all__ = ['urls']

View File

@@ -18,7 +18,7 @@ class Pagination(pagination.PageNumberPagination):
url = self.request and self.request.get_full_path() or ''
url = url.encode('utf-8')
page_number = self.page.next_page_number()
return replace_query_param(url, self.page_query_param, page_number)
return replace_query_param(self.cap_page_size(url), self.page_query_param, page_number)
def get_previous_link(self):
if not self.page.has_previous():
@@ -26,4 +26,16 @@ class Pagination(pagination.PageNumberPagination):
url = self.request and self.request.get_full_path() or ''
url = url.encode('utf-8')
page_number = self.page.previous_page_number()
return replace_query_param(url, self.page_query_param, page_number)
return replace_query_param(self.cap_page_size(url), self.page_query_param, page_number)
def cap_page_size(self, url):
if int(self.request.query_params.get(self.page_size_query_param, 0)) > self.max_page_size:
url = replace_query_param(url, self.page_size_query_param, self.max_page_size)
return url
def get_html_context(self):
context = super().get_html_context()
context['page_links'] = [pl._replace(url=self.cap_page_size(pl.url))
for pl in context['page_links']]
return context

View File

@@ -15,7 +15,7 @@ from awx.main.utils import get_object_or_400
logger = logging.getLogger('awx.api.permissions')
__all__ = ['ModelAccessPermission', 'JobTemplateCallbackPermission',
__all__ = ['ModelAccessPermission', 'JobTemplateCallbackPermission', 'VariableDataPermission',
'TaskPermission', 'ProjectUpdatePermission', 'InventoryInventorySourcesUpdatePermission',
'UserPermission', 'IsSuperUser', 'InstanceGroupTowerPermission',]
@@ -74,12 +74,8 @@ class ModelAccessPermission(permissions.BasePermission):
# FIXME: For some reason this needs to return True
# because it is first called with obj=None?
return True
if getattr(view, 'is_variable_data', False):
return check_user_access(request.user, view.model, 'change', obj,
dict(variables=request.data))
else:
return check_user_access(request.user, view.model, 'change', obj,
request.data)
return check_user_access(request.user, view.model, 'change', obj,
request.data)
def check_patch_permissions(self, request, view, obj=None):
return self.check_put_permissions(request, view, obj)
@@ -99,12 +95,11 @@ 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
if getattr(view, 'always_allow_superuser', True) and request.user.is_superuser \
and not hasattr(request.user, 'oauth_scopes'):
if getattr(view, 'always_allow_superuser', True) and request.user.is_superuser:
return True
# Check if view supports the request method before checking permission
@@ -164,6 +159,15 @@ class JobTemplateCallbackPermission(ModelAccessPermission):
return True
class VariableDataPermission(ModelAccessPermission):
def check_put_permissions(self, request, view, obj=None):
if not obj:
return True
return check_user_access(request.user, view.model, 'change', obj,
dict(variables=request.data))
class TaskPermission(ModelAccessPermission):
'''
Permission checks used for API callbacks from running a task.

File diff suppressed because it is too large Load Diff

View File

@@ -53,7 +53,6 @@ class AutoSchema(DRFAuthSchema):
return link
def get_description(self, path, method):
self.view._request = self.view.request
setattr(self.view.request, 'swagger_method', method)
description = super(AutoSchema, self).get_description(path, method)
return description

View File

@@ -5,7 +5,7 @@ The following lists the expected format and details of our rrules:
* INTERVAL is required
* SECONDLY is not supported
* TZID is not supported
* RRULE must preceed the rule statements
* RRULE must precede the rule statements
* BYDAY is supported but not BYDAY with a numerical prefix
* BYYEARDAY and BYWEEKNO are not supported
* Only one rrule statement per schedule is supported

View File

@@ -29,17 +29,6 @@ to the redirect_uri specified in the application. The client application will th
AWX will respond with the `access_token`, `token_type`, `refresh_token`, and `expires_in`. For more
information on testing this flow, refer to [django-oauth-toolkit](http://django-oauth-toolkit.readthedocs.io/en/latest/tutorial/tutorial_01.html#test-your-authorization-server).
## Create Token for an Application using Implicit grant type
Suppose we have an application "admin's app" of grant type `implicit`.
In API browser, first make sure the user is logged in via session auth, then visit authorization
endpoint with given parameters:
```text
http://localhost:8013/api/o/authorize/?response_type=token&client_id=L0uQQWW8pKX51hoqIRQGsuqmIdPi2AcXZ9EJRGmj&scope=read
```
Here the value of `client_id` should be the same as that of `client_id` field of underlying application.
On success, an authorization page should be displayed asking the logged in user to grant/deny the access token.
Once the user clicks on 'grant', the API browser will try POSTing to the same endpoint with the same parameters
in POST body, on success a 302 redirect will be returned.
## Create Token for an Application using Password grant type

View File

@@ -8,15 +8,15 @@ job template.
For example, using curl:
curl -H "Content-Type: application/json" -d '{"host_config_key": "HOST_CONFIG_KEY"}' http://server/api/v1/job_templates/N/callback/
curl -H "Content-Type: application/json" -d '{"host_config_key": "HOST_CONFIG_KEY"}' http://server/api/v2/job_templates/N/callback/
Or using wget:
wget -O /dev/null --post-data='{"host_config_key": "HOST_CONFIG_KEY"}' --header=Content-Type:application/json http://server/api/v1/job_templates/N/callback/
wget -O /dev/null --post-data='{"host_config_key": "HOST_CONFIG_KEY"}' --header=Content-Type:application/json http://server/api/v2/job_templates/N/callback/
You may also pass `extra_vars` to the callback:
curl -H "Content-Type: application/json" -d '{"host_config_key": "HOST_CONFIG_KEY", "extra_vars": {"key": "value"}}' http://server/api/v1/job_templates/N/callback/
curl -H "Content-Type: application/json" -d '{"host_config_key": "HOST_CONFIG_KEY", "extra_vars": {"key": "value"}}' http://server/api/v2/job_templates/N/callback/
The response will return status 202 if the request is valid, 403 for an
invalid host config key, or 400 if the host cannot be determined from the
@@ -30,7 +30,7 @@ A GET request may be used to verify that the correct host will be selected.
This request must authenticate as a valid user with permission to edit the
job template. For example:
curl http://user:password@server/api/v1/job_templates/N/callback/
curl http://user:password@server/api/v2/job_templates/N/callback/
The response will include the host config key as well as the host name(s)
that would match the request:

View File

@@ -3,7 +3,7 @@ Launch a Job Template:
Make a POST request to this resource to launch the system job template.
Variables specified inside of the parameter `extra_vars` are passed to the
system job task as command line parameters. These tasks can be ran manually
system job task as command line parameters. These tasks can be run manually
on the host system via the `awx-manage` command.
For example on `cleanup_jobs` and `cleanup_activitystream`:

View File

@@ -6,4 +6,4 @@ One result should be returned containing the following fields:
{% include "api/_result_fields_common.md" %}
Use the primary URL for the user (/api/v1/users/N/) to modify the user.
Use the primary URL for the user (/api/v2/users/N/) to modify the user.

View File

@@ -4,4 +4,7 @@
from __future__ import absolute_import, unicode_literals
from .urls import urlpatterns
__all__ = ['urlpatterns']
__all__ = ['urlpatterns', 'app_name']
app_name = 'api'

View File

@@ -12,6 +12,8 @@ from awx.api.views import (
CredentialOwnerUsersList,
CredentialOwnerTeamsList,
CredentialCopy,
CredentialInputSourceSubList,
CredentialExternalTest,
)
@@ -24,6 +26,8 @@ urls = [
url(r'^(?P<pk>[0-9]+)/owner_users/$', CredentialOwnerUsersList.as_view(), name='credential_owner_users_list'),
url(r'^(?P<pk>[0-9]+)/owner_teams/$', CredentialOwnerTeamsList.as_view(), name='credential_owner_teams_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', CredentialCopy.as_view(), name='credential_copy'),
url(r'^(?P<pk>[0-9]+)/input_sources/$', CredentialInputSourceSubList.as_view(), name='credential_input_source_sublist'),
url(r'^(?P<pk>[0-9]+)/test/$', CredentialExternalTest.as_view(), name='credential_external_test'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,17 @@
# Copyright (c) 2019 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
CredentialInputSourceDetail,
CredentialInputSourceList,
)
urls = [
url(r'^$', CredentialInputSourceList.as_view(), name='credential_input_source_list'),
url(r'^(?P<pk>[0-9]+)/$', CredentialInputSourceDetail.as_view(), name='credential_input_source_detail'),
]
__all__ = ['urls']

View File

@@ -8,6 +8,7 @@ from awx.api.views import (
CredentialTypeDetail,
CredentialTypeCredentialList,
CredentialTypeActivityStreamList,
CredentialTypeExternalTest,
)
@@ -16,6 +17,7 @@ urls = [
url(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'),
url(r'^(?P<pk>[0-9]+)/credentials/$', CredentialTypeCredentialList.as_view(), name='credential_type_credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'),
]
__all__ = ['urls']

View File

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

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

@@ -6,7 +6,6 @@ from django.conf.urls import url
from awx.api.views import (
JobList,
JobDetail,
JobStart,
JobCancel,
JobRelaunch,
JobCreateSchedule,
@@ -23,7 +22,6 @@ from awx.api.views import (
urls = [
url(r'^$', JobList.as_view(), name='job_list'),
url(r'^(?P<pk>[0-9]+)/$', JobDetail.as_view(), name='job_detail'),
url(r'^(?P<pk>[0-9]+)/start/$', JobStart.as_view(), name='job_start'), # Todo: Remove In 3.3
url(r'^(?P<pk>[0-9]+)/cancel/$', JobCancel.as_view(), name='job_cancel'),
url(r'^(?P<pk>[0-9]+)/relaunch/$', JobRelaunch.as_view(), name='job_relaunch'),
url(r'^(?P<pk>[0-9]+)/create_schedule/$', JobCreateSchedule.as_view(), name='job_create_schedule'),

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

@@ -11,10 +11,9 @@ from awx.api.generics import (
)
from awx.api.views import (
ApiRootView,
ApiV1RootView,
ApiV2RootView,
ApiV1PingView,
ApiV1ConfigView,
ApiV2PingView,
ApiV2ConfigView,
AuthView,
UserMeList,
DashboardView,
@@ -34,6 +33,8 @@ from awx.api.views import (
OAuth2ApplicationDetail,
)
from awx.api.views.metrics import MetricsView
from .organization import urls as organization_urls
from .user import urls as user_urls
from .project import urls as project_urls
@@ -47,6 +48,7 @@ from .inventory_update import urls as inventory_update_urls
from .inventory_script import urls as inventory_script_urls
from .credential_type import urls as credential_type_urls
from .credential import urls as credential_urls
from .credential_input_source import urls as credential_input_source_urls
from .role import urls as role_urls
from .job_template import urls as job_template_urls
from .job import urls as job_urls
@@ -71,10 +73,25 @@ from .oauth2 import urls as oauth2_urls
from .oauth2_root import urls as oauth2_root_urls
v1_urls = [
url(r'^$', ApiV1RootView.as_view(), name='api_v1_root_view'),
url(r'^ping/$', ApiV1PingView.as_view(), name='api_v1_ping_view'),
url(r'^config/$', ApiV1ConfigView.as_view(), name='api_v1_config_view'),
v2_urls = [
url(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'),
url(r'^credential_types/', include(credential_type_urls)),
url(r'^credential_input_sources/', include(credential_input_source_urls)),
url(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'),
url(r'^jobs/(?P<pk>[0-9]+)/extra_credentials/$', JobExtraCredentialsList.as_view(), name='job_extra_credentials_list'),
url(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/extra_credentials/$', JobTemplateExtraCredentialsList.as_view(), name='job_template_extra_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'),
url(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
url(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
url(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
url(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='application_o_auth2_token_list'),
url(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
url(r'^', include(oauth2_urls)),
url(r'^metrics/$', MetricsView.as_view(), name='metrics_view'),
url(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'),
url(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'),
url(r'^auth/$', AuthView.as_view()),
url(r'^me/$', UserMeList.as_view(), name='user_me_list'),
url(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),
@@ -116,28 +133,10 @@ v1_urls = [
url(r'^activity_stream/', include(activity_stream_urls)),
]
v2_urls = [
url(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'),
url(r'^credential_types/', include(credential_type_urls)),
url(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'),
url(r'^jobs/(?P<pk>[0-9]+)/extra_credentials/$', JobExtraCredentialsList.as_view(), name='job_extra_credentials_list'),
url(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/extra_credentials/$', JobTemplateExtraCredentialsList.as_view(), name='job_template_extra_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'),
url(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
url(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
url(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
url(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='application_o_auth2_token_list'),
url(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
url(r'^', include(oauth2_urls)),
]
app_name = 'api'
urlpatterns = [
url(r'^$', ApiRootView.as_view(), name='api_root_view'),
url(r'^(?P<version>(v2))/', include(v2_urls)),
url(r'^(?P<version>(v1|v2))/', include(v1_urls)),
url(r'^login/$', LoggedLoginView.as_view(
template_name='rest_framework/login.html',
extra_context={'inside_login_context': True}

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

@@ -2,7 +2,7 @@
# All Rights Reserved.
from django.conf import settings
from django.core.urlresolvers import NoReverseMatch
from django.urls import NoReverseMatch
from rest_framework.reverse import _reverse
from rest_framework.versioning import URLPathVersioning as BaseVersioning
@@ -27,19 +27,6 @@ def drf_reverse(viewname, args=None, kwargs=None, request=None, format=None, **e
return url
def get_request_version(request):
"""
The API version of a request as an integer i.e., 1 or 2
"""
version = settings.REST_FRAMEWORK['DEFAULT_VERSION']
if request and hasattr(request, 'version'):
version = request.version
if version is None:
# For requests to /api/
return None
return int(version.lstrip('v'))
def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
if request is None or getattr(request, 'version', None) is None:
# We need the "current request" to determine the correct version to

File diff suppressed because it is too large Load Diff

View File

@@ -44,11 +44,9 @@ from awx.api.serializers import (
InstanceGroupSerializer,
InventoryUpdateEventSerializer,
CustomInventoryScriptSerializer,
InventoryDetailSerializer,
JobTemplateSerializer,
)
from awx.api.views.mixin import (
ActivityStreamEnforcementMixin,
RelatedJobsPreventDeleteMixin,
ControlledByScmMixin,
)
@@ -62,7 +60,7 @@ class InventoryUpdateEventsList(SubListAPIView):
serializer_class = InventoryUpdateEventSerializer
parent_model = InventoryUpdate
relationship = 'inventory_update_events'
view_name = _('Inventory Update Events List')
name = _('Inventory Update Events List')
search_fields = ('stdout',)
def finalize_response(self, request, response, *args, **kwargs):
@@ -116,17 +114,11 @@ class InventoryList(ListCreateAPIView):
model = Inventory
serializer_class = InventorySerializer
def get_queryset(self):
qs = Inventory.accessible_objects(self.request.user, 'read_role')
qs = qs.select_related('admin_role', 'read_role', 'update_role', 'use_role', 'adhoc_role')
qs = qs.prefetch_related('created_by', 'modified_by', 'organization')
return qs
class InventoryDetail(RelatedJobsPreventDeleteMixin, ControlledByScmMixin, RetrieveUpdateDestroyAPIView):
model = Inventory
serializer_class = InventoryDetailSerializer
serializer_class = InventorySerializer
def update(self, request, *args, **kwargs):
obj = self.get_object()
@@ -149,7 +141,7 @@ class InventoryDetail(RelatedJobsPreventDeleteMixin, ControlledByScmMixin, Retri
return Response(dict(error=_("{0}".format(e))), status=status.HTTP_400_BAD_REQUEST)
class InventoryActivityStreamList(ActivityStreamEnforcementMixin, SubListAPIView):
class InventoryActivityStreamList(SubListAPIView):
model = ActivityStream
serializer_class = ActivityStreamSerializer

40
awx/api/views/metrics.py Normal file
View File

@@ -0,0 +1,40 @@
# Copyright (c) 2018 Red Hat, Inc.
# All Rights Reserved.
# Python
import logging
# Django
from django.utils.translation import ugettext_lazy as _
# Django REST Framework
from rest_framework.response import Response
from rest_framework.exceptions import PermissionDenied
# AWX
# from awx.main.analytics import collectors
from awx.main.analytics.metrics import metrics
from awx.api import renderers
from awx.api.generics import (
APIView,
)
logger = logging.getLogger('awx.main.analytics')
class MetricsView(APIView):
name = _('Metrics')
swagger_topic = 'Metrics'
renderer_classes = [renderers.PlainTextRenderer,
renderers.BrowsableAPIRenderer,]
def get(self, request, format='txt'):
''' Show Metrics Details '''
if (request.user.is_superuser or request.user.is_system_auditor):
return Response(metrics().decode('UTF-8'))
raise PermissionDenied()

View File

@@ -31,48 +31,11 @@ from awx.main.models.organization import Team
from awx.main.models.projects import Project
from awx.main.models.inventory import Inventory
from awx.main.models.jobs import JobTemplate
from awx.conf.license import (
feature_enabled,
LicenseForbids,
)
from awx.api.exceptions import ActiveJobConflict
logger = logging.getLogger('awx.api.views.mixin')
class ActivityStreamEnforcementMixin(object):
'''
Mixin to check that license supports activity streams.
'''
def check_permissions(self, request):
ret = super(ActivityStreamEnforcementMixin, self).check_permissions(request)
if not feature_enabled('activity_streams'):
raise LicenseForbids(_('Your license does not allow use of the activity stream.'))
return ret
class SystemTrackingEnforcementMixin(object):
'''
Mixin to check that license supports system tracking.
'''
def check_permissions(self, request):
ret = super(SystemTrackingEnforcementMixin, self).check_permissions(request)
if not feature_enabled('system_tracking'):
raise LicenseForbids(_('Your license does not permit use of system tracking.'))
return ret
class WorkflowsEnforcementMixin(object):
'''
Mixin to check that license supports workflows.
'''
def check_permissions(self, request):
ret = super(WorkflowsEnforcementMixin, self).check_permissions(request)
if not feature_enabled('workflows') and request.method not in ('GET', 'OPTIONS', 'DELETE'):
raise LicenseForbids(_('Your license does not allow use of workflows.'))
return ret
class UnifiedJobDeletionMixin(object):
'''
Special handling when deleting a running unified job object.

View File

@@ -7,13 +7,8 @@ import logging
# Django
from django.db.models import Count
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
# AWX
from awx.conf.license import (
feature_enabled,
LicenseForbids,
)
from awx.main.models import (
ActivityStream,
Inventory,
@@ -50,7 +45,6 @@ from awx.api.serializers import (
InstanceGroupSerializer,
)
from awx.api.views.mixin import (
ActivityStreamEnforcementMixin,
RelatedJobsPreventDeleteMixin,
OrganizationCountsMixin,
)
@@ -69,24 +63,6 @@ class OrganizationList(OrganizationCountsMixin, ListCreateAPIView):
qs = qs.prefetch_related('created_by', 'modified_by')
return qs
def create(self, request, *args, **kwargs):
"""Create a new organzation.
If there is already an organization and the license of this
instance does not permit multiple organizations, then raise
LicenseForbids.
"""
# Sanity check: If the multiple organizations feature is disallowed
# by the license, then we are only willing to create this organization
# if no organizations exist in the system.
if (not feature_enabled('multiple_organizations') and
self.model.objects.exists()):
raise LicenseForbids(_('Your license only permits a single '
'organization to exist.'))
# Okay, create the organization as usual.
return super(OrganizationList, self).create(request, *args, **kwargs)
class OrganizationDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAPIView):
@@ -140,6 +116,7 @@ class OrganizationUsersList(BaseUsersList):
serializer_class = UserSerializer
parent_model = Organization
relationship = 'member_role.members'
ordering = ('username',)
class OrganizationAdminsList(BaseUsersList):
@@ -148,6 +125,7 @@ class OrganizationAdminsList(BaseUsersList):
serializer_class = UserSerializer
parent_model = Organization
relationship = 'admin_role.members'
ordering = ('username',)
class OrganizationProjectsList(SubListCreateAttachDetachAPIView):
@@ -177,7 +155,7 @@ class OrganizationTeamsList(SubListCreateAttachDetachAPIView):
parent_key = 'organization'
class OrganizationActivityStreamList(ActivityStreamEnforcementMixin, SubListAPIView):
class OrganizationActivityStreamList(SubListAPIView):
model = ActivityStream
serializer_class = ActivityStreamSerializer
@@ -200,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'
@@ -244,4 +220,3 @@ class OrganizationObjectRolesList(SubListAPIView):
po = self.get_parent_object()
content_type = ContentType.objects.get_for_model(self.parent_model)
return Role.objects.filter(content_type=content_type, object_id=po.pk)

View File

@@ -25,8 +25,8 @@ from awx.main.utils import (
get_custom_venv_choices,
to_python_boolean,
)
from awx.api.versioning import reverse, get_request_version, drf_reverse
from awx.conf.license import get_license, feature_enabled
from awx.api.versioning import reverse, drf_reverse
from awx.conf.license import get_license
from awx.main.constants import PRIVILEGE_ESCALATION_METHODS
from awx.main.models import (
Project,
@@ -42,7 +42,7 @@ logger = logging.getLogger('awx.api.views.root')
class ApiRootView(APIView):
permission_classes = (AllowAny,)
view_name = _('REST API')
name = _('REST API')
versioning_class = None
swagger_topic = 'Versioning'
@@ -50,23 +50,21 @@ class ApiRootView(APIView):
def get(self, request, format=None):
''' List supported API versions '''
v1 = reverse('api:api_v1_root_view', kwargs={'version': 'v1'})
v2 = reverse('api:api_v2_root_view', kwargs={'version': 'v2'})
data = OrderedDict()
data['description'] = _('AWX REST API')
data['current_version'] = v2
data['available_versions'] = dict(v1 = v1, v2 = v2)
data['available_versions'] = dict(v2 = v2)
data['oauth2'] = drf_reverse('api:oauth_authorization_root_view')
if feature_enabled('rebranding'):
data['custom_logo'] = settings.CUSTOM_LOGO
data['custom_login_info'] = settings.CUSTOM_LOGIN_INFO
data['custom_logo'] = settings.CUSTOM_LOGO
data['custom_login_info'] = settings.CUSTOM_LOGIN_INFO
return Response(data)
class ApiOAuthAuthorizationRootView(APIView):
permission_classes = (AllowAny,)
view_name = _("API OAuth 2 Authorization Root")
name = _("API OAuth 2 Authorization Root")
versioning_class = None
swagger_topic = 'Authentication'
@@ -86,10 +84,10 @@ class ApiVersionRootView(APIView):
def get(self, request, format=None):
''' List top level resources '''
data = OrderedDict()
data['ping'] = reverse('api:api_v1_ping_view', request=request)
data['ping'] = reverse('api:api_v2_ping_view', request=request)
data['instances'] = reverse('api:instance_list', request=request)
data['instance_groups'] = reverse('api:instance_group_list', request=request)
data['config'] = reverse('api:api_v1_config_view', request=request)
data['config'] = reverse('api:api_v2_config_view', request=request)
data['settings'] = reverse('api:setting_category_list', request=request)
data['me'] = reverse('api:user_me_list', request=request)
data['dashboard'] = reverse('api:dashboard_view', request=request)
@@ -99,10 +97,11 @@ class ApiVersionRootView(APIView):
data['project_updates'] = reverse('api:project_update_list', request=request)
data['teams'] = reverse('api:team_list', request=request)
data['credentials'] = reverse('api:credential_list', request=request)
if get_request_version(request) > 1:
data['credential_types'] = reverse('api:credential_type_list', request=request)
data['applications'] = reverse('api:o_auth2_application_list', request=request)
data['tokens'] = reverse('api:o_auth2_token_list', request=request)
data['credential_types'] = reverse('api:credential_type_list', request=request)
data['credential_input_sources'] = reverse('api:credential_input_source_list', request=request)
data['applications'] = reverse('api:o_auth2_application_list', request=request)
data['tokens'] = reverse('api:o_auth2_token_list', request=request)
data['metrics'] = reverse('api:metrics_view', request=request)
data['inventory'] = reverse('api:inventory_list', request=request)
data['inventory_scripts'] = reverse('api:inventory_script_list', request=request)
data['inventory_sources'] = reverse('api:inventory_source_list', request=request)
@@ -130,21 +129,17 @@ class ApiVersionRootView(APIView):
return Response(data)
class ApiV1RootView(ApiVersionRootView):
view_name = _('Version 1')
class ApiV2RootView(ApiVersionRootView):
view_name = _('Version 2')
name = _('Version 2')
class ApiV1PingView(APIView):
class ApiV2PingView(APIView):
"""A simple view that reports very basic information about this
instance, which is acceptable to be public information.
"""
permission_classes = (AllowAny,)
authentication_classes = ()
view_name = _('Ping')
name = _('Ping')
swagger_topic = 'System Configuration'
def get(self, request, format=None):
@@ -157,29 +152,30 @@ class ApiV1PingView(APIView):
'ha': is_ha_environment(),
'version': get_awx_version(),
'active_node': settings.CLUSTER_HOST_ID,
'install_uuid': settings.INSTALL_UUID,
}
response['instances'] = []
for instance in Instance.objects.all():
response['instances'].append(dict(node=instance.hostname, heartbeat=instance.modified,
response['instances'].append(dict(node=instance.hostname, uuid=instance.uuid, heartbeat=instance.modified,
capacity=instance.capacity, version=instance.version))
sorted(response['instances'], key=operator.itemgetter('node'))
response['instance_groups'] = []
for instance_group in InstanceGroup.objects.all():
for instance_group in InstanceGroup.objects.prefetch_related('instances'):
response['instance_groups'].append(dict(name=instance_group.name,
capacity=instance_group.capacity,
instances=[x.hostname for x in instance_group.instances.all()]))
return Response(response)
class ApiV1ConfigView(APIView):
class ApiV2ConfigView(APIView):
permission_classes = (IsAuthenticated,)
view_name = _('Configuration')
name = _('Configuration')
swagger_topic = 'System Configuration'
def check_permissions(self, request):
super(ApiV1ConfigView, self).check_permissions(request)
super(ApiV2ConfigView, self).check_permissions(request)
if not request.user.is_superuser and request.method.lower() not in {'options', 'head', 'get'}:
self.permission_denied(request) # Raises PermissionDenied exception.
@@ -211,7 +207,7 @@ class ApiV1ConfigView(APIView):
# If LDAP is enabled, user_ldap_fields will return a list of field
# names that are managed by LDAP and should be read-only for users with
# a non-empty ldap_dn attribute.
if getattr(settings, 'AUTH_LDAP_SERVER_URI', None) and feature_enabled('ldap'):
if getattr(settings, 'AUTH_LDAP_SERVER_URI', None):
user_ldap_fields = ['username', 'password']
user_ldap_fields.extend(getattr(settings, 'AUTH_LDAP_USER_ATTR_MAP', {}).keys())
user_ldap_fields.extend(getattr(settings, 'AUTH_LDAP_USER_FLAGS_BY_GROUP', {}).keys())
@@ -220,7 +216,8 @@ class ApiV1ConfigView(APIView):
if request.user.is_superuser \
or request.user.is_system_auditor \
or Organization.accessible_objects(request.user, 'admin_role').exists() \
or Organization.accessible_objects(request.user, 'auditor_role').exists():
or Organization.accessible_objects(request.user, 'auditor_role').exists() \
or Organization.accessible_objects(request.user, 'project_admin_role').exists():
data.update(dict(
project_base_dir = settings.PROJECTS_ROOT,
project_local_paths = Project.get_local_path_choices(),
@@ -276,6 +273,3 @@ class ApiV1ConfigView(APIView):
except Exception:
# FIX: Log
return Response({"error": _("Failed to remove license.")}, status=status.HTTP_400_BAD_REQUEST)

View File

@@ -78,9 +78,6 @@ register(
# the other settings change, the cached value for this setting will be
# cleared to require it to be recomputed.
depends_on=['ANSIBLE_COW_SELECTION'],
# Optional; licensed feature required to be able to view or modify this
# setting.
feature_required='rebranding',
# Optional; field is stored encrypted in the database and only $encrypted$
# is returned via the API.
encrypted=True,

View File

@@ -1,64 +1,19 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved.
# Django
from django.core.signals import setting_changed
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
# Django REST Framework
from rest_framework.exceptions import APIException
# Tower
from awx.main.utils.common import get_licenser
from awx.main.utils import memoize, memoize_delete
__all__ = ['LicenseForbids', 'get_license', 'get_licensed_features',
'feature_enabled', 'feature_exists']
class LicenseForbids(APIException):
status_code = 402
default_detail = _('Your Tower license does not allow that.')
__all__ = ['get_license']
def _get_validated_license_data():
return get_licenser().validate()
@receiver(setting_changed)
def _on_setting_changed(sender, **kwargs):
# Clear cached result above when license changes.
if kwargs.get('setting', None) == 'LICENSE':
memoize_delete('feature_enabled')
def get_license(show_key=False):
"""Return a dictionary representing the active license on this Tower instance."""
license_data = _get_validated_license_data()
if not show_key:
license_data.pop('license_key', None)
return license_data
def get_licensed_features():
"""Return a set of all features enabled by the active license."""
features = set()
for feature, enabled in _get_validated_license_data().get('features', {}).items():
if enabled:
features.add(feature)
return features
@memoize(track_function=True)
def feature_enabled(name):
"""Return True if the requested feature is enabled, False otherwise."""
validated_license_data = _get_validated_license_data()
if validated_license_data.get('license_type', 'UNLICENSED') == 'open':
return True
return validated_license_data.get('features', {}).get(name, False)
def feature_exists(name):
"""Return True if the requested feature name exists, False otherwise."""
return bool(name in _get_validated_license_data().get('features', {}))

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

@@ -22,7 +22,7 @@ def fill_ldap_group_type_params(apps, schema_editor):
modified=now())
init_attrs = set(inspect.getargspec(group_type.__init__).args[1:])
for k in group_type_params.keys():
for k in list(group_type_params.keys()):
if k not in init_attrs:
del group_type_params[k]

View File

@@ -68,7 +68,7 @@ class SettingsRegistry(object):
def get_dependent_settings(self, setting):
return self._dependent_settings.get(setting, set())
def get_registered_categories(self, features_enabled=None):
def get_registered_categories(self):
categories = {
'all': _('All'),
'changed': _('Changed'),
@@ -77,10 +77,6 @@ class SettingsRegistry(object):
category_slug = kwargs.get('category_slug', None)
if category_slug is None or category_slug in categories:
continue
if features_enabled is not None:
feature_required = kwargs.get('feature_required', None)
if feature_required and feature_required not in features_enabled:
continue
if category_slug == 'user':
categories['user'] = _('User')
categories['user-defaults'] = _('User-Defaults')
@@ -88,7 +84,7 @@ class SettingsRegistry(object):
categories[category_slug] = kwargs.get('category', None) or category_slug
return categories
def get_registered_settings(self, category_slug=None, read_only=None, features_enabled=None, slugs_to_ignore=set()):
def get_registered_settings(self, category_slug=None, read_only=None, slugs_to_ignore=set()):
setting_names = []
if category_slug == 'user-defaults':
category_slug = 'user'
@@ -100,14 +96,10 @@ class SettingsRegistry(object):
if kwargs.get('category_slug', None) in slugs_to_ignore:
continue
if (read_only in {True, False} and kwargs.get('read_only', False) != read_only and
setting not in ('AWX_ISOLATED_PRIVATE_KEY', 'AWX_ISOLATED_PUBLIC_KEY')):
setting not in ('INSTALL_UUID', 'AWX_ISOLATED_PRIVATE_KEY', 'AWX_ISOLATED_PUBLIC_KEY')):
# Note: Doesn't catch fields that set read_only via __init__;
# read-only field kwargs should always include read_only=True.
continue
if features_enabled is not None:
feature_required = kwargs.get('feature_required', None)
if feature_required and feature_required not in features_enabled:
continue
setting_names.append(setting)
return setting_names
@@ -135,7 +127,6 @@ class SettingsRegistry(object):
category = field_kwargs.pop('category', None)
depends_on = frozenset(field_kwargs.pop('depends_on', None) or [])
placeholder = field_kwargs.pop('placeholder', empty)
feature_required = field_kwargs.pop('feature_required', empty)
encrypted = bool(field_kwargs.pop('encrypted', False))
defined_in_file = bool(field_kwargs.pop('defined_in_file', False))
if getattr(field_kwargs.get('child', None), 'source', None) is not None:
@@ -146,8 +137,6 @@ class SettingsRegistry(object):
field_instance.depends_on = depends_on
if placeholder is not empty:
field_instance.placeholder = placeholder
if feature_required is not empty:
field_instance.feature_required = feature_required
field_instance.defined_in_file = defined_in_file
if field_instance.defined_in_file:
field_instance.help_text = (

View File

@@ -88,7 +88,7 @@ class SettingSingletonSerializer(serializers.Serializer):
continue
extra_kwargs = {}
# Make LICENSE and AWX_ISOLATED_KEY_GENERATION read-only here;
# LICENSE is only updated via /api/v1/config/
# LICENSE is only updated via /api/v2/config/
# AWX_ISOLATED_KEY_GENERATION is only set/unset via the setup playbook
if key in ('LICENSE', 'AWX_ISOLATED_KEY_GENERATION'):
extra_kwargs['read_only'] = True

View File

@@ -24,7 +24,6 @@ from rest_framework.fields import empty, SkipField
# Tower
from awx.main.utils import encrypt_field, decrypt_field
from awx.main.utils.db import get_tower_migration_version
from awx.conf import settings_registry
from awx.conf.models import Setting
from awx.conf.migrations._reencrypt import decrypt_field as old_decrypt_field
@@ -90,45 +89,42 @@ def _ctit_db_wrapper(trans_safe=False):
transaction.set_rollback(False)
yield
except DBError:
if 'migrate' in sys.argv and get_tower_migration_version() < '310':
logger.info('Using default settings until version 3.1 migration.')
else:
# We want the _full_ traceback with the context
# First we get the current call stack, which constitutes the "top",
# it has the context up to the point where the context manager is used
top_stack = StringIO()
traceback.print_stack(file=top_stack)
top_lines = top_stack.getvalue().strip('\n').split('\n')
top_stack.close()
# Get "bottom" stack from the local error that happened
# inside of the "with" block this wraps
exc_type, exc_value, exc_traceback = sys.exc_info()
bottom_stack = StringIO()
traceback.print_tb(exc_traceback, file=bottom_stack)
bottom_lines = bottom_stack.getvalue().strip('\n').split('\n')
# Glue together top and bottom where overlap is found
bottom_cutoff = 0
for i, line in enumerate(bottom_lines):
if line in top_lines:
# start of overlapping section, take overlap from bottom
top_lines = top_lines[:top_lines.index(line)]
bottom_cutoff = i
break
bottom_lines = bottom_lines[bottom_cutoff:]
tb_lines = top_lines + bottom_lines
# We want the _full_ traceback with the context
# First we get the current call stack, which constitutes the "top",
# it has the context up to the point where the context manager is used
top_stack = StringIO()
traceback.print_stack(file=top_stack)
top_lines = top_stack.getvalue().strip('\n').split('\n')
top_stack.close()
# Get "bottom" stack from the local error that happened
# inside of the "with" block this wraps
exc_type, exc_value, exc_traceback = sys.exc_info()
bottom_stack = StringIO()
traceback.print_tb(exc_traceback, file=bottom_stack)
bottom_lines = bottom_stack.getvalue().strip('\n').split('\n')
# Glue together top and bottom where overlap is found
bottom_cutoff = 0
for i, line in enumerate(bottom_lines):
if line in top_lines:
# start of overlapping section, take overlap from bottom
top_lines = top_lines[:top_lines.index(line)]
bottom_cutoff = i
break
bottom_lines = bottom_lines[bottom_cutoff:]
tb_lines = top_lines + bottom_lines
tb_string = '\n'.join(
['Traceback (most recent call last):'] +
tb_lines +
['{}: {}'.format(exc_type.__name__, str(exc_value))]
)
bottom_stack.close()
# Log the combined stack
if trans_safe:
if 'check_migrations' not in sys.argv:
logger.warning('Database settings are not available, using defaults, error:\n{}'.format(tb_string))
else:
logger.error('Error modifying something related to database settings.\n{}'.format(tb_string))
tb_string = '\n'.join(
['Traceback (most recent call last):'] +
tb_lines +
['{}: {}'.format(exc_type.__name__, str(exc_value))]
)
bottom_stack.close()
# Log the combined stack
if trans_safe:
if 'check_migrations' not in sys.argv:
logger.debug('Database settings are not available, using defaults, error:\n{}'.format(tb_string))
else:
logger.debug('Error modifying something related to database settings.\n{}'.format(tb_string))
finally:
if trans_safe and is_atomic and rollback_set:
transaction.set_rollback(rollback_set)
@@ -381,8 +377,9 @@ class SettingsWrapper(UserSettingsHolder):
setting = None
setting_id = None
if not field.read_only or name in (
# these two values are read-only - however - we *do* want
# these values are read-only - however - we *do* want
# to fetch their value from the database
'INSTALL_UUID',
'AWX_ISOLATED_PRIVATE_KEY',
'AWX_ISOLATED_PUBLIC_KEY',
):

View File

@@ -2,7 +2,7 @@ import urllib.parse
import pytest
from django.core.urlresolvers import resolve
from django.urls import resolve
from django.contrib.auth.models import User
from rest_framework.test import (

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
@@ -65,41 +66,6 @@ def test_non_admin_user_does_not_see_categories(api_request, dummy_setting, norm
assert not response.data['results']
@pytest.mark.django_db
@mock.patch(
'awx.conf.views.VERSION_SPECIFIC_CATEGORIES_TO_EXCLUDE',
{
1: set([]),
2: set(['foobar']),
}
)
def test_version_specific_category_slug_to_exclude_does_not_show_up(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
category='FooBar',
category_slug='foobar'
):
response = api_request(
'get',
reverse('api:setting_category_list',
kwargs={'version': 'v2'})
)
for item in response.data['results']:
assert item['slug'] != 'foobar'
response = api_request(
'get',
reverse('api:setting_category_list',
kwargs={'version': 'v1'})
)
contains = False
for item in response.data['results']:
if item['slug'] != 'foobar':
contains = True
break
assert contains
@pytest.mark.django_db
def test_setting_singleton_detail_retrieve(api_request, dummy_setting):
with dummy_setting(
@@ -172,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,
@@ -218,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(
@@ -241,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

@@ -119,20 +119,6 @@ def test_get_registered_read_only_settings(reg):
]
def test_get_registered_settings_with_required_features(reg):
reg.register(
'AWX_SOME_SETTING_ENABLED',
field_class=fields.BooleanField,
category=_('System'),
category_slug='system',
feature_required='superpowers',
)
assert reg.get_registered_settings(features_enabled=[]) == []
assert reg.get_registered_settings(features_enabled=['superpowers']) == [
'AWX_SOME_SETTING_ENABLED'
]
def test_get_dependent_settings(reg):
reg.register(
'AWX_SOME_SETTING_ENABLED',
@@ -173,45 +159,6 @@ def test_get_registered_categories(reg):
}
def test_get_registered_categories_with_required_features(reg):
reg.register(
'AWX_SOME_SETTING_ENABLED',
field_class=fields.BooleanField,
category=_('System'),
category_slug='system',
feature_required='superpowers'
)
reg.register(
'AWX_SOME_OTHER_SETTING_ENABLED',
field_class=fields.BooleanField,
category=_('OtherSystem'),
category_slug='other-system',
feature_required='sortapowers'
)
assert reg.get_registered_categories(features_enabled=[]) == {
'all': _('All'),
'changed': _('Changed'),
}
assert reg.get_registered_categories(features_enabled=['superpowers']) == {
'all': _('All'),
'changed': _('Changed'),
'system': _('System'),
}
assert reg.get_registered_categories(features_enabled=['sortapowers']) == {
'all': _('All'),
'changed': _('Changed'),
'other-system': _('OtherSystem'),
}
assert reg.get_registered_categories(
features_enabled=['superpowers', 'sortapowers']
) == {
'all': _('All'),
'changed': _('Changed'),
'system': _('System'),
'other-system': _('OtherSystem'),
}
def test_is_setting_encrypted(reg):
reg.register(
'AWX_SOME_SETTING_ENABLED',
@@ -237,7 +184,6 @@ def test_simple_field(reg):
category=_('System'),
category_slug='system',
placeholder='Example Value',
feature_required='superpowers'
)
field = reg.get_setting_field('AWX_SOME_SETTING')
@@ -246,7 +192,6 @@ def test_simple_field(reg):
assert field.category_slug == 'system'
assert field.default is empty
assert field.placeholder == 'Example Value'
assert field.feature_required == 'superpowers'
def test_field_with_custom_attribute(reg):

View File

@@ -24,11 +24,10 @@ from awx.api.generics import (
RetrieveUpdateDestroyAPIView,
)
from awx.api.permissions import IsSuperUser
from awx.api.versioning import reverse, get_request_version
from awx.api.versioning import reverse
from awx.main.utils import camelcase_to_underscore
from awx.main.utils.handlers import AWXProxyHandler, LoggingConnectivityException
from awx.main.tasks import handle_setting_changes
from awx.conf.license import get_licensed_features
from awx.conf.models import Setting
from awx.conf.serializers import SettingCategorySerializer, SettingSingletonSerializer
from awx.conf import settings_registry
@@ -36,24 +35,17 @@ from awx.conf import settings_registry
SettingCategory = collections.namedtuple('SettingCategory', ('url', 'slug', 'name'))
VERSION_SPECIFIC_CATEGORIES_TO_EXCLUDE = {
1: set([
'named-url',
]),
2: set([]),
}
class SettingCategoryList(ListAPIView):
model = Setting # Not exactly, but needed for the view.
serializer_class = SettingCategorySerializer
filter_backends = []
view_name = _('Setting Categories')
name = _('Setting Categories')
def get_queryset(self):
setting_categories = []
categories = settings_registry.get_registered_categories(features_enabled=get_licensed_features())
categories = settings_registry.get_registered_categories()
if self.request.user.is_superuser or self.request.user.is_system_auditor:
pass # categories = categories
elif 'user' in categories:
@@ -61,8 +53,6 @@ class SettingCategoryList(ListAPIView):
else:
categories = {}
for category_slug in sorted(categories.keys()):
if category_slug in VERSION_SPECIFIC_CATEGORIES_TO_EXCLUDE[get_request_version(self.request)]:
continue
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': category_slug}, request=self.request)
setting_categories.append(SettingCategory(url, category_slug, categories[category_slug]))
return setting_categories
@@ -73,13 +63,11 @@ class SettingSingletonDetail(RetrieveUpdateDestroyAPIView):
model = Setting # Not exactly, but needed for the view.
serializer_class = SettingSingletonSerializer
filter_backends = []
view_name = _('Setting Detail')
name = _('Setting Detail')
def get_queryset(self):
self.category_slug = self.kwargs.get('category_slug', 'all')
all_category_slugs = list(settings_registry.get_registered_categories(features_enabled=get_licensed_features()).keys())
for slug_to_delete in VERSION_SPECIFIC_CATEGORIES_TO_EXCLUDE[get_request_version(self.request)]:
all_category_slugs.remove(slug_to_delete)
all_category_slugs = list(settings_registry.get_registered_categories().keys())
if self.request.user.is_superuser or getattr(self.request.user, 'is_system_auditor', False):
category_slugs = all_category_slugs
else:
@@ -90,8 +78,7 @@ class SettingSingletonDetail(RetrieveUpdateDestroyAPIView):
raise PermissionDenied()
registered_settings = settings_registry.get_registered_settings(
category_slug=self.category_slug, read_only=False, features_enabled=get_licensed_features(),
slugs_to_ignore=VERSION_SPECIFIC_CATEGORIES_TO_EXCLUDE[get_request_version(self.request)]
category_slug=self.category_slug, read_only=False,
)
if self.category_slug == 'user':
return Setting.objects.filter(key__in=registered_settings, user=self.request.user)
@@ -101,8 +88,7 @@ class SettingSingletonDetail(RetrieveUpdateDestroyAPIView):
def get_object(self):
settings_qs = self.get_queryset()
registered_settings = settings_registry.get_registered_settings(
category_slug=self.category_slug, features_enabled=get_licensed_features(),
slugs_to_ignore=VERSION_SPECIFIC_CATEGORIES_TO_EXCLUDE[get_request_version(self.request)]
category_slug=self.category_slug,
)
all_settings = {}
for setting in settings_qs:
@@ -168,7 +154,7 @@ class SettingSingletonDetail(RetrieveUpdateDestroyAPIView):
class SettingLoggingTest(GenericAPIView):
view_name = _('Logging Connectivity Test')
name = _('Logging Connectivity Test')
model = Setting
serializer_class = SettingSingletonSerializer
permission_classes = (IsSuperUser,)

View File

@@ -1,30 +0,0 @@
# Copyright (c) 2017 Ansible by Red Hat
#
# This file is part of Ansible Tower, but depends on code imported from Ansible.
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
# Python
import os
import sys
# Add awx/lib to sys.path.
awx_lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if awx_lib_path not in sys.path:
sys.path.insert(0, awx_lib_path)
# Tower Display Callback
from awx_display_callback import AWXDefaultCallbackModule as CallbackModule # noqa

View File

@@ -1,30 +0,0 @@
# Copyright (c) 2017 Ansible by Red Hat
#
# This file is part of Ansible Tower, but depends on code imported from Ansible.
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
# Python
import os
import sys
# Add awx/lib to sys.path.
awx_lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if awx_lib_path not in sys.path:
sys.path.insert(0, awx_lib_path)
# Tower Display Callback
from awx_display_callback import AWXMinimalCallbackModule as CallbackModule # noqa

View File

@@ -1,26 +0,0 @@
# Python
import os
import sys
# Based on http://stackoverflow.com/a/6879344/131141 -- Initialize awx display
# callback as early as possible to wrap ansible.display.Display methods.
def argv_ready(argv):
if argv and os.path.basename(argv[0]) in {'ansible', 'ansible-playbook'}:
import awx_display_callback # noqa
class argv_placeholder(object):
def __del__(self):
try:
argv_ready(sys.argv)
except Exception:
pass
if hasattr(sys, 'argv'):
argv_ready(sys.argv)
else:
sys.argv = argv_placeholder()

View File

@@ -1,2 +0,0 @@
[pytest]
addopts = -v

View File

@@ -30,8 +30,8 @@ from awx.main.utils import (
)
from awx.main.models import (
ActivityStream, AdHocCommand, AdHocCommandEvent, Credential, CredentialType,
CustomInventoryScript, Group, Host, Instance, InstanceGroup, Inventory,
InventorySource, InventoryUpdate, InventoryUpdateEvent, Job, JobEvent,
CredentialInputSource, CustomInventoryScript, Group, Host, Instance, InstanceGroup,
Inventory, InventorySource, InventoryUpdate, InventoryUpdateEvent, Job, JobEvent,
JobHostSummary, JobLaunchConfig, JobTemplate, Label, Notification,
NotificationTemplate, Organization, Project, ProjectUpdate,
ProjectUpdateEvent, Role, Schedule, SystemJob, SystemJobEvent,
@@ -41,8 +41,6 @@ from awx.main.models import (
)
from awx.main.models.mixins import ResourceMixin
from awx.conf.license import LicenseForbids, feature_enabled
__all__ = ['get_user_queryset', 'check_user_access', 'check_user_access_with_errors',
'user_accessible_objects', 'consumer_access',]
@@ -84,6 +82,17 @@ def get_object_from_data(field, Model, data, obj=None):
raise ParseError(_("Bad data found in related field %s." % field))
def vars_are_encrypted(vars):
'''Returns True if any of the values in the dictionary vars contains
content which is encrypted by the AWX encryption algorithm
'''
for value in vars.values():
if isinstance(value, str):
if value.startswith('$encrypted$'):
return True
return False
def register_access(model_class, access_class):
access_registry[model_class] = access_class
@@ -324,12 +333,6 @@ class BaseAccess(object):
elif not add_host_name and free_instances < 0:
raise PermissionDenied(_("Host count exceeds available instances."))
if feature is not None:
if "features" in validation_info and not validation_info["features"].get(feature, False):
raise LicenseForbids(_("Feature %s is not enabled in the active license.") % feature)
elif "features" not in validation_info:
raise LicenseForbids(_("Features not found in active license."))
def check_org_host_limit(self, data, add_host_name=None):
validation_info = get_licenser().validate()
if validation_info.get('license_type', 'UNLICENSED') == 'open':
@@ -383,9 +386,6 @@ class BaseAccess(object):
if obj.validation_errors:
user_capabilities[display_method] = False
continue
elif isinstance(obj, (WorkflowJobTemplate, WorkflowJob)) and (not feature_enabled('workflows')):
user_capabilities[display_method] = (display_method == 'delete')
continue
elif display_method == 'copy' and isinstance(obj, WorkflowJobTemplate) and obj.organization_id is None:
user_capabilities[display_method] = self.user.is_superuser
continue
@@ -426,7 +426,7 @@ class BaseAccess(object):
if display_method == 'schedule':
user_capabilities['schedule'] = user_capabilities['start']
continue
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob, CustomInventoryScript)):
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob, CustomInventoryScript, CredentialInputSource)):
user_capabilities['delete'] = user_capabilities['edit']
continue
elif display_method == 'copy' and isinstance(obj, (Group, Host)):
@@ -460,6 +460,42 @@ class BaseAccess(object):
return False
class NotificationAttachMixin(BaseAccess):
'''For models that can have notifications attached
I can attach a notification template when
- I have notification_admin_role to organization of the NT
- I can read the object I am attaching it to
I can unattach when those same critiera are met
'''
notification_attach_roles = None
def _can_attach(self, notification_template, resource_obj):
if not NotificationTemplateAccess(self.user).can_change(notification_template, {}):
return False
if self.notification_attach_roles is None:
return self.can_read(resource_obj)
return any(self.user in getattr(resource_obj, role) for role in self.notification_attach_roles)
@check_superuser
def can_attach(self, obj, sub_obj, relationship, data, skip_sub_obj_read_check=False):
if isinstance(sub_obj, NotificationTemplate):
# reverse obj and sub_obj
return self._can_attach(notification_template=sub_obj, resource_obj=obj)
return super(NotificationAttachMixin, self).can_attach(
obj, sub_obj, relationship, data, skip_sub_obj_read_check=skip_sub_obj_read_check)
@check_superuser
def can_unattach(self, obj, sub_obj, relationship, data=None):
if isinstance(sub_obj, NotificationTemplate):
# due to this special case, we use symmetrical logic with attach permission
return self._can_attach(notification_template=sub_obj, resource_obj=obj)
return super(NotificationAttachMixin, self).can_unattach(
obj, sub_obj, relationship, relationship, data=data
)
class InstanceAccess(BaseAccess):
model = Instance
@@ -620,23 +656,22 @@ class UserAccess(BaseAccess):
return False
def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False
# Reverse obj and sub_obj, defer to RoleAccess if this is a role assignment.
# The only thing that a User should ever have attached is a Role
if relationship == 'roles':
role_access = RoleAccess(self.user)
return role_access.can_attach(sub_obj, obj, 'members', *args, **kwargs)
return super(UserAccess, self).can_attach(obj, sub_obj, relationship, *args, **kwargs)
logger.error('Unexpected attempt to associate {} with a user.'.format(sub_obj))
return False
def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs):
if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False
# The only thing that a User should ever have to be unattached is a Role
if relationship == 'roles':
role_access = RoleAccess(self.user)
return role_access.can_unattach(sub_obj, obj, 'members', *args, **kwargs)
return super(UserAccess, self).can_unattach(obj, sub_obj, relationship, *args, **kwargs)
logger.error('Unexpected attempt to de-associate {} from a user.'.format(sub_obj))
return False
class OAuth2ApplicationAccess(BaseAccess):
@@ -652,6 +687,7 @@ class OAuth2ApplicationAccess(BaseAccess):
model = OAuth2Application
select_related = ('user',)
prefetch_related = ('organization', 'oauth2accesstoken_set')
def filtered_queryset(self):
org_access_qs = Organization.accessible_objects(self.user, 'member_role')
@@ -690,6 +726,7 @@ class OAuth2TokenAccess(BaseAccess):
model = OAuth2AccessToken
select_related = ('user', 'application')
prefetch_related = ('refresh_token',)
def filtered_queryset(self):
org_access_qs = Organization.objects.filter(
@@ -715,7 +752,7 @@ class OAuth2TokenAccess(BaseAccess):
return True
class OrganizationAccess(BaseAccess):
class OrganizationAccess(NotificationAttachMixin, BaseAccess):
'''
I can see organizations when:
- I am a superuser.
@@ -729,6 +766,8 @@ class OrganizationAccess(BaseAccess):
model = Organization
prefetch_related = ('created_by', 'modified_by',)
# organization admin_role is not a parent of organization auditor_role
notification_attach_roles = ['admin_role', 'auditor_role']
def filtered_queryset(self):
return self.model.accessible_objects(self.user, 'read_role')
@@ -738,13 +777,18 @@ class OrganizationAccess(BaseAccess):
return self.user in obj.admin_role
def can_delete(self, obj):
self.check_license(feature='multiple_organizations', check_expiration=False)
self.check_license(check_expiration=False)
is_change_possible = self.can_change(obj, None)
if not is_change_possible:
return False
return True
def can_attach(self, obj, sub_obj, relationship, *args, **kwargs):
# If the request is updating the membership, check the membership role permissions instead
if relationship in ('member_role.members', 'admin_role.members'):
rel_role = getattr(obj, relationship.split('.')[0])
return RoleAccess(self.user).can_attach(rel_role, sub_obj, 'members', *args, **kwargs)
if relationship == "instance_groups":
if self.user.is_superuser:
return True
@@ -752,6 +796,11 @@ class OrganizationAccess(BaseAccess):
return super(OrganizationAccess, self).can_attach(obj, sub_obj, relationship, *args, **kwargs)
def can_unattach(self, obj, sub_obj, relationship, *args, **kwargs):
# If the request is updating the membership, check the membership role permissions instead
if relationship in ('member_role.members', 'admin_role.members'):
rel_role = getattr(obj, relationship.split('.')[0])
return RoleAccess(self.user).can_unattach(rel_role, sub_obj, 'members', *args, **kwargs)
if relationship == "instance_groups":
return self.can_attach(obj, sub_obj, relationship, *args, **kwargs)
return super(OrganizationAccess, self).can_attach(obj, sub_obj, relationship, *args, **kwargs)
@@ -779,7 +828,7 @@ class InventoryAccess(BaseAccess):
'''
model = Inventory
select_related = ('created_by', 'modified_by', 'organization',)
prefetch_related = ('created_by', 'modified_by', 'organization')
def filtered_queryset(self, allowed=None, ad_hoc=None):
return self.model.accessible_objects(self.user, 'read_role')
@@ -952,21 +1001,8 @@ class GroupAccess(BaseAccess):
def can_delete(self, obj):
return bool(obj and self.user in obj.inventory.admin_role)
def can_start(self, obj, validate_license=True):
# TODO: Delete for 3.3, only used by v1 serializer
# Used as another alias to inventory_source start access for user_capabilities
if obj:
try:
return self.user.can_access(
InventorySource, 'start', obj.deprecated_inventory_source,
validate_license=validate_license)
obj.deprecated_inventory_source
except Group.deprecated_inventory_source.RelatedObjectDoesNotExist:
return False
return False
class InventorySourceAccess(BaseAccess):
class InventorySourceAccess(NotificationAttachMixin, BaseAccess):
'''
I can see inventory sources whenever I can see their inventory.
I can change inventory sources whenever I can change their inventory.
@@ -1043,8 +1079,8 @@ class InventoryUpdateAccess(BaseAccess):
'''
model = InventoryUpdate
select_related = ('created_by', 'modified_by', 'inventory_source__inventory',)
prefetch_related = ('unified_job_template', 'instance_group', 'credentials',)
select_related = ('created_by', 'modified_by', 'inventory_source',)
prefetch_related = ('unified_job_template', 'instance_group', 'credentials__credential_type', 'inventory', 'source_script')
def filtered_queryset(self):
return self.model.objects.filter(inventory_source__inventory__in=Inventory.accessible_pk_qs(self.user, 'read_role'))
@@ -1058,11 +1094,7 @@ class InventoryUpdateAccess(BaseAccess):
return self.user in obj.inventory_source.inventory.admin_role
def can_start(self, obj, validate_license=True):
# For relaunching
if obj and obj.inventory_source:
access = InventorySourceAccess(self.user)
return access.can_start(obj.inventory_source, validate_license=validate_license)
return False
return InventorySourceAccess(self.user).can_start(obj, validate_license=validate_license)
@check_superuser
def can_delete(self, obj):
@@ -1080,6 +1112,7 @@ class CredentialTypeAccess(BaseAccess):
'''
model = CredentialType
prefetch_related = ('created_by', 'modified_by',)
def can_read(self, obj):
return True
@@ -1162,6 +1195,55 @@ class CredentialAccess(BaseAccess):
# return True
return self.can_change(obj, None)
def get_user_capabilities(self, obj, **kwargs):
user_capabilities = super(CredentialAccess, self).get_user_capabilities(obj, **kwargs)
user_capabilities['use'] = self.can_use(obj)
return user_capabilities
class CredentialInputSourceAccess(BaseAccess):
'''
I can see a CredentialInputSource when:
- I can see the associated target_credential
I can create/change a CredentialInputSource when:
- I'm an admin of the associated target_credential
- I have use access to the associated source credential
I can delete a CredentialInputSource when:
- I'm an admin of the associated target_credential
'''
model = CredentialInputSource
select_related = ('target_credential', 'source_credential')
def filtered_queryset(self):
return CredentialInputSource.objects.filter(
target_credential__in=Credential.accessible_pk_qs(self.user, 'read_role'))
@check_superuser
def can_read(self, obj):
return self.user in obj.target_credential.read_role
@check_superuser
def can_add(self, data):
return (
self.check_related('target_credential', Credential, data, role_field='admin_role') and
self.check_related('source_credential', Credential, data, role_field='use_role')
)
@check_superuser
def can_change(self, obj, data):
if self.can_add(data) is False:
return False
return (
self.user in obj.target_credential.admin_role and
self.user in obj.source_credential.use_role
)
@check_superuser
def can_delete(self, obj):
return self.user in obj.target_credential.admin_role
class TeamAccess(BaseAccess):
'''
@@ -1169,6 +1251,7 @@ class TeamAccess(BaseAccess):
- I'm a superuser.
- I'm an admin of the team
- I'm a member of that team.
- I'm a member of the team's organization
I can create/change a team when:
- I'm a superuser.
- I'm an admin for the team
@@ -1181,7 +1264,10 @@ class TeamAccess(BaseAccess):
if settings.ORG_ADMINS_CAN_SEE_ALL_USERS and \
(self.user.admin_of_organizations.exists() or self.user.auditor_of_organizations.exists()):
return self.model.objects.all()
return self.model.accessible_objects(self.user, 'read_role')
return self.model.objects.filter(
Q(organization__in=Organization.accessible_pk_qs(self.user, 'member_role')) |
Q(pk__in=self.model.accessible_pk_qs(self.user, 'read_role'))
)
@check_superuser
def can_add(self, data):
@@ -1219,6 +1305,12 @@ class TeamAccess(BaseAccess):
*args, **kwargs)
if self.user.is_superuser:
return True
# If the request is updating the membership, check the membership role permissions instead
if relationship in ('member_role.members', 'admin_role.members'):
rel_role = getattr(obj, relationship.split('.')[0])
return RoleAccess(self.user).can_attach(rel_role, sub_obj, 'members', *args, **kwargs)
return super(TeamAccess, self).can_attach(obj, sub_obj, relationship,
*args, **kwargs)
@@ -1229,11 +1321,17 @@ class TeamAccess(BaseAccess):
role_access = RoleAccess(self.user)
return role_access.can_unattach(sub_obj, obj, 'member_role.parents',
*args, **kwargs)
# If the request is updating the membership, check the membership role permissions instead
if relationship in ('member_role.members', 'admin_role.members'):
rel_role = getattr(obj, relationship.split('.')[0])
return RoleAccess(self.user).can_unattach(rel_role, sub_obj, 'members', *args, **kwargs)
return super(TeamAccess, self).can_unattach(obj, sub_obj, relationship,
*args, **kwargs)
class ProjectAccess(BaseAccess):
class ProjectAccess(NotificationAttachMixin, BaseAccess):
'''
I can see projects when:
- I am a superuser.
@@ -1251,7 +1349,9 @@ class ProjectAccess(BaseAccess):
'''
model = Project
select_related = ('modified_by', 'credential', 'current_job', 'last_job',)
select_related = ('credential',)
prefetch_related = ('modified_by', 'created_by', 'organization', 'last_job', 'current_job')
notification_attach_roles = ['admin_role']
def filtered_queryset(self):
return self.model.accessible_objects(self.user, 'read_role')
@@ -1314,7 +1414,7 @@ class ProjectUpdateAccess(BaseAccess):
return obj and self.user in obj.project.admin_role
class JobTemplateAccess(BaseAccess):
class JobTemplateAccess(NotificationAttachMixin, BaseAccess):
'''
I can see job templates when:
- I have read role for the job template.
@@ -1394,7 +1494,10 @@ class JobTemplateAccess(BaseAccess):
# obj.credentials.all() is accessible ONLY when object is saved (has valid id)
credential_manager = getattr(obj, 'credentials', None) if getattr(obj, 'id', False) else Credential.objects.none()
return reduce(lambda prev, cred: prev and self.user in cred.use_role, credential_manager.all(), True)
user_can_copy = reduce(lambda prev, cred: prev and self.user in cred.use_role, credential_manager.all(), True)
if not user_can_copy:
raise PermissionDenied(_('Insufficient access to Job Template credentials.'))
return user_can_copy
def can_start(self, obj, validate_license=True):
# Check license.
@@ -1404,11 +1507,6 @@ class JobTemplateAccess(BaseAccess):
# Check the per-org limit
self.check_org_host_limit({'inventory': obj.inventory})
if obj.survey_enabled:
self.check_license(feature='surveys')
if Instance.objects.active_count() > 1:
self.check_license(feature='ha')
# Super users can start any job
if self.user.is_superuser:
return True
@@ -1465,8 +1563,6 @@ class JobTemplateAccess(BaseAccess):
@check_superuser
def can_attach(self, obj, sub_obj, relationship, data, skip_sub_obj_read_check=False):
if isinstance(sub_obj, NotificationTemplate):
return self.check_related('organization', Organization, {}, obj=sub_obj, mandatory=True)
if relationship == "instance_groups":
if not obj.project.organization:
return False
@@ -1582,10 +1678,10 @@ class JobAccess(BaseAccess):
prompts_access = False
elif not config.has_user_prompts(obj.job_template):
prompts_access = True
elif obj.created_by_id != self.user.pk:
elif obj.created_by_id != self.user.pk and vars_are_encrypted(config.extra_data):
prompts_access = False
if self.save_messages:
self.messages['detail'] = _('Job was launched with prompts provided by another user.')
self.messages['detail'] = _('Job was launched with secret prompts provided by another user.')
else:
prompts_access = (
JobLaunchConfigAccess(self.user).can_add({'reference_obj': config}) and
@@ -1747,7 +1843,7 @@ class WorkflowJobTemplateNodeAccess(BaseAccess):
'''
model = WorkflowJobTemplateNode
prefetch_related = ('success_nodes', 'failure_nodes', 'always_nodes',
'unified_job_template', 'credentials',)
'unified_job_template', 'credentials', 'workflow_job_template')
def filtered_queryset(self):
return self.model.objects.filter(
@@ -1839,9 +1935,8 @@ class WorkflowJobNodeAccess(BaseAccess):
Deletion must happen as a cascade delete from the workflow job.
'''
model = WorkflowJobNode
select_related = ('unified_job_template', 'job',)
prefetch_related = ('success_nodes', 'failure_nodes', 'always_nodes',
'credentials',)
prefetch_related = ('unified_job_template', 'job', 'workflow_job', 'credentials',
'success_nodes', 'failure_nodes', 'always_nodes',)
def filtered_queryset(self):
return self.model.objects.filter(
@@ -1864,7 +1959,7 @@ class WorkflowJobNodeAccess(BaseAccess):
# TODO: notification attachments?
class WorkflowJobTemplateAccess(BaseAccess):
class WorkflowJobTemplateAccess(NotificationAttachMixin, BaseAccess):
'''
I can only see/manage Workflow Job Templates if I'm a super user
'''
@@ -1935,10 +2030,6 @@ class WorkflowJobTemplateAccess(BaseAccess):
# Check the per-org limit
self.check_org_host_limit({'inventory': obj.inventory})
# if surveys are added to WFJTs, check license here
if obj.survey_enabled:
self.check_license(feature='surveys')
# Super users can start any job
if self.user.is_superuser:
return True
@@ -1946,11 +2037,6 @@ class WorkflowJobTemplateAccess(BaseAccess):
return self.user in obj.execute_role
def can_change(self, obj, data):
# Check survey license if surveys are added to WFJTs
if (data and 'survey_enabled' in data and
obj.survey_enabled != data['survey_enabled'] and data['survey_enabled']):
self.check_license(feature='surveys')
if self.user.is_superuser:
return True
@@ -2030,9 +2116,9 @@ class WorkflowJobAccess(BaseAccess):
# Check if access to prompts to prevent relaunch
if config.prompts_dict():
if obj.created_by_id != self.user.pk:
if obj.created_by_id != self.user.pk and vars_are_encrypted(config.extra_data):
if self.save_messages:
self.messages['detail'] = _('Job was launched with prompts provided by another user.')
self.messages['detail'] = _('Job was launched with secret prompts provided by another user.')
return False
if not JobLaunchConfigAccess(self.user).can_add({'reference_obj': config}):
if self.save_messages:
@@ -2178,7 +2264,7 @@ class JobEventAccess(BaseAccess):
'''
model = JobEvent
prefetch_related = ('hosts', 'children', 'job__job_template', 'host',)
prefetch_related = ('hosts', 'job__job_template', 'host',)
def filtered_queryset(self):
return self.model.objects.filter(
@@ -2288,11 +2374,6 @@ class UnifiedJobTemplateAccess(BaseAccess):
Q(inventorysource__inventory__id__in=Inventory._accessible_pk_qs(
Inventory, self.user, 'read_role')))
def get_queryset(self):
# TODO: remove after the depreciation of v1 API
qs = super(UnifiedJobTemplateAccess, self).get_queryset()
return qs.exclude(inventorysource__source="")
def can_start(self, obj, validate_license=True):
access_class = access_registry[obj.__class__]
access_instance = access_class(self.user)
@@ -2397,6 +2478,7 @@ class NotificationTemplateAccess(BaseAccess):
I can see/use a notification_template if I have permission to
'''
model = NotificationTemplate
prefetch_related = ('created_by', 'modified_by', 'organization')
def filtered_queryset(self):
return self.model.objects.filter(
@@ -2583,6 +2665,7 @@ class ActivityStreamAccess(BaseAccess):
class CustomInventoryScriptAccess(BaseAccess):
model = CustomInventoryScript
prefetch_related = ('created_by', 'modified_by', 'organization')
def filtered_queryset(self):
return self.model.accessible_objects(self.user, 'read_role').all()
@@ -2616,6 +2699,17 @@ class RoleAccess(BaseAccess):
'''
model = Role
prefetch_related = ('content_type',)
def filtered_queryset(self):
result = Role.visible_roles(self.user)
# Sanity check: is the requesting user an orphaned non-admin/auditor?
# if yes, make system admin/auditor mandatorily visible.
if not self.user.is_superuser and not self.user.is_system_auditor and not self.user.organizations.exists():
mandatories = ('system_administrator', 'system_auditor')
super_qs = Role.objects.filter(singleton_name__in=mandatories)
result = result | super_qs
return result
def can_read(self, obj):
if not obj:
@@ -2635,10 +2729,6 @@ class RoleAccess(BaseAccess):
@check_superuser
def can_unattach(self, obj, sub_obj, relationship, data=None, skip_sub_obj_read_check=False):
if isinstance(obj.content_object, Team):
if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False
if not skip_sub_obj_read_check and relationship in ['members', 'member_role.parents', 'parents']:
# If we are unattaching a team Role, check the Team read access
if relationship == 'parents':
@@ -2650,18 +2740,22 @@ class RoleAccess(BaseAccess):
# Being a user in the member_role or admin_role of an organization grants
# administrators of that Organization the ability to edit that user. To prevent
# unwanted escalations lets ensure that the Organization administartor has the abilty
# unwanted escalations let's ensure that the Organization administrator has the ability
# to admin the user being added to the role.
if (isinstance(obj.content_object, Organization) and
obj.role_field in (Organization.member_role.field.parent_role + ['member_role'])):
if isinstance(obj.content_object, Organization) and obj.role_field in ['admin_role', 'member_role']:
if not isinstance(sub_obj, User):
logger.error('Unexpected attempt to associate {} with organization role.'.format(sub_obj))
return False
if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False
if not UserAccess(self.user).can_admin(sub_obj, None, allow_orphans=True):
return False
if isinstance(obj.content_object, ResourceMixin) and \
self.user in obj.content_object.admin_role:
if isinstance(obj.content_object, Team) and obj.role_field in ['admin_role', 'member_role']:
if not settings.MANAGE_ORGANIZATION_AUTH and not self.user.is_superuser:
return False
if isinstance(obj.content_object, ResourceMixin) and self.user in obj.content_object.admin_role:
return True
return False

View File

@@ -0,0 +1 @@
from .core import register, gather, ship # noqa

View File

@@ -0,0 +1,282 @@
import os
import os.path
import platform
from django.db import connection
from django.db.models import Count
from django.conf import settings
from django.utils.timezone import now
from awx.conf.license import get_license
from awx.main.utils import (get_awx_version, get_ansible_version,
get_custom_venv_choices, camelcase_to_underscore)
from awx.main import models
from django.contrib.sessions.models import Session
from awx.main.analytics import register
'''
This module is used to define metrics collected by awx.main.analytics.gather()
Each function is decorated with a key name, and should return a data
structure that can be serialized to JSON
@register('something')
def something(since):
# the generated archive will contain a `something.json` w/ this JSON
return {'some': 'json'}
All functions - when called - will be passed a datetime.datetime object,
`since`, which represents the last time analytics were gathered (some metrics
functions - like those that return metadata about playbook runs, may return
data _since_ the last report date - i.e., new data in the last 24 hours)
'''
@register('config')
def config(since):
license_info = get_license(show_key=False)
install_type = 'traditional'
if os.environ.get('container') == 'oci':
install_type = 'openshift'
elif 'KUBERNETES_SERVICE_PORT' in os.environ:
install_type = 'k8s'
return {
'platform': {
'system': platform.system(),
'dist': platform.dist(),
'release': platform.release(),
'type': install_type,
},
'install_uuid': settings.INSTALL_UUID,
'instance_uuid': settings.SYSTEM_UUID,
'tower_url_base': settings.TOWER_URL_BASE,
'tower_version': get_awx_version(),
'ansible_version': get_ansible_version(),
'license_type': license_info.get('license_type', 'UNLICENSED'),
'free_instances': license_info.get('free instances', 0),
'license_expiry': license_info.get('time_remaining', 0),
'pendo_tracking': settings.PENDO_TRACKING_STATE,
'authentication_backends': settings.AUTHENTICATION_BACKENDS,
'logging_aggregators': settings.LOG_AGGREGATOR_LOGGERS,
'external_logger_enabled': settings.LOG_AGGREGATOR_ENABLED,
'external_logger_type': getattr(settings, 'LOG_AGGREGATOR_TYPE', None),
}
@register('counts')
def counts(since):
counts = {}
for cls in (models.Organization, models.Team, models.User,
models.Inventory, models.Credential, models.Project,
models.JobTemplate, models.WorkflowJobTemplate,
models.Host, models.Schedule, models.CustomInventoryScript,
models.NotificationTemplate):
counts[camelcase_to_underscore(cls.__name__)] = cls.objects.count()
venvs = get_custom_venv_choices()
counts['custom_virtualenvs'] = len([
v for v in venvs
if os.path.basename(v.rstrip('/')) != 'ansible'
])
inv_counts = dict(models.Inventory.objects.order_by().values_list('kind').annotate(Count('kind')))
inv_counts['normal'] = inv_counts.get('', 0)
inv_counts.pop('', None)
inv_counts['smart'] = inv_counts.get('smart', 0)
counts['inventories'] = inv_counts
counts['unified_job'] = models.UnifiedJob.objects.exclude(launch_type='sync').count() # excludes implicit project_updates
counts['active_host_count'] = models.Host.objects.active_count()
active_sessions = Session.objects.filter(expire_date__gte=now()).count()
active_user_sessions = models.UserSessionMembership.objects.select_related('session').filter(session__expire_date__gte=now()).count()
active_anonymous_sessions = active_sessions - active_user_sessions
counts['active_sessions'] = active_sessions
counts['active_user_sessions'] = active_user_sessions
counts['active_anonymous_sessions'] = active_anonymous_sessions
counts['running_jobs'] = models.UnifiedJob.objects.exclude(launch_type='sync').filter(status__in=('running', 'waiting',)).count()
return counts
@register('org_counts')
def org_counts(since):
counts = {}
for org in models.Organization.objects.annotate(num_users=Count('member_role__members', distinct=True),
num_teams=Count('teams', distinct=True)).values('name', 'id', 'num_users', 'num_teams'):
counts[org['id']] = {'name': org['name'],
'users': org['num_users'],
'teams': org['num_teams']
}
return counts
@register('cred_type_counts')
def cred_type_counts(since):
counts = {}
for cred_type in models.CredentialType.objects.annotate(num_credentials=Count(
'credentials', distinct=True)).values('name', 'id', 'managed_by_tower', 'num_credentials'):
counts[cred_type['id']] = {'name': cred_type['name'],
'credential_count': cred_type['num_credentials'],
'managed_by_tower': cred_type['managed_by_tower']
}
return counts
@register('inventory_counts')
def inventory_counts(since):
counts = {}
for inv in models.Inventory.objects.filter(kind='').annotate(num_sources=Count('inventory_sources', distinct=True),
num_hosts=Count('hosts', distinct=True)).only('id', 'name', 'kind'):
counts[inv.id] = {'name': inv.name,
'kind': inv.kind,
'hosts': inv.num_hosts,
'sources': inv.num_sources
}
for smart_inv in models.Inventory.objects.filter(kind='smart'):
counts[smart_inv.id] = {'name': smart_inv.name,
'kind': smart_inv.kind,
'num_hosts': smart_inv.hosts.count(),
'num_sources': smart_inv.inventory_sources.count()
}
return counts
@register('projects_by_scm_type')
def projects_by_scm_type(since):
counts = dict(
(t[0] or 'manual', 0)
for t in models.Project.SCM_TYPE_CHOICES
)
for result in models.Project.objects.values('scm_type').annotate(
count=Count('scm_type')
).order_by('scm_type'):
counts[result['scm_type'] or 'manual'] = result['count']
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').values(
'uuid', 'version', 'capacity', 'cpu', 'memory', 'managed_by_policy', 'hostname', 'last_isolated_check', 'enabled')
for instance in instances:
instance_info = {
'uuid': instance['uuid'],
'version': instance['version'],
'capacity': instance['capacity'],
'cpu': instance['cpu'],
'memory': instance['memory'],
'managed_by_policy': instance['managed_by_policy'],
'last_isolated_check': _get_isolated_datetime(instance['last_isolated_check']),
'enabled': instance['enabled']
}
info[instance['uuid']] = instance_info
return info
@register('job_counts')
def job_counts(since):
counts = {}
counts['total_jobs'] = models.UnifiedJob.objects.exclude(launch_type='sync').count()
counts['status'] = dict(models.UnifiedJob.objects.exclude(launch_type='sync').values_list('status').annotate(Count('status')).order_by())
counts['launch_type'] = dict(models.UnifiedJob.objects.exclude(launch_type='sync').values_list(
'launch_type').annotate(Count('launch_type')).order_by())
return counts
@register('job_instance_counts')
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')).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')).order_by()
for job in job_statuses:
counts.setdefault(job[0], {}).setdefault('status', {})[job[1]] = job[2]
return counts
# Copies Job Events from db to a .csv to be shipped
def copy_tables(since, full_path):
def _copy_table(table, query, path):
file_path = os.path.join(path, table + '_table.csv')
file = open(file_path, 'w', encoding='utf-8')
with connection.cursor() as cursor:
cursor.copy_expert(query, file)
file.close()
return file_path
events_query = '''COPY (SELECT main_jobevent.id,
main_jobevent.created,
main_jobevent.uuid,
main_jobevent.parent_uuid,
main_jobevent.event,
main_jobevent.event_data::json->'task_action' AS task_action,
main_jobevent.failed,
main_jobevent.changed,
main_jobevent.playbook,
main_jobevent.play,
main_jobevent.task,
main_jobevent.role,
main_jobevent.job_id,
main_jobevent.host_id,
main_jobevent.host_name
FROM main_jobevent
WHERE main_jobevent.created > {}
ORDER BY main_jobevent.id ASC) TO STDOUT WITH CSV HEADER'''.format(since.strftime("'%Y-%m-%d %H:%M:%S'"))
_copy_table(table='events', query=events_query, path=full_path)
unified_job_query = '''COPY (SELECT main_unifiedjob.id,
main_unifiedjob.polymorphic_ctype_id,
django_content_type.model,
main_unifiedjob.created,
main_unifiedjob.name,
main_unifiedjob.unified_job_template_id,
main_unifiedjob.launch_type,
main_unifiedjob.schedule_id,
main_unifiedjob.execution_node,
main_unifiedjob.controller_node,
main_unifiedjob.cancel_flag,
main_unifiedjob.status,
main_unifiedjob.failed,
main_unifiedjob.started,
main_unifiedjob.finished,
main_unifiedjob.elapsed,
main_unifiedjob.job_explanation,
main_unifiedjob.instance_group_id
FROM main_unifiedjob, django_content_type
WHERE main_unifiedjob.created > {} AND
main_unifiedjob.polymorphic_ctype_id = django_content_type.id AND
main_unifiedjob.launch_type != 'sync'
ORDER BY main_unifiedjob.id ASC) TO STDOUT WITH CSV HEADER'''.format(since.strftime("'%Y-%m-%d %H:%M:%S'"))
_copy_table(table='unified_jobs', query=unified_job_query, path=full_path)
unified_job_template_query = '''COPY (SELECT main_unifiedjobtemplate.id,
main_unifiedjobtemplate.polymorphic_ctype_id,
django_content_type.model,
main_unifiedjobtemplate.created,
main_unifiedjobtemplate.modified,
main_unifiedjobtemplate.created_by_id,
main_unifiedjobtemplate.modified_by_id,
main_unifiedjobtemplate.name,
main_unifiedjobtemplate.current_job_id,
main_unifiedjobtemplate.last_job_id,
main_unifiedjobtemplate.last_job_failed,
main_unifiedjobtemplate.last_job_run,
main_unifiedjobtemplate.next_job_run,
main_unifiedjobtemplate.next_schedule_id,
main_unifiedjobtemplate.status
FROM main_unifiedjobtemplate, django_content_type
WHERE main_unifiedjobtemplate.polymorphic_ctype_id = django_content_type.id
ORDER BY main_unifiedjobtemplate.id ASC) TO STDOUT WITH CSV HEADER'''.format(since.strftime("'%Y-%m-%d %H:%M:%S'"))
_copy_table(table='unified_job_template', query=unified_job_template_query, path=full_path)
return

146
awx/main/analytics/core.py Normal file
View File

@@ -0,0 +1,146 @@
import inspect
import json
import logging
import os
import os.path
import tempfile
import shutil
import subprocess
from django.conf import settings
from django.utils.encoding import smart_str
from django.utils.timezone import now, timedelta
from rest_framework.exceptions import PermissionDenied
from awx.conf.license import get_license
from awx.main.models import Job
from awx.main.access import access_registry
from awx.main.models.ha import TowerAnalyticsState
__all__ = ['register', 'gather', 'ship']
logger = logging.getLogger('awx.main.analytics')
def _valid_license():
try:
if get_license(show_key=False).get('license_type', 'UNLICENSED') == 'open':
return False
access_registry[Job](None).check_license()
except PermissionDenied:
logger.exception("A valid license was not found:")
return False
return True
def register(key):
"""
A decorator used to register a function as a metric collector.
Decorated functions should return JSON-serializable objects.
@register('projects_by_scm_type')
def projects_by_scm_type():
return {'git': 5, 'svn': 1, 'hg': 0}
"""
def decorate(f):
f.__awx_analytics_key__ = key
return f
return decorate
def gather(dest=None, module=None):
"""
Gather all defined metrics and write them as JSON files in a .tgz
:param dest: the (optional) absolute path to write a compressed tarball
:pararm module: the module to search for registered analytic collector
functions; defaults to awx.main.analytics.collectors
"""
run_now = now()
state = TowerAnalyticsState.get_solo()
last_run = state.last_run
logger.debug("Last analytics run was: {}".format(last_run))
max_interval = now() - timedelta(days=7)
if last_run < max_interval or not last_run:
last_run = max_interval
if _valid_license() is False:
logger.exception("Invalid License provided, or No License Provided")
return "Error: Invalid License provided, or No License Provided"
if not settings.INSIGHTS_TRACKING_STATE:
logger.error("Insights analytics not enabled")
return
if module is None:
from awx.main.analytics import collectors
module = collectors
dest = dest or tempfile.mkdtemp(prefix='awx_analytics')
for name, func in inspect.getmembers(module):
if inspect.isfunction(func) and hasattr(func, '__awx_analytics_key__'):
key = func.__awx_analytics_key__
path = '{}.json'.format(os.path.join(dest, key))
with open(path, 'w', encoding='utf-8') as f:
try:
json.dump(func(last_run), f)
except Exception:
logger.exception("Could not generate metric {}.json".format(key))
f.close()
os.remove(f.name)
try:
collectors.copy_tables(since=last_run, full_path=dest)
except Exception:
logger.exception("Could not copy tables")
# can't use isoformat() since it has colons, which GNU tar doesn't like
tarname = '_'.join([
settings.SYSTEM_UUID,
run_now.strftime('%Y-%m-%d-%H%M%S%z')
])
tgz = shutil.make_archive(
os.path.join(os.path.dirname(dest), tarname),
'gztar',
dest
)
shutil.rmtree(dest)
return tgz
def ship(path):
"""
Ship gathered metrics via the Insights agent
"""
try:
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))
finally:
# cleanup tar.gz
os.remove(path)

View File

@@ -0,0 +1,121 @@
from django.conf import settings
from prometheus_client import (
REGISTRY,
PROCESS_COLLECTOR,
PLATFORM_COLLECTOR,
GC_COLLECTOR,
Gauge,
Info,
generate_latest
)
from awx.conf.license import get_license
from awx.main.utils import (get_awx_version, get_ansible_version)
from awx.main.analytics.collectors import (
counts,
instance_info,
job_instance_counts,
)
REGISTRY.unregister(PROCESS_COLLECTOR)
REGISTRY.unregister(PLATFORM_COLLECTOR)
REGISTRY.unregister(GC_COLLECTOR)
SYSTEM_INFO = Info('awx_system', 'AWX System Information')
ORG_COUNT = Gauge('awx_organizations_total', 'Number of organizations')
USER_COUNT = Gauge('awx_users_total', 'Number of users')
TEAM_COUNT = Gauge('awx_teams_total', 'Number of teams')
INV_COUNT = Gauge('awx_inventories_total', 'Number of inventories')
PROJ_COUNT = Gauge('awx_projects_total', 'Number of projects')
JT_COUNT = Gauge('awx_job_templates_total', 'Number of job templates')
WFJT_COUNT = Gauge('awx_workflow_job_templates_total', 'Number of workflow job templates')
HOST_COUNT = Gauge('awx_hosts_total', 'Number of hosts', ['type',])
SCHEDULE_COUNT = Gauge('awx_schedules_total', 'Number of schedules')
INV_SCRIPT_COUNT = Gauge('awx_inventory_scripts_total', 'Number of invetory scripts')
USER_SESSIONS = Gauge('awx_sessions_total', 'Number of sessions', ['type',])
CUSTOM_VENVS = Gauge('awx_custom_virtualenvs_total', 'Number of virtualenvs')
RUNNING_JOBS = Gauge('awx_running_jobs_total', 'Number of running jobs on the Tower system')
INSTANCE_CAPACITY = Gauge('awx_instance_capacity', 'Capacity of each node in a Tower system', ['instance_uuid',])
INSTANCE_CPU = Gauge('awx_instance_cpu', 'CPU cores on each node in a Tower system', ['instance_uuid',])
INSTANCE_MEMORY = Gauge('awx_instance_memory', 'RAM (Kb) on each node in a Tower system', ['instance_uuid',])
INSTANCE_INFO = Info('awx_instance', 'Info about each node in a Tower system', ['instance_uuid',])
INSTANCE_LAUNCH_TYPE = Gauge('awx_instance_launch_type_total', 'Type of Job launched', ['node', 'launch_type',])
INSTANCE_STATUS = Gauge('awx_instance_status_total', 'Status of Job launched', ['node', 'status',])
LICENSE_INSTANCE_TOTAL = Gauge('awx_license_instance_total', 'Total number of managed hosts provided by your license')
LICENSE_INSTANCE_FREE = Gauge('awx_license_instance_free', 'Number of remaining managed hosts provided by your license')
def metrics():
license_info = get_license(show_key=False)
SYSTEM_INFO.info({
'install_uuid': settings.INSTALL_UUID,
'insights_analytics': str(settings.INSIGHTS_TRACKING_STATE),
'tower_url_base': settings.TOWER_URL_BASE,
'tower_version': get_awx_version(),
'ansible_version': get_ansible_version(),
'license_type': license_info.get('license_type', 'UNLICENSED'),
'license_expiry': str(license_info.get('time_remaining', 0)),
'pendo_tracking': settings.PENDO_TRACKING_STATE,
'external_logger_enabled': str(settings.LOG_AGGREGATOR_ENABLED),
'external_logger_type': getattr(settings, 'LOG_AGGREGATOR_TYPE', 'None')
})
LICENSE_INSTANCE_TOTAL.set(str(license_info.get('available_instances', 0)))
LICENSE_INSTANCE_FREE.set(str(license_info.get('free_instances', 0)))
current_counts = counts(None)
ORG_COUNT.set(current_counts['organization'])
USER_COUNT.set(current_counts['user'])
TEAM_COUNT.set(current_counts['team'])
INV_COUNT.set(current_counts['inventory'])
PROJ_COUNT.set(current_counts['project'])
JT_COUNT.set(current_counts['job_template'])
WFJT_COUNT.set(current_counts['workflow_job_template'])
HOST_COUNT.labels(type='all').set(current_counts['host'])
HOST_COUNT.labels(type='active').set(current_counts['active_host_count'])
SCHEDULE_COUNT.set(current_counts['schedule'])
INV_SCRIPT_COUNT.set(current_counts['custom_inventory_script'])
CUSTOM_VENVS.set(current_counts['custom_virtualenvs'])
USER_SESSIONS.labels(type='all').set(current_counts['active_sessions'])
USER_SESSIONS.labels(type='user').set(current_counts['active_user_sessions'])
USER_SESSIONS.labels(type='anonymous').set(current_counts['active_anonymous_sessions'])
RUNNING_JOBS.set(current_counts['running_jobs'])
instance_data = instance_info(None)
for uuid in instance_data:
INSTANCE_CAPACITY.labels(instance_uuid=uuid).set(instance_data[uuid]['capacity'])
INSTANCE_CPU.labels(instance_uuid=uuid).set(instance_data[uuid]['cpu'])
INSTANCE_MEMORY.labels(instance_uuid=uuid).set(instance_data[uuid]['memory'])
INSTANCE_INFO.labels(instance_uuid=uuid).info({
'enabled': str(instance_data[uuid]['enabled']),
'last_isolated_check': getattr(instance_data[uuid], 'last_isolated_check', 'None'),
'managed_by_policy': str(instance_data[uuid]['managed_by_policy']),
'version': instance_data[uuid]['version']
})
instance_data = job_instance_counts(None)
for node in instance_data:
# skipping internal execution node (for system jobs)
if node == '':
continue
types = instance_data[node].get('launch_type', {})
for launch_type, value in types.items():
INSTANCE_LAUNCH_TYPE.labels(node=node, launch_type=launch_type).set(value)
statuses = instance_data[node].get('status', {})
for status, value in statuses.items():
INSTANCE_STATUS.labels(node=node, status=status).set(value)
return generate_latest()
__all__ = ['metrics']

View File

@@ -21,7 +21,6 @@ register(
help_text=_('Enable capturing activity for the activity stream.'),
category=_('System'),
category_slug='system',
feature_required='activity_streams',
)
register(
@@ -31,7 +30,6 @@ register(
help_text=_('Enable capturing activity for the activity stream when running inventory sync.'),
category=_('System'),
category_slug='system',
feature_required='activity_streams',
)
register(
@@ -120,12 +118,21 @@ register(
default=_load_default_license_from_file,
label=_('License'),
help_text=_('The license controls which features and functionality are '
'enabled. Use /api/v1/config/ to update or change '
'enabled. Use /api/v2/config/ to update or change '
'the license.'),
category=_('System'),
category_slug='system',
)
register(
'INSTALL_UUID',
field_class=fields.CharField,
label=_('Unique identifier for an AWX/Tower installation'),
category=_('System'),
category_slug='system',
read_only=True,
)
register(
'CUSTOM_VENV_PATHS',
field_class=fields.StringListPathField,
@@ -301,6 +308,16 @@ register(
placeholder={'HTTP_PROXY': 'myproxy.local:8080'},
)
register(
'INSIGHTS_TRACKING_STATE',
field_class=fields.BooleanField,
default=False,
label=_('Gather data for Automation Insights'),
help_text=_('Enables Tower to gather data on automation and send it to Red Hat Insights.'),
category=_('System'),
category_slug='system',
)
register(
'AWX_ROLES_ENABLED',
field_class=fields.BooleanField,
@@ -553,6 +570,16 @@ register(
)
register(
'BROKER_DURABILITY',
field_class=fields.BooleanField,
label=_('Message Durability'),
help_text=_('When set (the default), underlying queues will be persisted to disk. Disable this to enable higher message bus throughput.'),
category=_('System'),
category_slug='system',
)
def logging_validate(serializer, attrs):
if not serializer.instance or \
not hasattr(serializer.instance, 'LOG_AGGREGATOR_HOST') or \

View File

@@ -37,6 +37,17 @@ ENV_BLACKLIST = frozenset((
'INVENTORY_ID', 'INVENTORY_SOURCE_ID', 'INVENTORY_UPDATE_ID',
'AD_HOC_COMMAND_ID', 'REST_API_URL', 'REST_API_TOKEN', 'MAX_EVENT_RES',
'CALLBACK_QUEUE', 'CALLBACK_CONNECTION', 'CACHE',
'JOB_CALLBACK_DEBUG', 'INVENTORY_HOSTVARS', 'FACT_QUEUE',
'JOB_CALLBACK_DEBUG', 'INVENTORY_HOSTVARS',
'AWX_HOST', 'PROJECT_REVISION'
))
# loggers that may be called in process of emitting a log
LOGGER_BLACKLIST = (
'awx.main.utils.handlers',
'awx.main.utils.formatters',
'awx.main.utils.filters',
'awx.main.utils.encryption',
'awx.main.utils.log',
# loggers that may be called getting logging settings
'awx.conf'
)

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

@@ -0,0 +1,107 @@
from .plugin import CredentialPlugin
from urllib.parse import quote, urlencode, urljoin
from django.utils.translation import ugettext_lazy as _
import requests
# AWX
from awx.main.utils import (
create_temporary_fifo,
)
aim_inputs = {
'fields': [{
'id': 'url',
'label': _('CyberArk AIM URL'),
'type': 'string',
'format': 'url',
}, {
'id': 'app_id',
'label': _('Application ID'),
'type': 'string',
'secret': True,
}, {
'id': 'client_key',
'label': _('Client Key'),
'type': 'string',
'secret': True,
'multiline': True,
}, {
'id': 'client_cert',
'label': _('Client Certificate'),
'type': 'string',
'secret': True,
'multiline': True,
}, {
'id': 'verify',
'label': _('Verify SSL Certificates'),
'type': 'boolean',
'default': True,
}],
'metadata': [{
'id': 'object_query',
'label': _('Object Query'),
'type': 'string',
'help_text': _('Lookup query for the object. Ex: "Safe=TestSafe;Object=testAccountName123"'),
}, {
'id': 'object_query_format',
'label': _('Object Query Format'),
'type': 'string',
'default': 'Exact',
'choices': ['Exact', 'Regexp']
}, {
'id': 'reason',
'label': _('Reason'),
'type': 'string',
'help_text': _('Object request reason. This is only needed if it is required by the object\'s policy.')
}],
'required': ['url', 'app_id', 'object_query'],
}
def aim_backend(**kwargs):
url = kwargs['url']
client_cert = kwargs.get('client_cert', None)
client_key = kwargs.get('client_key', None)
verify = kwargs['verify']
app_id = kwargs['app_id']
object_query = kwargs['object_query']
object_query_format = kwargs['object_query_format']
reason = kwargs.get('reason', None)
query_params = {
'AppId': app_id,
'Query': object_query,
'QueryFormat': object_query_format,
}
if reason:
query_params['reason'] = reason
request_qs = '?' + urlencode(query_params, quote_via=quote)
request_url = urljoin(url, '/'.join(['AIMWebService', 'api', 'Accounts']))
cert = None
if client_cert and client_key:
cert = (
create_temporary_fifo(client_cert.encode()),
create_temporary_fifo(client_key.encode())
)
elif client_cert:
cert = create_temporary_fifo(client_cert.encode())
res = requests.get(
request_url + request_qs,
timeout=30,
cert=cert,
verify=verify,
)
res.raise_for_status()
return res.json()['Content']
aim_plugin = CredentialPlugin(
'CyberArk AIM Secret Lookup',
inputs=aim_inputs,
backend=aim_backend
)

View File

@@ -0,0 +1,65 @@
from .plugin import CredentialPlugin
from django.utils.translation import ugettext_lazy as _
from azure.keyvault import KeyVaultClient, KeyVaultAuthentication
from azure.common.credentials import ServicePrincipalCredentials
azure_keyvault_inputs = {
'fields': [{
'id': 'url',
'label': _('Vault URL (DNS Name)'),
'type': 'string',
'format': 'url',
}, {
'id': 'client',
'label': _('Client ID'),
'type': 'string'
}, {
'id': 'secret',
'label': _('Client Secret'),
'type': 'string',
'secret': True,
}, {
'id': 'tenant',
'label': _('Tenant ID'),
'type': 'string'
}],
'metadata': [{
'id': 'secret_field',
'label': _('Secret Name'),
'type': 'string',
'help_text': _('The name of the secret to look up.'),
}, {
'id': 'secret_version',
'label': _('Secret Version'),
'type': 'string',
'help_text': _('Used to specify a specific secret version (if left empty, the latest version will be used).'),
}],
'required': ['url', 'client', 'secret', 'tenant', 'secret_field'],
}
def azure_keyvault_backend(**kwargs):
url = kwargs['url']
def auth_callback(server, resource, scope):
credentials = ServicePrincipalCredentials(
url = url,
client_id = kwargs['client'],
secret = kwargs['secret'],
tenant = kwargs['tenant'],
resource = "https://vault.azure.net",
)
token = credentials.token
return token['token_type'], token['access_token']
kv = KeyVaultClient(KeyVaultAuthentication(auth_callback))
return kv.get_secret(url, kwargs['secret_field'], kwargs.get('secret_version', '')).value
azure_keyvault_plugin = CredentialPlugin(
'Microsoft Azure Key Vault',
inputs=azure_keyvault_inputs,
backend=azure_keyvault_backend
)

View File

@@ -0,0 +1,104 @@
from .plugin import CredentialPlugin
import base64
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': [{
'id': 'url',
'label': _('Conjur URL'),
'type': 'string',
'format': 'url',
}, {
'id': 'api_key',
'label': _('API Key'),
'type': 'string',
'secret': True,
}, {
'id': 'account',
'label': _('Account'),
'type': 'string',
}, {
'id': 'username',
'label': _('Username'),
'type': 'string',
}, {
'id': 'cacert',
'label': _('Public Key Certificate'),
'type': 'string',
'multiline': True
}],
'metadata': [{
'id': 'secret_path',
'label': _('Secret Identifier'),
'type': 'string',
'help_text': _('The identifier for the secret e.g., /some/identifier'),
}, {
'id': 'secret_version',
'label': _('Secret Version'),
'type': 'string',
'help_text': _('Used to specify a specific secret version (if left empty, the latest version will be used).'),
}],
'required': ['url', 'api_key', 'account', 'username'],
}
def conjur_backend(**kwargs):
url = kwargs['url']
api_key = kwargs['api_key']
account = quote_plus(kwargs['account'])
username = quote_plus(kwargs['username'])
secret_path = quote_plus(kwargs['secret_path'])
version = kwargs.get('secret_version')
cacert = kwargs.get('cacert', None)
auth_kwargs = {
'headers': {'Content-Type': 'text/plain'},
'data': api_key
}
if cacert:
auth_kwargs['verify'] = create_temporary_fifo(cacert.encode())
# https://www.conjur.org/api.html#authentication-authenticate-post
resp = requests.post(
urljoin(url, '/'.join(['authn', account, username, 'authenticate'])),
**auth_kwargs
)
resp.raise_for_status()
token = base64.b64encode(resp.content).decode('utf-8')
lookup_kwargs = {
'headers': {'Authorization': 'Token token="{}"'.format(token)},
}
if cacert:
lookup_kwargs['verify'] = create_temporary_fifo(cacert.encode())
# https://www.conjur.org/api.html#secrets-retrieve-a-secret-get
path = urljoin(url, '/'.join([
'secrets',
account,
'variable',
secret_path
]))
if version:
path = '?'.join([path, version])
resp = requests.get(path, timeout=30, **lookup_kwargs)
resp.raise_for_status()
return resp.text
conjur_plugin = CredentialPlugin(
'CyberArk Conjur Secret Lookup',
inputs=conjur_inputs,
backend=conjur_backend
)

View File

@@ -0,0 +1,179 @@
import copy
import os
import pathlib
from urllib.parse import urljoin
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': [{
'id': 'url',
'label': _('Server URL'),
'type': 'string',
'format': 'url',
'help_text': _('The URL to the HashiCorp Vault'),
}, {
'id': 'token',
'label': _('Token'),
'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 stored in the secret backend e.g, /some/secret/')
}],
'required': ['url', 'token', 'secret_path'],
}
hashi_kv_inputs = copy.deepcopy(base_inputs)
hashi_kv_inputs['fields'].append({
'id': 'api_version',
'label': _('API Version'),
'choices': ['v1', 'v2'],
'help_text': _('API v1 is for static key/value lookups. API v2 is for versioned key/value lookups.'),
'default': 'v1',
})
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',
'help_text': _('The name of the key to look up in the secret.'),
}, {
'id': 'secret_version',
'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)
hashi_ssh_inputs['metadata'] = [{
'id': 'public_key',
'label': _('Unsigned Public Key'),
'type': 'string',
'multiline': True,
}] + hashi_ssh_inputs['metadata'] + [{
'id': 'role',
'label': _('Role Name'),
'type': 'string',
'help_text': _('The name of the role used to sign.')
}, {
'id': 'valid_principals',
'label': _('Valid Principals'),
'type': 'string',
'help_text': _('Valid principals (either usernames or hostnames) that the certificate should be signed for.'),
}]
hashi_ssh_inputs['required'].extend(['public_key', 'role'])
def kv_backend(**kwargs):
token = kwargs['token']
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':
if kwargs.get('secret_version'):
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:
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:
return json['data'][secret_key]
except KeyError:
raise RuntimeError(
'{} is not present at {}'.format(secret_key, secret_path)
)
return json['data']
def ssh_backend(**kwargs):
token = kwargs['token']
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)
# https://www.vaultproject.io/api/secret/ssh/index.html#sign-ssh-key
request_url = '/'.join([url, secret_path, 'sign', role]).rstrip('/')
resp = sess.post(request_url, **request_kwargs)
resp.raise_for_status()
return resp.json()['data']['signed_key']
hashivault_kv_plugin = CredentialPlugin(
'HashiCorp Vault Secret Lookup',
inputs=hashi_kv_inputs,
backend=kv_backend
)
hashivault_ssh_plugin = CredentialPlugin(
'HashiCorp Vault Signed SSH',
inputs=hashi_ssh_inputs,
backend=ssh_backend
)

View File

@@ -0,0 +1,3 @@
from collections import namedtuple
CredentialPlugin = namedtuple('CredentialPlugin', ['name', 'inputs', 'backend'])

View File

@@ -4,7 +4,8 @@ import socket
from django.conf import settings
from awx.main.dispatch import get_local_queuename
from kombu import Connection, Queue, Exchange, Producer, Consumer
from awx.main.dispatch.kombu import Connection
from kombu import Queue, Exchange, Producer, Consumer
logger = logging.getLogger('awx.main.dispatch')

View File

@@ -0,0 +1,42 @@
from amqp.exceptions import PreconditionFailed
from django.conf import settings
from kombu.connection import Connection as KombuConnection
from kombu.transport import pyamqp
import logging
logger = logging.getLogger('awx.main.dispatch')
__all__ = ['Connection']
class Connection(KombuConnection):
def __init__(self, *args, **kwargs):
super(Connection, self).__init__(*args, **kwargs)
class _Channel(pyamqp.Channel):
def queue_declare(self, queue, *args, **kwargs):
kwargs['durable'] = settings.BROKER_DURABILITY
try:
return super(_Channel, self).queue_declare(queue, *args, **kwargs)
except PreconditionFailed as e:
if "inequivalent arg 'durable'" in getattr(e, 'reply_text', None):
logger.error(
'queue {} durability is not {}, deleting and recreating'.format(
queue,
kwargs['durable']
)
)
self.queue_delete(queue)
return super(_Channel, self).queue_declare(queue, *args, **kwargs)
class _Connection(pyamqp.Connection):
Channel = _Channel
class _Transport(pyamqp.Transport):
Connection = _Connection
self.transport_cls = _Transport

View File

@@ -4,7 +4,9 @@ import sys
from uuid import uuid4
from django.conf import settings
from kombu import Connection, Exchange, Producer
from kombu import Exchange, Producer
from awx.main.dispatch.kombu import Connection
logger = logging.getLogger('awx.main.dispatch')

View File

@@ -20,8 +20,8 @@ class CallbackBrokerWorker(BaseWorker):
A worker implementation that deserializes callback event data and persists
it into the database.
The code that *builds* these types of messages is found in the AWX display
callback (`awx.lib.awx_display_callback`).
The code that *generates* these types of messages is found in the
ansible-runner display callback plugin.
'''
MAX_RETRIES = 2

View File

@@ -1,402 +0,0 @@
import json
import os
import shutil
import stat
import tempfile
import time
import logging
from io import StringIO
from django.conf import settings
import awx
from awx.main.expect import run
from awx.main.utils import get_system_task_capacity
from awx.main.queue import CallbackQueueDispatcher
logger = logging.getLogger('awx.isolated.manager')
playbook_logger = logging.getLogger('awx.isolated.manager.playbooks')
class IsolatedManager(object):
def __init__(self, env, cancelled_callback=None, job_timeout=0,
idle_timeout=None):
"""
:param env: a dict containing environment variables for the
subprocess, ala `os.environ`
:param cancelled_callback: a callable - which returns `True` or `False`
- signifying if the job has been prematurely
cancelled
:param job_timeout a timeout (in seconds); if the total job runtime
exceeds this, the process will be killed
:param idle_timeout a timeout (in seconds); if new output is not
sent to stdout in this interval, the process
will be terminated
"""
self.management_env = self._base_management_env()
self.cancelled_callback = cancelled_callback
self.job_timeout = job_timeout
self.idle_timeout = idle_timeout
self.started_at = None
@staticmethod
def _base_management_env():
'''
Returns environment variables to use when running a playbook
that manages the isolated instance.
Use of normal job callback and other such configurations are avoided.
'''
env = dict(os.environ.items())
env['ANSIBLE_RETRY_FILES_ENABLED'] = 'False'
env['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
env['ANSIBLE_LIBRARY'] = os.path.join(os.path.dirname(awx.__file__), 'plugins', 'isolated')
return env
@staticmethod
def _build_args(playbook, hosts, extra_vars=None):
'''
Returns list of Ansible CLI command arguments for a management task
:param playbook: name of the playbook to run
:param hosts: host pattern to operate on, ex. "localhost,"
:param extra_vars: optional dictionary of extra_vars to apply
'''
args = [
'ansible-playbook',
playbook,
'-u', settings.AWX_ISOLATED_USERNAME,
'-T', str(settings.AWX_ISOLATED_CONNECTION_TIMEOUT),
'-i', hosts
]
if extra_vars:
args.extend(['-e', json.dumps(extra_vars)])
if settings.AWX_ISOLATED_VERBOSITY:
args.append('-%s' % ('v' * min(5, settings.AWX_ISOLATED_VERBOSITY)))
return args
@classmethod
def awx_playbook_path(cls):
return os.path.abspath(os.path.join(
os.path.dirname(awx.__file__),
'playbooks'
))
def path_to(self, *args):
return os.path.join(self.private_data_dir, *args)
def dispatch(self, playbook=None, module=None, module_args=None):
'''
Ship the runner payload to a remote host for isolated execution.
'''
self.handled_events = set()
self.started_at = time.time()
self.build_isolated_job_data()
extra_vars = {
'src': self.private_data_dir,
'dest': settings.AWX_PROOT_BASE_PATH,
'ident': self.ident
}
if playbook:
extra_vars['playbook'] = playbook
if module and module_args:
extra_vars['module'] = module
extra_vars['module_args'] = module_args
# Run ansible-playbook to launch a job on the isolated host. This:
#
# - sets up a temporary directory for proot/bwrap (if necessary)
# - copies encrypted job data from the controlling host to the isolated host (with rsync)
# - writes the encryption secret to a named pipe on the isolated host
# - launches ansible-runner
args = self._build_args('run_isolated.yml', '%s,' % self.host, extra_vars)
if self.instance.verbosity:
args.append('-%s' % ('v' * min(5, self.instance.verbosity)))
buff = StringIO()
logger.debug('Starting job {} on isolated host with `run_isolated.yml` playbook.'.format(self.instance.id))
status, rc = IsolatedManager.run_pexpect(
args, self.awx_playbook_path(), self.management_env, buff,
idle_timeout=self.idle_timeout,
job_timeout=settings.AWX_ISOLATED_LAUNCH_TIMEOUT,
pexpect_timeout=5
)
output = buff.getvalue()
playbook_logger.info('Isolated job {} dispatch:\n{}'.format(self.instance.id, output))
if status != 'successful':
for event_data in [
{'event': 'verbose', 'stdout': output},
{'event': 'EOF', 'final_counter': 1},
]:
event_data.setdefault(self.event_data_key, self.instance.id)
CallbackQueueDispatcher().dispatch(event_data)
return status, rc
@classmethod
def run_pexpect(cls, pexpect_args, *args, **kw):
isolated_ssh_path = None
try:
if all([
getattr(settings, 'AWX_ISOLATED_KEY_GENERATION', False) is True,
getattr(settings, 'AWX_ISOLATED_PRIVATE_KEY', None)
]):
isolated_ssh_path = tempfile.mkdtemp(prefix='awx_isolated', dir=settings.AWX_PROOT_BASE_PATH)
os.chmod(isolated_ssh_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
isolated_key = os.path.join(isolated_ssh_path, '.isolated')
ssh_sock = os.path.join(isolated_ssh_path, '.isolated_ssh_auth.sock')
run.open_fifo_write(isolated_key, settings.AWX_ISOLATED_PRIVATE_KEY)
pexpect_args = run.wrap_args_with_ssh_agent(pexpect_args, isolated_key, ssh_sock, silence_ssh_add=True)
return run.run_pexpect(pexpect_args, *args, **kw)
finally:
if isolated_ssh_path:
shutil.rmtree(isolated_ssh_path)
def build_isolated_job_data(self):
'''
Write metadata related to the playbook run into a collection of files
on the local file system.
'''
rsync_exclude = [
# don't rsync source control metadata (it can be huge!)
'- /project/.git',
'- /project/.svn',
'- /project/.hg',
# don't rsync job events that are in the process of being written
'- /artifacts/job_events/*-partial.json.tmp',
# don't rsync the ssh_key FIFO
'- /env/ssh_key',
]
for filename, data in (
['.rsync-filter', '\n'.join(rsync_exclude)],
):
path = self.path_to(filename)
with open(path, 'w') as f:
f.write(data)
os.chmod(path, stat.S_IRUSR)
def check(self, interval=None):
"""
Repeatedly poll the isolated node to determine if the job has run.
On success, copy job artifacts to the controlling node.
On failure, continue to poll the isolated node (until the job timeout
is exceeded).
For a completed job run, this function returns (status, rc),
representing the status and return code of the isolated
`ansible-playbook` run.
:param interval: an interval (in seconds) to wait between status polls
"""
interval = interval if interval is not None else settings.AWX_ISOLATED_CHECK_INTERVAL
extra_vars = {'src': self.private_data_dir}
args = self._build_args('check_isolated.yml', '%s,' % self.host, extra_vars)
if self.instance.verbosity:
args.append('-%s' % ('v' * min(5, self.instance.verbosity)))
status = 'failed'
output = ''
rc = None
buff = StringIO()
last_check = time.time()
job_timeout = remaining = self.job_timeout
dispatcher = CallbackQueueDispatcher()
while status == 'failed':
if job_timeout != 0:
remaining = max(0, job_timeout - (time.time() - self.started_at))
canceled = self.cancelled_callback() if self.cancelled_callback else False
if not canceled and time.time() - last_check < interval:
# If the job isn't cancelled, but we haven't waited `interval` seconds, wait longer
time.sleep(1)
continue
if canceled:
logger.warning('Isolated job {} was manually cancelled.'.format(self.instance.id))
buff = StringIO()
logger.debug('Checking on isolated job {} with `check_isolated.yml`.'.format(self.instance.id))
status, rc = IsolatedManager.run_pexpect(
args, self.awx_playbook_path(), self.management_env, buff,
cancelled_callback=self.cancelled_callback,
idle_timeout=remaining,
job_timeout=remaining,
pexpect_timeout=5,
proot_cmd='bwrap'
)
output = buff.getvalue().encode('utf-8')
playbook_logger.info('Isolated job {} check:\n{}'.format(self.instance.id, output))
# discover new events and ingest them
events_path = self.path_to('artifacts', self.ident, 'job_events')
# it's possible that `events_path` doesn't exist *yet*, because runner
# hasn't actually written any events yet (if you ran e.g., a sleep 30)
# only attempt to consume events if any were rsynced back
if os.path.exists(events_path):
for event in set(os.listdir(events_path)) - self.handled_events:
path = os.path.join(events_path, event)
if os.path.exists(path):
event_data = json.load(
open(os.path.join(events_path, event), 'r')
)
event_data.setdefault(self.event_data_key, self.instance.id)
dispatcher.dispatch(event_data)
self.handled_events.add(event)
# handle artifacts
if event_data.get('event_data', {}).get('artifact_data', {}):
self.instance.artifacts = event_data['event_data']['artifact_data']
self.instance.save(update_fields=['artifacts'])
last_check = time.time()
if status == 'successful':
status_path = self.path_to('artifacts', self.ident, 'status')
rc_path = self.path_to('artifacts', self.ident, 'rc')
with open(status_path, 'r') as f:
status = f.readline()
with open(rc_path, 'r') as f:
rc = int(f.readline())
# emit an EOF event
event_data = {
'event': 'EOF',
'final_counter': len(self.handled_events)
}
event_data.setdefault(self.event_data_key, self.instance.id)
dispatcher.dispatch(event_data)
return status, rc
def cleanup(self):
# If the job failed for any reason, make a last-ditch effort at cleanup
extra_vars = {
'private_data_dir': self.private_data_dir,
'cleanup_dirs': [
self.private_data_dir,
],
}
args = self._build_args('clean_isolated.yml', '%s,' % self.host, extra_vars)
logger.debug('Cleaning up job {} on isolated host with `clean_isolated.yml` playbook.'.format(self.instance.id))
buff = StringIO()
timeout = max(60, 2 * settings.AWX_ISOLATED_CONNECTION_TIMEOUT)
status, rc = IsolatedManager.run_pexpect(
args, self.awx_playbook_path(), self.management_env, buff,
idle_timeout=timeout, job_timeout=timeout,
pexpect_timeout=5
)
output = buff.getvalue().encode('utf-8')
playbook_logger.info('Isolated job {} cleanup:\n{}'.format(self.instance.id, output))
if status != 'successful':
# stdout_handle is closed by this point so writing output to logs is our only option
logger.warning('Isolated job {} cleanup error, output:\n{}'.format(self.instance.id, output))
@classmethod
def update_capacity(cls, instance, task_result, awx_application_version):
instance.version = 'ansible-runner-{}'.format(task_result['version'])
if instance.capacity == 0 and task_result['capacity_cpu']:
logger.warning('Isolated instance {} has re-joined.'.format(instance.hostname))
instance.cpu_capacity = int(task_result['capacity_cpu'])
instance.mem_capacity = int(task_result['capacity_mem'])
instance.capacity = get_system_task_capacity(scale=instance.capacity_adjustment,
cpu_capacity=int(task_result['capacity_cpu']),
mem_capacity=int(task_result['capacity_mem']))
instance.save(update_fields=['cpu_capacity', 'mem_capacity', 'capacity', 'version', 'modified'])
@classmethod
def health_check(cls, instance_qs, awx_application_version):
'''
:param instance_qs: List of Django objects representing the
isolated instances to manage
Runs playbook that will
- determine if instance is reachable
- find the instance capacity
- clean up orphaned private files
Performs save on each instance to update its capacity.
'''
hostname_string = ''
for instance in instance_qs:
hostname_string += '{},'.format(instance.hostname)
args = cls._build_args('heartbeat_isolated.yml', hostname_string)
args.extend(['--forks', str(len(instance_qs))])
env = cls._base_management_env()
try:
facts_path = tempfile.mkdtemp()
env['ANSIBLE_CACHE_PLUGIN'] = 'jsonfile'
env['ANSIBLE_CACHE_PLUGIN_CONNECTION'] = facts_path
buff = StringIO()
timeout = max(60, 2 * settings.AWX_ISOLATED_CONNECTION_TIMEOUT)
status, rc = IsolatedManager.run_pexpect(
args, cls.awx_playbook_path(), env, buff,
idle_timeout=timeout, job_timeout=timeout,
pexpect_timeout=5
)
heartbeat_stdout = buff.getvalue().encode('utf-8')
buff.close()
for instance in instance_qs:
output = heartbeat_stdout
task_result = {}
try:
with open(os.path.join(facts_path, instance.hostname), 'r') as facts_data:
output = facts_data.read()
task_result = json.loads(output)
except Exception:
logger.exception('Failed to read status from isolated instances, output:\n {}'.format(output))
if 'awx_capacity_cpu' in task_result and 'awx_capacity_mem' in task_result:
task_result = {
'capacity_cpu': task_result['awx_capacity_cpu'],
'capacity_mem': task_result['awx_capacity_mem'],
'version': task_result['awx_capacity_version']
}
cls.update_capacity(instance, task_result, awx_application_version)
logger.debug('Isolated instance {} successful heartbeat'.format(instance.hostname))
elif instance.capacity == 0:
logger.debug('Isolated instance {} previously marked as lost, could not re-join.'.format(
instance.hostname))
else:
logger.warning('Could not update status of isolated instance {}'.format(instance.hostname))
if instance.is_lost(isolated=True):
instance.capacity = 0
instance.save(update_fields=['capacity'])
logger.error('Isolated instance {} last checked in at {}, marked as lost.'.format(
instance.hostname, instance.modified))
finally:
if os.path.exists(facts_path):
shutil.rmtree(facts_path)
def run(self, instance, private_data_dir, playbook, module, module_args,
event_data_key, ident=None):
"""
Run a job on an isolated host.
:param instance: a `model.Job` instance
:param private_data_dir: an absolute path on the local file system
where job-specific data should be written
(i.e., `/tmp/ansible_awx_xyz/`)
:param playbook: the playbook to run
:param module: the module to run
:param module_args: the module args to use
:param event_data_key: e.g., job_id, inventory_id, ...
For a completed job run, this function returns (status, rc),
representing the status and return code of the isolated
`ansible-playbook` run.
"""
self.ident = ident
self.event_data_key = event_data_key
self.instance = instance
self.host = instance.execution_node
self.private_data_dir = private_data_dir
status, rc = self.dispatch(playbook, module, module_args)
if status == 'successful':
status, rc = self.check()
self.cleanup()
return status, rc

View File

@@ -1,316 +0,0 @@
#! /usr/bin/env python
import argparse
import base64
import codecs
import collections
import logging
import json
import os
import stat
import pipes
import re
import signal
import sys
import threading
import time
from io import StringIO
import pexpect
import psutil
logger = logging.getLogger('awx.main.utils.expect')
def args2cmdline(*args):
return ' '.join([pipes.quote(a) for a in args])
def wrap_args_with_ssh_agent(args, ssh_key_path, ssh_auth_sock=None, silence_ssh_add=False):
if ssh_key_path:
ssh_add_command = args2cmdline('ssh-add', ssh_key_path)
if silence_ssh_add:
ssh_add_command = ' '.join([ssh_add_command, '2>/dev/null'])
cmd = ' && '.join([ssh_add_command,
args2cmdline('rm', '-f', ssh_key_path),
args2cmdline(*args)])
args = ['ssh-agent']
if ssh_auth_sock:
args.extend(['-a', ssh_auth_sock])
args.extend(['sh', '-c', cmd])
return args
def open_fifo_write(path, data):
'''open_fifo_write opens the fifo named pipe in a new thread.
This blocks the thread until an external process (such as ssh-agent)
reads data from the pipe.
'''
os.mkfifo(path, 0o600)
threading.Thread(
target=lambda p, d: open(p, 'w').write(d),
args=(path, data)
).start()
def run_pexpect(args, cwd, env, logfile,
cancelled_callback=None, expect_passwords={},
extra_update_fields=None, idle_timeout=None, job_timeout=0,
pexpect_timeout=5, proot_cmd='bwrap'):
'''
Run the given command using pexpect to capture output and provide
passwords when requested.
:param args: a list of `subprocess.call`-style arguments
representing a subprocess e.g., ['ls', '-la']
:param cwd: the directory in which the subprocess should
run
:param env: a dict containing environment variables for the
subprocess, ala `os.environ`
:param logfile: a file-like object for capturing stdout
:param cancelled_callback: a callable - which returns `True` or `False`
- signifying if the job has been prematurely
cancelled
:param expect_passwords: a dict of regular expression password prompts
to input values, i.e., {r'Password:*?$':
'some_password'}
:param extra_update_fields: a dict used to specify DB fields which should
be updated on the underlying model
object after execution completes
:param idle_timeout a timeout (in seconds); if new output is not
sent to stdout in this interval, the process
will be terminated
:param job_timeout a timeout (in seconds); if the total job runtime
exceeds this, the process will be killed
:param pexpect_timeout a timeout (in seconds) to wait on
`pexpect.spawn().expect()` calls
:param proot_cmd the command used to isolate processes, `bwrap`
Returns a tuple (status, return_code) i.e., `('successful', 0)`
'''
expect_passwords[pexpect.TIMEOUT] = None
expect_passwords[pexpect.EOF] = None
if not isinstance(expect_passwords, collections.OrderedDict):
# We iterate over `expect_passwords.keys()` and
# `expect_passwords.values()` separately to map matched inputs to
# patterns and choose the proper string to send to the subprocess;
# enforce usage of an OrderedDict so that the ordering of elements in
# `keys()` matches `values()`.
expect_passwords = collections.OrderedDict(expect_passwords)
password_patterns = list(expect_passwords.keys())
password_values = list(expect_passwords.values())
child = pexpect.spawn(
args[0], args[1:], cwd=cwd, env=env, ignore_sighup=True,
encoding='utf-8', echo=False, use_poll=True
)
child.logfile_read = logfile
canceled = False
timed_out = False
errored = False
last_stdout_update = time.time()
job_start = time.time()
while child.isalive():
result_id = child.expect(password_patterns, timeout=pexpect_timeout, searchwindowsize=100)
password = password_values[result_id]
if password is not None:
child.sendline(password)
last_stdout_update = time.time()
if cancelled_callback:
try:
canceled = cancelled_callback()
except Exception:
logger.exception('Could not check cancel callback - canceling immediately')
if isinstance(extra_update_fields, dict):
extra_update_fields['job_explanation'] = "System error during job execution, check system logs"
errored = True
else:
canceled = False
if not canceled and job_timeout != 0 and (time.time() - job_start) > job_timeout:
timed_out = True
if isinstance(extra_update_fields, dict):
extra_update_fields['job_explanation'] = "Job terminated due to timeout"
if canceled or timed_out or errored:
handle_termination(child.pid, child.args, proot_cmd, is_cancel=canceled)
if idle_timeout and (time.time() - last_stdout_update) > idle_timeout:
child.close(True)
canceled = True
if errored:
return 'error', child.exitstatus
elif canceled:
return 'canceled', child.exitstatus
elif child.exitstatus == 0 and not timed_out:
return 'successful', child.exitstatus
else:
return 'failed', child.exitstatus
def run_isolated_job(private_data_dir, secrets, logfile=sys.stdout):
'''
Launch `ansible-playbook`, executing a job packaged by
`build_isolated_job_data`.
:param private_data_dir: an absolute path on the local file system where
job metadata exists (i.e.,
`/tmp/ansible_awx_xyz/`)
:param secrets: a dict containing sensitive job metadata, {
'env': { ... } # environment variables,
'passwords': { ... } # pexpect password prompts
'ssh_key_data': 'RSA KEY DATA',
}
:param logfile: a file-like object for capturing stdout
Returns a tuple (status, return_code) i.e., `('successful', 0)`
'''
with open(os.path.join(private_data_dir, 'args'), 'r') as args:
args = json.load(args)
env = secrets.get('env', {})
expect_passwords = {
re.compile(pattern, re.M): password
for pattern, password in secrets.get('passwords', {}).items()
}
if 'AD_HOC_COMMAND_ID' in env:
cwd = private_data_dir
else:
cwd = os.path.join(private_data_dir, 'project')
# write the SSH key data into a fifo read by ssh-agent
ssh_key_data = secrets.get('ssh_key_data')
if ssh_key_data:
ssh_key_path = os.path.join(private_data_dir, 'ssh_key_data')
ssh_auth_sock = os.path.join(private_data_dir, 'ssh_auth.sock')
open_fifo_write(ssh_key_path, ssh_key_data)
args = wrap_args_with_ssh_agent(args, ssh_key_path, ssh_auth_sock)
idle_timeout = secrets.get('idle_timeout', 10)
job_timeout = secrets.get('job_timeout', 10)
pexpect_timeout = secrets.get('pexpect_timeout', 5)
env['AWX_ISOLATED_DATA_DIR'] = private_data_dir
venv_path = env.get('VIRTUAL_ENV')
if venv_path and not os.path.exists(venv_path):
raise RuntimeError(
'a valid Python virtualenv does not exist at {}'.format(venv_path)
)
return run_pexpect(args, cwd, env, logfile,
expect_passwords=expect_passwords,
idle_timeout=idle_timeout,
job_timeout=job_timeout,
pexpect_timeout=pexpect_timeout)
def handle_termination(pid, args, proot_cmd, is_cancel=True):
'''
Terminate a subprocess spawned by `pexpect`.
:param pid: the process id of the running the job.
:param args: the args for the job, i.e., ['ansible-playbook', 'abc.yml']
:param proot_cmd the command used to isolate processes i.e., `bwrap`
:param is_cancel: flag showing whether this termination is caused by
instance's cancel_flag.
'''
try:
used_proot = proot_cmd.encode('utf-8') in args
if used_proot:
if not psutil:
os.kill(pid, signal.SIGKILL)
else:
try:
main_proc = psutil.Process(pid=pid)
child_procs = main_proc.children(recursive=True)
for child_proc in child_procs:
os.kill(child_proc.pid, signal.SIGKILL)
os.kill(main_proc.pid, signal.SIGKILL)
except (TypeError, psutil.Error):
os.kill(pid, signal.SIGKILL)
else:
os.kill(pid, signal.SIGTERM)
time.sleep(3)
except OSError:
keyword = 'cancel' if is_cancel else 'timeout'
logger.warn("Attempted to %s already finished job, ignoring" % keyword)
def __run__(private_data_dir):
buff = StringIO()
with codecs.open(os.path.join(private_data_dir, 'env'), 'r', encoding='utf-8') as f:
for line in f:
buff.write(line)
artifacts_dir = os.path.join(private_data_dir, 'artifacts')
# Standard out directed to pickup location without event filtering applied
stdout_filename = os.path.join(artifacts_dir, 'stdout')
os.mknod(stdout_filename, stat.S_IFREG | stat.S_IRUSR | stat.S_IWUSR)
stdout_handle = codecs.open(stdout_filename, 'w', encoding='utf-8')
status, rc = run_isolated_job(
private_data_dir,
json.loads(base64.b64decode(buff.getvalue())),
stdout_handle
)
for filename, data in [
('status', status),
('rc', rc),
]:
artifact_path = os.path.join(private_data_dir, 'artifacts', filename)
os.mknod(artifact_path, stat.S_IFREG | stat.S_IRUSR | stat.S_IWUSR)
with open(artifact_path, 'w') as f:
f.write(str(data))
if __name__ == '__main__':
import awx
__version__ = awx.__version__
parser = argparse.ArgumentParser(description='manage a daemonized, isolated ansible playbook')
parser.add_argument('--version', action='version', version=__version__ + '-isolated')
parser.add_argument('command', choices=['start', 'stop', 'is-alive'])
parser.add_argument('private_data_dir')
args = parser.parse_args()
private_data_dir = args.private_data_dir
pidfile = os.path.join(private_data_dir, 'pid')
if args.command == 'start':
# create a file to log stderr in case the daemonized process throws
# an exception before it gets to `pexpect.spawn`
stderr_path = os.path.join(private_data_dir, 'artifacts', 'daemon.log')
if not os.path.exists(stderr_path):
os.mknod(stderr_path, stat.S_IFREG | stat.S_IRUSR | stat.S_IWUSR)
stderr = open(stderr_path, 'w+')
import daemon
from daemon.pidfile import TimeoutPIDLockFile
context = daemon.DaemonContext(
pidfile=TimeoutPIDLockFile(pidfile),
stderr=stderr
)
with context:
__run__(private_data_dir)
sys.exit(0)
try:
with open(pidfile, 'r') as f:
pid = int(f.readline())
except IOError:
sys.exit(1)
if args.command == 'stop':
try:
with open(os.path.join(private_data_dir, 'args'), 'r') as args:
handle_termination(pid, json.load(args), 'bwrap')
except IOError:
handle_termination(pid, [], 'bwrap')
elif args.command == 'is-alive':
try:
os.kill(pid, signal.SIG_DFL)
sys.exit(0)
except OSError:
sys.exit(1)

View File

@@ -11,21 +11,25 @@ from jinja2 import Environment, StrictUndefined
from jinja2.exceptions import UndefinedError, TemplateSyntaxError
# 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,
)
from django.db.models.signals import m2m_changed
from django.db import models
from django.db.models.fields.related import add_lazy_relation
from django.db.models.fields.related import lazy_related_operation
from django.db.models.fields.related_descriptors import (
ReverseOneToOneDescriptor,
ForwardManyToOneDescriptor,
ManyToManyDescriptor,
ReverseManyToOneDescriptor,
create_forward_many_to_many_manager
)
from django.utils.encoding import smart_text
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
# jsonschema
@@ -34,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
@@ -43,14 +46,17 @@ from rest_framework import serializers
from awx.main.utils.filters import SmartFilter
from awx.main.utils.encryption import encrypt_value, decrypt_value, get_encryption_key
from awx.main.validators import validate_ssh_private_key
from awx.main.models.rbac import batch_role_ancestor_rebuilding, Role
from awx.main.models.rbac import (
batch_role_ancestor_rebuilding, Role,
ROLE_SINGLETON_SYSTEM_ADMINISTRATOR, ROLE_SINGLETON_SYSTEM_AUDITOR
)
from awx.main.constants import ENV_BLACKLIST
from awx.main import utils
__all__ = ['AutoOneToOneField', 'ImplicitRoleField', 'JSONField',
'SmartFilterField', 'update_role_parentage_for_instance',
'is_implicit_parent']
'SmartFilterField', 'OrderedManyToManyField',
'update_role_parentage_for_instance', 'is_implicit_parent']
# Provide a (better) custom error message for enum jsonschema validation
@@ -70,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):
@@ -85,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):
@@ -106,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
@@ -159,6 +160,13 @@ def is_implicit_parent(parent_role, child_role):
the model definition. This does not include any role parents that
might have been set by the user.
'''
if child_role.content_object is None:
# The only singleton implicit parent is the system admin being
# a parent of the system auditor role
return bool(
child_role.singleton_name == ROLE_SINGLETON_SYSTEM_AUDITOR and
parent_role.singleton_name == ROLE_SINGLETON_SYSTEM_ADMINISTRATOR
)
# Get the list of implicit parents that were defined at the class level.
implicit_parents = getattr(
child_role.content_object.__class__, child_role.role_field
@@ -217,6 +225,7 @@ class ImplicitRoleField(models.ForeignKey):
kwargs.setdefault('related_name', '+')
kwargs.setdefault('null', 'True')
kwargs.setdefault('editable', False)
kwargs.setdefault('on_delete', models.CASCADE)
super(ImplicitRoleField, self).__init__(*args, **kwargs)
def deconstruct(self):
@@ -234,7 +243,9 @@ class ImplicitRoleField(models.ForeignKey):
post_save.connect(self._post_save, cls, True, dispatch_uid='implicit-role-post-save')
post_delete.connect(self._post_delete, cls, True, dispatch_uid='implicit-role-post-delete')
add_lazy_relation(cls, self, "self", self.bind_m2m_changed)
function = lambda local, related, field: self.bind_m2m_changed(field, related, local)
lazy_related_operation(function, cls, "self", field=self)
def bind_m2m_changed(self, _self, _role_class, cls):
if not self.parent_role:
@@ -437,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):
@@ -480,6 +476,86 @@ def format_ssh_private_key(value):
return True
@JSONSchemaField.format_checker.checks('url')
def format_url(value):
try:
parsed = urllib.parse.urlparse(value)
except Exception as e:
raise jsonschema.exceptions.FormatError(str(e))
if parsed.scheme == '':
raise jsonschema.exceptions.FormatError(
'Invalid URL: Missing url scheme (http, https, etc.)'
)
if parsed.netloc == '':
raise jsonschema.exceptions.FormatError(
'Invalid URL: {}'.format(value)
)
return True
class DynamicCredentialInputField(JSONSchemaField):
"""
Used to validate JSON for
`awx.main.models.credential:CredentialInputSource().metadata`.
Metadata for input sources is represented as a dictionary e.g.,
{'secret_path': '/kv/somebody', 'secret_key': 'password'}
For the data to be valid, the keys of this dictionary should correspond
with the metadata field (and datatypes) defined in the associated
target CredentialType e.g.,
"""
def schema(self, credential_type):
# determine the defined fields for the associated credential type
properties = {}
for field in credential_type.inputs.get('metadata', []):
field = field.copy()
properties[field['id']] = field
if field.get('choices', []):
field['enum'] = list(field['choices'])[:]
return {
'type': 'object',
'properties': properties,
'additionalProperties': False,
}
def validate(self, value, model_instance):
if not isinstance(value, dict):
return super(DynamicCredentialInputField, self).validate(value, model_instance)
super(JSONSchemaField, self).validate(value, model_instance)
credential_type = model_instance.source_credential.credential_type
errors = {}
for error in Draft4Validator(
self.schema(credential_type),
format_checker=self.format_checker
).iter_errors(value):
if error.validator == 'pattern' and 'error' in error.schema:
error.message = error.schema['error'].format(instance=error.instance)
if 'id' not in error.schema:
# If the error is not for a specific field, it's specific to
# `inputs` in general
raise django_exceptions.ValidationError(
error.message,
code='invalid',
params={'value': value},
)
errors[error.schema['id']] = [error.message]
defined_metadata = [field.get('id') for field in credential_type.inputs.get('metadata', [])]
for field in credential_type.inputs.get('required', []):
if field in defined_metadata and not value.get(field, None):
errors[field] = [_('required for %s') % (
credential_type.name
)]
if errors:
raise serializers.ValidationError({
'metadata': errors
})
class CredentialInputField(JSONSchemaField):
"""
Used to validate JSON for
@@ -542,7 +618,7 @@ class CredentialInputField(JSONSchemaField):
v != '$encrypted$',
model_instance.pk
]):
if not isinstance(getattr(model_instance, k), str):
if not isinstance(model_instance.inputs.get(k), str):
raise django_exceptions.ValidationError(
_('secret values must be of type string, not {}').format(type(v).__name__),
code='invalid',
@@ -592,18 +668,13 @@ class CredentialInputField(JSONSchemaField):
)
errors[error.schema['id']] = [error.message]
inputs = model_instance.credential_type.inputs
for field in inputs.get('required', []):
if not value.get(field, None):
errors[field] = [_('required for %s') % (
model_instance.credential_type.name
)]
defined_fields = model_instance.credential_type.defined_fields
# `ssh_key_unlock` requirements are very specific and can't be
# represented without complicated JSON schema
if (
model_instance.credential_type.managed_by_tower is True and
'ssh_key_unlock' in model_instance.credential_type.defined_fields
'ssh_key_unlock' in defined_fields
):
# in order to properly test the necessity of `ssh_key_unlock`, we
@@ -613,15 +684,15 @@ class CredentialInputField(JSONSchemaField):
# 'ssh_key_unlock': 'do-you-need-me?',
# }
# ...we have to fetch the actual key value from the database
if model_instance.pk and model_instance.ssh_key_data == '$encrypted$':
model_instance.ssh_key_data = model_instance.__class__.objects.get(
if model_instance.pk and model_instance.inputs.get('ssh_key_data') == '$encrypted$':
model_instance.inputs['ssh_key_data'] = model_instance.__class__.objects.get(
pk=model_instance.pk
).ssh_key_data
).inputs.get('ssh_key_data')
if model_instance.has_encrypted_ssh_key_data and not value.get('ssh_key_unlock'):
errors['ssh_key_unlock'] = [_('must be set when SSH key is encrypted.')]
if all([
model_instance.ssh_key_data,
model_instance.inputs.get('ssh_key_data'),
value.get('ssh_key_unlock'),
not model_instance.has_encrypted_ssh_key_data
]):
@@ -654,7 +725,7 @@ class CredentialTypeInputField(JSONSchemaField):
'type': 'object',
'properties': {
'type': {'enum': ['string', 'boolean']},
'format': {'enum': ['ssh_private_key']},
'format': {'enum': ['ssh_private_key', 'url']},
'choices': {
'type': 'array',
'minItems': 1,
@@ -895,7 +966,87 @@ 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
class OrderedManyToManyDescriptor(ManyToManyDescriptor):
"""
Django doesn't seem to support:
class Meta:
ordering = [...]
...on custom through= relations for ManyToMany fields.
Meaning, queries made _through_ the intermediary table will _not_ apply an
ORDER_BY clause based on the `Meta.ordering` of the intermediary M2M class
(which is the behavior we want for "ordered" many to many relations):
https://github.com/django/django/blob/stable/1.11.x/django/db/models/fields/related_descriptors.py#L593
This descriptor automatically sorts all queries through this relation
using the `position` column on the M2M table.
"""
@cached_property
def related_manager_cls(self):
model = self.rel.related_model if self.reverse else self.rel.model
def add_custom_queryset_to_many_related_manager(many_related_manage_cls):
class OrderedManyRelatedManager(many_related_manage_cls):
def get_queryset(self):
return super(OrderedManyRelatedManager, self).get_queryset().order_by(
'%s__position' % self.through._meta.model_name
)
return OrderedManyRelatedManager
return add_custom_queryset_to_many_related_manager(
create_forward_many_to_many_manager(
model._default_manager.__class__,
self.rel,
reverse=self.reverse,
)
)
class OrderedManyToManyField(models.ManyToManyField):
"""
A ManyToManyField that automatically sorts all querysets
by a special `position` column on the M2M table
"""
def _update_m2m_position(self, sender, **kwargs):
if kwargs.get('action') in ('post_add', 'post_remove'):
order_with_respect_to = None
for field in sender._meta.local_fields:
if (
isinstance(field, models.ForeignKey) and
isinstance(kwargs['instance'], field.related_model)
):
order_with_respect_to = field.name
for i, ig in enumerate(sender.objects.filter(**{
order_with_respect_to: kwargs['instance'].pk}
)):
if ig.position != i:
ig.position = i
ig.save()
def contribute_to_class(self, cls, name, **kwargs):
super(OrderedManyToManyField, self).contribute_to_class(cls, name, **kwargs)
setattr(
cls, name,
OrderedManyToManyDescriptor(self.remote_field, reverse=False)
)
through = getattr(cls, name).through
if isinstance(through, str) and "." not in through:
# support lazy loading of string model names
through = '.'.join([cls._meta.app_label, through])
m2m_changed.connect(
self._update_m2m_position,
sender=through
)

View File

@@ -0,0 +1,404 @@
import fnmatch
import json
import os
import shutil
import stat
import tempfile
import time
import logging
from django.conf import settings
import ansible_runner
import awx
from awx.main.utils import get_system_task_capacity
from awx.main.queue import CallbackQueueDispatcher
logger = logging.getLogger('awx.isolated.manager')
playbook_logger = logging.getLogger('awx.isolated.manager.playbooks')
def set_pythonpath(venv_libdir, env):
env.pop('PYTHONPATH', None) # default to none if no python_ver matches
for version in os.listdir(venv_libdir):
if fnmatch.fnmatch(version, 'python[23].*'):
if os.path.isdir(os.path.join(venv_libdir, version)):
env['PYTHONPATH'] = os.path.join(venv_libdir, version, "site-packages") + ":"
break
class IsolatedManager(object):
def __init__(self, cancelled_callback=None, check_callback=None):
"""
:param cancelled_callback: a callable - which returns `True` or `False`
- signifying if the job has been prematurely
cancelled
"""
self.cancelled_callback = cancelled_callback
self.check_callback = check_callback
self.idle_timeout = max(60, 2 * settings.AWX_ISOLATED_CONNECTION_TIMEOUT)
self.started_at = None
self.captured_command_artifact = False
def build_runner_params(self, hosts, verbosity=1):
env = dict(os.environ.items())
env['ANSIBLE_RETRY_FILES_ENABLED'] = 'False'
env['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
env['ANSIBLE_LIBRARY'] = os.path.join(os.path.dirname(awx.__file__), 'plugins', 'isolated')
set_pythonpath(os.path.join(settings.ANSIBLE_VENV_PATH, 'lib'), env)
def finished_callback(runner_obj):
if runner_obj.status == 'failed' and runner_obj.config.playbook != 'check_isolated.yml':
# failed for clean_isolated.yml just means the playbook hasn't
# exited on the isolated host
stdout = runner_obj.stdout.read()
playbook_logger.error(stdout)
elif runner_obj.status == 'timeout':
# this means that the default idle timeout of
# (2 * AWX_ISOLATED_CONNECTION_TIMEOUT) was exceeded
# (meaning, we tried to sync with an isolated node, and we got
# no new output for 2 * AWX_ISOLATED_CONNECTION_TIMEOUT seconds)
# this _usually_ means SSH key auth from the controller ->
# isolated didn't work, and ssh is hung waiting on interactive
# input e.g.,
#
# awx@isolated's password:
stdout = runner_obj.stdout.read()
playbook_logger.error(stdout)
else:
playbook_logger.info(runner_obj.stdout.read())
inventory = '\n'.join([
'{} ansible_ssh_user={}'.format(host, settings.AWX_ISOLATED_USERNAME)
for host in hosts
])
return {
'project_dir': os.path.abspath(os.path.join(
os.path.dirname(awx.__file__),
'playbooks'
)),
'inventory': inventory,
'envvars': env,
'finished_callback': finished_callback,
'verbosity': verbosity,
'cancel_callback': self.cancelled_callback,
'settings': {
'idle_timeout': self.idle_timeout,
'job_timeout': settings.AWX_ISOLATED_LAUNCH_TIMEOUT,
'pexpect_timeout': getattr(settings, 'PEXPECT_TIMEOUT', 5),
'suppress_ansible_output': True,
},
}
def path_to(self, *args):
return os.path.join(self.private_data_dir, *args)
def run_management_playbook(self, playbook, private_data_dir, **kw):
iso_dir = tempfile.mkdtemp(
prefix=playbook,
dir=private_data_dir
)
params = self.runner_params.copy()
params['playbook'] = playbook
params['private_data_dir'] = iso_dir
params.update(**kw)
if all([
getattr(settings, 'AWX_ISOLATED_KEY_GENERATION', False) is True,
getattr(settings, 'AWX_ISOLATED_PRIVATE_KEY', None)
]):
params['ssh_key'] = settings.AWX_ISOLATED_PRIVATE_KEY
return ansible_runner.interface.run(**params)
def dispatch(self, playbook=None, module=None, module_args=None):
'''
Ship the runner payload to a remote host for isolated execution.
'''
self.handled_events = set()
self.started_at = time.time()
# exclude certain files from the rsync
rsync_exclude = [
# don't rsync source control metadata (it can be huge!)
'- /project/.git',
'- /project/.svn',
'- /project/.hg',
# don't rsync job events that are in the process of being written
'- /artifacts/job_events/*-partial.json.tmp',
# don't rsync the ssh_key FIFO
'- /env/ssh_key',
]
for filename, data in (
['.rsync-filter', '\n'.join(rsync_exclude)],
):
path = self.path_to(filename)
with open(path, 'w') as f:
f.write(data)
os.chmod(path, stat.S_IRUSR)
extravars = {
'src': self.private_data_dir,
'dest': settings.AWX_PROOT_BASE_PATH,
'ident': self.ident
}
if playbook:
extravars['playbook'] = playbook
if module and module_args:
extravars['module'] = module
extravars['module_args'] = module_args
logger.debug('Starting job {} on isolated host with `run_isolated.yml` playbook.'.format(self.instance.id))
runner_obj = self.run_management_playbook('run_isolated.yml',
self.private_data_dir,
extravars=extravars)
return runner_obj.status, runner_obj.rc
def check(self, interval=None):
"""
Repeatedly poll the isolated node to determine if the job has run.
On success, copy job artifacts to the controlling node.
On failure, continue to poll the isolated node (until the job timeout
is exceeded).
For a completed job run, this function returns (status, rc),
representing the status and return code of the isolated
`ansible-playbook` run.
:param interval: an interval (in seconds) to wait between status polls
"""
interval = interval if interval is not None else settings.AWX_ISOLATED_CHECK_INTERVAL
extravars = {'src': self.private_data_dir}
status = 'failed'
rc = None
last_check = time.time()
dispatcher = CallbackQueueDispatcher()
while status == 'failed':
canceled = self.cancelled_callback() if self.cancelled_callback else False
if not canceled and time.time() - last_check < interval:
# If the job isn't cancelled, but we haven't waited `interval` seconds, wait longer
time.sleep(1)
continue
if canceled:
logger.warning('Isolated job {} was manually cancelled.'.format(self.instance.id))
logger.debug('Checking on isolated job {} with `check_isolated.yml`.'.format(self.instance.id))
runner_obj = self.run_management_playbook('check_isolated.yml',
self.private_data_dir,
extravars=extravars)
status, rc = runner_obj.status, runner_obj.rc
if self.check_callback is not None and not self.captured_command_artifact:
command_path = self.path_to('artifacts', self.ident, 'command')
# If the configuration artifact has been synced back, update the model
if os.path.exists(command_path):
try:
with open(command_path, 'r') as f:
data = json.load(f)
self.check_callback(data)
self.captured_command_artifact = True
except json.decoder.JSONDecodeError: # Just in case it's not fully here yet.
pass
self.consume_events(dispatcher)
last_check = time.time()
if status == 'successful':
status_path = self.path_to('artifacts', self.ident, 'status')
rc_path = self.path_to('artifacts', self.ident, 'rc')
if os.path.exists(status_path):
with open(status_path, 'r') as f:
status = f.readline()
with open(rc_path, 'r') as f:
rc = int(f.readline())
else:
# if there's no status file, it means that runner _probably_
# exited with a traceback (which should be logged to
# daemon.log) Record it so we can see how runner failed.
daemon_path = self.path_to('daemon.log')
if os.path.exists(daemon_path):
with open(daemon_path, 'r') as f:
self.instance.result_traceback = f.read()
self.instance.save(update_fields=['result_traceback'])
else:
logger.error('Failed to rsync daemon.log (is ansible-runner installed on the isolated host?)')
status = 'failed'
rc = 1
# consume events one last time just to be sure we didn't miss anything
# in the final sync
self.consume_events(dispatcher)
# emit an EOF event
event_data = {
'event': 'EOF',
'final_counter': len(self.handled_events)
}
event_data.setdefault(self.event_data_key, self.instance.id)
dispatcher.dispatch(event_data)
return status, rc
def consume_events(self, dispatcher):
# discover new events and ingest them
events_path = self.path_to('artifacts', self.ident, 'job_events')
# it's possible that `events_path` doesn't exist *yet*, because runner
# hasn't actually written any events yet (if you ran e.g., a sleep 30)
# only attempt to consume events if any were rsynced back
if os.path.exists(events_path):
for event in set(os.listdir(events_path)) - self.handled_events:
path = os.path.join(events_path, event)
if os.path.exists(path):
try:
event_data = json.load(
open(os.path.join(events_path, event), 'r')
)
except json.decoder.JSONDecodeError:
# This means the event we got back isn't valid JSON
# that can happen if runner is still partially
# writing an event file while it's rsyncing
# these event writes are _supposed_ to be atomic
# but it doesn't look like they actually are in
# practice
# in this scenario, just ignore this event and try it
# again on the next sync
pass
event_data.setdefault(self.event_data_key, self.instance.id)
dispatcher.dispatch(event_data)
self.handled_events.add(event)
# handle artifacts
if event_data.get('event_data', {}).get('artifact_data', {}):
self.instance.artifacts = event_data['event_data']['artifact_data']
self.instance.save(update_fields=['artifacts'])
def cleanup(self):
# If the job failed for any reason, make a last-ditch effort at cleanup
extravars = {
'private_data_dir': self.private_data_dir,
'cleanup_dirs': [
self.private_data_dir,
],
}
logger.debug('Cleaning up job {} on isolated host with `clean_isolated.yml` playbook.'.format(self.instance.id))
self.run_management_playbook(
'clean_isolated.yml',
self.private_data_dir,
extravars=extravars
)
@classmethod
def update_capacity(cls, instance, task_result):
instance.version = 'ansible-runner-{}'.format(task_result['version'])
if instance.capacity == 0 and task_result['capacity_cpu']:
logger.warning('Isolated instance {} has re-joined.'.format(instance.hostname))
instance.cpu = int(task_result['cpu'])
instance.memory = int(task_result['mem'])
instance.cpu_capacity = int(task_result['capacity_cpu'])
instance.mem_capacity = int(task_result['capacity_mem'])
instance.capacity = get_system_task_capacity(scale=instance.capacity_adjustment,
cpu_capacity=int(task_result['capacity_cpu']),
mem_capacity=int(task_result['capacity_mem']))
instance.save(update_fields=['cpu', 'memory', 'cpu_capacity', 'mem_capacity', 'capacity', 'version', 'modified'])
def health_check(self, instance_qs):
'''
:param instance_qs: List of Django objects representing the
isolated instances to manage
Runs playbook that will
- determine if instance is reachable
- find the instance capacity
- clean up orphaned private files
Performs save on each instance to update its capacity.
'''
instance_qs = [i for i in instance_qs if i.enabled]
if not len(instance_qs):
return
try:
private_data_dir = tempfile.mkdtemp(
prefix='awx_iso_heartbeat_',
dir=settings.AWX_PROOT_BASE_PATH
)
self.runner_params = self.build_runner_params([
instance.hostname for instance in instance_qs
])
self.runner_params['private_data_dir'] = private_data_dir
self.runner_params['forks'] = len(instance_qs)
runner_obj = self.run_management_playbook(
'heartbeat_isolated.yml',
private_data_dir
)
if runner_obj.status == 'successful':
for instance in instance_qs:
task_result = {}
try:
task_result = runner_obj.get_fact_cache(instance.hostname)
except Exception:
logger.exception('Failed to read status from isolated instances')
if 'awx_capacity_cpu' in task_result and 'awx_capacity_mem' in task_result:
task_result = {
'cpu': task_result['awx_cpu'],
'mem': task_result['awx_mem'],
'capacity_cpu': task_result['awx_capacity_cpu'],
'capacity_mem': task_result['awx_capacity_mem'],
'version': task_result['awx_capacity_version']
}
IsolatedManager.update_capacity(instance, task_result)
logger.debug('Isolated instance {} successful heartbeat'.format(instance.hostname))
elif instance.capacity == 0:
logger.debug('Isolated instance {} previously marked as lost, could not re-join.'.format(
instance.hostname))
else:
logger.warning('Could not update status of isolated instance {}'.format(instance.hostname))
if instance.is_lost(isolated=True):
instance.capacity = 0
instance.save(update_fields=['capacity'])
logger.error('Isolated instance {} last checked in at {}, marked as lost.'.format(
instance.hostname, instance.modified))
finally:
if os.path.exists(private_data_dir):
shutil.rmtree(private_data_dir)
def run(self, instance, private_data_dir, playbook, module, module_args,
event_data_key, ident=None):
"""
Run a job on an isolated host.
:param instance: a `model.Job` instance
:param private_data_dir: an absolute path on the local file system
where job-specific data should be written
(i.e., `/tmp/awx_N_xyz/`)
:param playbook: the playbook to run
:param module: the module to run
:param module_args: the module args to use
:param event_data_key: e.g., job_id, inventory_id, ...
For a completed job run, this function returns (status, rc),
representing the status and return code of the isolated
`ansible-playbook` run.
"""
self.ident = ident
self.event_data_key = event_data_key
self.instance = instance
self.private_data_dir = private_data_dir
self.runner_params = self.build_runner_params(
[instance.execution_node],
verbosity=min(5, self.instance.verbosity)
)
status, rc = self.dispatch(playbook, module, module_args)
if status == 'successful':
status, rc = self.check()
else:
# emit an EOF event
event_data = {'event': 'EOF', 'final_counter': 0}
event_data.setdefault(self.event_data_key, self.instance.id)
CallbackQueueDispatcher().dispatch(event_data)
return status, rc

View File

@@ -59,7 +59,7 @@ class Command(BaseCommand):
if len(pks_to_delete):
ActivityStream.objects.filter(pk__in=pks_to_delete).delete()
n_deleted_items += len(pks_to_delete)
self.logger.log(99, "Removed %d items", n_deleted_items)
self.logger.info("Removed {} items".format(n_deleted_items))
def handle(self, *args, **options):
self.verbosity = int(options.get('verbosity', 1))

View File

@@ -1,148 +0,0 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved
# Python
import re
import sys
from dateutil.relativedelta import relativedelta
# Django
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.utils.timezone import now
# AWX
from awx.main.models.fact import Fact
from awx.conf.license import feature_enabled
OLDER_THAN = 'older_than'
GRANULARITY = 'granularity'
class CleanupFacts(object):
def __init__(self):
self.timestamp = None
# Find all with timestamp < older_than
# Start search at < older_than, stop search at oldest entry
# Find all factVersion < pivot && > (pivot - granularity) grouped by host sorted by time descending (because it's indexed this way)
# foreach group
# Delete all except LAST entry (or Delete all except the FIRST entry, it's an arbitrary decision)
#
# pivot -= granularity
# group by host
def cleanup(self, older_than_abs, granularity, module=None):
fact_oldest = Fact.objects.all().order_by('timestamp').first()
if not fact_oldest:
return 0
kv = {
'timestamp__lte': older_than_abs
}
if module:
kv['module'] = module
# Special case, granularity=0x where x is d, w, or y
# The intent is to delete all facts < older_than_abs
if granularity == relativedelta():
qs = Fact.objects.filter(**kv)
count = qs.count()
qs.delete()
return count
total = 0
date_pivot = older_than_abs
while date_pivot > fact_oldest.timestamp:
date_pivot_next = date_pivot - granularity
# For the current time window.
# Delete all facts expect the fact that matches the largest timestamp.
kv = {
'timestamp__lte': date_pivot
}
if module:
kv['module'] = module
fact_version_obj = Fact.objects.filter(**kv).order_by('-timestamp').first()
if fact_version_obj:
kv = {
'timestamp__lt': fact_version_obj.timestamp,
'timestamp__gt': date_pivot_next
}
if module:
kv['module'] = module
qs = Fact.objects.filter(**kv)
count = qs.count()
qs.delete()
total += count
date_pivot = date_pivot_next
return total
'''
older_than and granularity are of type relativedelta
'''
def run(self, older_than, granularity, module=None):
t = now()
deleted_count = self.cleanup(t - older_than, granularity, module=module)
print("Deleted %d facts." % deleted_count)
class Command(BaseCommand):
help = 'Cleanup facts. For each host older than the value specified, keep one fact scan for each time window (granularity).'
def add_arguments(self, parser):
parser.add_argument('--older_than',
dest='older_than',
default='30d',
help='Specify the relative time to consider facts older than (w)eek (d)ay or (y)ear (i.e. 5d, 2w, 1y). Defaults to 30d.')
parser.add_argument('--granularity',
dest='granularity',
default='1w',
help='Window duration to group same hosts by for deletion (w)eek (d)ay or (y)ear (i.e. 5d, 2w, 1y). Defaults to 1w.')
parser.add_argument('--module',
dest='module',
default=None,
help='Limit cleanup to a particular module.')
def __init__(self):
super(Command, self).__init__()
def string_time_to_timestamp(self, time_string):
units = {
'y': 'years',
'd': 'days',
'w': 'weeks',
'm': 'months'
}
try:
match = re.match(r'(?P<value>[0-9]+)(?P<unit>.*)', time_string)
group = match.groupdict()
kv = {}
units_verbose = units[group['unit']]
kv[units_verbose]= int(group['value'])
return relativedelta(**kv)
except (KeyError, TypeError, AttributeError):
return None
@transaction.atomic
def handle(self, *args, **options):
sys.stderr.write("This command has been deprecated and will be removed in a future release.\n")
if not feature_enabled('system_tracking'):
raise CommandError("The System Tracking feature is not enabled for your instance")
cleanup_facts = CleanupFacts()
if not all([options[GRANULARITY], options[OLDER_THAN]]):
raise CommandError('Both --granularity and --older_than are required.')
older_than = self.string_time_to_timestamp(options[OLDER_THAN])
granularity = self.string_time_to_timestamp(options[GRANULARITY])
if older_than is None:
raise CommandError('--older_than invalid value "%s"' % options[OLDER_THAN])
if granularity is None:
raise CommandError('--granularity invalid value "%s"' % options[GRANULARITY])
cleanup_facts.run(older_than, granularity, module=options['module'])

View File

@@ -0,0 +1,25 @@
import logging
from django.core import management
from django.core.management.base import BaseCommand
from django.contrib.sessions.models import Session
class Command(BaseCommand):
def init_logging(self):
log_levels = dict(enumerate([logging.ERROR, logging.INFO,
logging.DEBUG, 0]))
self.logger = logging.getLogger('awx.main.commands.cleanup_sessions')
self.logger.setLevel(log_levels.get(self.verbosity, 0))
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(message)s'))
self.logger.addHandler(handler)
self.logger.propagate = False
def execute(self, *args, **options):
self.verbosity = int(options.get('verbosity', 1))
self.init_logging()
total_sessions = Session.objects.all().count()
management.call_command('clearsessions')
self.logger.info("Expired Sessions deleted {}".format(total_sessions - Session.objects.all().count()))

View File

@@ -0,0 +1,28 @@
import logging
from django.core import management
from django.core.management.base import BaseCommand
from awx.main.models import OAuth2AccessToken
from oauth2_provider.models import RefreshToken
class Command(BaseCommand):
def init_logging(self):
log_levels = dict(enumerate([logging.ERROR, logging.INFO,
logging.DEBUG, 0]))
self.logger = logging.getLogger('awx.main.commands.cleanup_tokens')
self.logger.setLevel(log_levels.get(self.verbosity, 0))
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(message)s'))
self.logger.addHandler(handler)
self.logger.propagate = False
def execute(self, *args, **options):
self.verbosity = int(options.get('verbosity', 1))
self.init_logging()
total_accesstokens = OAuth2AccessToken.objects.all().count()
total_refreshtokens = RefreshToken.objects.all().count()
management.call_command('cleartokens')
self.logger.info("Expired OAuth 2 Access Tokens deleted: {}".format(total_accesstokens - OAuth2AccessToken.objects.all().count()))
self.logger.info("Expired OAuth 2 Refresh Tokens deleted: {}".format(total_refreshtokens - RefreshToken.objects.all().count()))

View File

@@ -34,7 +34,7 @@ class Command(BaseCommand):
scm_update_cache_timeout=0,
organization=o)
p.save(skip_update=True)
ssh_type = CredentialType.from_v1_kind('ssh')
ssh_type = CredentialType.objects.filter(namespace='ssh').first()
c = Credential.objects.create(credential_type=ssh_type,
name='Demo Credential',
inputs={
@@ -47,7 +47,7 @@ class Command(BaseCommand):
created_by=superuser)
Host.objects.create(name='localhost',
inventory=i,
variables="ansible_connection: local",
variables="ansible_connection: local\nansible_python_interpreter: '{{ ansible_playbook_python }}'",
created_by=superuser)
jt = JobTemplate.objects.create(name='Demo Job Template',
playbook='hello_world.yml',

View File

@@ -4,8 +4,6 @@ from importlib import import_module
# Django
from django.utils import timezone
from django.conf import settings
from django.contrib.auth import logout
from django.http import HttpRequest
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth.models import User
from django.contrib.sessions.models import Session
@@ -29,9 +27,9 @@ class Command(BaseCommand):
# with consideration for timezones.
start = timezone.now()
sessions = Session.objects.filter(expire_date__gte=start).iterator()
request = HttpRequest()
for session in sessions:
user_id = session.get_decoded().get('_auth_user_id')
if (user is None) or (user_id and user.id == int(user_id)):
request.session = import_module(settings.SESSION_ENGINE).SessionStore(session.session_key)
logout(request)
session = import_module(settings.SESSION_ENGINE).SessionStore(session.session_key)
# Log out the session, but without the need for a request object.
session.flush()

View File

@@ -0,0 +1,31 @@
import logging
from awx.main.analytics import gather, ship
from django.core.management.base import BaseCommand
class Command(BaseCommand):
'''
Gather AWX analytics data
'''
help = 'Gather AWX analytics data'
def add_arguments(self, parser):
parser.add_argument('--ship', dest='ship', action='store_true',
help='Enable to ship metrics via insights-client')
def init_logging(self):
self.logger = logging.getLogger('awx.main.analytics')
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
handler.setFormatter(logging.Formatter('%(message)s'))
self.logger.addHandler(handler)
self.logger.propagate = False
def handle(self, *args, **options):
tgz = gather()
self.init_logging()
if tgz:
self.logger.debug(tgz)
if options.get('ship'):
ship(tgz)

View File

@@ -41,6 +41,7 @@ from awx.main.utils import (
from awx.main.utils.common import _get_ansible_version
from awx.main.signals import disable_activity_stream
from awx.main.constants import STANDARD_INVENTORY_UPDATE_ENV
from awx.main.utils.pglock import advisory_lock
logger = logging.getLogger('awx.main.commands.inventory_import')
@@ -75,12 +76,13 @@ class AnsibleInventoryLoader(object):
/usr/bin/ansible/ansible-inventory -i hosts --list
'''
def __init__(self, source, is_custom=False, venv_path=None):
def __init__(self, source, is_custom=False, venv_path=None, verbosity=0):
self.source = source
self.source_dir = functioning_dir(self.source)
self.is_custom = is_custom
self.tmp_private_dir = None
self.method = 'ansible-inventory'
self.verbosity = verbosity
if venv_path:
self.venv_path = venv_path
else:
@@ -134,8 +136,14 @@ class AnsibleInventoryLoader(object):
# https://github.com/ansible/ansible/issues/50714
bargs = ['python', ansible_inventory_path, '-i', self.source]
ansible_version = _get_ansible_version(ansible_inventory_path[:-len('-inventory')])
if ansible_version != 'unknown' and Version(ansible_version) >= Version('2.5'):
bargs.extend(['--playbook-dir', self.source_dir])
if ansible_version != 'unknown':
this_version = Version(ansible_version)
if this_version >= Version('2.5'):
bargs.extend(['--playbook-dir', self.source_dir])
if this_version >= Version('2.8'):
if self.verbosity:
# INFO: -vvv, DEBUG: -vvvvv, for inventory, any more than 3 makes little difference
bargs.append('-{}'.format('v' * min(5, self.verbosity * 2 + 1)))
logger.debug('Using base command: {}'.format(' '.join(bargs)))
return bargs
@@ -302,7 +310,7 @@ class Command(BaseCommand):
if enabled is not default:
enabled_value = getattr(self, 'enabled_value', None)
if enabled_value is not None:
enabled = bool(str(enabled_value) == str(enabled))
enabled = bool(str(enabled_value).lower() == str(enabled).lower())
else:
enabled = bool(enabled)
if enabled is default:
@@ -870,20 +878,21 @@ class Command(BaseCommand):
Load inventory from in-memory groups to the database, overwriting or
merging as appropriate.
'''
# FIXME: Attribute changes to superuser?
# Perform __in queries in batches (mainly for unit tests using SQLite).
self._batch_size = 500
self._build_db_instance_id_map()
self._build_mem_instance_id_map()
if self.overwrite:
self._delete_hosts()
self._delete_groups()
self._delete_group_children_and_hosts()
self._update_inventory()
self._create_update_groups()
self._create_update_hosts()
self._create_update_group_children()
self._create_update_group_hosts()
with advisory_lock('inventory_{}_update'.format(self.inventory.id)):
# FIXME: Attribute changes to superuser?
# Perform __in queries in batches (mainly for unit tests using SQLite).
self._batch_size = 500
self._build_db_instance_id_map()
self._build_mem_instance_id_map()
if self.overwrite:
self._delete_hosts()
self._delete_groups()
self._delete_group_children_and_hosts()
self._update_inventory()
self._create_update_groups()
self._create_update_hosts()
self._create_update_group_children()
self._create_update_group_hosts()
def remote_tower_license_compare(self, local_license_type):
# this requires https://github.com/ansible/ansible/pull/52747
@@ -1025,7 +1034,8 @@ class Command(BaseCommand):
source = self.get_source_absolute_path(self.source)
data = AnsibleInventoryLoader(source=source, is_custom=self.is_custom, venv_path=venv_path).load()
data = AnsibleInventoryLoader(source=source, is_custom=self.is_custom,
venv_path=venv_path, verbosity=self.verbosity).load()
logger.debug('Finished loading from source: %s', source)
logger.info('Processing JSON output...')
@@ -1078,7 +1088,7 @@ class Command(BaseCommand):
logger.warning('update computed fields took %d queries',
len(connection.queries) - queries_before2)
# Check if the license is valid.
# If the license is not valid, a CommandError will be thrown,
# If the license is not valid, a CommandError will be thrown,
# and inventory update will be marked as invalid.
# with transaction.atomic() will roll back the changes.
license_fail = True

View File

@@ -44,8 +44,10 @@ class Command(BaseCommand):
print((fmt + ']').format(instance_group))
for x in instance_group.instances.all():
color = '\033[92m'
if x.capacity == 0 or x.enabled is False:
if x.capacity == 0:
color = '\033[91m'
if x.enabled is False:
color = '\033[90m[DISABLED] '
fmt = '\t' + color + '{0.hostname} capacity={0.capacity} version={1}'
if x.last_isolated_check:
fmt += ' last_isolated_check="{0.last_isolated_check:%Y-%m-%d %H:%M:%S}"'

View File

@@ -3,14 +3,15 @@
from django.conf import settings
from django.core.management.base import BaseCommand
from kombu import Connection, Exchange, Queue
from kombu import Exchange, Queue
from awx.main.dispatch.kombu import Connection
from awx.main.dispatch.worker import AWXConsumer, CallbackBrokerWorker
class Command(BaseCommand):
'''
Save Job Callback receiver (see awx.plugins.callbacks.job_event_callback)
Save Job Callback receiver
Runs as a management command and receives job save events. It then hands
them off to worker processors (see Worker) which writes them to the database
'''

View File

@@ -8,10 +8,12 @@ from django.conf import settings
from django.core.cache import cache as django_cache
from django.core.management.base import BaseCommand
from django.db import connection as django_connection, connections
from kombu import Connection, Exchange, Queue
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
from awx.main.dispatch.pool import AutoscalePool
from awx.main.dispatch.worker import AWXConsumer, TaskWorker
@@ -120,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

@@ -0,0 +1,14 @@
# Copyright (c) 2019 Ansible by Red Hat
# All Rights Reserved.
from django.core.management.base import BaseCommand
from awx.main.models import CredentialType
class Command(BaseCommand):
help = 'Load default managed credential types.'
def handle(self, *args, **options):
CredentialType.setup_tower_managed_defaults()

View File

@@ -1,13 +1,14 @@
import os
import shutil
import subprocess
import sys
import tempfile
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from awx.main.expect import run
import ansible_runner
from awx.main.isolated.manager import set_pythonpath
class Command(BaseCommand):
@@ -25,23 +26,24 @@ class Command(BaseCommand):
try:
path = tempfile.mkdtemp(prefix='awx_isolated_ssh', dir=settings.AWX_PROOT_BASE_PATH)
args = [
'ansible', 'all', '-i', '{},'.format(hostname), '-u',
settings.AWX_ISOLATED_USERNAME, '-T5', '-m', 'shell',
'-a', 'ansible-runner --version', '-vvv'
]
ssh_key = None
if all([
getattr(settings, 'AWX_ISOLATED_KEY_GENERATION', False) is True,
getattr(settings, 'AWX_ISOLATED_PRIVATE_KEY', None)
]):
ssh_key_path = os.path.join(path, '.isolated')
ssh_auth_sock = os.path.join(path, 'ssh_auth.sock')
run.open_fifo_write(ssh_key_path, settings.AWX_ISOLATED_PRIVATE_KEY)
args = run.wrap_args_with_ssh_agent(args, ssh_key_path, ssh_auth_sock)
try:
print(' '.join(args))
subprocess.check_call(args)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
ssh_key = settings.AWX_ISOLATED_PRIVATE_KEY
env = dict(os.environ.items())
set_pythonpath(os.path.join(settings.ANSIBLE_VENV_PATH, 'lib'), env)
res = ansible_runner.interface.run(
private_data_dir=path,
host_pattern='all',
inventory='{} ansible_ssh_user={}'.format(hostname, settings.AWX_ISOLATED_USERNAME),
module='shell',
module_args='ansible-runner --version',
envvars=env,
verbosity=3,
ssh_key=ssh_key,
)
sys.exit(res.rc)
finally:
shutil.rmtree(path)

View File

@@ -18,9 +18,9 @@ from django.db import IntegrityError, connection
from django.utils.functional import curry
from django.shortcuts import get_object_or_404, redirect
from django.apps import apps
from django.utils.deprecation import MiddlewareMixin
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.urls import resolve
from django.urls import reverse, resolve
from awx.main.models import ActivityStream
from awx.main.utils.named_url_graph import generate_graph, GraphNode
@@ -32,7 +32,7 @@ analytics_logger = logging.getLogger('awx.analytics.activity_stream')
perf_logger = logging.getLogger('awx.analytics.performance')
class TimingMiddleware(threading.local):
class TimingMiddleware(threading.local, MiddlewareMixin):
dest = '/var/log/tower/profile'
@@ -65,14 +65,15 @@ class TimingMiddleware(threading.local):
return filepath
class ActivityStreamMiddleware(threading.local):
class ActivityStreamMiddleware(threading.local, MiddlewareMixin):
def __init__(self):
def __init__(self, get_response=None):
self.disp_uid = None
self.instance_ids = []
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
@@ -119,7 +120,7 @@ class ActivityStreamMiddleware(threading.local):
self.instance_ids.append(instance.id)
class SessionTimeoutMiddleware(object):
class SessionTimeoutMiddleware(MiddlewareMixin):
"""
Resets the session timeout for both the UI and the actual session for the API
to the value of SESSION_COOKIE_AGE on every request if there is a valid session.
@@ -127,8 +128,11 @@ class SessionTimeoutMiddleware(object):
def process_response(self, request, response):
should_skip = 'HTTP_X_WS_SESSION_QUIET' in request.META
req_session = getattr(request, 'session', None)
if req_session and not req_session.is_empty() and should_skip is False:
# Something went wrong, such as upgrade-in-progress page
if not hasattr(request, 'session'):
return response
# Only update the session if it hasn't been flushed by being forced to log out.
if request.session and not request.session.is_empty() and not should_skip:
expiry = int(settings.SESSION_COOKIE_AGE)
request.session.set_expiry(expiry)
response['Session-Timeout'] = expiry
@@ -149,9 +153,9 @@ def _customize_graph():
settings.NAMED_URL_GRAPH[Instance].add_bindings()
class URLModificationMiddleware(object):
class URLModificationMiddleware(MiddlewareMixin):
def __init__(self):
def __init__(self, get_response=None):
models = [m for m in apps.get_app_config('main').get_models() if hasattr(m, 'get_absolute_url')]
generate_graph(models)
_customize_graph()
@@ -175,6 +179,7 @@ class URLModificationMiddleware(object):
category=_('Named URL'),
category_slug='named-url',
)
super().__init__(get_response)
def _named_url_to_pk(self, node, named_url):
kwargs = {}
@@ -205,7 +210,7 @@ class URLModificationMiddleware(object):
request.path_info = new_path
class MigrationRanCheckMiddleware(object):
class MigrationRanCheckMiddleware(MiddlewareMixin):
def process_request(self, request):
executor = MigrationExecutor(connection)

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',

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