Compare commits

...

1024 Commits
1.0.0 ... 1.0.2

Author SHA1 Message Date
Ryan Petrello
05bec924e4 Merge pull request #795 from ryanpetrello/move-deprecated-stdout
move legacy UnifiedJob stdout data to a separate unmanaged model
2017-12-13 09:35:58 -05:00
Jake McDermott
40d1f2671f Merge pull request #811 from AlanCoding/i_wont_be_ignored
Fix bug creating inventory source schedules
2017-12-12 18:32:54 -05:00
Ryan Petrello
202161f090 move legacy UnifiedJob stdout data to a separate unmanaged model
This data often (in the case of inventory updates) represents large data
blobs (5+MB per job run).  Storing it on the polymorphic base class
table, `main_unifiedjob`, causes it to be automatically fetched on every
query (and every polymorphic join) against that table, which can result
in _very_ poor performance for awx across the board.  Django offers
`defer()`, but it's quite complicated to sprinkle this everywhere (and
easy to get wrong/introduce side effects related to our RBAC and usage
of polymorphism).

This change moves the field definition to a separate unmanaged model
(which references the same underlying `main_unifiedjob` table) and adds
a proxy for fetching the data as needed

see https://github.com/ansible/awx/issues/200
2017-12-12 18:16:19 -05:00
AlanCoding
7243f871b4 fix bug creating inventory source schedules 2017-12-12 17:49:51 -05:00
Jared Tabor
2c64a2ce63 Merge pull request #783 from jaredevantabor/notification-toggle
fixing url used for determining which notification to toggle on/off
2017-12-12 11:31:48 -08:00
Jared Tabor
86eb0353c5 fixing url used for determining which notification to toggle on/off
for #711
2017-12-12 11:07:21 -08:00
Matthew Jones
282290e151 Fix an issue referencing postgres port from openshift deployment 2017-12-12 10:52:02 -05:00
Alan Rominger
8d348f916b Merge pull request #794 from AlanCoding/hide_config_pass
Hide survey passwords in saved launch configs
2017-12-12 10:37:41 -05:00
AlanCoding
659d31324d hide survey passwords in saved launch configs 2017-12-12 09:35:46 -05:00
Ryan Petrello
1bc2d83403 Merge pull request #789 from ryanpetrello/multivault-acceptance
add some more tests and acceptance docs to wrap up multivault support
2017-12-11 20:35:27 -05:00
Ryan Petrello
8c90d36290 add some more tests and acceptance docs to wrap up multivault support
see: https://github.com/ansible/awx/issues/352
2017-12-11 16:56:02 -05:00
Bill Nottingham
9be438a60a Merge pull request #788 from wenottingham/no-country-for-old-python
Don't bother checking for python 2.6 in the venv
2017-12-11 14:57:25 -05:00
Bill Nottingham
c62430c282 Drop python2.6 checks. 2017-12-11 13:59:00 -05:00
Alan Rominger
1be3c77ac6 Merge pull request #787 from AlanCoding/workflow_system_jobs
allow using SystemJobTemplates in workflows
2017-12-11 13:21:33 -05:00
AlanCoding
4adfb9804e allow using SystemJobTemplates in workflows 2017-12-11 08:58:45 -05:00
Alan Rominger
64ac1ee238 Merge pull request #746 from AlanCoding/i_forgot
Intentionally forget start_args when job is done
2017-12-11 08:08:27 -05:00
AlanCoding
0bf06479d5 add migration to remove old start_args 2017-12-10 12:08:59 -05:00
AlanCoding
1f8cab4171 intentionally forget start_args when job is done 2017-12-10 12:08:54 -05:00
Jake McDermott
526bcc4a68 Merge pull request #785 from jakemcdermott/stored-xss-test-update
fix lint error and stabilize stored xss test case
2017-12-10 12:07:46 -05:00
Jake McDermott
9dcdf20fb0 stabilize template form stored xss test case 2017-12-10 11:41:41 -05:00
Jake McDermott
be0f66fd94 fix linting error in stored xss test 2017-12-10 11:39:13 -05:00
Alan Rominger
2135291f35 Merge pull request #740 from AlanCoding/configs_rebased5
Feature: saved launchtime configurations
2017-12-08 16:55:00 -05:00
AlanCoding
a9aae91634 generalize schedule prompts validation
This makes ScheduleSerializer behave same as WFJT nodes
Prevents providing job_type for workflow jobs, as example
2017-12-08 16:23:56 -05:00
AlanCoding
905ff7dad7 fix bugs where ask_ var was checked on node 2017-12-08 13:57:33 -05:00
AlanCoding
e59a724efa fix bug that broke combining WFJT and node vars 2017-12-08 13:48:45 -05:00
AlanCoding
1c8217936d Bug fixes from integration ran on launchtime branch
Make error message for muti-vault validation more
consistent with historical message
2017-12-08 13:46:38 -05:00
AlanCoding
72a8854c27 Make ask_mapping a simple class property
from PR feedback of saved launchtime configurations
2017-12-08 13:45:23 -05:00
AlanCoding
98df442ced combine launch config and multi-cred migrations 2017-12-08 13:45:21 -05:00
AlanCoding
5ada021a6e Tweak validation to allow multiple vault credentials
support providing vault passwords based on id
include needed passwords in launch serializer defaults
2017-12-08 13:43:43 -05:00
AlanCoding
34a8e0a9b6 Feature: saved launchtime configurations
Consolidate prompts accept/reject logic in unified models
Break out accept/reject logic for variables
Surface new promptable fields on WFJT nodes, schedules

Make schedules and workflows accurately reject variables
  that are not allowed by the prompting
  rules or the survey rules on the template

Validate against unallowed extra_data in system job schedules
Prevent schedule or WFJT node POST/PATCH with unprompted data
Move system job days validation to new mechanism
Add new psuedo-field for WFJT node credential
Add validation for node related credentials
Add related config model to unified job
Use JobLaunchConfig model for launch RBAC check

Support credential overwrite behavior with multi-creds
  change modern manual launch to use merge behavior
Refactor JobLaunchSerializer, self.instance=None
Modularize job launch view to create "modern" data
Auto-create config object with every job
Add create schedule endpoint for jobs
2017-12-08 13:38:54 -05:00
Marliana Lara
cd8a4b4669 Merge pull request #645 from marshmalien/feature/retry_failed_hosts
Feature - Retry failed hosts
2017-12-07 12:54:11 -05:00
Matthew Jones
7fc896e183 Merge pull request #774 from matburt/jupyter_for_devel
Adding jupyter notebook support to the AWX development environment
2017-12-06 09:49:07 -05:00
Matthew Jones
da0b686369 Adding jupyter notebook support to the AWX development environment
* Jupyter starts alongside the other awx services and is available on
  0.0.0.0:8888
* make target: make jupyter
* default settings in settings/development.py
* Added jupyter, matplotlib, numpy to dev dependencies
2017-12-05 23:46:18 -05:00
Matthew Jones
9488105381 Merge pull request #773 from shanemcd/devel
Add m2r to setup requirements file
2017-12-05 15:38:31 -05:00
Shane McDonald
ec14ae1930 Add m2r to setup requirements file
We `pip download` this file for offline installs. Automat lists this package as a setup_requires, but `pip download` doesn’t resolve these dependencies (distutils will attempt to install them via easy_install when setup.py is invoked).
2017-12-05 15:26:56 -05:00
Greg Considine
e1e225d6a0 Merge pull request #771 from gconsidine/ui/fix/input-replace-revert
Ui/fix/input replace revert
2017-12-05 13:43:32 -05:00
gconsidine
3ad174b15b Add e2e test case to verify revert/replace 2017-12-05 12:25:48 -05:00
gconsidine
b5644ed65b Fix replace/revert functionality on secret input fields 2017-12-05 10:39:15 -05:00
Jake McDermott
13d84b8d35 Merge pull request #768 from tchia04/fix_typo_credential_types
Fix typo: Failed to get credential tpyes
2017-12-04 22:26:52 -05:00
Tony Chia
9275b024de Update main.js
Changed "credential tpyes" to "credential types"
2017-12-04 16:27:46 -08:00
Jared Tabor
4f8d4994cf Merge pull request #765 from jaredevantabor/fix-764
Update error handling on host service after angular upgrade
2017-12-04 14:28:41 -08:00
Jared Tabor
a3144ee234 Update error handling on host service after angular upgrade 2017-12-04 13:52:34 -08:00
Alan Rominger
7fe22e9c53 Merge pull request #757 from AlanCoding/vault_cred_noop
allow no-op case for vault_credential
2017-12-04 16:01:00 -05:00
Alan Rominger
42d8368596 Merge pull request #763 from AlanCoding/remember_where_you_came_from
add AWX meta extra_vars for workflow + schedule
2017-12-04 15:52:30 -05:00
AlanCoding
eecf997856 add AWX meta extra_vars: WFJT + schedule 2017-12-04 15:33:05 -05:00
Matthew Jones
21bdea05a0 Merge pull request #762 from matburt/fix_pg_port
Make sure we define postgres port customization during install
2017-12-04 14:16:09 -05:00
Matthew Jones
a3071c2a1f Make sure we define postgres port customization during install 2017-12-04 11:08:40 -05:00
Matthew Jones
cf0cc2e2f2 Add system requirements to install docs 2017-12-04 07:56:34 -05:00
Ryan Petrello
e7918ad637 Merge pull request #752 from ryanpetrello/multivault
support specifying multiple vault IDs for a playbook run
2017-12-01 11:43:39 -05:00
AlanCoding
dfc154ed95 allow no-op case for vault_credential 2017-12-01 10:29:23 -05:00
Ryan Petrello
a1f8f65add support specifying multiple vault IDs for a playbook run
see: https://github.com/ansible/awx/issues/352
2017-11-30 16:55:17 -05:00
Alan Rominger
fde5a8850d Merge pull request #748 from AlanCoding/no_job_in_relaunch
Do not show job serialization in relaunch GET
2017-11-30 09:58:35 -05:00
AlanCoding
c359c072c4 do not show job serialization in relaunch GET 2017-11-30 08:47:35 -05:00
Jake McDermott
ee0aa40542 Merge pull request #743 from jakemcdermott/gcp-service-file
fix submit when no input object defined
2017-11-29 20:50:24 -05:00
Jake McDermott
81f2184aa7 fix submit when no input object defined 2017-11-29 19:50:46 -05:00
Jake McDermott
96c66b1e20 Merge pull request #712 from jakemcdermott/gcp-service-file
add input field for gcp service account json file
2017-11-29 18:41:23 -05:00
Jake McDermott
dbb9ffbaf4 use settings when setting up user data 2017-11-29 18:27:46 -05:00
Jake McDermott
06a7c024fe add e2e test for gcp service account file input 2017-11-29 18:27:34 -05:00
Jake McDermott
1229a10f35 add gcp service account file input 2017-11-29 18:27:24 -05:00
Jake McDermott
f15b1ae549 disable textarea drag and drop when field is disabled 2017-11-29 18:27:12 -05:00
Jake McDermott
71fea2e360 allow for programmatic input to text and textarea-secret fields 2017-11-29 18:26:59 -05:00
Jake McDermott
5baa371739 add unit test for file input component 2017-11-29 18:26:47 -05:00
Jake McDermott
cc8b5bc808 add file input component 2017-11-29 18:26:36 -05:00
Alan Rominger
53c6248a6d Merge pull request #647 from AlanCoding/no_sql
remove raw SQL in visible_roles
2017-11-29 16:46:09 -05:00
AlanCoding
c4bc310271 remove raw SQL in visible_roles 2017-11-29 16:04:31 -05:00
Chris Meyers
1899795d08 Merge pull request #721 from chrismeyersfsu/feature-2_factor
allow support for saml + 2-factor
2017-11-29 14:54:57 -05:00
Alan Rominger
43c58b5bf5 Merge pull request #731 from AlanCoding/enabled_fix
fix inventory import bug with enabled_var
2017-11-29 14:46:16 -05:00
AlanCoding
2c06bfc9ce fix inventory import bug with enabled_var 2017-11-29 14:12:03 -05:00
Alan Rominger
5602b5d2d7 Merge pull request #733 from AlanCoding/credentials_in_list
Show credentials in list view
2017-11-29 12:09:52 -05:00
Chris Meyers
032318494b added tests for new settings field type 2017-11-29 11:52:00 -05:00
Bill Nottingham
40c22dcec8 Merge pull request #643 from wenottingham/whitespace-the-final-frontier
Fix extra whitespace in callback URL.
2017-11-29 11:29:45 -05:00
Alan Rominger
04f682bf7a Merge pull request #694 from AlanCoding/credentials_not_a_thing
adjust assertions about JT credentials to be correct
2017-11-29 10:41:48 -05:00
Alan Rominger
070a12a10c Merge pull request #692 from AlanCoding/vault_credential_check
Modify JT access tests to reflect new vault_credential reality
2017-11-29 10:40:35 -05:00
Wayne Witzel III
53460db4d7 Merge pull request #736 from ewjoachim/fix-social-core
Fix import of social_core.exceptions in sso/pipeline.py
2017-11-29 09:26:43 -05:00
AlanCoding
37a44c439e show credentials in list view 2017-11-29 08:14:45 -05:00
Joachim Jablon
6609f38fa2 Fix import of social_core.exceptions in sso/pipeline.py
Signed-off-by: Joachim Jablon <ewjoachim@gmail.com>
2017-11-29 14:08:58 +01:00
Alan Rominger
8f5be46d52 Merge pull request #730 from AlanCoding/list_bug
fix bug with inventory update queryset
2017-11-28 18:41:39 -05:00
Bill Nottingham
3866dcaaae Merge pull request #732 from wenottingham/quote-fu
Remove stray quote from help string.
2017-11-28 15:38:42 -05:00
Bill Nottingham
8cede51bac Remove stray quote from help string. 2017-11-28 14:32:39 -05:00
AlanCoding
a880f47925 fix bug with inventory update queryset 2017-11-28 14:13:35 -05:00
Chris Meyers
383c3cfe3e add more saml fields 2017-11-28 13:49:35 -05:00
Shane McDonald
32fcb84cf6 Merge pull request #722 from jakemcdermott/tools-awx-pycrypto
add pycrypto distro package to tools awx container image
2017-11-28 13:42:02 -05:00
Jake McDermott
34195a1b35 add pycrypto distro package to tools awx container image 2017-11-28 12:45:53 -05:00
Greg Considine
c723ba5289 Merge pull request #717 from gconsidine/ui/bump-dependency-versions
Update dependency versions to pull in latest 1.x Angular version
2017-11-28 10:11:12 -05:00
gconsidine
3ff9fa9931 Remove test on async fn with no callback and no returned promise 2017-11-28 09:54:54 -05:00
Wayne Witzel III
3202e77b57 Merge pull request #720 from wwitzel3/devel
Update to asgi_amqp 1.0.1
2017-11-27 14:57:39 -05:00
Wayne Witzel III
a858093db8 Update to asgi_amqp 1.0.1 2017-11-27 19:41:30 +00:00
gconsidine
86a559caef Update dependency versions to pull in latest 1.x Angular version 2017-11-27 11:12:45 -05:00
Michael Abashian
33ff10728d Merge pull request #680 from mabashian/delete-warning-text
Tweaked language on delete warning modal
2017-11-22 15:02:55 -05:00
mabashian
ff1f322c88 Removed unused string from credentials strings 2017-11-22 13:29:52 -05:00
mabashian
d3da899459 Defined delete string in the base with the ability to pass the resource name in 2017-11-22 13:28:02 -05:00
AlanCoding
9fe524cd20 adjust assertions about JT credentials to be correct 2017-11-21 10:03:57 -05:00
AlanCoding
1481a62b23 modify JT access tests to reflect new vault_credential reality 2017-11-21 08:40:04 -05:00
Alan Rominger
ce6d96feda Merge pull request #687 from AlanCoding/new_kill
allow deletion of new jobs
2017-11-21 07:20:05 -05:00
AlanCoding
6c57a3bb68 allow deletion of new jobs 2017-11-20 11:19:22 -05:00
mabashian
565b0b82dd Tweaked language on delete warning modal 2017-11-17 12:45:01 -05:00
Chris Meyers
98f2d936d9 allow support for saml + 2-factor
* python-social-auth has SOCIAL_AUTH_SAML_SECURITY_CONFIG, which is
forwarded to python-saml settings configuration. This commit exposes
SOCIAL_AUTH_SAML_SECURITY_CONFIG to configure tower in tower to allow
users to set requestedAuthnContext, which will disable the requesting of
password type auth from the idp. Thus, it's up to the idp to choose
which auth to use (i.e. 2-factor).
2017-11-17 09:25:50 -05:00
Matthew Jones
9b5371f2ab Merge pull request #670 from chrismeyersfsu/job_events_docs
add docs for job events
2017-11-16 13:46:35 -05:00
Chris Meyers
c4e6fc23fc add docs for job events
* Focus on the ordering of Job Event creation. Important to know when
thinking through different Ansible execution strategies.
2017-11-16 12:48:48 -05:00
Alan Rominger
71127c039d Merge pull request #668 from AlanCoding/null_cred_okay2
Do not filter out JTs with null credentials
2017-11-16 11:18:16 -05:00
AlanCoding
127da5525c do not filter out JTs with null credentials 2017-11-16 10:20:41 -05:00
Alan Rominger
0f52ab47a0 Merge pull request #665 from AlanCoding/prefetch_credentials
prefetch UnifiedJob related credentials
2017-11-16 09:57:22 -05:00
Matthew Jones
b06a508ceb Merge pull request #651 from tumbl3w33d/646_configurable_search_domains
Make DNS search domain configurable for awx containers
2017-11-15 23:32:16 -05:00
AlanCoding
8cb5ce8307 prefetch UnifiedJob related credentials 2017-11-15 22:35:10 -05:00
Benjamin Wenzel
c1aa4129f9 Make DNS search domain configurable for awx containers
related #646
2017-11-15 21:11:56 +01:00
Matthew Jones
d6b10b7f44 Merge pull request #657 from ansible/openshift_fixes
Openshift fixes
2017-11-15 13:29:41 -05:00
Shane McDonald
e2aa9dc599 Merge pull request #658 from shanemcd/devel
Enable image stream lookups in AWX OpenShift Project
2017-11-15 13:21:51 -05:00
Shane McDonald
a043369d07 Enable image stream lookups in AWX OpenShift Project
See the OpenShift docs on this for more info: https://docs.openshift.com/container-platform/3.6/dev_guide/managing_images.html#using-is-with-k8s

If you are not using OpenShift’s internal registry you will need to manually set awx_task_openshift_image and awx_web_openshift_image.
2017-11-15 13:15:56 -05:00
Matthew Jones
03eca250d9 Fix an openshift issue writing the inventory file
Openshift was throwing an error here, though I'm not sure why it makes
a whole lot of difference to call fdopen() vs open(). This was
introduced when this method was unified under the new
ansible-inventory system. This fixes it for all cases. mkstemp(),
while not necessary, is a useful addition to keep from leaking
inventory details unnecessarily.
2017-11-15 13:12:54 -05:00
Matthew Jones
65d01d508b Fix an issue with handler tasks after celery upgrade
There's a bug in celery 4.X when using bound tasks as error
handlers. We don't actually need it to be bound especially since the
request object is now available in the function signature
2017-11-15 13:12:06 -05:00
Ryan Petrello
3a2ec25fb4 Merge pull request #649 from ryanpetrello/multicred
fix a permissions bug for credentials specified at JT launch time
2017-11-15 08:49:08 -05:00
Ryan Petrello
fa09d68603 add a few minor optimizations and some refactoring for multi-cred 2017-11-14 16:47:28 -05:00
Ryan Petrello
eb140d9e69 fix a permissions bug for credentials specified at JT launch time
hat tip to @alancoding for spotting this one
2017-11-14 16:21:05 -05:00
Jared Tabor
5852c16ba6 Merge pull request #613 from jaredevantabor/fix-569
removing codemirror instantiation from $transition event
2017-11-14 11:09:41 -08:00
Ryan Petrello
ebd8941439 Merge pull request #595 from ryanpetrello/multicred
replace all Job/JT relations with a single M2M credentials relation
2017-11-14 14:07:18 -05:00
Jared Tabor
32cb18fc85 removing codemirror instantiation from $transition event 2017-11-14 10:24:36 -08:00
Marliana Lara
aeb8eb3d1e Fix jshint errors 2017-11-14 13:23:05 -05:00
Marliana Lara
6654cc35f7 Add relaunch component to Completed Jobs list 2017-11-14 13:04:20 -05:00
Ryan Petrello
28ce9b700e replace all Job/JT relations with a single M2M credentials relation
Includes backwards compatibility for now-deprecated .credential,
.vault_credential, and .extra_credentials

This is a building block for multi-vault implementation and Alan's saved
launch configurations (both coming soon)

see: https://github.com/ansible/awx/issues/352
see: https://github.com/ansible/awx/issues/169
2017-11-14 12:49:12 -05:00
Bill Nottingham
0558bd82bb Fix extra whitespace in callback URL. 2017-11-14 12:03:52 -05:00
Ryan Petrello
f887aaa71f Merge pull request #637 from ryanpetrello/fix-django-settings-bug
undo an optimization in django.conf.settings that breaks awx settings
2017-11-14 11:56:24 -05:00
Marliana Lara
69ada03b7b Add relaunch component to Job Results panel 2017-11-14 11:51:53 -05:00
Marliana Lara
ee6beae50a Add relaunchButton component and styles 2017-11-14 11:41:46 -05:00
Matthew Jones
799feac0e1 Merge pull request #638 from shanemcd/devel
Fix OpenShift configmap
2017-11-14 11:40:12 -05:00
Shane McDonald
0d86678a44 Fix OpenShift configmap
These variables changed in 8faf588775
2017-11-14 11:32:05 -05:00
Ryan Petrello
38f893c124 undo an optimization in django.conf.settings that breaks awx settings 2017-11-14 11:03:50 -05:00
Greg Considine
a2b444f179 Merge pull request #625 from gconsidine/ui/fix/home-dashboard-popover
Revert versions of D3 used by awx and ansible/nvd3
2017-11-14 10:48:40 -05:00
Matthew Jones
f46bacdeaa Merge pull request #636 from ansible/fix_celery_inspector
Delay instantiation of the celery app for the inspector
2017-11-14 10:42:10 -05:00
Matthew Jones
9ee77a95c6 Delay instantiation of the celery app for the inspector
This keeps the instance from re-using a pool that might have already
expired and is unusable for the inspector that needs to run as part of
the task manager
2017-11-14 10:33:47 -05:00
Alan Rominger
93b80307db Merge pull request #624 from AlanCoding/dev_super
get development supervisor use working again
2017-11-14 10:14:11 -05:00
Alan Rominger
0a883edd4d Merge pull request #632 from AlanCoding/some_test_fixes
do not use expensive visible_roles for Activity Stream filter
2017-11-14 09:56:27 -05:00
gconsidine
4cd9556f7b Revert versions of D3 used by awx and ansible/nvd3 2017-11-14 09:47:25 -05:00
Wayne Witzel III
9ed2a0da8f Merge pull request #627 from wwitzel3/devel
Fix image_build
2017-11-14 08:53:21 -05:00
AlanCoding
7eac219eae do not use expensive visible_roles for Act Stream filter 2017-11-14 08:37:14 -05:00
AlanCoding
805170ffd7 get development supervisor use working again 2017-11-13 20:31:32 -05:00
Wayne Witzel III
d696f6c3f6 Fix image_build 2017-11-13 19:11:58 -05:00
Wayne Witzel III
3cdeb446c4 Merge pull request #622 from wwitzel3/devel
Using metavar with a flag is not allowed or useful
2017-11-13 17:12:03 -05:00
Wayne Witzel III
58737a8e28 Using metavar with a flag is not allowed or useful 2017-11-13 16:05:54 -05:00
Wayne Witzel III
2fb74f5b02 Merge pull request #621 from wwitzel3/devel
Fix mgmt cmds, use real types not strings
2017-11-13 15:38:19 -05:00
Wayne Witzel III
768a3f62f1 Fix mgmt cmds, use real types not strings 2017-11-13 15:32:31 -05:00
Bill Nottingham
b03a64dd53 Merge pull request #567 from wenottingham/the-source--not-just-a-magazine
Assorted updates to project_update.yml
2017-11-13 15:18:42 -05:00
Shane McDonald
386382c456 Merge pull request #619 from wwitzel3/devel
Fix installer references to asgi_amqp
2017-11-13 14:10:58 -05:00
Wayne Witzel III
d9f8f7721a Fix installer references to asgi_amqp 2017-11-13 13:39:39 -05:00
Wayne Witzel III
d2711f4af0 Merge pull request #618 from wwitzel3/devel
Silence models.E006 until rename the Project and InventorySource
2017-11-13 13:23:15 -05:00
Wayne Witzel III
77fd7ea4a8 Silence models.E006 until we can rename the Project and InventorySource models 2017-11-13 13:19:29 -05:00
Wayne Witzel III
faa5a5e024 Merge pull request #600 from wwitzel3/django111
Upgrade AWX major dependencies
2017-11-13 12:26:04 -05:00
Wayne Witzel III
798d27c2cb Fix task_manager test 2017-11-13 12:02:00 -05:00
Wayne Witzel III
5b4dc9e7ee Disable group sending in consumer (Issue ansible/awx#615) 2017-11-13 10:19:14 -05:00
Wayne Witzel III
f118e27047 Flake8 fixes and URL updates 2017-11-10 17:04:33 -05:00
Michael Abashian
2ab33467d8 Merge pull request #601 from mabashian/275-delete-warnings
More verbose delete warnings
2017-11-10 16:40:12 -05:00
mabashian
42a6757a10 Pass params in object to request function 2017-11-10 16:14:40 -05:00
gconsidine
aa38c1123c Check for null resource and update e2e model usage 2017-11-10 15:59:38 -05:00
gconsidine
5fcff09aae Update string-related component tests 2017-11-10 12:33:27 -05:00
mabashian
5e2ecda413 Define type in delete jt unit test 2017-11-10 11:55:41 -05:00
mabashian
25dc3f8778 Update delete modals and fixed unit test failures 2017-11-10 11:31:11 -05:00
Michael Abashian
2957f5bc7f Merge pull request #1 from gconsidine/275-delete-warnings
275 delete warnings
2017-11-10 11:28:33 -05:00
gconsidine
8713e38c44 Update the base model to use string service instead of each sub model 2017-11-10 10:42:05 -05:00
Wayne Witzel III
96904968d8 Fix migration issues, tests, and templates 2017-11-09 17:29:48 -05:00
Wayne Witzel III
6d6bbbb627 Update URL strucuture, fixed string based calls 2017-11-09 17:24:04 -05:00
Wayne Witzel III
14c5123fda Update celery environ and tasks 2017-11-09 17:21:19 -05:00
Wayne Witzel III
de376292ba Update management commands 2017-11-09 17:18:18 -05:00
Wayne Witzel III
8faf588775 Update package versions, settings, and tooling 2017-11-09 17:17:30 -05:00
gconsidine
e8fd40ace0 Update model request interface and references 2017-11-09 17:01:32 -05:00
Bill Nottingham
a2b18a9f6e Add test to short-circuit checkout if revision is already checked out.
Move role checkout to a separate play, to work with this.
2017-11-08 18:29:59 -05:00
Jake McDermott
8f6289707b Merge pull request #596 from jakemcdermott/stored-xss-test
add test suite for stored xss
2017-11-08 16:47:03 -05:00
mabashian
4cd2f93c31 Updated delete warnings to indicate resources that may be invalidated as a result of deletion 2017-11-08 16:38:34 -05:00
Jake McDermott
79f450df8e add stored xss test suite 2017-11-07 13:43:20 -05:00
Jake McDermott
aab66b8ce8 add namespacing, schedules, and sources to fixtures 2017-11-07 13:43:05 -05:00
Jake McDermott
0afe94c4d4 add navigateTo command 2017-11-07 13:42:41 -05:00
Chris Church
6c1919273b Merge pull request #551 from cchurch/🥓
Include JSON string in temporary inventory script with %r
2017-11-06 17:46:12 -05:00
Alan Rominger
1ed3a8f0e9 Merge pull request #566 from AlanCoding/no_can_read
Fix bug where system gets 404 viewing job detail view
2017-11-06 15:23:30 -05:00
Michael Abashian
7dc30ab866 Merge pull request #554 from mabashian/274-right-click-new-tab
Fixed most lists so that name links can be opened in a new tab
2017-11-06 15:18:11 -05:00
mabashian
8f82fc26a2 Removed commented line from schedule list config 2017-11-06 14:46:31 -05:00
Matthew Jones
74c9b9cf6a Adding pycrypto distro package
Without this a lot of things break and it's no longer marked as a
dependency for the ansible core project
2017-11-06 11:18:45 -05:00
Bill Nottingham
632ff959ff Merge pull request #573 from wenottingham/going-up-for-some-headers
Preformatted text doesn't actually work in our popovers; don't try to use it.
2017-11-03 15:23:05 -04:00
Bill Nottingham
19d093f7aa Preformatted text doesn't actually work in our popovers; don't try to use it. 2017-11-03 13:25:58 -04:00
AlanCoding
270a41443c fix bug of system auditor 404 viewing job 2017-11-03 08:20:15 -04:00
Jake McDermott
8666512d99 Merge pull request #550 from jakemcdermott/run_both_unit_test_suites
run both ui unit test suites and linting tasks, collect results for shippable
2017-11-02 15:40:30 -04:00
Bill Nottingham
c827e73dac Update comments and task names. 2017-11-02 14:11:48 -04:00
Matthew Jones
b70f7bd866 Merge pull request #549 from cchurch/allow-non-fqdn-for-ldap-server-uri
Allow non-FQDN for AUTH_LDAP_SERVER_URI.
2017-11-02 08:57:04 -04:00
Jake McDermott
77e11fe8fe collect unit test results for shippable
Signed-off-by: Jake McDermott <jmcdermott@ansible.com>
2017-11-02 01:22:07 -04:00
Jake McDermott
93f35b037d remove unused config 2017-11-01 15:31:00 -04:00
mabashian
d056cb22ef Fixed most lists so that name links can be opened in a new tab 2017-11-01 14:26:48 -04:00
Jake McDermott
4883876dc5 run both unit test suites and linting tasks 2017-11-01 13:36:34 -04:00
Chris Church
863b5e2e8e Output repr() of JSON in temporary inventory script to prevent Python from devouring escape sequences. 2017-11-01 12:59:49 -04:00
Chris Church
0f8e073d10 Allow non-FQDN for AUTH_LDAP_SERVER_URI. 2017-11-01 12:51:41 -04:00
Alan Rominger
0579db1162 Merge pull request #439 from AlanCoding/retry_subset
Feature: retry on subset of jobs hosts
2017-11-01 11:33:15 -04:00
Bill Nottingham
7f20118d48 Merge pull request #547 from wenottingham/its-time-for-an-audit
Add system auditor placeholder.
2017-11-01 11:32:15 -04:00
Bill Nottingham
89d0f90e27 Add system auditor placeholder. 2017-11-01 10:46:39 -04:00
AlanCoding
41c84b4652 update retry-on-failed acceptance docs
Relaunching by other status values is tabled for later.
2017-11-01 10:24:46 -04:00
AlanCoding
0ae9283fba Feature: retry on subset of jobs hosts 2017-11-01 10:22:52 -04:00
Matthew Jones
f1813c35ed Merge pull request #528 from AlanCoding/fix_dep_update
fix bug with dependent SCM inv updates
2017-11-01 09:03:11 -04:00
Matthew Jones
0c5978715e Merge pull request #523 from AlanCoding/wfjt_spec_fix
fix admin edit of WFJT survey spec
2017-11-01 09:02:36 -04:00
Matthew Jones
5c1a6b7d6d Merge pull request #535 from matburt/fix_pgdata_issue
Specify a PGDATA directory to prevent container re-create issues
2017-11-01 08:46:24 -04:00
Jim Ladd
84c439b774 Merge pull request #542 from jladdjr/awx_349_acceptance_doc
Update custom credential document for mult-file injection
2017-10-31 19:14:37 -04:00
Jim Ladd
655759a5fc Update custom credential document for mult-file injection 2017-10-31 16:34:03 -04:00
Jake McDermott
6c85902ce8 Merge pull request #541 from jakemcdermott/update-credentials-title-selector
fix credentials form title selector
2017-10-31 16:30:00 -04:00
Jake McDermott
ef0c2086eb fix credentials form title selector when running container chrome 2017-10-31 16:11:44 -04:00
Matthew Jones
ffb148aaa9 Merge pull request #534 from dleehr/fix-install-2.3
Updates INSTALL.md to reflect Ansible 2.4 requirement
2017-10-31 15:07:06 -04:00
Matthew Jones
bf281f6ea9 Specify a PGDATA directory to prevent container re-create issues 2017-10-31 10:20:08 -04:00
Dan Leehr
641897713f Updates INSTALL.md to reflect Ansible 2.4 requirement 2017-10-30 22:41:58 -04:00
AlanCoding
d7ae95684c fix bug with dependent SCM inv updates
This change causes all SCM inventory updates to run a local
project sync unless they were specifically marked as a
dependency of an already-existing project update, as
opposed to just doing so on manual launch types.

This should be a more robust criteria.
2017-10-30 11:59:33 -04:00
AlanCoding
8b39b3b41a fix admin edit of WFJT survey spec 2017-10-29 16:27:16 -04:00
Ryan Petrello
0876d7825c Merge pull request #520 from ryanpetrello/phantom-version-comment
help people avoid mistakenly inputting their version info as a comment
2017-10-27 14:59:11 -04:00
Ryan Petrello
3953366a9e help people avoid mistakenly inputting their version info as a comment 2017-10-27 14:43:20 -04:00
Alan Rominger
d7f5ef6564 Merge pull request #511 from AlanCoding/wrong_type_error
raise error for invalid type lookup
2017-10-27 14:14:11 -04:00
Matthew Jones
63cf681369 Merge pull request #418 from Comradephate/patch-1
Divorce the "local docker install" portion of the install playbook from the image build + push logic
2017-10-27 12:31:09 -04:00
Jared Tabor
a0f1c8fc7c Merge pull request #499 from jaredevantabor/project-based-nav
Adding Project Based Navigation of Job Templates
2017-10-26 18:11:34 -07:00
Jared Tabor
4fbfddaa93 changes from PR feedback: removing ghost action icon
and fixing a bug where the list of job templates was improperly
updated when a job was running and live events were received.
2017-10-26 16:50:12 -07:00
Alan Rominger
bc7793def1 Merge pull request #494 from AlanCoding/get_queryset_modest_refactor
Refactor get_queryset inside of access.py
2017-10-26 13:52:08 -04:00
AlanCoding
4e16b19ae6 Refactor access.py get_queryset into filtering method
Use BaseAccess class to enforce the superuser and system
  auditor conditions, as well as the optimizations.
Declare optimizations on access class as tuple.
Limit role of access class method narrowly to RBAC filtering.
2017-10-26 11:40:08 -04:00
AlanCoding
b4a446dba0 raise error for invalid type lookup 2017-10-26 11:25:40 -04:00
Alan Rominger
641b18fe13 Merge pull request #509 from AlanCoding/lib_test_fixes
update tests to new Ansible core code
2017-10-26 09:28:52 -04:00
Bill Nottingham
c680327ec3 Merge pull request #506 from wenottingham/its-log
Remove accidentally committed log files
2017-10-26 09:17:30 -04:00
AlanCoding
e5d2eb9f3d update tests to new Ansible core code 2017-10-26 08:34:00 -04:00
Bill Nottingham
da25f4104c Update .gitignore for npm log files. 2017-10-25 21:37:29 -04:00
Bill Nottingham
871dc81da3 Avoid task duplication by using default(omit). 2017-10-25 21:30:46 -04:00
Bill Nottingham
1285e8ffef Add blocks around the different SCMs, for clarity purposes. 2017-10-25 16:58:41 -04:00
Bill Nottingham
a8947c3b96 Remove accidentally committed log files 2017-10-25 16:38:56 -04:00
Greg Considine
565d116955 Merge pull request #505 from gconsidine/ui/fix/multiple-dependency-include
Update dependencies that share Angular as a dependency
2017-10-25 16:07:29 -04:00
Jake McDermott
1fe9f43690 Merge pull request #502 from jakemcdermott/update_test_config
test config cleanup and tooling updates
2017-10-25 15:39:55 -04:00
gconsidine
4a522fd10f Update dependencies that share Angular as a dependency 2017-10-25 14:48:18 -04:00
Jared Tabor
5e349590fd making JOB TEMPLATES tab the last tab on the projects form 2017-10-25 11:21:36 -07:00
Jared Tabor
625c0ad578 Adding Project Based Navigation of Job Templates
This adds a Job Templates tab onto the Project form that gives
the user the ability to see all the job templates using a project.
Clicking the add button on this list will take the user to the job
template form with the project field auto-filled with the project.
2017-10-25 11:21:36 -07:00
Jake McDermott
3800a16f3e refactor e2e settings and config modules
This should make the settings and configuration logic less implicit and
a little easier to follow. Some familiarity with the configuration behavior
of nightwatch is still necessary in places - specifically, one should know
that all test_settings defined for non-default environments are treated as
overrides to the values defined for the default environment.
2017-10-25 10:58:39 -04:00
Jake McDermott
d70a0c8c24 cleanup e2e test development tooling and add readme examples 2017-10-25 10:22:18 -04:00
Aaron Tan
e999b35c42 Merge pull request #493 from jangsutsr/fix-474
Add protection against credential getattr
2017-10-25 09:45:25 -04:00
Aaron Tan
553e81f888 Add protection against credential getattr
Relates #474.

Add protection in `__getattr__` method to prevent possible infinite
recursion loop.

Signed-off-by: Aaron Tan <jangsutsr@gmail.com>
2017-10-24 12:08:41 -04:00
Alan Rominger
73ece87e68 Merge pull request #487 from AlanCoding/E722
flake8: comply with new E722 rule
2017-10-23 14:58:27 -04:00
AlanCoding
90f63774f4 flake8: comply with new E722 rule 2017-10-23 14:36:48 -04:00
Marliana Lara
17aecc17d2 Merge pull request #472 from marshmalien/angular_upgrade_1_6_6
Upgrade to AngularJS v1.6.6
2017-10-23 14:13:11 -04:00
Marliana Lara
9157f53d43 Update angular-scheduler and angular-tz-extensions versions 2017-10-23 12:29:28 -04:00
Marliana Lara
9bb696aa6e Fix for input directive using strict comparison to determined "checked" row 2017-10-23 12:29:27 -04:00
Marliana Lara
32da686724 Handle errors with ProcessErrors 2017-10-23 12:29:26 -04:00
Marliana Lara
cee81e9df6 Fix any unhandled rejections 2017-10-23 12:29:25 -04:00
Ben Thomasson
b544922da1 Fix incorrect JS syntax 2017-10-23 12:29:24 -04:00
Ben Thomasson
b3c2f35358 Change success to then manually 2017-10-23 12:29:23 -04:00
Ben Thomasson
7d767f8f63 Automatically change .error to .catch.
Use this script to change .error to .catch using this linux script:

    #!/bin/bash -ex
    #Run in awx/awx/ui/client/src
    FILES=`grep -l -R "\.error(\s*function\s*(data,\s*status)\s*{" . | xargs`
    sed -i "s/\.error(\s*function\s*(data,\s*status)\s*{/.catch(({data, status}) => {/g" $FILES

    FILES=`grep -l -R "\.error(this\.error\.bind(this))" . | xargs`
    sed -i "s/\.error(this\.error\.bind(this))/\.catch(this\.catch\.bind(this))/g" $FILES

    FILES=`grep -l -R "\.error(\s*function\s*(error)\s*{" . | xargs`
    sed -i "s/\.error(\s*function\s*(error)\s*{/.catch(({error}) => {/g" $FILES

    FILES=`grep -l -R "\.error(\s*function\s*(obj,\s*status)\s*{" . | xargs`
    sed -i "s/\.error(\s*function\s*(obj,\s*status)\s*{/.catch(({obj, status}) => {/g" $FILES

    FILES=`grep -l -R "\.error(\s*function\s*(res,\s*status)\s*{" . | xargs`
    sed -i "s/\.error(\s*function\s*(res,\s*status)\s*{/.catch(({res, status}) => {/g" $FILES

    FILES=`grep -l -R "\.error(\s*function\s*(msg,\s*code)\s*{" . | xargs`
    sed -i "s/\.error(\s*function\s*(msg,\s*code)\s*{/.catch(({msg, code}) => {/g" $FILES

    FILES=`grep -l -R "\.error(\s*function\s*()\s*{" . | xargs`
    sed -i "s/\.error(\s*function\s*()\s*{/.catch(() => {/g" $FILES
2017-10-23 12:29:22 -04:00
Ben Thomasson
834e6c692c Automatically change instances of .success to .then with this linux script:
#Run in awx/awx/ui/client/src

    #!/bin/bash -ex
    FILES=`grep -l -R "\.success(\s*function\s*(data)\s*{" . | xargs`
    sed -i "s/\.success(\s*function\s*(data)\s*{/\.then(({data}) => {/g" $FILES

    FILES=`grep -l -R "\.success(\s*function\s*()\s*{" . | xargs`
    sed -i "s/\.success(\s*function\s*()\s*{/\.then(() => {/g" $FILES

    FILES=`grep -l -R "\.success(this\.success\.bind(this))" . | xargs`
    sed -i "s/\.success(this\.success\.bind(this))/\.then(this\.then\.bind(this))/g" $FILES
2017-10-23 12:29:21 -04:00
Ben Thomasson
fabdab78ef Upgrade AngularJS to 1.6.6 2017-10-23 12:29:10 -04:00
Bill Nottingham
a313109b15 Merge pull request #475 from wenottingham/scm-tooltip
Update tooltip for update-on-launch.
2017-10-20 10:32:34 -04:00
Ryan Petrello
7b36630f47 Merge pull request #460 from ryanpetrello/cloudforms-cache-path
store cloudforms inventory cache files in the proper location on disk
2017-10-20 09:40:02 -04:00
Jaron Rolfe
cc5f329d33 Explanation for image removal block and idiomatic handling of var that enables it 2017-10-19 21:43:37 -04:00
Bill Nottingham
31c1e1684d Update tooltip for update-on-launch.
This better describes how this setting is used.
2017-10-19 16:57:50 -04:00
Alan Rominger
083e56d97d Merge pull request #464 from AlanCoding/actiony_permissions
fix bug where JT admins could not edit spec
2017-10-19 16:22:14 -04:00
AlanCoding
098a407e25 fix bug where JT admins could not edit spec 2017-10-19 16:05:44 -04:00
Alan Rominger
6347db56c5 Merge pull request #473 from AlanCoding/test_fix_exc
fix test fallout from 321 merge
2017-10-19 16:05:01 -04:00
AlanCoding
e660879a00 fix test fallout from 321 merge 2017-10-19 15:47:51 -04:00
Matthew Jones
5635f5fb49 Merge branch 'release_3.2.1' into devel
* release_3.2.1:
  fallback to empty dict when processing extra_data
  fix migration problem from 3.1.1
  move 0005a migration to 0005b
  feedback on ad hoc prohibited vars error msg
  Fix the way we include i18n files in sdist
  Fix migrations to support 3.1.2 -> 3.2.1+ upgrade path
  fix missing parameter to update_capacity method
  fix WARNING log when launching ad hoc command
  Validate against ansible variables on ad hoc launch
  do not allow ansible connection type of local for ad_hoc
  work around an ansible 2.4 inventory caching bug
  fix scan job migration unicode issue
  Assert isolated nodes have capacity set to 0 and restored based on version
  Set capacity to zero if the isolated node has an old version
2017-10-19 13:30:26 -04:00
Jared Tabor
0497a4ba96 Merge pull request #396 from jaredevantabor/ui-router
Upgrade Angular UI Router to v1.0.7
2017-10-18 20:31:03 -07:00
Jared Tabor
275e02a8cf fixing issue with scrolling due to UI-router upgrade 2017-10-18 20:16:05 -07:00
Jared Tabor
887a09d052 fixing issue from UI-router upgrade where document title wouldn't update
with the name of the state.
2017-10-18 16:34:39 -07:00
Jared Tabor
02af117f51 adjusting unit tests to pass 2017-10-18 16:34:39 -07:00
Jared Tabor
6e2de1b4b0 changing "dyanmic" to "dynamic" 2017-10-18 16:34:39 -07:00
Jared Tabor
47f743e623 fixing removeTerm for smart search to work 2017-10-18 16:34:39 -07:00
Jared Tabor
4f0fa57a1b removing $urlMatcherFactory and $urlRouter b/c they're deprecated
in favor or $urlService
2017-10-18 16:34:39 -07:00
Jared Tabor
3d5f301a07 removing notify:false, it's deprecated 2017-10-18 16:34:39 -07:00
Jared Tabor
f9c991e660 replacing all stateChangeSuccess for $transition.onSuccess 2017-10-18 16:34:39 -07:00
Jared Tabor
6e3f4a7a6e fixing issues w/ lazyloaded states 2017-10-18 16:34:38 -07:00
Jared Tabor
07139820cb updating angular-ui-router to v. 1.0.7 2017-10-18 16:34:38 -07:00
Ryan Petrello
764356bf47 Merge pull request #459 from ryanpetrello/simplified-inventory-building
remove support for job-scoped auth tokens
2017-10-18 17:35:37 -04:00
Ryan Petrello
ea683344f5 remove support for job-scoped auth tokens
When Jobs and Adhoc Commands are launched, awx uses a job-scoped auth
token to dynamically fetch inventory via the awx REST API; this process
is complicated, hard to debug, and likely won't work going forward with
oauth2-based tokens in awx

see: https://github.com/ansible/awx/issues/21
2017-10-18 17:11:47 -04:00
Jared Tabor
bff13e168a Merge pull request #461 from jaredevantabor/host-event-selecting
Fixing Host Event Modal Selecting
2017-10-18 09:23:46 -07:00
Jared Tabor
774a3da7f4 generalizing class which is ignored when trying to drag the host-event-modal
it was only applied to .CodeMirror, which is only used by the JSON tab
2017-10-17 16:03:39 -07:00
Bill Nottingham
5f3b4575de Merge pull request #456 from wenottingham/i-am-becoming
Set ANSIBLE_BECOME_ASK_PASS to avoid deprecation warning.
2017-10-17 18:11:33 -04:00
Ryan Petrello
59f9967dba store cloudforms inventory cache files in the proper location on disk
with process isolation enabled (which is the awx default), cloudforms
caches inventory script results on disk; awx should direct cloudforms to
store these cache files in a location that's exposed to the isolated
environment

see: ansible/ansible#31760
2017-10-17 17:06:48 -04:00
Bill Nottingham
058475c131 Set ANSIBLE_BECOME_ASK_PASS to avoid deprecation warning. 2017-10-17 16:00:16 -04:00
Chris Meyers
3685cb5517 Merge pull request #440 from chrismeyersfsu/fix-callback_unit_tests
fixes ansible callback import json warning
2017-10-17 13:53:45 -04:00
Chris Meyers
4e2cf62e89 fixes ansible callback import json warning
[WARNING]: Failure using method (v2_runner_on_ok) in callback plugin
(<awx_display_callback.module.AWXDefaultCallbackModule object at
0x47f6090>):
'module' object has no attribute 'dumps'

The above error is thrown by ansible if callback plugins don't respect
the same import precedence configuration as Ansible. ansible callback/*
dir includes a json.py file. This is imported by ansible
callback/__init__.py when a callback plugin implementation imports from
Ansible callback base without setting the correct import precedence.
2017-10-16 10:29:41 -04:00
Jaron Rolfe
5e17d72922 Improve push capabilities and allow build playbook to push 2017-10-16 00:38:28 -04:00
Jaron Rolfe
67df298f21 Replace deprecated "include" with "include_tasks" 2017-10-15 22:15:11 -04:00
Alan Rominger
353a9a55c7 Merge pull request #406 from AlanCoding/variables_debt
Consolidation of variables parsing throughout codebase
2017-10-13 15:40:36 -04:00
Matthew Jones
0ac3598ca5 Merge pull request #431 from matburt/lower_awx_uid
Lower the default uid by which we'll rewrite passwd
2017-10-13 15:33:36 -04:00
Jake McDermott
06f06173b0 Merge pull request #408 from jakemcdermott/smoke-tests
add smoke test
2017-10-13 15:21:00 -04:00
Matthew Jones
da5e6883d4 Lower the default uid by which we'll rewrite passwd
This fixes some issues with openshift under certain security policies
2017-10-13 14:27:30 -04:00
Matthew Jones
ef05df9224 Merge pull request #421 from carbonin/use_http_host_in_slash_redirect
Use $http_host in trailing slash redirect
2017-10-13 14:12:21 -04:00
Ryan Petrello
8b8c0e325f Merge pull request #430 from ryanpetrello/fix-isolated-version
stop hard-coding the awx version in the isolated development environment
2017-10-13 12:35:37 -04:00
Ryan Petrello
5bb06fdb50 stop hard-coding the awx version in the isolated development environment
see: #296
2017-10-13 12:17:04 -04:00
AlanCoding
993fa9290d additional verbosity for vars parsing exceptions 2017-10-13 11:41:11 -04:00
Jim Ladd
5924571904 Merge pull request #384 from jladdjr/awx365_post_response_discrepancy
Address discrepancy in POST response between jobs launches and project / inventory source updates
2017-10-13 09:59:29 -04:00
Chris Meyers
9cc4520a34 Merge pull request #409 from chrismeyersfsu/replay_job_events
add job event replay awx-manage command
2017-10-13 09:39:28 -04:00
Chris Meyers
62987196cb add speedup support to event replay and stats
* add tests
* add verbosity support
2017-10-13 09:25:18 -04:00
Nick Carboni
cfa21af432 Use $http_host in trailing slash redirect
This allows the port from the request header to be used
rather than having the request redirected to the port
being used inside the container which may not be
accessible

Fixes #420
related #420

Signed-off-by: Nick Carboni <ncarboni@redhat.com>
2017-10-12 17:35:55 -04:00
Jim Ladd
6f1c7ee733 Update several endpoints to match JT launch POST response
Signed-off-by: Jim Ladd <jladd@redhat.com>
2017-10-12 17:35:34 -04:00
Aaron Tan
bcd2a8f211 Merge pull request #382 from jangsutsr/fix-264
Implement workflow job failure
2017-10-12 16:34:08 -04:00
Jaron Rolfe
ee15db4c7c allow for private registry without latest tag
The logic that sets awx_web_docker_actual_image and awx_task_docker_actual_image creates and pushes images to the private registry tagged with the awx version, which is appropriate, but then tries to pull with no tag. (so docker defaults to "latest", which does not exist)
2017-10-12 15:57:34 -04:00
Alan Rominger
ad0e43dc52 Merge pull request #379 from AlanCoding/awx160
Enforce max line length of 160 characters
2017-10-12 14:05:31 -04:00
Aaron Tan
5287e5c111 Implement workflow job failure
Relates #264.

This PR proposed and implemented a way of defining workflow failure
state:

A workflow job fails if one of the conditions below satisfies.
* At least one node runs into states `canceled` or `error`.
* At least one leaf node runs into states `failed`, but no child node is
  spawned to run (no error handler).

Signed-off-by: Aaron Tan <jangsutsr@gmail.com>
2017-10-12 11:08:33 -04:00
Chris Meyers
e19a57c50a add job event replay awx-manage command
* awx-manage replay_job_event --job_id <id>
2017-10-12 09:40:30 -04:00
Jake McDermott
113d62a95f add smoke test 2017-10-11 18:28:56 -04:00
Jake McDermott
b5899c193a update object fields and commands 2017-10-11 18:28:36 -04:00
AlanCoding
8b41810189 Consolidation of variables parsing throughout codebase
* Remove attempted support of key=value pattern, because
  it is not actually allowed in practice
* Have variables validator defer to the utils variables parser
* Prune serializers of a handful of cases that previous
  attempts at cleanup have missed
2017-10-11 16:21:50 -04:00
Matthew Jones
f25ab7c6da Merge pull request #403 from jangsutsr/fix-391
Add extra encoding to ldap_dn verification
2017-10-11 14:35:35 -04:00
AlanCoding
f03b40aa50 enforce max line length of 160 characters 2017-10-11 12:38:39 -04:00
Aaron Tan
9dd4c7aaa3 Add extra encoding to ldap_dn verification
Relates #391.

Upstream `python-ldap` (surprisingly) does not support utf-8 DN. So
explicit encoding is needed.

Signed-off-by: Aaron Tan <jangsutsr@gmail.com>
2017-10-11 12:28:26 -04:00
Jake McDermott
d4af743805 Merge pull request #397 from jakemcdermott/unit-linting
additional test de-linting
2017-10-10 20:56:40 -04:00
Jake McDermott
8b395c934c de-lint unit tests 2017-10-10 20:23:15 -04:00
Jake McDermott
ae0855614b update unit test file names 2017-10-10 20:18:05 -04:00
Jake McDermott
169cd1a466 Merge pull request #395 from gconsidine/ui/combine-test-dirs
Ui/combine test dirs
2017-10-10 18:33:12 -04:00
gconsidine
82f81752e4 De-lint test files and update test,build config 2017-10-10 16:59:42 -04:00
gconsidine
8b6cc0e323 Combine test directories 2017-10-10 16:59:42 -04:00
Greg Considine
c0996f5fb1 Merge pull request #394 from gconsidine/ui/fix/closing-curly-brace
Add closing curly brace in strings file
2017-10-10 16:58:41 -04:00
gconsidine
3998796bf0 Add closing curly brace in strings file 2017-10-10 16:42:56 -04:00
Matthew Jones
6fa283fc98 Merge branch 'release_3.2.0' into devel
* release_3.2.0: (66 commits)
  fix workflow maker lookup issues
  adding extra logic check for ansible_facts in smart search
  adding "admin_role" as a default query param for insights cred lookup
  changing insights cred lookup to not use hard coded cred type
  fix rounding of capacity percentage
  Catch potential unicode errors when looking up addrinfo
  fixing typo with adding query params for instance groups modal
  move percentage capacitty to variable
  Add unit test for inventory_sources_already_updated
  Check for inventory sources already updated from start args
  Fixed inventory completed jobs pagination bug by setting default page size
  Remove the logic blocking dependent inventory updates on callbacks
  fix instance group percentage
  Remove host-filter-modal import
  Fix partial hover highlight of host filter modal row
  Removed leading slash on basePath
  Fixed host nested groups pagination
  Added trailing slash to basePath
  Fixed nested groups pagination
  Fixed host_filter searching related fields
  ...
2017-10-10 16:09:43 -04:00
Alan Rominger
70f8ec78de Merge pull request #517 from AlanCoding/vars_exception
fallback to empty dict when processing extra_data
2017-10-10 09:30:06 -04:00
AlanCoding
e2c398ade2 fallback to empty dict when processing extra_data 2017-10-10 08:13:45 -04:00
Matthew Jones
87e695ff6c Merge pull request #330 from Kickimanjaro/patch-1
Update INSTALL.md
2017-10-09 22:44:58 -04:00
Oliver Vollmer
8a8d710e20 moved note to Docker Prereqs, dropped extra OS specific commands 2017-10-09 19:13:55 -05:00
Alan Rominger
7365e4a63f Merge pull request #516 from AlanCoding/abc_migrations
Fix 3.1.1->3.2.1 migration error
2017-10-09 16:37:35 -04:00
AlanCoding
d4fc4bcd61 fix migration problem from 3.1.1 2017-10-09 15:49:38 -04:00
AlanCoding
4237b9ed5c move 0005a migration to 0005b 2017-10-09 15:48:52 -04:00
Alan Rominger
2dd2541550 Merge pull request #507 from AlanCoding/adhoc_word_smithing
[3.2.2] feedback on ad hoc prohibited vars error msg
2017-10-06 14:15:16 -04:00
AlanCoding
edda5e5420 feedback on ad hoc prohibited vars error msg 2017-10-06 14:07:38 -04:00
Matthew Jones
721674f0cd Merge pull request #502 from wwitzel3/release_3.2.1
[3.2.1] Fix broken migration from 3.1.1/3.1.2 -> 3.2.1
2017-10-06 13:19:34 -04:00
Shane McDonald
f97ca9c42f Fix the way we include i18n files in sdist 2017-10-06 11:57:08 -04:00
Wayne Witzel III
8f883d8d43 Fix migrations to support 3.1.2 -> 3.2.1+ upgrade path 2017-10-06 09:25:43 -04:00
Wayne Witzel III
5bcf704b76 Merge pull request #501 from wwitzel3/release_3.2.1
[3.2.1] Fix missing update_capacity paramenter
2017-10-06 00:37:07 -04:00
Wayne Witzel III
2818bb5833 fix missing parameter to update_capacity method 2017-10-06 00:23:12 -04:00
Alan Rominger
e8b79cde4a Merge pull request #499 from AlanCoding/adhoc_local
[3.2.1] Disallow Ansible vars in adhoc launch serializer + wayne's change
2017-10-05 15:30:06 -04:00
AlanCoding
81c14ce942 fix WARNING log when launching ad hoc command 2017-10-05 13:42:23 -04:00
AlanCoding
eacbeef660 Validate against ansible variables on ad hoc launch
Share code between this check for ad hoc and JT callback
2017-10-05 12:14:05 -04:00
Wayne Witzel III
02e3f45422 do not allow ansible connection type of local for ad_hoc 2017-10-04 17:55:36 -04:00
Chris Meyers
00afc87af1 Merge pull request #493 from chrismeyersfsu/fix-scan_job_migrations_unicode2
fix scan job migration unicode issue
2017-10-03 16:28:54 -04:00
Ryan Petrello
e48bebb761 Merge pull request #495 from ryanpetrello/fix-7713
work around an ansible 2.4 inventory caching bug
2017-10-03 16:26:41 -04:00
Ryan Petrello
4c5ec2fb3a work around an ansible 2.4 inventory caching bug
see: https://github.com/ansible/awx/issues/246
2017-10-03 15:45:11 -04:00
Chris Meyers
cad8710ac7 fix scan job migration unicode issue 2017-10-03 11:31:43 -04:00
Greg Considine
d02221702f Merge pull request #348 from gconsidine/ui/fix/disable-autofill-on-form
Add autocomplete attr to component form
2017-10-02 19:27:02 -04:00
gconsidine
4955dd9ab3 Add autocomplete attr to component form
Signed-off-by: gconsidine <greg@gregconsidine.com>
2017-10-02 17:06:07 -04:00
Marliana Lara
40f57b2552 Merge pull request #314 from marshmalien/test/side-nav
Side Nav Unit Tests
2017-10-02 15:36:36 -04:00
Marliana Lara
e19b4e0c8c Fix karma config and remove karma-ng-html2js-preprocessor 2017-10-02 15:10:36 -04:00
Wayne Witzel III
96fd07d0f3 Assert isolated nodes have capacity set to 0 and restored based on version 2017-10-02 14:43:19 -04:00
Wayne Witzel III
692007072d Set capacity to zero if the isolated node has an old version 2017-10-02 14:43:18 -04:00
Marliana Lara
2f8155763b Add Side Nav Item unit tests
Signed-off-by: Marliana Lara <mlara@redhat.com>
2017-10-02 13:36:06 -04:00
Marliana Lara
5c5293783d Add Side Nav directive unit tests 2017-10-02 13:35:32 -04:00
Marliana Lara
7486503a16 Add Layout directive unit tests 2017-10-02 13:35:31 -04:00
Greg Considine
e7f4e79248 Merge pull request #339 from gconsidine/ui/fix/document-reference-on-start
Use $document instead of document for on fn
2017-10-02 13:34:27 -04:00
gconsidine
f49ed838c7 Use $document instead of document for on fn
Signed-off-by: gconsidine <greg@gregconsidine.com>
2017-10-02 12:53:56 -04:00
Alan Rominger
8c117e9ef1 Merge pull request #337 from AlanCoding/admin_cancel
allow WFJT admins to cancel scheduled jobs
2017-10-02 11:33:46 -04:00
AlanCoding
681770e25a allow WFJT admins to cancel scheduled jobs 2017-10-02 10:25:49 -04:00
jlmitch5
06210624ce Merge pull request #486 from jlmitch5/fixModalOnModalBS
fix workflow maker lookup issues
2017-09-29 19:55:20 -04:00
John Mitchell
713c9614a9 fix workflow maker lookup issues 2017-09-29 19:50:17 -04:00
Kickimanjaro
cbb95b3bd4 Update INSTALL.md
Followed instructions to the letter from a new install and found that there was no mention that Docker service must be started. Tried to add this mention where it would have benefited me, but I am new to github and not sure if I'm doing this right.
2017-09-29 18:48:33 -05:00
Jared Tabor
f3c5607d6e Merge pull request #485 from jaredevantabor/smart-search
Smart Search fix for ansible_facts
2017-09-29 15:26:24 -07:00
Jared Tabor
c9ffc0e7c1 adding extra logic check for ansible_facts in smart search
a change related to related-group-searches caused a regression when
searching for ansible_facts
2017-09-29 15:02:50 -07:00
Jared Tabor
3d71c93262 Merge pull request #484 from jaredevantabor/insights
Insights
2017-09-29 12:42:38 -07:00
Jared Tabor
140af9ea47 adding "admin_role" as a default query param for insights cred lookup 2017-09-29 12:25:21 -07:00
Jared Tabor
8980e70918 changing insights cred lookup to not use hard coded cred type
and rather, do a comparison against the credential_type endpoint
2017-09-29 12:18:30 -07:00
Matthew Jones
ca4a1f37cd Merge pull request #323 from tvieira/doc_fix_link
Fix markdown link in CONTRIBUTING for enhancements list.
2017-09-29 13:31:39 -04:00
Matthew Jones
c234b9fb99 Merge pull request #321 from chrismeyersfsu/github_issues_template_include_awx_install_type
add awx install type to issue template
2017-09-29 13:26:58 -04:00
Matthew Jones
480e20136a Merge pull request #301 from romainrbr/devel
Changing the color option for hipchat to always be lowercase
2017-09-28 21:16:21 -04:00
Greg Considine
91bceefee7 Merge pull request #317 from gconsidine/ui/angular-manual-init-for-locale
Implement manual initialzation for Angular app
2017-09-28 19:31:58 -04:00
Tiago M. Vieira
b338959279 Fix markdown link in CONTRIBUTING for enhancements list. 2017-09-28 16:09:32 -04:00
gconsidine
d9e360e575 Add check if navigator.languages exists to use 2017-09-28 14:46:56 -04:00
Chris Meyers
a7ec5876ce add awx install type to issue template
* Recreation of user-issues increasing depends on the chosen install
path used. Thus, we need this information when recreating the issue
locally. Ask the user to include this information in the issue template.
2017-09-28 14:37:26 -04:00
Romain Brucker
cdc6096515 fixing indent 2017-09-28 11:37:07 -05:00
Romain Brucker
31e559b6a1 Checking if color is not None before setting it to lowercase 2017-09-28 11:33:45 -05:00
Romain Brucker
1bb72cc680 Adding a check to see if the color is 'None' before lowercasing it for @matburt 2017-09-28 11:15:14 -05:00
Matthew Jones
128eaaf60f Fix an issue where mercurial wasn't getting installed in the image
Also fixes an issue assigning proxy environment variables
2017-09-28 11:37:10 -04:00
John Mitchell
c57d39dcd9 fix rounding of capacity percentage 2017-09-28 11:18:55 -04:00
Matthew Jones
cd35704b0b Merge pull request #298 from st0ne-dot-at/proxy_fix
added proxy settings to docker runtimes
2017-09-28 08:46:38 -04:00
Steininger Robert, IR
46287f6923 proxy settings default omit 2017-09-28 10:11:29 +02:00
Matthew Jones
9219f0f682 Catch potential unicode errors when looking up addrinfo 2017-09-27 20:14:47 -04:00
Jared Tabor
feb0cd5e7c Merge pull request #479 from jaredevantabor/instance-groups-queryparams
fixing typo with adding query params for instance groups modal
2017-09-27 14:17:39 -07:00
jlmitch5
e877651a1e Merge pull request #476 from jlmitch5/fixIGPercentage
fix instance group percentage
2017-09-27 17:11:17 -04:00
Jared Tabor
3c29baea61 fixing typo with adding query params for instance groups modal
it was missing the query params for order_by and page_size
2017-09-27 13:57:02 -07:00
John Mitchell
b05925cc0e move percentage capacitty to variable 2017-09-27 16:53:31 -04:00
Matthew Jones
a5c028cd45 Merge pull request #477 from ansible/remove_callback_blocked_dependency
Remove the logic blocking dependent inventory updates on callbacks
2017-09-27 16:53:12 -04:00
Matthew Jones
3e38a0c17d Add unit test for inventory_sources_already_updated 2017-09-27 16:52:05 -04:00
Christopher Wang
e8b45d3be1 Merge pull request #478 from mabashian/inv-completed-jobs-pagination-fix
Fixed inventory completed jobs pagination bug by setting default page size
2017-09-27 16:46:59 -04:00
Matthew Jones
f4c9617f95 Check for inventory sources already updated from start args
In the case where the host didn't exist in the inventory source and
was found in the first inventory sync
2017-09-27 16:31:22 -04:00
mabashian
8a8a064821 Fixed inventory completed jobs pagination bug by setting default page size 2017-09-27 16:11:35 -04:00
Marliana Lara
0b11a0d642 Merge pull request #475 from marshmalien/fix/remove-host-filter-import
Remove host-filter-modal import
2017-09-27 16:06:07 -04:00
Matthew Jones
7861cda6fe Remove the logic blocking dependent inventory updates on callbacks 2017-09-27 16:00:05 -04:00
John Mitchell
32920739ef fix instance group percentage 2017-09-27 15:56:36 -04:00
Marliana Lara
0eadd69934 Remove host-filter-modal import 2017-09-27 15:47:27 -04:00
gconsidine
297904462d Implement manual initialzation for Angular app
Manual initialization allows for some asynchronous work to
finish ahead of Angular's startup. The initial motivation is
to be able to guarantee translation files have been fetched
before rendering content that needs translation. If a locale
isn't supported or if the request to get a json file fails,
the i18n service falls back to en.

Signed-off-by: gconsidine <gconsidi@redhat.com>
2017-09-27 15:12:03 -04:00
Marliana Lara
a886747676 Merge pull request #473 from marshmalien/fix/7691-host-filter-modal-hover
Fix partial hover highlight of host filter modal row
2017-09-27 14:59:26 -04:00
Marliana Lara
d4d2f04fc3 Fix partial hover highlight of host filter modal row 2017-09-27 14:38:19 -04:00
Michael Abashian
1e9b5824a4 Merge pull request #472 from mabashian/7688-groups-pagination
Fixed nested groups pagination
2017-09-27 13:00:30 -04:00
Michael Abashian
dcdb094c92 Merge pull request #471 from mabashian/7676-smart-inv-related-search
Fixed host_filter searching related fields
2017-09-27 12:06:34 -04:00
mabashian
cfe8a6580b Removed leading slash on basePath 2017-09-27 10:40:49 -04:00
mabashian
61b741030d Fixed host nested groups pagination 2017-09-27 10:34:55 -04:00
mabashian
6c19bbb6de Added trailing slash to basePath 2017-09-27 10:00:28 -04:00
mabashian
0193377d18 Fixed nested groups pagination 2017-09-27 09:54:00 -04:00
Jake McDermott
f3a8d612f3 Merge pull request #257 from mabashian/auditor-read-only-e2e
Added e2e tests for auditor read-only forms
2017-09-26 23:44:09 -04:00
Jake McDermott
fddecfdd25 use launch_url to specify awx host for workers 2017-09-26 23:26:54 -04:00
Jake McDermott
09a6a326d1 use fixture data in read-only form test 2017-09-26 21:54:47 -04:00
Jake McDermott
069ca1c755 add utils for bootstrapping test fixtures 2017-09-26 21:54:29 -04:00
Matthew Jones
e1804400ec Merge pull request #294 from matburt/official_awx_image_install
Add support for installing AWX from official images
2017-09-26 20:47:14 -04:00
Wayne Witzel III
e233926a4a Merge pull request #467 from wwitzel3/release_3.2.0
add --comment-only option to the migrate_to_database_settings mgmt cmd
2017-09-26 19:07:46 -04:00
mabashian
1752a97315 Fixed host_filter searching related fields 2017-09-26 16:51:08 -04:00
Matthew Jones
4d24318f70 Update install documentation with official image information 2017-09-26 14:56:46 -04:00
Wayne Witzel III
ba23f1728a add --comment-only option to the migrate_to_database_settings mgmt command 2017-09-26 14:51:59 -04:00
Alan Rominger
2ec675cf54 Merge pull request #465 from AlanCoding/retry_retry
broaden inventory deletion retry condition
2017-09-26 14:48:13 -04:00
mabashian
5b29e51a24 Moved form element selectors out into props in the form definition. Added checkAllFieldsDisabled to createFormSection. 2017-09-26 14:30:45 -04:00
Romain Brucker
e67549e4a1 Changing the color option for hipchat to always be lowercase (expected by the API)
Signed-off-by: Romain Brucker <romain.brucker@amalto.com>
2017-09-26 11:32:05 -05:00
AlanCoding
bfccd49a64 broaden inventory deletion retry condition 2017-09-26 10:45:30 -04:00
Steininger Robert, IR
5a95f2c793 added proxy settings to docker runtimes 2017-09-26 16:40:04 +02:00
Aaron Tan
723f4b0a7a Merge pull request #463 from jangsutsr/7666-fix
Restore SAML enterprise user auth logic
2017-09-26 10:03:08 -04:00
Matthew Jones
b89d1781a2 Modify openshift roles to support official AWX images 2017-09-26 09:58:07 -04:00
Aaron Tan
9bae656676 Restore SAML enterprise user auth logic
Connect #7666 of ansible-tower and follow up original fix tower #455.
The original fix solves the problem of duplicated db keys, but breaks a
rule of enterprise users that 'Enterprise users cannot be
created/authenticated if non-enterprise users with the same name has
already been created in Tower.'. This fix resumes that rule.

Signed-off-by: Aaron Tan <jangsutsr@gmail.com>
2017-09-26 09:51:42 -04:00
Greg Considine
45c516bf02 Merge pull request #291 from Zokormazo/fix-const
Use const instead of let on never reassigned var
2017-09-26 09:45:42 -04:00
Matthew Jones
2e7b4529f8 Add support for installing AWX from official images
* New options in the inventory file
* Add defaults to some variables
2017-09-25 21:52:23 -04:00
Chris Church
ddb689bded Merge pull request #293 from Zokormazo/fix-link
Fix link
2017-09-25 18:28:21 -04:00
John Mitchell
a6e6298575 remove notice from unnecessary partials 2017-09-25 18:08:58 -04:00
Julen Landa Alustiza
50b4002280 Fix broken link on LDAP group type help text
Signed-off-by: Julen Landa Alustiza <julen@zokormazo.info>
2017-09-25 23:43:41 +02:00
Julen Landa Alustiza
22887c47bc Use const instead of let on never reassigned var
Signed-off-by: Julen Landa Alustiza <julen@zokormazo.info>
2017-09-25 22:59:35 +02:00
Marliana Lara
2677a17c8a Merge pull request #213 from marshmalien/mobile-menu
Add mobile menu
2017-09-25 14:24:41 -04:00
Michael Abashian
8dae16bc98 Merge pull request #460 from mabashian/7675-jt-edit-permissions
Tweaked permissions logic to fix bug which prevented editing a JT without a default inv
2017-09-25 13:46:47 -04:00
Alan Rominger
4c0fd573c6 Merge pull request #459 from AlanCoding/special_treatment
always ignore deprecated_group if in groups
2017-09-25 13:35:55 -04:00
Alan Rominger
5bec43fc8e Merge pull request #462 from AlanCoding/bad_groups
handle additional cases of inv script output
2017-09-25 13:31:16 -04:00
Greg Considine
827cea53e4 Merge pull request #461 from gconsidine/ui/fix/wss-auth-token
Add quotes to auth token when stored as a cookie
2017-09-25 12:50:09 -04:00
John Mitchell
82b2fd102c add disassociate message to other modals 2017-09-25 12:24:39 -04:00
Matthew Jones
3201436edb Add image builder playbook for installer 2017-09-25 12:23:15 -04:00
AlanCoding
647d272a31 handle additional cases of inv script output 2017-09-25 12:20:21 -04:00
Marliana Lara
bb625264d4 Move DOM event listener to directive 2017-09-25 11:56:26 -04:00
gconsidine
8fff5db758 Add quotes to auth token when stored as a cookie 2017-09-25 11:45:52 -04:00
mabashian
37003a52cf Tweaked permissions logic to fix bug which prevented editing a JT without a default inv 2017-09-25 11:35:03 -04:00
AlanCoding
a4a17fe14c always ignore deprecated_group if in groups
If overwrite=True for an inventory source import, then this matters
creating a new inventory source through v1 API will not include
deprecated_group inside of the InventorySource groups m2m related
connection, but migrations from 3.1 will

In those migrated cases, this code will leave the deprecated_group
untouched, so as to not trigger its cascade delete
2017-09-25 11:22:12 -04:00
mabashian
101c1d7229 removed test-credentials-read-only.js 2017-09-25 10:41:28 -04:00
Greg Considine
2ad26008cc Merge pull request #458 from gconsidine/ui/fix/login-auth-token
Fix login and authorization token errors
2017-09-25 10:14:47 -04:00
Michael Abashian
c9ce751bf0 Merge pull request #447 from jaredevantabor/socket-fix
Final Socket Fix!
2017-09-25 10:09:08 -04:00
Chris Houseknecht
bd5e33c2f4 Clarify awx-logos location. Add 'docker' group note. 2017-09-25 09:48:59 -04:00
Chris Houseknecht
fa28d680c4 Synchronize breaks with localhost delegation 2017-09-25 09:48:59 -04:00
Matthew Jones
b9f2aa3437 Merge pull request #249 from matburt/preopulate_awx_user
Allow pre-populating the default AWX superuser account
2017-09-22 21:52:03 -04:00
gconsidine
4ad2af30cf Fix login and authorization token errors
* Remove extraneous quotes when authroization token is retrieved
from a cookie
* Fix thrown error when invalid creds are supplied on login due to
attempt to access property of an undefined value
2017-09-22 17:58:16 -04:00
John Mitchell
0bb7b0700d changed popover help text for overwrite sources 2017-09-22 17:31:28 -04:00
Wayne Witzel III
0b0afe91ab Merge pull request #457 from wwitzel3/release_3.2.0
get_or_create already saves, no need to call again
2017-09-22 16:42:47 -04:00
Greg Considine
3c062b36df Merge pull request #244 from gconsidine/ui/fix-schedules
Fix how global dependencies are loaded in the UI
2017-09-22 16:36:00 -04:00
Wayne Witzel III
39cc427668 get_or_create already saves, no need to call again 2017-09-22 16:25:55 -04:00
Wayne Witzel III
9e9692971f Merge pull request #455 from wwitzel3/release_3.2.0
Various SAML / auth fixes.
2017-09-22 16:10:49 -04:00
Wayne Witzel III
e9e027ecd7 Fix issue when the enterprise_auth has already been created 2017-09-22 15:58:39 -04:00
Wayne Witzel III
723449818d Fix issue when per user tokens are disabled 2017-09-22 15:58:26 -04:00
jlmitch5
851bccccee Merge pull request #256 from Zokormazo/fix-cutoff-days
Fix text visibility on cleanup facts modal
2017-09-22 14:36:14 -04:00
mabashian
75eace1b67 Added e2e tests for auditor read-only forms 2017-09-22 14:08:17 -04:00
jlmitch5
b2b45ddeda Merge pull request #443 from jlmitch5/instanceCapacityBarOffline
update instance capacity bar to be grey when instance or group is off…
2017-09-22 13:46:52 -04:00
jlmitch5
904cb4af34 Merge pull request #247 from Zokormazo/fix-chrome-survey-dnd
Set bigger dropping zone after last item on survey drag and drop list
2017-09-22 13:39:24 -04:00
Marliana Lara
8d9ef4445a Update webpack config to require webpack.test.js 2017-09-22 13:33:36 -04:00
Julen Landa Alustiza
913d65106a Fix text visibility on cleanup facts modal 2017-09-22 18:45:00 +02:00
Marliana Lara
851f01ddd2 Add mobile menu styles and click handlers
Signed-off-by: Marliana Lara <mlara@redhat.com>
2017-09-22 11:32:04 -04:00
gconsidine
34ca4e5623 Make asset hashes unique per file instead of per build 2017-09-22 10:51:39 -04:00
Aaron Tan
ba9668623a Merge pull request #254 from ansible/revert-211-fix_114
Revert "Add Tower Configuration setting AUTH_LDAP_GROUP_TYPE_MEMBER_ATTR"
2017-09-22 10:12:50 -04:00
Matthew Jones
73a37a281d Allow pre-populating the default AWX superuser account 2017-09-22 10:10:51 -04:00
John Mitchell
46eb1727ad add tooltip 2017-09-22 10:07:51 -04:00
Aaron Tan
93341d6108 Revert "Add Tower Configuration setting AUTH_LDAP_GROUP_TYPE_MEMBER_ATTR" 2017-09-22 09:48:32 -04:00
Alan Rominger
9662719660 Merge pull request #226 from AlanCoding/host_option
add back logic to re-call script for hostvars
2017-09-22 06:46:32 -04:00
Jared Tabor
a2e947ff70 turning off debug mode 2017-09-21 20:17:54 -07:00
Matthew Jones
55259b4445 Update minishift documentation relative to postgresql
Also bump the default claim value to 5G
2017-09-21 22:19:08 -04:00
Matthew Jones
d0a38816b5 Merge pull request #228 from mwasilew2/restart-policy-of-containers
auto restart containers created by the installer
2017-09-21 18:45:31 -07:00
Matthew Jones
523734a6af omit old unit tests from "test" make target 2017-09-21 21:33:34 -04:00
Chris Church
7a052e6f0c Merge pull request #238 from APenketh/devel
Added In Ansible Version Requirement Into Installation Doc
2017-09-21 20:38:02 -04:00
Julen Landa Alustiza
003e0e7a91 Set bigger dropping zone after last item on survey drag and drop list
Signed-off-by: Julen Landa Alustiza <julen@zokormazo.info>
2017-09-21 23:16:10 +02:00
Chris Meyers
bc7640e4ac Merge pull request #450 from chrismeyersfsu/fix-feature_cache2
2-level memoize
2017-09-21 16:37:16 -04:00
Alan Rominger
186d61aac4 Merge pull request #448 from AlanCoding/more_task_mgr_fixing
fix task manager running task structures
2017-09-21 16:27:32 -04:00
gconsidine
159fdfe7ad Fix how global dependencies are loaded in the UI
The UI has a handful of dependencies attached to window (angular,
jquery, lodash, etc). In the case of schedules, jquery was included
and extended as expected, but then clobbered by another module. This
prevented the Select2 dependency from working as expected.

Rather than relying on webpack to export particular dependencies as
global, that work is done in the vendor entry point now instead.
2017-09-21 15:52:19 -04:00
Chris Meyers
26d393e5c2 2-level memoize
* Allows for invalidating an entire function from the memoizer
2017-09-21 15:34:51 -04:00
Ryan Petrello
a298f797b5 Merge pull request #449 from ryanpetrello/fix-7668
fix a bug that causes azure inventory syncs w/ region='all' to fail
2017-09-21 15:17:32 -04:00
Michal Wasilewski
4236654b0c use unless-stopped instead always 2017-09-21 21:15:01 +02:00
Ryan Petrello
328b70ceb8 fix a bug that causes azure inventory syncs w/ region='all' to fail
see: https://github.com/ansible/ansible-tower/issues/7668
2017-09-21 15:08:54 -04:00
AlanCoding
dba83674a2 fix task manager running task structures
- prevent dual-entry for first item in running jobs due to
   setdefault syntax
 - fix issue where queues (celery tasks) only returned the last
   item in the inspector output due to looping problem
   this caused reaper bugs in production
2017-09-21 14:38:58 -04:00
John Mitchell
25e503219f tweaks to styling of capacity bar 2017-09-21 11:07:50 -04:00
Jared Tabor
44af8ac629 Merge pull request #446 from jaredevantabor/translations
Translations
2017-09-21 14:37:22 +00:00
Alex Penketh
6b6dcc46ca Added In Ansible Version Requirement Into Installation Doc
Signed-off-by: Alex Penketh <alex@apenketh.com>
2017-09-21 15:15:29 +02:00
Jared Tabor
4aa841f44b Final fix for socket connection when emitting messages before connection is open
using setTimeout
2017-09-20 20:07:17 -07:00
Jared Tabor
28c1718965 tagging ON/OFF toggles for translations 2017-09-20 17:58:52 -07:00
Jared Tabor
557780bf08 adding translation tag for "No records matched your search" 2017-09-20 17:52:13 -07:00
Jared Tabor
d0cb11acb3 Merge pull request #444 from jaredevantabor/socket-fix
send last socket message if last socket didn't go thru due to socket …
2017-09-20 23:04:43 +00:00
John Mitchell
2306c34689 update instance capacity bar to be grey when instance or group is offline 2017-09-20 17:49:02 -04:00
Shane McDonald
1e03654c0b Pull updated translations 2017-09-20 17:29:20 -04:00
Wayne Witzel III
7960525c20 Merge pull request #440 from wwitzel3/release_3.2.0
Merge pull request #224 from wwitzel3/fix-shared-deps
2017-09-20 16:50:08 -04:00
Michal Wasilewski
f00dc426e0 make containers start when docker daemon comes up 2017-09-20 22:29:44 +02:00
Alan Rominger
428eca1c35 Merge pull request #439 from AlanCoding/custom_hostvars
add back logic to re-call script for hostvars
2017-09-20 15:43:52 -04:00
AlanCoding
f1219ea001 add back logic to recall script for hostvars 2017-09-20 15:31:13 -04:00
Chris Meyers
0d08509e6d Merge pull request #437 from chrismeyersfsu/fix-feature_cache
cache license validation
2017-09-20 14:00:44 -05:00
Chris Meyers
062ff7153d resurrect cchurch's license feature caching 2017-09-20 14:57:24 -04:00
Wayne Witzel III
439beeab3b Merge pull request #224 from wwitzel3/fix-shared-deps
Fix job shared dependencies.
2017-09-20 14:56:22 -04:00
Jared Tabor
0b1d8ccd92 send last socket message if last socket didn't go thru due to socket not open 2017-09-20 18:40:37 +00:00
Wayne Witzel III
e6777577b6 Merge pull request #224 from wwitzel3/fix-shared-deps
Fix job shared dependencies.
2017-09-20 14:21:39 -04:00
Wayne Witzel III
095a93d895 remove duplicated get_latest calls 2017-09-20 13:57:01 -04:00
Chris Meyers
c265ed2722 Revert "use request response cache for license checks"
This reverts commit 93acae9367023fec153aa7980f2edd9f96822ba2.
2017-09-20 13:47:44 -04:00
Wayne Witzel III
0f4523fabf Fix up unit and functional tests 2017-09-20 13:22:41 -04:00
AlanCoding
80a944dd31 add back logic to recall script for hostvars 2017-09-20 13:20:04 -04:00
Wayne Witzel III
2889df8013 ensure project sync/inv updates are added to the dependencies 2017-09-20 13:15:02 -04:00
Wayne Witzel III
11b2bc33fe add scheduler module __init__ 2017-09-20 13:14:01 -04:00
Wayne Witzel III
1beaccb9c9 move TaskManager out of init 2017-09-20 13:13:10 -04:00
Alan Rominger
9db91b4344 Merge pull request #436 from AlanCoding/set_node_early
set execution_node right when jobs are accepted
2017-09-20 12:43:51 -04:00
AlanCoding
892ca98709 set execution_node right when jobs are accepted 2017-09-20 11:49:09 -04:00
Greg Considine
7268dd473d Merge pull request #212 from gconsidine/ui/eslint-refactor
Ui/eslint refactor
2017-09-20 11:35:50 -04:00
Jake McDermott
d6a6087ff9 Merge pull request #216 from jakemcdermott/fix-e2e-navbar-select
fix e2e navbar select
2017-09-20 09:43:35 -04:00
Wayne Witzel III
c868f7e91f Merge pull request #435 from wwitzel3/release_3.2.0
just fall through to the DjangoStrategy constructor
2017-09-20 09:02:58 -04:00
Wayne Witzel III
bab4cbbcf7 just fall through to the DjangoStrategy constructor 2017-09-20 08:50:39 -04:00
Wayne Witzel III
2ea1aee8ba Merge pull request #218 from subuk/devel
Fix typo in AWXDjangoStrategy constructor
2017-09-20 08:48:56 -04:00
Matvey Kruglov
4c7c1aa8b3 Fix typo in AWXDjangoStrategy constructor
Signed-off-by: Matvey Kruglov <kubuzzzz@gmail.com>
2017-09-20 11:47:18 +03:00
Jared Tabor
d31afdc749 Merge pull request #433 from jaredevantabor/socket-fix
using settimeout if socket.readyState = 0
2017-09-19 16:37:31 -07:00
Jared Tabor
44be46a436 using settimeout if connection not opened 2017-09-19 16:28:12 -07:00
Jared Tabor
55662efd4c Merge pull request #431 from jaredevantabor/delete-translations
taging some delete modals for translations
2017-09-19 13:45:50 -07:00
jlmitch5
e4fa0e8a39 Merge pull request #215 from Zokormazo/license-info-from-config
Move license checking logic to /api/v2/config
2017-09-19 16:39:50 -04:00
Jared Tabor
e23be23a83 Merge pull request #203 from jaredevantabor/i18n-initialization
initializing i18nInit module
2017-09-19 13:29:01 -07:00
Jared Tabor
ef4388f414 taging some delete modals for translations 2017-09-19 13:25:45 -07:00
Jake McDermott
1f083b57de fix e2e navbar select 2017-09-19 16:09:05 -04:00
gconsidine
b7d4f0b5ff Fix lint error after rebasing 2017-09-19 15:26:38 -04:00
Julen Landa Alustiza
9c2cf6b7ca Move license checking logic to /api/v2/config
Use license_info.features.ldap & license_info.feature.enterprise_auth from /api/v2/config for
auth providers button enabling instead of using info from /api/v2/settings/all

Signed-off-by: Julen Landa Alustiza <julen@zokormazo.info>
2017-09-19 21:24:07 +02:00
gconsidine
0b50794614 Update out of date karma and test dependencies 2017-09-19 14:53:23 -04:00
gconsidine
fad12e3a13 Update e2e tests after rebasing 2017-09-19 14:53:23 -04:00
gconsidine
777ef3fe90 Add more linter rules and de-lint 2017-09-19 14:53:23 -04:00
gconsidine
cec9507504 Use eslint on ui/lib and ui/features code 2017-09-19 14:53:23 -04:00
Matthew Jones
6b7126ab6b Updating contributing for What should I work on? 2017-09-19 13:46:45 -04:00
Marliana Lara
bb6fab08a3 Merge pull request #141 from marshmalien/side-nav-tooltips
Side navigation panel tooltips
2017-09-19 13:45:10 -04:00
Aaron Tan
ee762d4bbd Merge pull request #211 from jangsutsr/fix_114
Add Tower Configuration setting AUTH_LDAP_GROUP_TYPE_MEMBER_ATTR
2017-09-19 13:28:30 -04:00
Aaron Tan
d271757eba Fix issue #114
Add Tower Configuration setting AUTH_LDAP_GROUP_TYPE_MEMBER_ATTR.

Signed-off-by: Aaron Tan <jangsutsr@gmail.com>
2017-09-19 11:15:45 -04:00
Ryan Petrello
3fb6b5594d Merge pull request #429 from ryanpetrello/fix-6810
Fix an issue not populating the version metadata for isolated sdist
2017-09-19 10:44:41 -04:00
Alan Rominger
88ffb32d4f Merge pull request #427 from AlanCoding/inv_for_the_people
Inventory file suggestion adjustments from user feedback
2017-09-19 10:36:02 -04:00
Marliana Lara
9b7eb52772 Replace translate filter and retrieve tooltip text from strings file 2017-09-19 10:27:23 -04:00
Ryan Petrello
1af9c43b5b Fix an issue not populating the version metadata for isolated sdist
see: https://github.com/ansible/ansible-tower/issues/6810
2017-09-19 10:25:21 -04:00
Matthew Jones
b46c6e4aad Merge pull request #207 from matburt/add_krb_support
Add krb package dependencies to support windows connections
2017-09-19 06:55:47 -07:00
Matthew Jones
52aa38e742 Merge pull request #197 from ansible/fix_secret_key
Fix an issue where we ignored the secret key during install
2017-09-19 06:36:54 -07:00
Matthew Jones
476dae5418 Add krb package dependencies to support windows connections 2017-09-19 09:23:27 -04:00
Alan Rominger
bc4b622e6b Merge pull request #199 from AlanCoding/inv_no_yaml
Inventory file suggestion adjustments from user feedback
2017-09-19 08:40:20 -04:00
Jared Tabor
458779d897 Merge pull request #428 from jaredevantabor/socket-fix2
adding more console.logs for socket debugging
2017-09-18 20:25:25 -07:00
Jared Tabor
b593adcf84 adding more console.logs for socket debugging 2017-09-18 19:59:20 -07:00
Jared Tabor
3b83d6639a initializing i18nInit module 2017-09-18 16:29:49 -07:00
AlanCoding
f455f1b257 Inventory file suggestion adjustments from user feedback
- ditch yaml files as suggestions
 - automatically greenlight any hosts or inventory titled file
2017-09-18 15:29:03 -04:00
Matthew Jones
f5ccb51ef2 Fix an issue where we ignored the secret key during install 2017-09-18 15:11:04 -04:00
AlanCoding
120b5297e3 Inventory file suggestion adjustments from user feedback
- ditch yaml files as suggestions
 - automatically greenlight any hosts or inventory titled file
2017-09-18 14:28:29 -04:00
Marliana Lara
5c108bfa1b Add side nav panel tooltips 2017-09-18 13:53:21 -04:00
Bill Nottingham
710aaaa2c8 Merge pull request #195 from JeLuF/patch-1
Fix typo ("directory" misspelled)
2017-09-18 13:47:40 -04:00
JeLuF
1925a439d7 Fix typo ("directory" misspelled) 2017-09-18 19:34:56 +02:00
Michael Abashian
50d6981695 Merge pull request #410 from mabashian/7629-remove-deprecated-azure
Removed UI references to deprecated Azure inv source and cred
2017-09-18 13:08:25 -04:00
mabashian
c63c523089 Pull azure regions from azure_rm_region_choices not azure_region_choices
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-18 12:40:46 -04:00
mabashian
e6631d1516 Removed UI references to deprecated Azure inv source and cred
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-18 12:40:45 -04:00
Matthew Jones
87b58e6bc2 Apply ephemeral cache for some memoize tasks recently merged 2017-09-18 12:31:33 -04:00
Matthew Jones
84f9c49b6f Propogate cert validation to inventory updates for vmware 2017-09-18 12:21:27 -04:00
Matthew Jones
2fe5c2ac83 Merge pull request #424 from ansible/isolated_sdist_version
Fix an issue not populating the version metadata for isolated sdist
2017-09-18 08:57:48 -07:00
Ryan Petrello
21e3078853 Merge pull request #425 from ryanpetrello/release_3.2.0
remove support for azure classic
2017-09-18 11:26:55 -04:00
Matthew Jones
64415872a0 Merge branch 'release_3.2.0' into devel 2017-09-18 10:55:45 -04:00
Matthew Jones
0ee3b0e59b Fix an issue not populating the version metadata for isolated sdist 2017-09-18 10:51:56 -04:00
Ryan Petrello
cfe1f1e8e4 more legacy azure deprecation cleanup 2017-09-18 10:43:16 -04:00
Ryan Petrello
14b0f9aa24 remove reference to legacy rax credentials 2017-09-18 10:43:02 -04:00
Ryan Petrello
4dd265633e remove legacy azure inventory script
see: ansible/ansible-tower#7629
2017-09-18 10:41:49 -04:00
Alan Rominger
4c28e04e5e Merge pull request #191 from AlanCoding/step_parent
do not use parent_model with GenericAPIView
2017-09-18 10:36:59 -04:00
Chris Meyers
0b40331107 azure migrations
* delete azure credentials
* delete azure inventory sources
2017-09-18 10:35:42 -04:00
Chris Meyers
a08a158672 remove azure 2017-09-18 10:35:32 -04:00
Wayne Witzel III
540bda1d09 Merge pull request #420 from wwitzel3/release_3.2.0
Merge pull request #161 from wwitzel3/devel
2017-09-18 09:54:54 -04:00
Ryan Petrello
97609746c0 Merge pull request #423 from ryanpetrello/stdout_defer
more 3.1.5 result_stdout_text optimizations -> 3.2 so we don't regress
2017-09-18 09:53:17 -04:00
Ryan Petrello
68b924efe5 flake8 fixup 2017-09-18 09:44:39 -04:00
jlmitch5
37487b2427 Merge pull request #412 from jlmitch5/fixFormSaveEnterpriseDisabling
fix config forms from having save button disabled when no license is …
2017-09-18 09:37:30 -04:00
Ryan Petrello
6a4b4edea3 properly detect deferred ORM objects 2017-09-18 09:08:53 -04:00
Matthew Jones
ebbd42322d Fix an issue with hasattr call 2017-09-18 09:08:44 -04:00
Matthew Jones
c07a4ff93d Catch any unhandled exceptions grabbing notification templates 2017-09-18 09:08:40 -04:00
Matthew Jones
8091b84344 Fixing up some activity stream deferreds 2017-09-18 09:08:30 -04:00
Matthew Jones
cba8914aae Merge pull request #183 from matburt/latest_greatest_ansible
Include ansible centos repo link and install the latest ansible
2017-09-17 05:16:32 -07:00
Matthew Jones
663257a690 Merge pull request #182 from matburt/installer_updates
Rework installer to support local minishift environment
2017-09-17 05:15:43 -07:00
Jared Tabor
6a9bfa74c4 Merge pull request #422 from jaredevantabor/socket-fix
Socket fix
2017-09-16 09:20:59 -07:00
Jared Tabor
4bbd486389 removing code that puts the UI in an infinite loop 2017-09-16 09:12:32 -07:00
Matthew Jones
27d5eb4ef9 Rework installer to support local minishift environment
This also adds an option to *not* use the local container for building
the software distribution which is required for a local minishift
environment based install
2017-09-16 10:09:41 -04:00
Matthew Jones
f1a9c4ef0e Include ansible centos repo link and install the latest ansible
Instead of sourcing ansible from epel or extras, we'll now use the
official Ansible repo
2017-09-15 23:31:10 -04:00
Matthew Jones
a2f4134ee0 Merge pull request #417 from ansible/vmware_cert_validation
Add a setting for vmware inventory cert validation
2017-09-15 17:57:59 -07:00
Jared Tabor
2c7abc8bca Merge pull request #421 from jaredevantabor/socket-fix
Socket Fix
2017-09-15 15:58:58 -07:00
Jared Tabor
f7312691e1 resubscribe to last group if readyState is 0, aka connection isn't open yet 2017-09-15 15:56:32 -07:00
Jake McDermott
9cbe2faed6 Merge pull request #26 from jakemcdermott/test-e2e
add e2e tests
2017-09-15 17:35:30 -04:00
Wayne Witzel III
dafd6acf1a Merge pull request #161 from wwitzel3/devel
update social auth strategy to have fixes from social-app-django
2017-09-15 17:22:32 -04:00
Jake McDermott
2a9c97f96d remove unused config 2017-09-15 17:22:23 -04:00
Jake McDermott
573d35feff use dataset name as naming prefix 2017-09-15 17:22:13 -04:00
Jake McDermott
ab87f81ad8 add data generator preset 2017-09-15 17:22:03 -04:00
Jake McDermott
19f96b1f6f add e2e tests 2017-09-15 17:21:55 -04:00
Jake McDermott
05b4b875e2 move unit tests 2017-09-15 17:21:43 -04:00
Bill Nottingham
ece93c45c9 Merge pull request #178 from Numblesix/devel
Fixed Typo in Install.md
2017-09-15 15:11:51 -04:00
Michael Abashian
ca72722b39 Merge pull request #419 from mabashian/7647-i18n-search-key
Fixed search key styling with wider text
2017-09-15 15:03:44 -04:00
AlanCoding
1b48b99ba7 do not use parent_model with GenericAPIView 2017-09-15 14:41:12 -04:00
Sandro Emma
52c0a37174 Fixed Typo in Install.md
Signed-off-by: Sandro Emma <feeds.sandro@gmail.com>
2017-09-15 20:31:12 +02:00
Ryan Petrello
ff385ddf17 Merge pull request #416 from ryanpetrello/stdout_defer
Add 3.1.5 result_stdout_text optimizations into 3.2 so we don't regress
2017-09-15 14:24:47 -04:00
Michael Abashian
80e692656c Merge pull request #406 from mabashian/7578-jt-admin-edit-v2
Fixed jt admin edit bug
2017-09-15 14:13:04 -04:00
Jared Tabor
6374be15fd Merge pull request #418 from jaredevantabor/socket-fix
another potential socket fix
2017-09-15 10:58:43 -07:00
Matthew Jones
f9185b02b5 Merge pull request #167 from Numblesix/devel
updated Docu
2017-09-15 10:56:40 -07:00
Matthew Jones
418acbf218 Merge pull request #177 from pchauncey/faster
only pause when containers are launched
2017-09-15 10:56:13 -07:00
mabashian
9765623d03 Fixed search key styling with wider text
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-15 13:55:44 -04:00
Sandro
af56a75dce Update Install.md to include proxy vars
Signed-off-by: Sandro Emma <feeds.sandro@gmail.com>
2017-09-15 19:45:54 +02:00
Jared Tabor
325e7f3cce checking socket.readyState before emitting socket message 2017-09-15 10:37:35 -07:00
pchauncey
24465bee79 'activate' is a better variable name than 'started' 2017-09-15 12:32:32 -05:00
pchauncey
8576e8d51a only pause when containers are launched 2017-09-15 12:04:51 -05:00
mabashian
8b7639fd3a Removed extra GET call for extra creds when user cannot edit JT
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-15 11:54:42 -04:00
Matthew Jones
713e368557 Merge pull request #413 from ansible/invscript_endpoint_performance
Improve script endpoint performance by removing forced ordering
2017-09-15 08:16:02 -07:00
Matthew Jones
47c976ee91 Add a setting for vmware inventory cert validation
This uses the environment var expected by the vmware inventory script.
Defaults to off but can be turned on
2017-09-15 11:14:10 -04:00
Matthew Jones
645d2d852f Update scan job migration to public project to use the correct URL 2017-09-15 10:19:33 -04:00
Ryan Petrello
7a958a1af1 more result_stdout_text defer optimization for inventory updates
see: https://github.com/ansible/ansible-tower/issues/7568
2017-09-15 09:51:53 -04:00
Ryan Petrello
1bb6c17fe2 trick django-polymorphic into allowing defer() on polymorphic objects
django-polymorphic itself generates queries for polymorphic object
lookups, and these queries for UnifiedJob are *not* properly defering the
`result_stdout_text` column, resulting in more very slow queries.  This
solution is _very_ hacky, and very specific to this specific
version of Django and django-polymorphic, but it works until we can
solve this problem the proper way in 3.3 (by removing large stdout blobs
from the database).

see: https://github.com/ansible/ansible-tower/issues/7568
2017-09-15 09:51:43 -04:00
Matthew Jones
4657f29df9 Merge pull request #103 from ragingpastry/add-mattermost-notification
Add mattermost notification
2017-09-15 06:42:37 -07:00
Nicholas O. Wilburn
68d240b77b Add "Disable SSL Verification" button to mattermost notification
This commit will add a button which will disable SSL notifications
for the mattermost webhook. This is required when using self-signed
certificates.
2017-09-14 18:25:04 -07:00
Nicholas O. Wilburn
cd3ba08c7d Update mattermost notification docs with examples 2017-09-14 18:25:01 -07:00
Nicholas O. Wilburn
bdcd3f9dc2 Remove unnecessary fields from mattermost notification UI files 2017-09-14 18:24:57 -07:00
Nicholas O. Wilburn
69122a5454 Remove trailing whitespace 2017-09-14 18:24:54 -07:00
Nicholas O. Wilburn
e8e06f2b71 Revert unintended changes to ui/index.html 2017-09-14 18:24:51 -07:00
Nicholas O. Wilburn
684c637ac0 Remove package-lock.json 2017-09-14 18:24:47 -07:00
Nicholas O. Wilburn
03832c9065 Add mattermost import to reencrypt 2017-09-14 18:24:44 -07:00
Nicholas O. Wilburn
29451cf88c Add mattermost to notification_system docs 2017-09-14 18:24:40 -07:00
Nicholas O. Wilburn
f347caf825 Remove debugging line 2017-09-14 18:24:29 -07:00
Jared Tabor
436df168f0 Merge pull request #415 from jaredevantabor/socket-fix
deleting socket on logout
2017-09-14 15:51:15 -07:00
Jared Tabor
7ccedfb1df adding console.log for debug purposes in prod, will delete later 2017-09-14 15:50:35 -07:00
Jared Tabor
bd95197709 deleting socket on logout 2017-09-14 15:45:35 -07:00
Greg Considine
5897aebdf9 Merge pull request #414 from gconsidine/ui/fix/host-filter-parsing
Fix host filter parsing
2017-09-14 17:40:41 -04:00
gconsidine
dd62e8ce92 Replace use of string.includes due lack of browser support 2017-09-14 17:27:27 -04:00
gconsidine
eab3cb8efd Add support for quoted without spaces and falsey input 2017-09-14 15:57:52 -04:00
gconsidine
57c9224b5c Fix host filter parsing 2017-09-14 15:31:29 -04:00
John Mitchell
8c2b9905d1 fix config forms from having save button disabled when no license is given 2017-09-14 13:59:58 -04:00
Jared Tabor
bd5846d143 Merge pull request #95 from Zokormazo/fix-footer-blocking
Fix footer blocks visibility of items
2017-09-14 10:58:15 -07:00
Matthew Jones
39994186df Improve script endpoint performance by removing forced ordering 2017-09-14 13:05:31 -04:00
mabashian
549737405b Fixed multi credential service unit test failures
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-14 09:14:27 -04:00
Matthew Jones
a5ade10bff Merge pull request #162 from matburt/force_awxweb_hostname
Force awxweb hostname
2017-09-14 05:32:48 -07:00
Chris Meyers
28a26e6e81 Merge pull request #408 from chrismeyersfsu/7500_process_workflow_cornercase_for_user_capability
memoize workflow license feature check
2017-09-14 08:29:41 -04:00
Julen Landa Alustiza
7dc7f7815a Replace static footer with an always down non static footer
Hide footer on login screen

Signed-off-by: Julen Landa Alustiza <julen@zokormazo.info>
2017-09-14 08:33:34 +02:00
Matthew Jones
e7ce2fcc8d Merge pull request #149 from gdahlm/devel
Fix issue with python virtual environments and localhost.
2017-09-13 21:02:22 -07:00
Matthew Jones
25c457f578 Force awxweb hostname
For some reason some docker deployments seem not to be able to resolve
the awxweb host from the awx task host at least when started from the
playbook. This hopefully provides a resolution for that
2017-09-13 23:53:23 -04:00
Wayne Witzel III
7c7c7db345 Merge pull request #161 from wwitzel3/devel
update social auth strategy to have fixes from social-app-django
2017-09-13 23:00:41 -04:00
Jared Tabor
acbf9f517b Merge pull request #409 from jaredevantabor/socket-fix
move socketPromise.resolve() until handshake message is received
2017-09-13 18:55:39 -07:00
Jared Tabor
9cf683ea75 move socketPromise.resolve() until handshake message is received
instead of happening after the socket.onopen event.
2017-09-13 18:49:15 -07:00
Wayne Witzel III
5cc0552b05 remove AWXDjangoStrategy in the future 2017-09-13 21:28:26 -04:00
Wayne Witzel III
f44adb98cb update social auth strategy to have fixes from social-app-django 2017-09-13 21:16:10 -04:00
mabashian
f90771ee1a More fixes for JT admin edit use cases
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-13 16:48:04 -04:00
Matthew Jones
e7eeb86709 Merge pull request #154 from snahelou/devel
add proxy support
2017-09-13 12:37:21 -07:00
Greg Considine
93927717c8 Merge pull request #403 from gconsidine/ui/fix/host-search-with-spaces
Add support for quoted values containing spaces in search
2017-09-13 14:34:05 -04:00
Ryan Petrello
761e42c5d6 Merge pull request #407 from ryanpetrello/fix-7568
build extra_cred related urls for jobs and JTs a less volatile way
2017-09-13 13:42:49 -04:00
Chris Meyers
1ce3c7937b use request response cache for license checks 2017-09-13 13:34:39 -04:00
Ryan Petrello
d3df5de0ce build extra_cred related urls for jobs and JTs a less volatile way
see: https://github.com/ansible/ansible-tower/issues/7635
2017-09-13 13:28:26 -04:00
Matthew Jones
ca094f0e86 Merge pull request #156 from swills/portable-get_system_task_capacity
Make get_system_task_capacity portable
2017-09-13 10:19:12 -07:00
Michael Abashian
19d838ff49 Merge pull request #399 from mabashian/7588-deleted-inv-source-message
Deleted custom inv script on source update
2017-09-13 13:13:14 -04:00
NAHELOU SÉBASTIEN
6cd77dc6b8 add proxy support 2017-09-13 18:27:36 +02:00
Steve Wills
769ee8ac54 Remove unnecessary int coercion
Signed-off-by: Steve Wills <steve@mouf.net>
2017-09-13 11:55:44 -04:00
mabashian
28fa5077d5 Fixed jt admin edit bug
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-13 11:38:56 -04:00
Steve Wills
f0cf325831 Add whitespace around arithmetic operator
Signed-off-by: Steve Wills <steve@mouf.net>
2017-09-13 11:37:57 -04:00
Steve Wills
b8651bfd72 Make get_system_task_capacity portable
Signed-off-by: Steve Wills <steve@mouf.net>
2017-09-13 11:15:09 -04:00
Matthew Jones
7e754e20ae Merge pull request #404 from ansible/sys_auditor_can_set_pass
Allow System Auditor to set password
2017-09-13 06:32:10 -07:00
Matthew Jones
2dda863baf Merge pull request #155 from ansible/add_missing_svn
Add missing subversion to image
2017-09-13 06:27:47 -07:00
Matthew Jones
10a3959f52 Merge pull request #400 from ansible/taskman_dep_update_improve
Fix an issue where dependent updates weren't sorted correctly
2017-09-13 06:17:56 -07:00
Matthew Jones
309577f3ef Add missing subversion to image 2017-09-13 08:57:14 -04:00
Greg Dahlman
39756e6dc4 Fix issue with python virtual environments and localhost. 2017-09-12 18:45:18 -07:00
Ryan Petrello
66d78bca8a Merge pull request #405 from ryanpetrello/fix-7568
defer UnifiedJob.result_stdout_text for improved performance
2017-09-12 19:04:37 -04:00
Ryan Petrello
bd42dfe474 defer UnifiedJob.result_stdout_text for improved performance
result_stdout_text can be _very_ large - some customers have 5MB+ per
job; querying for this in list contexts results in _very_ large datasets
being read from the database which is very slow.  It's very uncommon to
actually need this column outside of the context of job details, so
defer it.

see: https://github.com/ansible/ansible-tower/issues/7568
2017-09-12 16:35:49 -04:00
Wayne Witzel III
50e3a9dee6 Merge pull request #142 from wwitzel3/devel
Update ISSUES.md and bot metadata
2017-09-12 16:19:38 -04:00
Ryan Petrello
bd088d31ca Merge pull request #334 from ryanpetrello/fix-7506
add process isolation to project updates
2017-09-12 16:15:37 -04:00
Matthew Jones
d308946360 Allow system auditor to set their own password 2017-09-12 16:07:47 -04:00
jlmitch5
8a282030a1 Merge pull request #401 from jlmitch5/fixSyncAll
always start sync all updates
2017-09-12 15:51:09 -04:00
Shane McDonald
de2a77adec Merge pull request #140 from eikef/delegate_sdist_localhost
Make sure sdist builder image and AWX distribution are built locally
2017-09-12 15:34:35 -04:00
gconsidine
87eab79f70 Add support for quoted values containing spaces in search 2017-09-12 14:57:07 -04:00
Matthew Jones
9827a4b758 Merge pull request #129 from stephenpc/bugfix/postgres_container_perms
Update selinux context for postgres volume
2017-09-12 11:49:13 -07:00
Jared Tabor
18fa0d5057 Merge pull request #402 from jaredevantabor/org-save-error-catching
catching org save error
2017-09-12 11:24:24 -07:00
Wayne Witzel III
c2b4756a4f Merge pull request #10 from wwitzel3/botdoc
Update ISSUES.md with bot doc
2017-09-12 14:07:18 -04:00
Wayne Witzel III
8e22bc2ce5 Update ISSUES.md with bot doc 2017-09-12 13:58:35 -04:00
Wayne Witzel III
2882ac4da8 extend api maintainers folder to main 2017-09-12 13:40:17 -04:00
Wayne Witzel III
b0d7a16f49 Add docs and PR labels 2017-09-12 13:37:57 -04:00
Jared Tabor
ae5b309de0 catching org save error
the org PUT was missing a .catch, however the edit controller already had it.
2017-09-12 10:21:52 -07:00
Eike Frost
96156f148e Make sure sdist builder image and AWX distribution are built on localhost even when deploying the final image remotely
Signed-off-by: Eike Frost <ei@kefro.st>
2017-09-12 19:04:15 +02:00
John Mitchell
5009f283d5 always start sync all updates 2017-09-12 12:01:06 -04:00
Wayne Witzel III
c695234ed1 Merge pull request #134 from wwitzel3/devel
Add PR template and tweak `make VERSION` output to be pastable
2017-09-12 11:32:41 -04:00
Ryan Petrello
d9e50ab6d5 Merge pull request #132 from richlv/setup_licence
- list the licence as Apache License 2.0 everywhere
2017-09-12 10:56:27 -04:00
richlv
644dc9f4a2 - list the licence as Apache License 2.0 everywhere
Signed-off-by: richlv <richlv@nakts.net>
2017-09-12 17:49:47 +03:00
Wayne Witzel III
f1c9d5a8f4 Add PR template and tweak make VERSION output to be pastable 2017-09-12 09:56:35 -04:00
Matthew Jones
9f3a0c0716 Fix an issue where dependent updates weren't sorted correctly
When considering previous / current Project Updates we weren't
properly sorting the previous runs.

We also make sure we filter down to just "check" style project updates
and don't consider 'run' style standalone project updates when
deciding what are potentially related project updates
2017-09-12 09:42:50 -04:00
Stephen Clayton
87472484d6 Update selinux context for postgres volume
Signed-off-by: Stephen Clayton <sclayton@tweddle.com>
2017-09-12 08:52:30 -04:00
Matthew Jones
c7f498fd01 Merge pull request #125 from wwitzel3/devel
fix issue template section, component => component name
2017-09-12 04:48:37 -07:00
Matthew Jones
f44dcd7c02 Merge pull request #120 from shanemcd/fix-docker-volume-issue-selinux
Fix selinux issue w/ docker volume in sdist builder
2017-09-12 04:48:06 -07:00
Wayne Witzel III
e00c65072b fix issue template section, component => component name 2017-09-11 18:15:56 -04:00
Matthew Jones
6dbbd7d605 Merge pull request #122 from gconsidine/ui/move-install-template-to-prod-build
Move install.template.ejs to be built for prod only
2017-09-11 14:46:57 -07:00
Ryan Petrello
4213960ec3 write the scm_revision_output to the project path instead of /tmp
see: https://github.com/ansible/ansible-tower/issues/7558
2017-09-11 17:44:53 -04:00
gconsidine
054710e1a2 Move install.template.ejs to be built for prod only 2017-09-11 16:12:09 -04:00
Ryan Petrello
a9c9ecb5ea bind ansible and awx virtualenvs readonly so that jobs can't modify them
see: https://github.com/ansible/ansible-tower/issues/7558
2017-09-11 15:57:35 -04:00
Ryan Petrello
a2ca0e6012 add process isolation to project updates
see: https://github.com/ansible/ansible-tower/issues/7506
2017-09-11 15:57:28 -04:00
Jared Tabor
6068eafeb6 Merge pull request #384 from jaredevantabor/job_explanation_label
showing job explanation if it wasn't "Previous Task Failed..."
2017-09-11 12:37:03 -07:00
Shane McDonald
f2ddf2af95 Fix selinux issue w/ docker volume in sdist builder
See https://www.projectatomic.io/blog/2015/06/using-volumes-with-docker-can-cause-problems-with-selinux/
2017-09-11 15:11:03 -04:00
Wayne Witzel III
3118092e51 Merge pull request #113 from matburt/waiting_install_screen
Integrate a migration-detector middleware
2017-09-11 12:55:10 -04:00
Ryan Petrello
434d115fb3 Merge pull request #398 from ryanpetrello/release_3.2.0
fix busted conf unit tests
2017-09-11 08:45:59 -07:00
mabashian
d38264660e Updated error message when can_update comes back false on an inventory source update GET
Signed-off-by: mabashian <mabashia@redhat.com>
2017-09-11 11:40:35 -04:00
Ryan Petrello
4cc58a221b fix busted conf unit tests 2017-09-11 11:28:43 -04:00
Ryan Petrello
e5043093eb Merge pull request #393 from jangsutsr/7587_remove_cred_type_id_in_api_v1
Remove credential_type_id in API v1
2017-09-11 08:22:10 -07:00
Matthew Jones
b39db745d4 Integrate a migration-detector middleware
This attempts to detect if there are migrations in-progress and will
force display an interstitial page in the process that attempts to
load the index page every 10s until it succeeds.

This is only attached in production settings so the development
environment can proceed even if the migrations haven't been applied yet
2017-09-11 11:09:45 -04:00
Matthew Jones
0e04b8e4d4 Merge pull request #112 from gconsidine/ui/remove-generated-html
Remove generated index.html file
2017-09-11 08:08:00 -07:00
Ryan Petrello
6f26f88bbd Add a TODO for 3.3 cleanup 2017-09-11 10:48:32 -04:00
Ryan Petrello
2f14dc7e5d Merge pull request #388 from ryanpetrello/fix-7470
bump azurerm dependencies to support Ansible 2.4
2017-09-11 07:45:51 -07:00
gconsidine
7296bfd5ee Remove generated index.html file 2017-09-11 10:19:54 -04:00
Aaron Tan
bf7c96defb Merge pull request #372 from jangsutsr/7536_prevent_mistakenly_truncate_sgr
Prevent mistakenly truncate ANSI SGR code in job event stdout
2017-09-11 09:32:58 -04:00
Matthew Jones
d503091b30 Merge pull request #91 from it-praktyk/FAQ_added
The link to the AWX project FAQ added
2017-09-11 06:32:14 -07:00
Matthew Jones
25612f8809 Merge pull request #71 from marshmalien/fix/27-side-nav-height
Fix height of side navigation panel
2017-09-11 06:30:29 -07:00
Shane McDonald
3e50a5da70 Merge pull request #104 from shanemcd/sdist-builder-image
Build sdist inside of a container
2017-09-11 09:29:46 -04:00
Ryan Petrello
b63d4da048 Merge pull request #109 from wwitzel3/devel
Update .github metadata for awxbot
2017-09-11 06:29:21 -07:00
Shane McDonald
b8e628958e Update INSTALL.md
These dependencies are unnecessary now that we are building the sdist inside of a container.
2017-09-11 08:42:56 -04:00
Wayne Witzel III
d3ca35ac42 Fix component labels to match defaults in issue template. 2017-09-11 07:40:23 -04:00
Matthew Jones
22359b427f Merge pull request #38 from MikeMcMahon/devel
Reduces the job to only looking at objects older than the cutoff date
2017-09-10 19:20:44 -07:00
Shane McDonald
a1bd84af5e Build sdist inside of a container
A lot of people have experienced issues with the system-level dependencies that are required in order to build the source distribution that is handed off to the image builds. This makes it unnecessary to install any additional software on the host machine aside from Ansible and Docker.
2017-09-10 19:00:33 -04:00
crepe
bb0e968704 Add mattermost notifications 2017-09-09 22:00:31 -07:00
Wayne Witzel III
66865c8b63 Update .github metadata for awxbot 2017-09-10 00:22:08 -04:00
Alan Rominger
7c920c305f Merge pull request #397 from AlanCoding/7583
add help for instance provisioning
2017-09-09 15:17:37 -07:00
Wojciech Sciesinski
aa8bb1f45d The link to the AWX project FAQ added
Signed-off-by: Wojciech Sciesinski <wojciech@sciesinski.net>
2017-09-09 11:19:56 +02:00
Mike McMahon
0cd34c1498 jobs take count of gte cutoff, process only lt cutoff
Signed-off-by: Mike McMahon <mike.mcmahon@wavefront.com>
2017-09-08 18:46:52 -07:00
Mike McMahon
399e0e5e24 switching to iterator and adding the missed Job cleanup
Signed-off-by: Mike McMahon <mike.mcmahon@wavefront.com>
2017-09-08 18:37:59 -07:00
Matthew Jones
2fb9b6cf25 Merge pull request #14 from AlanCoding/rel_obj_conservation
Pass existing object references within access methods
2017-09-08 15:22:40 -07:00
Matthew Jones
c6ae6b84d5 Merge pull request #13 from AlanCoding/exceptions
use exceptions for job cancel and failure
2017-09-08 15:19:41 -07:00
Matthew Jones
2620da1f4e Merge pull request #85 from sebthebert/sebthebert-patch-1
Add the 'installer' directory to 'inventory' and 'install.yml' files
2017-09-08 15:11:24 -07:00
John Mitchell
11b06a2e5e add disassociation disclaimer 2017-09-08 17:55:41 -04:00
Sebastien Thebert
f4770d065e Add the 'installer' directory to 'inventory' and 'install.yml' files
Add the 'installer' directory to 'inventory' and 'install.yml' files in the 'Docker' Section
2017-09-08 23:43:00 +02:00
AlanCoding
42ee804464 add help for instance provisioning 2017-09-08 14:36:17 -07:00
Matthew Jones
c5c926f29c Merge pull request #82 from Zokormazo/fix-typo-local_docker
Fix typo in local_docker task
2017-09-08 13:35:09 -07:00
Julen Landa Alustiza
98c7f1181e Fix typo in local_docker task
Signed-off-by: Julen Landa Alustiza <julen@zokormazo.info>
2017-09-08 22:21:23 +02:00
Matthew Jones
1098f7d9f4 Merge pull request #81 from ansible/revert-61-devel
Revert "Ensure Docker is running fixes #59"
2017-09-08 13:10:35 -07:00
Matthew Jones
493094dc18 Revert "Ensure Docker is running fixes #59" 2017-09-08 16:10:01 -04:00
Matthew Jones
4067cf639b Merge pull request #77 from martinbydefault/patch-1
typo fix
2017-09-08 12:52:40 -07:00
Greg Considine
ccbf7af7f2 Merge pull request #49 from gconsidine/ui/clean-build
Update UI build system
2017-09-08 15:49:02 -04:00
Alan Rominger
19ebd0aa68 Merge pull request #382 from AlanCoding/isolated_reaper
reap isolated jobs
2017-09-08 12:41:03 -07:00
AlanCoding
8e1e60c187 simplify isolated job reaping by checking all task ids 2017-09-08 12:30:05 -07:00
martinbydefault
133e9fed4a typo fix 2017-09-08 16:26:13 -03:00
gconsidine
fba8a48d91 Update dependencies, template file, and docs
* Use git+https prefix in git-based npm dependencies
* Use ejs template for index to fix extraneous slash in path
* Remove outdated documentation
* Remove unused service
* Regenerate shrinkwrap
2017-09-08 15:17:01 -04:00
Greg DeKoenigsberg
75699f82e9 update code of conduct url 2017-09-08 14:33:48 -04:00
Marliana Lara
7a2a4cc4a9 Merge pull request #396 from marshmalien/fix/7591-quirky-lookup-modals
Fix form field lookup by populating the field name
2017-09-08 13:46:39 -04:00
Marliana Lara
e131c0e5b9 Merge pull request #395 from marshmalien/fix/7572-remove-modal-backdrop
Remove modal backdrop on hidden modal event
2017-09-08 13:46:17 -04:00
Greg DeKoenigsberg
05ce5e6e2f Fixing code of conduct url
never swapped out the old url, fixing
2017-09-08 13:41:48 -04:00
AlanCoding
878e7ef49f reap isolated jobs 2017-09-08 10:40:39 -07:00
Marliana Lara
1a9379b41d Fix the height style of the side navigation panel 2017-09-08 12:38:05 -04:00
Wayne Witzel III
0da416b141 Merge pull request #46 from swills/install-req-gmake-git
add missing build deps
2017-09-08 10:36:29 -04:00
Wayne Witzel III
a825c84521 Merge pull request #61 from Numblesix/devel
Ensure Docker is running fixes #59
2017-09-08 09:34:18 -04:00
Wayne Witzel III
a8841e2e2b Merge pull request #60 from FooBarQuaxx/patch-1
Fixed typo in supervisor autorestart option
2017-09-08 09:22:22 -04:00
Sandro Emma
21ae187d02 Ensure Docker is running fixes #59
Signed-off-by: Sandro Emma <feeds.sandro@gmail.com>
2017-09-08 14:52:06 +02:00
MAA
6915c21092 Fixed typo in supervisor autorestart option 2017-09-08 13:38:30 +02:00
Ryan Petrello
37bbb0758c Merge pull request #51 from puiterwijk/fixbackport
Use distutils find_executable instead of which
2017-09-07 20:06:42 -07:00
Patrick Uiterwijk
3816791aa4 Use distutils find_executable instead of which
Fixes: #44

Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
2017-09-08 01:49:50 +00:00
Matthew Jones
534fefd82f Merge pull request #42 from geerlingguy/installer-whitespace-cleanup
Whitespace cleanup for installer.
2017-09-07 17:23:42 -07:00
gconsidine
c57c17546e Update UI build system
* Faster build times
* Smaller bundle sizes
* Adjust paths
* Cleanup npm dependencies
* Remove unneded Grunt tasks
2017-09-07 18:09:14 -04:00
Matthew Jones
33c0f8c721 Merge pull request #39 from puiterwijk/fix-nameid
Fix using SAML NameID
2017-09-07 14:28:13 -07:00
Steve Wills
dfaca1c42b add missing build deps 2017-09-07 17:22:59 -04:00
Jeff Geerling
6abffcb1df Whitespace cleanup for installer. 2017-09-07 14:21:28 -07:00
Bill Nottingham
0489d945fb Merge pull request #36 from Zokormazo/fix-typo
Fix typo in contributing guide
2017-09-07 14:11:18 -07:00
Mike McMahon
023431165a fixing missing colon and missing variable usage
Signed-off-by: Mike McMahon <mike.mcmahon@wavefront.com>
2017-09-07 14:03:18 -07:00
Patrick Uiterwijk
830012e2f4 Fix using SAML NameID
Without this patch, SAML backend will only use the first letter of the NameID as attribute value.

Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
2017-09-07 20:54:27 +00:00
Mike McMahon
0388568ea0 Reduces the job to only looking at objects older than the cutoff date
Signed-off-by: Mike McMahon <mike.mcmahon@wavefront.com>
2017-09-07 13:41:43 -07:00
Marliana Lara
7965f9df6c Fix form field lookup by populating the field name 2017-09-07 16:24:01 -04:00
Julen Landa Alustiza
81ef293361 Fix typo in contributing guide
Signed-off-by: Julen Landa Alustiza <julen@zokormazo.info>
2017-09-07 21:48:55 +02:00
Bill Nottingham
b565fd2ec1 Merge pull request #29 from bjoernfan/doc-install-fixes
Documentation fixes in INSTALL.md
2017-09-07 09:33:57 -07:00
Marliana Lara
2f3124edf4 Remove modal backdrop on hidden modal event
Signed-off-by: Marliana Lara <mlara@redhat.com>
2017-09-07 11:58:36 -04:00
Bill Nottingham
8cb55107d0 Merge pull request #32 from wenottingham/devel
Nuke old license file.
2017-09-07 07:46:02 -07:00
Marliana Lara
56e9d7b8e2 Merge pull request #392 from marshmalien/fix/7576-pagination-space
Add margin between pagination pages and totals
2017-09-07 10:22:55 -04:00
Bill Nottingham
9524a5c860 Nuke old license file.
Signed-off-by: Bill Nottingham <notting@splat.cc>
2017-09-07 07:19:03 -07:00
Aaron Tan
42bbd7d47a Merge pull request #18 from jangsutsr/wrap_up_ctint_unit_tests
Wrap up Tower configuration unit tests
2017-09-07 09:49:14 -04:00
Björn Pettersson
b833451257 doc: Add missing bracket to anchor link
Signed-off-by: Björn Pettersson <bjorn@undef.io>
2017-09-07 13:15:50 +02:00
Björn Pettersson
ea61aa1e1c doc: Fix docker anchor links
Signed-off-by: Björn Pettersson <bjorn@undef.io>
2017-09-07 13:15:49 +02:00
Björn Pettersson
8f4bb3f19c doc: Remove trailing whitespace
Signed-off-by: Björn Pettersson <bjorn@undef.io>
2017-09-07 13:15:47 +02:00
Björn Pettersson
4704800ce3 doc: intalling -> installing
Signed-off-by: Björn Pettersson <bjorn@undef.io>
2017-09-07 13:15:40 +02:00
Ryan Petrello
2f915c2182 Merge pull request #25 from ryanpetrello/devel
add a badge for shippable build status
2017-09-06 21:29:55 -07:00
Ryan Petrello
77f07ca0e3 add a badge for shippable build status 2017-09-06 21:15:49 -07:00
AlanCoding
41940687f1 Pass existing object references within access methods
This avoids re-loading objects from the database in our
chain of permission checking, wherever possible.
access.py is equiped to handle object references instead
of pk ints, and permissions.py is changed to pass those refs.
2017-09-06 16:34:00 -07:00
Ryan Petrello
bfea00f6dc Merge pull request #24 from ryanpetrello/devel
fix broken shippable test suite
2017-09-06 19:32:51 -04:00
Ryan Petrello
44702c5cfd fix broken shippable test suite 2017-09-06 16:12:43 -07:00
jlmitch5
37c2d01260 Merge pull request #16 from jlmitch5/newNav
new navigation in UI
2017-09-06 17:54:21 -04:00
John Mitchell
ea91fabba0 implement componenitized navigation and remove old nav and layout code 2017-09-06 17:32:32 -04:00
Jared Tabor
a8d882dcc5 Merge pull request #22 from jaredevantabor/spud-logo-placement
adjusting placement of spud on login screen
2017-09-06 14:08:28 -07:00
Jared Tabor
35b44af030 adjusting placement of spud on login screen 2017-09-06 13:37:41 -07:00
Matthew Jones
4127aad3d4 Merge branch 'awx_installer' into devel
* awx_installer:
  Adds docker installation steps (#15)
  Call out eval for setting up the minishift environment
  Support official image builds with awx logos
  Add support for standalone docker install
  First iteration on INSTALL
  Adds edge terminated route
  Ignore Pycharm droppings
  Force reauth docker registry login in installer
  Reduce the size of the production container image
  Initial awx installer
2017-09-06 16:25:55 -04:00
Matthew Jones
67d1a86d81 Merge branch 'release_3.2.0' into devel
* release_3.2.0: (138 commits)
  Pull Dutch and Spanish translations
  Increase verbosity of CTiT Logging test error handling
  fix to console error of conditional toggle showing
  Fix error message when calling remove on undefined DOM element
  fix ctit logging toggle from being showed for log types other than https
  Remove delete and edit buttons from smart inventory host list.  Only option should be view.
  feedback from PR
  Enhance query string in ad hoc command event save to consider smart inventory
  Fixed host filter clearall
  fuller validation for host_filter
  On JT form, Show credential tags from summary_fields if user doesn't have view permission on the credential
  Align key toggle button to role dropdown in user team permissions modal
  Removed rogue console.logs
  Removed extra refresh call
  Enhace query string in job event save to consider smart inventory
  Fix typo in scan_packages plugin
  Switch running_jobs and capacity table columns
  Disable insights cred when user doesn't have edit permissions
  Disallow changing credential_type of an existing credential
  fix bug with host_filter RBAC check
  ...
2017-09-06 16:10:08 -04:00
Shane McDonald
df8ab0d9a9 Pull Dutch and Spanish translations 2017-09-06 14:46:06 -04:00
Michael Abashian
a93cdf8c86 Merge pull request #389 from mabashian/7574-smart-inv-host-list
Hide delete, edit buttons on smart inventory host list
2017-09-06 14:25:41 -04:00
Marliana Lara
ecf92e8fe4 Merge pull request #394 from marshmalien/fix/7579-test-error-handling
Increase verbosity of CTiT Logging test error handling
2017-09-06 13:29:35 -04:00
Marliana Lara
9329092c32 Increase verbosity of CTiT Logging test error handling 2017-09-06 12:51:52 -04:00
Aaron Tan
94d4a7e3f0 Fix 7587: Remove credential_type_id in API v1 2017-09-06 10:39:49 -04:00
Marliana Lara
48e583026f Add margin between pagination pages and totals 2017-09-05 18:01:41 -04:00
Marliana Lara
ce6aea7437 Merge pull request #391 from marshmalien/fix/7577-undefined-required-label
Prevent TypeError when removing asterisk DOM element
2017-09-05 16:59:33 -04:00
jlmitch5
986f2c0941 Merge pull request #390 from jlmitch5/fixCtitLoggingToggle
Fix ctit logging toggle
2017-09-05 16:59:13 -04:00
John Mitchell
1238c788e1 fix to console error of conditional toggle showing 2017-09-05 16:56:00 -04:00
Aaron Tan
64b6b18a81 Wrap up Tower configuration unit tests 2017-09-05 15:16:51 -04:00
Marliana Lara
03932c7bdb Fix error message when calling remove on undefined DOM element 2017-09-05 15:10:33 -04:00
Ryan Fitzpatrick
8a4d915c8d Merge pull request #378 from rmfitzpatrick/at6392_correct_deb_package_scan
Correct deb package scan typo
2017-09-05 13:17:20 -04:00
John Mitchell
86a6e5ee63 fix ctit logging toggle from being showed for log types other than https 2017-09-05 12:29:07 -04:00
Alan Rominger
757a91a7d2 Merge pull request #385 from AlanCoding/smart_validation
fuller validation for host_filter
2017-09-05 10:39:33 -04:00
mabashian
a09bd5a90d Remove delete and edit buttons from smart inventory host list. Only option should be view. 2017-09-01 16:32:38 -04:00
Aaron Tan
c70362cb57 Merge pull request #381 from jangsutsr/7515_enhance_ad_hoc_cmd_evt_save_query_for_fetching_hosts
Enhance query str in AHC event save to consider smart inventory
2017-09-01 16:01:43 -04:00
Ryan Petrello
768c7ba3dc bump azurerm dependencies to support Ansible 2.4
see: https://github.com/ansible/ansible-tower/issues/7470
2017-09-01 15:15:53 -04:00
Jared Tabor
e053e5a84e Merge pull request #383 from jaredevantabor/403-on-JT2
Show credentials on JT form, despite not having permission to the creds
2017-09-01 11:21:43 -07:00
Jared Tabor
2857bfd8a0 feedback from PR 2017-09-01 11:03:03 -07:00
Marliana Lara
4877dc4612 Merge pull request #380 from marshmalien/fix/7562-add-permissions-key-button
Align key toggle button to role dropdown in user team permissions modal
2017-09-01 13:20:17 -04:00
Michael Abashian
10a0c0164b Merge pull request #386 from mabashian/7566-clearall-host-filter
Fixed host filter clear all
2017-09-01 11:32:48 -04:00
Michael Abashian
a9f4b4883a Merge pull request #370 from mabashian/7542-cancel-sync-tooltip
Reload the project list when we get a canceled socket message
2017-09-01 11:32:33 -04:00
Michael Abashian
f314367bc8 Merge pull request #368 from mabashian/7549-auto-pop
Removed prepend-asterisk in favor of an injected span
2017-09-01 11:30:18 -04:00
Aaron Tan
c866b9d768 Enhance query string in ad hoc command event save to consider smart inventory 2017-09-01 10:15:29 -04:00
Aaron Tan
6f96df6bbb Merge pull request #379 from jangsutsr/7514_enhance_job_event_save_query_for_fetching_hosts
Enhace query string in job event save to consider smart inventory
2017-09-01 09:53:14 -04:00
mabashian
7318cbae9b Fixed host filter clearall 2017-09-01 09:27:48 -04:00
AlanCoding
a36a141141 fuller validation for host_filter 2017-08-31 23:10:09 -04:00
Chris Houseknecht
e2a0fd7b0b Adds docker installation steps (#15) 2017-08-31 22:21:25 -04:00
Jared Tabor
1cdab96e02 showing job explanation if it wasn't "Previous Task Failed..." 2017-08-31 15:37:49 -07:00
Jared Tabor
a3c8bd6b6f On JT form, Show credential tags from summary_fields if user
doesn't have view permission on the credential
2017-08-31 15:11:17 -07:00
Marliana Lara
faa45cc606 Align key toggle button to role dropdown in user team permissions modal 2017-08-31 15:38:00 -04:00
Michael Abashian
ddc2af0691 Merge pull request #375 from mabashian/7545-cancel-flash
Fix cancel delete button flash
2017-08-31 14:51:46 -04:00
Michael Abashian
381a27957a Merge pull request #377 from mabashian/insights-cred-disable
Disable insights cred when user doesn't have edit permissions
2017-08-31 14:51:29 -04:00
mabashian
41799521c6 Removed rogue console.logs 2017-08-31 14:49:40 -04:00
mabashian
1617700ee0 Removed extra refresh call 2017-08-31 14:42:36 -04:00
Aaron Tan
839f3a4d2c Enhace query string in job event save to consider smart inventory 2017-08-31 14:39:39 -04:00
Marliana Lara
2b99ddda02 Merge pull request #367 from marshmalien/7551-invert-capacity-percentages
Invert capacity bar UI to display capacity consumed
2017-08-31 14:34:16 -04:00
Jared Tabor
c3a7adcb0d Merge pull request #373 from jaredevantabor/disabled-orgs
Disabling Organization fields for non super-users/org-admins
2017-08-31 11:06:36 -07:00
Marliana Lara
9efdd01e2b Merge pull request #371 from marshmalien/7552-job-event-scrollbars
Remove extra horizontal scrollbar from CodeMirror in Host Event modal
2017-08-31 13:30:57 -04:00
Ryan Fitzpatrick
5cbdadc3e8 Fix typo in scan_packages plugin 2017-08-31 13:17:30 -04:00
Marliana Lara
c5d4ea01f6 Switch running_jobs and capacity table columns 2017-08-31 12:52:50 -04:00
Alan Rominger
12537c2739 Merge pull request #376 from AlanCoding/host_filter_goof
fix bug with host_filter RBAC check
2017-08-31 12:09:00 -04:00
Aaron Tan
15f57eb911 Merge pull request #333 from jangsutsr/7505_disallow_changing_credential_type_of_credential
Disallow changing credential_type of an existing credential
2017-08-31 11:37:43 -04:00
Alan Rominger
3530b643b6 Merge pull request #374 from AlanCoding/v1_adhoc
remove can_run_ad_hoc_commands in v2
2017-08-31 11:33:18 -04:00
mabashian
ddb588f7a6 Disable insights cred when user doesn't have edit permissions 2017-08-31 11:31:51 -04:00
Aaron Tan
68391301b0 Pick up workflow cornercase in get_user_capabilities 2017-08-31 11:31:41 -04:00
Aaron Tan
276bed2d0b Disallow changing credential_type of an existing credential 2017-08-31 11:25:01 -04:00
AlanCoding
2027047220 fix bug with host_filter RBAC check 2017-08-31 10:42:16 -04:00
Marliana Lara
00a49482f2 Merge pull request #369 from marshmalien/6908-diff-mode
Add diff_mode to job launch data object
2017-08-31 10:20:56 -04:00
mabashian
e60fcf93ba Fix cancel delete button flash 2017-08-31 10:19:19 -04:00
Aaron Tan
35110ef738 Prevent mistakenly truncate ANSI SGR code in job event stdout 2017-08-31 10:19:04 -04:00
Marliana Lara
383d6d6071 Edit Capacity column header and style 2017-08-31 10:12:07 -04:00
Shane McDonald
2419e5594b Update QA'd Japanese translations. 2017-08-31 10:08:22 -04:00
Ryan Petrello
5f416cce74 Merge pull request #365 from ryanpetrello/fix-7521
include extra_credentials data in summary fields for JT/Job detail view
2017-08-31 09:53:21 -04:00
AlanCoding
ceafa3803a remove can_run_ad_hoc_commands in v2 2017-08-30 23:14:05 -04:00
Jared Tabor
39a4dee84f adding model for admin of orgs and disabling credential's org field
when appropriate
2017-08-30 16:25:20 -07:00
Jared Tabor
ec4877f10b adding org-admin check for projects and teams 2017-08-30 16:25:19 -07:00
Marliana Lara
89db868d02 Remove extra horizontal scrollbar on Host Event Modal 2017-08-30 16:54:37 -04:00
mabashian
e0a10fb9d6 Reload the project list when we get a canceled socket message 2017-08-30 16:49:45 -04:00
Marliana Lara
1c05c60bd4 Add diff_mode to job launch data and POST it 2017-08-30 16:28:29 -04:00
Michael Abashian
5501d42de0 Merge pull request #361 from mabashian/7544-host-filter-org
Org-centric smart inventory UI changes
2017-08-30 15:46:53 -04:00
mabashian
f8c6690d6d Properly name the required asterisks class 2017-08-30 15:41:45 -04:00
mabashian
33c470ebc5 Removed prepend-asterisk in favor of an injected span 2017-08-30 15:36:20 -04:00
Matthew Jones
c1ffa6e5d9 Call out eval for setting up the minishift environment 2017-08-30 15:02:06 -04:00
AlanCoding
853d38b757 remove unused signal_finished method 2017-08-30 13:44:37 -04:00
Matthew Jones
f1af6b9bf2 Support official image builds with awx logos 2017-08-30 13:40:48 -04:00
Marliana Lara
69710366b6 Revert capacity bar to display consumed_capacity instead of percent_capacity_remaining 2017-08-30 13:30:21 -04:00
AlanCoding
de58d6764f use exceptions for job cancel and failure 2017-08-30 13:19:53 -04:00
Ryan Petrello
7192d5c4bb include extra_credentials data in summary fields for JT/Job detail view
see: https://github.com/ansible/ansible-tower/issues/7521
2017-08-30 11:56:24 -04:00
Alan Rominger
de3b9fc70d Merge pull request #364 from AlanCoding/null_inv_val
more coherent source_script & inv validation
2017-08-30 10:35:04 -04:00
Alan Rominger
2385c28046 Merge pull request #366 from AlanCoding/logger_unicode
smart_str in log statement to avoid unicode error
2017-08-30 10:33:43 -04:00
Shane McDonald
d3507eb42c Pull updated Japanese and French translation files. 2017-08-30 09:53:56 -04:00
AlanCoding
78ab13a44e smart_str in log statement to avoid unicode error 2017-08-30 09:47:18 -04:00
Matthew Jones
2daaef2a99 Contributing updates for clarity 2017-08-30 09:24:44 -04:00
Matthew Jones
3adc332ea7 Merge pull request #10 from chouseknecht/devel
Community updates
2017-08-30 09:20:20 -04:00
Ryan Petrello
6941df940f Merge pull request #360 from ryanpetrello/license_type_check
update the license check command to return license type, not validity
2017-08-30 09:12:44 -04:00
AlanCoding
20e82eba42 more coherent source_script & inv validation 2017-08-30 08:31:08 -04:00
Chris Houseknecht
5754952660 Updates CONTRIBUTING and README 2017-08-29 21:18:56 -04:00
Alan Rominger
7a1f674abc Merge pull request #363 from AlanCoding/org_smart_inv
backend of org-scoped smart inventories
2017-08-29 20:51:03 -04:00
Aaron Tan
3874476d84 Merge pull request #357 from jangsutsr/6103_enhance_log_protocol_choice_layout
Enhance LOG_AGGREGATOR_PROTOCOL choice options layout
2017-08-29 17:02:47 -04:00
jlmitch5
69c12aa9e3 Merge pull request #362 from mabashian/7541-autopopulate
Fixed autopopulate for a few fields
2017-08-29 16:57:11 -04:00
Alan Rominger
e679997ecc Merge pull request #359 from AlanCoding/fail_ans_inv
set flag to fail imports on errors
2017-08-29 16:51:48 -04:00
Matthew Jones
5d3bc95283 Merge pull request #355 from ansible/fix_ig_org_rbac
Ensure that only the super user can dis/associate IGs from Orgs
2017-08-29 16:50:31 -04:00
AlanCoding
ff96a750e1 backend of org-scoped smart inventories 2017-08-29 16:43:56 -04:00
Matthew Jones
067beb90c9 Add support for standalone docker install 2017-08-29 16:14:53 -04:00
mabashian
ca62c8931f Fixed autopopulate for a few fields 2017-08-29 15:40:47 -04:00
Michael Abashian
100413fdff Merge pull request #358 from mabashian/6034-basic-workflow-copy-error
Properly catch and display workflow copy error when basic license installed
2017-08-29 15:31:15 -04:00
Michael Abashian
0362d42007 Merge pull request #354 from mabashian/7526-instance-group-noitems-text
Updated instance groups empty list text
2017-08-29 15:30:34 -04:00
Michael Abashian
9b15beead7 Merge pull request #353 from mabashian/7265-deselect
Fixed deselect team/user when adding permission
2017-08-29 15:30:08 -04:00
Ryan Petrello
beae7ffa20 update the license check command to return license type, not validity
we care about preventing upgradability from AWX installs w/ the open
source license, not general license validity

see: https://github.com/ansible/ansible-tower/issues/6555
2017-08-29 15:25:32 -04:00
mabashian
663d95c388 Use org when showing host filter matches. Make org required before user can interact with host filter. 2017-08-29 15:25:27 -04:00
AlanCoding
9d91875832 set flag to fail imports on errors 2017-08-29 14:36:53 -04:00
Marliana Lara
748c8543b9 Merge pull request #351 from marshmalien/fix/7537-Select2-dropdown-decrease-stack-order
Decrease Select2 dropdown stack order
2017-08-29 14:25:42 -04:00
Chris Houseknecht
327be00e8f Merge pull request #9 from chouseknecht/awx_installer
Awx installer
2017-08-29 12:27:27 -04:00
mabashian
2f6e16f7ba Properly catch and display workflow copy error when basic license installed 2017-08-29 11:42:24 -04:00
Aaron Tan
68cccb77a0 Enhance LOG_AGGREGATOR_PROTOCOL choice options layout 2017-08-29 11:13:36 -04:00
jlmitch5
a3b29a196c Fix revert of log aggregator protocol 2017-08-29 11:02:40 -04:00
Matthew Jones
d7fd3a467a Ensure that only the super user can dis/associate IGs from Orgs 2017-08-29 09:36:42 -04:00
Chris Houseknecht
a144738094 First iteration on INSTALL 2017-08-28 17:18:12 -04:00
Jared Tabor
e2d943fd1a adding ng-if to tabs in order to hide insights tab on host-add-form 2017-08-28 13:52:39 -07:00
Alan Rominger
ba8326285e Merge pull request #337 from AlanCoding/capacity_fix
correct capacity algorithm for task manager
2017-08-28 16:49:19 -04:00
AlanCoding
d54eb93f26 Handle capacity algorithm corner cases
Instance has gone lost, and jobs are still either running
or waiting inside of its instance group
RBAC - user does not have permission to see some of the
groups that would be used in the capacity calculation

For some cases, a naive capacity dictionary is returned,
main goal is to not throw errors and avoid unpredicted behavior

Detailed capacity tests are moved into new unit test file.
2017-08-28 16:12:12 -04:00
mabashian
351b88b6ca Updated instance groups empty list text 2017-08-28 15:45:19 -04:00
Michael Abashian
41b1dc2ddd Merge pull request #350 from mabashian/7488-smart-inv-host-filter
Updated smart inv host filter list empty text
2017-08-28 15:21:45 -04:00
Michael Abashian
4043ec3bbd Merge pull request #338 from mabashian/7524-duplicate-host-filter
Prevent duplicate host filter strings
2017-08-28 15:20:31 -04:00
jlmitch5
2b1df7ba63 Merge pull request #344 from jlmitch5/fixStdout
fix stdout ordering
2017-08-28 15:20:12 -04:00
Michael Abashian
8d6de99a12 Merge pull request #335 from mabashian/7489-edit-smart-inv-host
Edit a host from within the smart inventory tree
2017-08-28 15:19:57 -04:00
John Mitchell
a5321179ac fix stdout ordering missing event issue 2017-08-28 15:06:58 -04:00
mabashian
ffcab7e33b Fixed deselect team/user when adding permission 2017-08-28 15:06:17 -04:00
Chris Houseknecht
291d5fb0b5 Adds edge terminated route 2017-08-28 14:49:50 -04:00
Chris Houseknecht
c0c6170ba6 Ignore Pycharm droppings 2017-08-28 14:48:28 -04:00
Marliana Lara
1cbe3c3fe5 Decrease Select2 dropdown stack order 2017-08-28 13:35:15 -04:00
mabashian
0be16239a0 Small tweaks to empty list text styling 2017-08-28 12:43:47 -04:00
mabashian
d0c9d8ce4e Updated smart inv host filter list empty text 2017-08-28 12:37:41 -04:00
Alan Rominger
c2d59e4815 Merge pull request #347 from AlanCoding/no_start
remove job start endpoint in v2
2017-08-28 12:11:32 -04:00
AlanCoding
5327a4c622 Use global capacity algorithm in serializer
The task manager was doing work to compute currently consumed
capacity, this is moved into the manager and applied in the
same form to the instance group list.
2017-08-28 12:07:47 -04:00
Marliana Lara
d01d8b86b2 Merge pull request #342 from marshmalien/7529-Diff-mode-popover-typo
Replace single apostrophe with Unicode equivalent
2017-08-28 11:20:41 -04:00
Marliana Lara
48d37c8522 Merge pull request #341 from marshmalien/fix/7517-asterisk-whitespace
Keep whitespace between field label asterisk and label title
2017-08-28 11:20:28 -04:00
AlanCoding
495d6e9887 remove job start endpoint in v2 2017-08-28 11:12:13 -04:00
Alan Rominger
c904ed62fe Merge pull request #348 from AlanCoding/jobs_opt
optimizations for unified job subtypes
2017-08-28 11:06:26 -04:00
Michael Abashian
3b2149f252 Merge pull request #336 from mabashian/7523-search-spaces
Re-included logic for stripping out quotes from search value that was inadvertently removed
2017-08-28 10:05:34 -04:00
Aaron Tan
fd08314dcb Merge pull request #345 from jangsutsr/7532_disallow_custom_inv_src_from_using_wrong_cred
Disallow custom inventory sources from using meaningless credentials
2017-08-28 09:45:19 -04:00
Shane McDonald
d5c1f34016 Update pot files 2017-08-27 15:32:21 -04:00
AlanCoding
ce3c969c08 correct capacity algorithm for task manager 2017-08-26 11:59:25 -04:00
Alan Rominger
34a375542e Merge pull request #339 from AlanCoding/encrypted_fix2
allow cache storing of non-DB settings
2017-08-26 11:57:29 -04:00
Alan Rominger
d97cf263c1 Merge pull request #308 from AlanCoding/calm_your_signals2
avoid every-request user signals
2017-08-26 11:56:41 -04:00
Aaron Tan
853b9d1001 Merge pull request #343 from jangsutsr/7530_add_pending_deletion_check_to_job_relaunch_validation
Add pending_deletion check to job relaunch validation
2017-08-25 16:50:16 -04:00
Aaron Tan
90bff467a4 Merge pull request #326 from jangsutsr/7500_add_workflow_license_check_to_user_capabilities
Allow lower-licensed user to delete workflow resources
2017-08-25 16:49:12 -04:00
Aaron Tan
11e924b344 Disallow custom inventory sources from using meaningless credentials 2017-08-25 16:47:08 -04:00
John Mitchell
e6d4de301b fix stdout ordering 2017-08-25 16:26:07 -04:00
Aaron Tan
baa7478ff0 Add pending_deletion check to job relaunch validation 2017-08-25 15:34:32 -04:00
Marliana Lara
db3ee977fa Replace single apostrophe with Unicode equivalent 2017-08-25 14:43:17 -04:00
Marliana Lara
a64bd7e829 Keep whitespace between field label asterisk and title 2017-08-25 14:20:34 -04:00
AlanCoding
5cc5d4deff allow cache storing of non-DB settings 2017-08-25 13:59:31 -04:00
mabashian
5be6d5bf26 Prevent duplicate host filter strings 2017-08-25 13:30:24 -04:00
Greg Considine
e1ee95234e Delete unwanted (and accidentally created) file 2017-08-25 12:41:26 -04:00
Matthew Jones
ddbb845e36 Force reauth docker registry login in installer 2017-08-25 11:39:56 -04:00
mabashian
78b132580b Re-included logic for stripping out quotes from search value that was inadvertently removed 2017-08-25 09:50:58 -04:00
mabashian
5be3105d60 Edit a host from within the smart inventory tree 2017-08-24 17:12:58 -04:00
Jared Tabor
d1503e974b Merge pull request #332 from jaredevantabor/smart-host-inventories
adding inventory column to smart inventory host search modal
2017-08-24 17:00:00 -04:00
Jared Tabor
74e9834c42 adding inventory column to smart inventory host search modal 2017-08-24 16:25:10 -04:00
Aaron Tan
bd7cd9281b Allow lower-licensed user to delete workflow resources 2017-08-24 15:59:08 -04:00
AlanCoding
50ff18ba25 avoid every-request user signals 2017-08-24 11:20:39 -04:00
Michael Abashian
b4e78b6131 Merge pull request #331 from mabashian/7509-host-filter-permissions
Smart Inv permissions bug fixes
2017-08-23 18:20:08 -04:00
mabashian
be4ddab218 Hide filter tooltip when host filter is disabled 2017-08-23 18:13:33 -04:00
Michael Abashian
6e12fee5ec Merge pull request #329 from mabashian/7491-host-on-off
Disable togglehost when user cannot edit host
2017-08-23 18:02:28 -04:00
Michael Abashian
097c6463ad Merge pull request #327 from mabashian/7493-smart-inv-host-groups
Remove groups column from smart inventory hosts list
2017-08-23 18:01:55 -04:00
Michael Abashian
dbc95b39b7 Merge pull request #324 from mabashian/7265-permissions
Fixed bug removing item from allSelected when adding permissions
2017-08-23 17:59:14 -04:00
Michael Abashian
3aa9d2e64c Merge pull request #320 from mabashian/6034-workflow-402
Basic license wfjt fixes
2017-08-23 17:58:32 -04:00
mabashian
29fcf336c1 Disable host filter lookup for users who don't have edit permissions. Hide delete/edit inv list icons for users who don't have proper permissions. 2017-08-23 12:11:40 -04:00
Jared Tabor
1270a9365b Merge pull request #325 from jaredevantabor/danger
fixing ngToast.danger message for failed test aggregation
2017-08-23 12:03:55 -04:00
Jared Tabor
ba1d196a42 Merge pull request #328 from jaredevantabor/insights
changing logic for Remediate Inventory button
2017-08-23 12:02:59 -04:00
Jared Tabor
9ac29a95ce Merge pull request #330 from jaredevantabor/oops
Oops
2017-08-23 12:02:08 -04:00
Jared Tabor
ba88d1822b removing tower-license submodule...oops 2017-08-23 11:54:38 -04:00
mabashian
991e1916bf Iterator is nested_host and not host 2017-08-23 11:35:06 -04:00
mabashian
51c3d77a92 Disable togglehost when user cannot edit host 2017-08-23 11:07:02 -04:00
Michael Abashian
0cbe083dcf Merge pull request #323 from mabashian/7498-custom-inv-script-cred
Show credential lookup when source is 'custom'
2017-08-22 16:41:18 -04:00
Michael Abashian
105cead4da Merge pull request #313 from mabashian/2989-management-schedule
Fix management job scheduler time inputs by resetting invalid input to 00
2017-08-22 16:40:30 -04:00
Michael Abashian
4e6722a171 Merge pull request #309 from mabashian/roll-back-survey-question-changes
Rolled back survey question preview enhancements
2017-08-22 16:39:06 -04:00
Wayne Witzel III
05b4bff388 Merge pull request #322 from wwitzel3/issue-7501
Update HostManager to return distinct hostnames
2017-08-22 16:31:57 -04:00
Jared Tabor
dd7ebbc461 changing logic for Remediate Inventory button
to only check for any insights projects, instead of insights projects with
specifically the same credential as the insights inventory
2017-08-22 16:08:25 -04:00
John Mitchell
813a66cafe hide run commands for related host, groups nested hosts lists if user does not have permission 2017-08-22 16:07:55 -04:00
mabashian
e7e47c8906 Update name column classes after deleting groups column 2017-08-22 15:26:54 -04:00
mabashian
2d0cac7c4d Remove groups column from smart inventory hosts list 2017-08-22 15:25:15 -04:00
Jared Tabor
d3826c5c50 fixing ngToast.danger message for failed test aggregation 2017-08-22 15:02:17 -04:00
Matthew Jones
f107372464 Rename LICENSE to LICENSE.md 2017-08-22 14:34:25 -04:00
Matthew Jones
c3fec00562 Delete LICENSE.md 2017-08-22 14:34:09 -04:00
Matthew Jones
5d79d7a14a Updating license
markdown formatted license
2017-08-22 14:33:50 -04:00
James Laska
9503a5c07b Fix broken markdown 2017-08-22 14:30:31 -04:00
Aaron Tan
c2e8200c81 Merge pull request #319 from jangsutsr/7496_handle_empty_named_url_id_cornercase
Handle named URL processing corner case where identifier is empty string
2017-08-22 14:25:06 -04:00
James Laska
d2be1e83ce Minor adjustments to CONTRIBUTING.md 2017-08-22 14:25:04 -04:00
Matthew Jones
a9dcf6650b Adding apache v2 license 2017-08-22 14:19:52 -04:00
Shane McDonald
16ef7e1950 Remove EULA
Rather than deleting this file we are just removing the content, so that existing references to the file do not break.
2017-08-22 13:59:44 -04:00
mabashian
d2378637fa Fixed bug removing item from allSelected 2017-08-22 13:31:33 -04:00
Matthew Jones
6e4d886ea4 Reduce the size of the production container image 2017-08-22 13:21:53 -04:00
jlmitch5
9007965a8e Merge pull request #316 from jlmitch5/fixInvRecentJobsPopover
Fix inv recent jobs popover
2017-08-22 13:11:31 -04:00
mabashian
4fe8cde660 Show credential lookup when source is 'custom' 2017-08-22 12:03:36 -04:00
mabashian
03903c59b6 Handle delete wfjt error with basic license. Remove old 402 logic for hiding wf permissions tab 2017-08-22 11:13:40 -04:00
Matthew Jones
031b5f3269 Merge pull request #318 from ansible/405_v2_job_launch
Prevent v2 direct job launches
2017-08-22 11:01:14 -04:00
Alan Rominger
223a198bc4 Merge pull request #317 from AlanCoding/token_on_commit
[WIP] delay token expiration update to on_commit
2017-08-22 10:56:15 -04:00
Aaron Tan
c321819547 Handle named URL processing corner case where identifier is empty string 2017-08-22 10:40:45 -04:00
Matthew Jones
f3f10df361 IFF v2 api disallow direct job launches 2017-08-22 09:53:58 -04:00
Chris Meyers
022de2aa3e Merge pull request #314 from chrismeyersfsu/fix-session_deletion
do not re-create django session on every request
2017-08-22 09:38:37 -04:00
AlanCoding
4d41e31639 delay token expiration update to on_commit 2017-08-21 16:56:07 -04:00
Aaron Tan
f14a47caa0 Merge pull request #311 from jangsutsr/7484_update_ctint_help_to_remove_newline_escape
Update Tower Configuration help text to remove \n escape
2017-08-21 16:29:00 -04:00
Aaron Tan
1df3432130 Merge pull request #298 from jangsutsr/7479_prevent_accessing_none_attr_in_host_summary_repr
Prevent accessing None attributes in host summary __unicode__
2017-08-21 16:16:24 -04:00
John Mitchell
59fcf4b8ca update which jobs are shown in recent jobs popover 2017-08-21 15:40:39 -04:00
jlmitch5
ee4364996d Merge pull request #302 from jlmitch5/scheduleTogglesDisabledCtit
Schedule toggles disabled ctit
2017-08-21 15:25:18 -04:00
Jared Tabor
f6b60bb200 Merge pull request #305 from jaredevantabor/tooltip-content
Tooltip content Audit on the UI
2017-08-21 11:34:43 -04:00
Jared Tabor
7d7b917523 tooltip content audit for sources form 2017-08-21 11:21:33 -04:00
Chris Meyers
45813bea16 do not re-create django session on every request
* The django middleware call stack behavior is changed by DRF. As a
result, during the process_request in sso/middlware.py request.user
is not set as you would expect it to be set from the middleware
django.contrib.auth.middleware.AuthenticationMiddleware
2017-08-21 11:19:52 -04:00
Ryan Petrello
b5903ab7f4 Merge pull request #310 from ryanpetrello/fix-7476
properly sanitize conf.settings debug logs
2017-08-21 11:18:13 -04:00
mabashian
3d03855cd9 Fix management job scheduler time inputs by resetting invalid input to 00 2017-08-21 11:16:06 -04:00
Christian Adams
49aa43f8e4 Merge pull request #312 from rooftopcellist/auth_text_fix
Removes auth field from Access List serializer
2017-08-21 11:10:40 -04:00
Jared Tabor
b281b563e0 tooltip content audit for survey maker 2017-08-21 11:04:28 -04:00
Jared Tabor
e5efbcf42f tooltip content audit for workflows form 2017-08-21 11:04:28 -04:00
Jared Tabor
a589bc4562 tooltip content audit for inventory form 2017-08-21 11:04:28 -04:00
Jared Tabor
22afd8b044 tooltip content for inventory scripts form 2017-08-21 11:04:28 -04:00
Jared Tabor
50852e406a popover content for notification templates form 2017-08-21 11:04:28 -04:00
Jared Tabor
7a5899a968 popover content audit for JT form 2017-08-21 11:04:28 -04:00
adamscmRH
9b84670cf0 Removes auth field from Access List serializer 2017-08-21 10:43:28 -04:00
Aaron Tan
d243b587f4 Update Tower Configuration help text to remove \n escape. 2017-08-21 10:27:42 -04:00
Ryan Petrello
0b68ad9b10 properly sanitize conf.settings debug logs
cache.set() and cache.get() arguments are logged when the log level is
DEBUG; this _may_ include plaintext secrets; strip sensitive values
before logging them

see: https://github.com/ansible/ansible-tower/issues/7476
2017-08-21 10:23:39 -04:00
Aaron Tan
ff51fe3050 Prevent accessing None attributes in host summary __unicode__ 2017-08-21 09:56:11 -04:00
mabashian
0daa203fe0 Rolled back several survey question enhancements which caused drag and drop to break 2017-08-21 09:23:34 -04:00
Wayne Witzel III
ca9a1a0ca1 remove tests that execute distinct logic, sqlite3 does not support 2017-08-21 06:16:44 -04:00
Wayne Witzel III
f8c2b466a8 sometimes core_filters is not an attribute, so just set it to empty instead of pop 2017-08-21 06:03:37 -04:00
Wayne Witzel III
eb6a27653f Adjust HostManager and update summary host query 2017-08-21 04:01:58 -04:00
Wayne Witzel III
c352ea7596 Update HostManager to return only a single matching hostname for SmartInventory filter 2017-08-21 02:17:27 -04:00
AlanCoding
a1083d45c5 optimizations for unified job subtypes 2017-08-19 07:05:37 -04:00
Aaron Tan
708efbd165 Merge pull request #300 from jangsutsr/7482_tower_configuration_help_text_updates
Update API help text for Tower configuration
2017-08-18 18:45:43 -04:00
Alan Rominger
66a3680134 Merge pull request #295 from ansible/labels_load
basic API optimization of labels list
2017-08-18 17:23:55 -04:00
Alan Rominger
caf15abc4f Merge pull request #297 from AlanCoding/cache_ids
Make cache compatible with encrypted settings
2017-08-18 17:20:57 -04:00
Ryan Petrello
54d6c4ebfd Merge pull request #304 from ryanpetrello/required-cred-fields
mark a variety of credential fields as required
2017-08-18 17:02:24 -04:00
Ryan Petrello
05eac58c65 Merge pull request #301 from ryanpetrello/release_3.2.0
make `vault_password` required for Vault credentials
2017-08-18 17:02:15 -04:00
Matthew Jones
d39c70d9f2 Initial awx installer 2017-08-18 16:40:41 -04:00
Marliana Lara
dc65f459ec Merge pull request #299 from marshmalien/fix/4514-vmware-instance-filter-tooltip
Change the instance filters tooltip text and add translations
2017-08-18 16:39:47 -04:00
Ryan Petrello
b0a1988c29 add required fields for cloudforms credentials
see: https://github.com/ansible/ansible-tower/issues/7462
2017-08-18 16:18:06 -04:00
Ryan Petrello
bcd8e13c24 add required fields for gce credentials
see: https://github.com/ansible/ansible-tower/issues/7463
2017-08-18 16:18:06 -04:00
Ryan Petrello
fc73bdcc18 add required fields for azure classic credentials
https://github.com/ansible/ansible-tower/issues/7464
2017-08-18 16:18:05 -04:00
Ryan Petrello
5ba76f28ce add required fields for azure credentials
see: https://github.com/ansible/ansible-tower/issues/7465
2017-08-18 16:18:05 -04:00
Ryan Petrello
90b5d98e5c add required fields for network credentials
see: https://github.com/ansible/ansible-tower/issues/7466
2017-08-18 16:18:04 -04:00
Ryan Petrello
50782b9465 add required fields for RHSatellite6 credentials
see: https://github.com/ansible/ansible-tower/issues/7467
2017-08-18 16:18:04 -04:00
Ryan Fitzpatrick
a7a607e440 Merge pull request #303 from rmfitzpatrick/credential_help_text_updates
Minor credential help text correction
2017-08-18 16:17:13 -04:00
Ryan Fitzpatrick
da70c11da5 Minor credential help text correction 2017-08-18 16:09:13 -04:00
Ryan Petrello
2e719e5bc6 Merge pull request #5 from ryanpetrello/shippable-ci
get CI passing on shippable CI
2017-08-18 16:02:24 -04:00
AlanCoding
1f2a7801fd fix flake8 and data gen functionality 2017-08-18 15:30:20 -04:00
Aaron Tan
0121e5c22b Update API help text for Tower configuration. 2017-08-18 15:02:12 -04:00
John Mitchell
08574428f1 add disabled toggle to job templte diff mode 2017-08-18 14:28:25 -04:00
Ryan Petrello
c4a1dfc4e8 only run shippable UI for devel and release branches 2017-08-18 14:21:48 -04:00
Ryan Petrello
438d41c986 make vault_password required for Vault credentials
see: https://github.com/ansible/ansible-tower/issues/7468
2017-08-18 14:10:19 -04:00
John Mitchell
d2595944fc make sure all toggles on ctit form are disabled 2017-08-18 14:01:12 -04:00
Jared Tabor
4d83e696f7 Merge pull request #296 from jaredevantabor/host-event-modal
Fixing host-event's stdout/stdout ng-if logic
2017-08-18 13:50:08 -04:00
Jared Tabor
f1c7286448 Merge pull request #294 from jaredevantabor/translations
adding translation directive in places
2017-08-18 08:56:25 -07:00
Marliana Lara
6bd5679429 Update the instance filters popover text and add translations 2017-08-18 11:47:41 -04:00
Jared Tabor
043523b6d2 adding translate directive to parts of components 2017-08-18 11:45:32 -04:00
Jared Tabor
4e077e2b95 fixing unit test for column-sort
after adding the translate directive
2017-08-18 11:28:42 -04:00
Michael Abashian
856d1a8047 Merge pull request #292 from mabashian/5092-credential-filtering
Add user credential permissions without org
2017-08-18 10:03:16 -04:00
Michael Abashian
74a1dbfe6c Merge pull request #291 from mabashian/5893-workflow-fixes
Fixed some delete workflow node bugs
2017-08-18 10:02:29 -04:00
AlanCoding
9254bcaf16 Make cache compatible with encrypted settings
This saves the id value of the setting into the cache
if the setting is encrypted. That can then be combined
with the secret_key in order to decrypt the setting,
without having to make an additional query to the database.
2017-08-17 17:18:41 -04:00
Jared Tabor
1944c7fbd7 Fixing host-event's stdout/stdout ng-if logic
and fixing small issue with resizing the host event modal
2017-08-17 13:04:25 -07:00
John Mitchell
3957797815 fix scheduler inner panel border 2017-08-17 12:16:21 -04:00
AlanCoding
66a8170bbc basic API optimization of labels list 2017-08-17 10:33:10 -04:00
Ryan Petrello
f495615435 Merge pull request #1 from ryanpetrello/shippable-ci
set up shippable ci
2017-08-17 10:14:25 -04:00
Wayne Witzel III
ba1ed5b6fd Merge pull request #293 from wwitzel3/release_3.2.0
Provide history to hosts that are part of smart inventory jobs.
2017-08-17 09:58:32 -04:00
Ryan Petrello
cebc9326cd set up shippable ci 2017-08-17 09:46:22 -04:00
Marliana Lara
b5c7753291 Merge pull request #290 from marshmalien/fix/7446-survey-maker-empty-prompt
Generalize empty SurveyMaker prompt text
2017-08-17 09:36:47 -04:00
Marliana Lara
d64e804bf6 Merge pull request #288 from marshmalien/fix/5919-read-only-multi-choice
Default value of preview multiple select dropdown should be read-only
2017-08-17 09:36:35 -04:00
Shane McDonald
da18033a46 Make parent image tag for unit tests a build arg 2017-08-17 09:16:52 -04:00
Chris Meyers
d0c8366bb4 Merge pull request #289 from chrismeyersfsu/fix-7452
account for waiting tasks not having execution_nodes yet
2017-08-17 08:54:49 -04:00
Alan Rominger
bd0d911376 Merge pull request #2 from AlanCoding/rollbacktothewall
data generator schema update
2017-08-17 08:15:52 -04:00
Shane McDonald
7ac2376a01 Make parent image tag for unit tests a build arg 2017-08-16 22:31:15 -04:00
Jared Tabor
1edc688acb adding translation directive in places 2017-08-16 16:50:48 -07:00
AlanCoding
d48c1bd71d data generator schema update for 3.2 2017-08-16 17:14:56 -04:00
Wayne Witzel III
67c25570f3 Ensure Smart Inventory hosts are assigned job history 2017-08-16 17:04:17 -04:00
mabashian
116a47fc6a Filter credentials to only credentials not associated with an organization when adding permissions for a user not associated with an organization. 2017-08-16 15:53:48 -04:00
Michael Abashian
6915e95f58 Merge pull request #286 from mabashian/7237-smart-inv-help
Changed smart host filter help text from RHEL to RedHat
2017-08-16 14:52:20 -04:00
Michael Abashian
07d9d4bca6 Merge pull request #284 from mabashian/7273-explanation
Fixed explanation for inv sync and playbook run stdout
2017-08-16 14:51:01 -04:00
Michael Abashian
cfc83f5a23 Merge pull request #282 from mabashian/5092-cred-permissions
Credential permissions fixes
2017-08-16 14:50:17 -04:00
mabashian
dfc4070dba Fixed some delete workflow node bugs 2017-08-16 14:44:01 -04:00
Marliana Lara
ad4b1650e3 Generalize empty SurveyMaker prompt text 2017-08-16 14:19:07 -04:00
Chris Meyers
1df47a2ddd account for waiting tasks not having execution_nodes yet
* Reap running tasks on non-netsplit nodes
* Reap running tasks on known to be offline nodes
* Reap waiting tasks with no celery id anywhere if waiting >= 60 seconds
2017-08-16 13:18:25 -04:00
Marliana Lara
1b6e4af9a7 Default value of preview multiple select dropdown should be read-only 2017-08-16 12:35:07 -04:00
mabashian
2908a0c2bd Changed smart host filter help text from RHEL to RedHat. Removed rogue console.log 2017-08-16 10:45:23 -04:00
Chris Meyers
2bccb5e753 Merge pull request #285 from chrismeyersfsu/fix-reap_workflow_jobs
do not include workflow jobs for reaping
2017-08-16 09:56:39 -04:00
Aaron Tan
ee06dab4d6 Merge pull request #283 from jangsutsr/6313_add_time_unit_to_uj_timeout_help_text
Add time unit to all unified job timeout conf help texts
2017-08-16 09:45:19 -04:00
Chris Meyers
d615e2e9ff do not include workflow jobs for reaping
* Workflow jobs are virtual jobs that don't actually run. Thus they
won't have a celery id and aren't candidates for the generic reaping.
* Better error logging when Instance not found in reaping code.
2017-08-16 08:51:27 -04:00
mabashian
01c3f62ed7 Added show/hide to explanation to limit long strings 2017-08-15 16:59:28 -04:00
Aaron Tan
4bc26310ac Add time unit to all unified job timeout conf help texts 2017-08-15 16:16:34 -04:00
mabashian
b5a34e45d2 Fixed credential permission user/teams lists. Fixed user permission credentials list 2017-08-15 15:37:56 -04:00
843 changed files with 46194 additions and 23287 deletions

16
.github/BOTMETA.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
files:
awx/ui/:
labels: component:ui
maintainers: $team_ui
awx/api/:
labels: component:api
maintainers: $team_api
awx/main/:
labels: component:api
maintainers: $team_api
installer/:
labels: component:installer
macros:
team_api: wwitzel3 matburt chrismeyersfsu cchurch AlanCoding ryanpetrello jangstur
team_ui: jlmitch5 jaredevantabor mabashian gconsidine marshmalien benthomasson

View File

@@ -1,31 +1,40 @@
### Summary
##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
- Bug Report
- Feature Idea
- Documentation
##### 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. -->
### Environment
<!--
##### ENVIRONMENT
* AWX version: X.Y.Z
* AWX install method: openshift, minishift, docker on linux, docker for mac, boot2docker
* Ansible version: X.Y.Z
* Operating System:
* Web Browser:
-->
### Steps To Reproduce:
##### STEPS TO REPRODUCE
<!-- For bugs, please show exactly how to reproduce the problem. For new
features, show how the feature would be used. -->
### Expected Results:
##### EXPECTED RESULTS
<!-- For bug reports, what did you expect to happen when running the steps
above? -->
### Actual Results:
##### ACTUAL RESULTS
<!-- For bug reports, what actually happened? -->
### Additional Information:
##### ADDITIONAL INFORMATION
<!-- Include any links to sosreport, database dumps, screenshots or other
information. -->

9
.github/LABEL_MAP.md vendored Normal file
View File

@@ -0,0 +1,9 @@
Bug Report: type:bug
Bugfix Pull Request: type:bug
Feature Request: type:enhancement
Feature Pull Request: type:enhancement
UI: component:ui
API: component:api
Installer: component:installer
Docs Pull Request: component:docs
Documentation: component:docs

39
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,39 @@
##### SUMMARY
<!--- Describe the change, including rationale and design decisions -->
<!---
If you are fixing an existing issue, please include "related #nnn" in your
commit message and your description; but you should still explain what
the change does.
-->
##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
- Feature Pull Request
- Bugfix Pull Request
- Docs Pull Request
##### COMPONENT NAME
<!--- Name of the module/plugin/module/task -->
- API
- UI
- Installer
##### AWX VERSION
<!--- Paste verbatim output from `make VERSION` between quotes below -->
```
```
##### ADDITIONAL INFORMATION
<!---
Include additional information to help people understand the change here.
For bugs that don't have a linked bug report, a step-by-step reproduction
of the problem is helpful.
-->
<!--- Paste verbatim command output below, e.g. before and after your change -->
```
```

7
.gitignore vendored
View File

@@ -20,6 +20,8 @@ celerybeat-schedule
awx/ui/static
awx/ui/build_test
awx/ui/client/languages
awx/ui/templates/ui/index.html
awx/ui/templates/ui/installing.html
# Tower setup playbook testing
setup/test/roles/postgresql
@@ -47,7 +49,7 @@ __pycache__
/.istanbul.yml
**/node_modules/**
/tmp
npm-debug.log
**/npm-debug.log*
# UI build flag files
awx/ui/.deps_built
@@ -108,9 +110,12 @@ local/
requirements/vendor
.i18n_built
VERSION
.idea/*
# AWX python libs populated by requirements.txt
awx/lib/.deps_built
awx/lib/site-packages
venv/*
use_dev_supervisor.txt
.idea/*

View File

@@ -1,233 +1,301 @@
AWX
===========
# AWX
Hi there! We're excited to have you as a contributor.
Have questions about this document or anything not covered here? Come chat with us on IRC (#ansible-awx on freenode) or the mailing list.
Have questions about this document or anything not covered here? Come chat with us at `#ansible-awx` on irc.freenode.net, or submit your question to the [mailing list](https://groups.google.com/forum/#!forum/awx-project) .
Table of contents
-----------------
## Table of contents
* [Contributing Agreement](#dco)
* [Code of Conduct](#code-of-conduct)
* [Setting up the development environment](#setting-up-the-development-environment)
* [Things to know prior to submitting code](#things-to-know-before-contributing-code)
* [Setting up your development environment](#setting-up-your-development-environment)
* [Prerequisites](#prerequisites)
* [Local Settings](#local-settings)
* [Building the base image](#building-the-base-image)
* [Building the user interface](#building-the-user-interface)
* [Starting up the development environment](#starting-up-the-development-environment)
* [Starting the development environment at the container shell](#starting-the-container-environment-at-the-container-shell)
* [Using the development environment](#using-the-development-environment)
* [Docker](#docker)
* [Docker compose](#docker-compose)
* [Node and npm](#node-and-npm)
* [Building the environment](#building-the-environment)
* [Clone the AWX repo](#clone-the-awx-repo)
* [Create local settings](#create-local-settings)
* [Build the base image](#build-the-base-image)
* [Build the user interface](#build-the-user-interface)
# [Running the environment](#running-the-environment)
* [Start the containers](#start-the-containers)
* [Start from the container shell](#start-from-the-container-shell)
* [Post Build Steps](#post-build-steps)
* [Start a shell](#start-the-shell)
* [Create a superuser](#create-a-superuser)
* [Load the data](#load-the-data)
* [Accessing the AWX web interface](#accessing-the-awx-web-interface)
* [Purging containers and images](#purging-containers-and-images)
* [What should I work on?](#what-should-i-work-on)
* [Submitting Pull Requests](#submitting-pull-requests)
* [Reporting Issues](#reporting-issues)
* [How issues are resolved](#how-issues-are-resolved)
* [Ansible Issue Bot](#ansible-issue-bot)
DCO
===
## Things to know prior to submitting code
All contributors must use "git commit --signoff" for any
commit to be merged, and agree that usage of --signoff constitutes
agreement with the terms of DCO 1.1. Any contribution that does not
have such a signoff will not be merged.
- All code submissions are done through pull requests against the `devel` branch.
- You must use `git commit --signoff` for any commit to be merged, and agree that usage of --signoff constitutes agreement with the terms of [DCO 1.1](./DCO_1_1.md).
- Take care to make sure no merge commits are in the submission, and use `git rebase` vs `git merge` for this reason.
- If submitting a large code change, it's a good idea to join the `#ansible-awx` channel on irc.freenode.net, and talk about what you would like to do or add first. This not only helps everyone know what's going on, it also helps save time and effort, if the community decides some changes are needed.
- We ask all of our community members and contributors to adhere to the [Ansible code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html). If you have questions, or need assistance, please reach out to our community team at [codeofconduct@ansible.com](mailto:codeofconduct@ansible.com)
```
Developer Certificate of Origin
Version 1.1
## Setting up your development environment
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
The AWX development environment workflow and toolchain is based on Docker, and the docker-compose tool, to provide dependencies, services, and databases necessary to run all of the components. It also binds the local source tree into the development container, making it possible to observe and test changes in real time.
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
### Prerequisites
Developer's Certificate of Origin 1.1
#### Docker
By making a contribution to this project, I certify that:
Prior to starting the development services, you'll need `docker` and `docker-compose`. On Linux, you can generally find these in your distro's packaging, but you may find that Docker themselves maintain a separate repo that tracks more closely to the latest releases.
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
For macOS and Windows, we recommend [Docker for Mac](https://www.docker.com/docker-mac) and [Docker for Windows](https://www.docker.com/docker-windows)
respectively.
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
For Linux platforms, refer to the following from Docker:
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
**Fedora**
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
> https://docs.docker.com/engine/installation/linux/docker-ce/fedora/
**Centos**
> https://docs.docker.com/engine/installation/linux/docker-ce/centos/
**Ubuntu**
> https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
**Debian**
> https://docs.docker.com/engine/installation/linux/docker-ce/debian/
**Arch**
> https://wiki.archlinux.org/index.php/Docker
#### Docker compose
If you're not using Docker for Mac, or Docker for Windows, you may need, or choose to, install the Docker compose Python module separately, in which case you'll need to run the following:
```bash
(host)$ pip install docker-compose
```
Code of Conduct
===============
#### Node and npm
All contributors are expected to adhere to the Ansible Community Code of Conduct: http://docs.ansible.com/ansible/latest/community/code_of_conduct.html
The AWX UI requires the following:
Setting up the development environment
======================================
- Node 6.x LTS version
- NPM 3.x LTS
The AWX development environment workflow and toolchain is based on Docker and the docker-compose tool to contain
the dependencies, services, and databases necessary to run everything. It will bind the local source tree into the container
making it possible to observe changes while developing.
### Build the environment
Prerequisites
-------------
`docker` and `docker-compose` are required for starting the development services, on Linux you can generally find these in your
distro's packaging, but you may find that Docker themselves maintain a seperate repo that tracks more closely to the latest releases.
For macOS and Windows, we recommend Docker for Mac (https://www.docker.com/docker-mac) and Docker for Windows (https://www.docker.com/docker-windows)
respectively. Docker for Mac/Windows automatically comes with `docker-compose`.
#### Fork and clone the AWX repo
> Fedora
If you have not done so already, you'll need to fork the AWX repo on GitHub. For more on how to do this, see [Fork a Repo](https://help.github.com/articles/fork-a-repo/).
https://docs.docker.com/engine/installation/linux/docker-ce/fedora/
#### Create local settings
> Centos
AWX will import the file `awx/settings/local_settings.py` and combine it with defaults in `awx/settings/defaults.py`. This file is required for starting the development environment and startup will fail if it's not provided.
https://docs.docker.com/engine/installation/linux/docker-ce/centos/
An example is provided. Make a copy of it, and edit as needed (the defaults are usually fine):
> Ubuntu
```bash
(host)$ cp awx/settings/local_settings.py.docker_compose awx/settings/local_settings.py
```
https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
#### Build the base image
> Debian
The AWX base container image (defined in `tools/docker-compose/Dockerfile`) contains basic OS dependencies and symbolic links into the development environment that make running the services easy.
https://docs.docker.com/engine/installation/linux/docker-ce/debian/
Run the following to build the image:
> Arch
```bash
(host)$ make docker-compose-build
```
https://wiki.archlinux.org/index.php/Docker
**NOTE**
For `docker-compose` you may need/choose to install it seperately:
> The image will need to be rebuilt, if the Python requirements or OS dependencies change.
pip install docker-compose
Once the build completes, you will have a `ansible/awx_devel` image in your local image cache. Use the `docker images` command to view it, as follows:
```bash
(host)$ docker images
Local Settings
--------------
REPOSITORY TAG IMAGE ID CREATED SIZE
ansible/awx_devel latest ba9ec3e8df74 26 minutes ago 1.42GB
```
In development mode (i.e. when running from a source checkout), AWX
will import the file `awx/settings/local_settings.py` and combine it with defaults in `awx/settings/defaults.py`. This file
is required for starting the development environment and startup will fail if it's not provided
#### Build the user interface
An example file that works for the `docker-compose` tool is provided. Make a copy of it and edit as needed (the defaults are usually fine):
Run the following to build the AWX UI:
(host)$ cp awx/settings/local_settings.py.docker_compose awx/settings/local_settings.py
```bash
(host) $ make ui-devel
```
### Running the environment
Building the base image
-----------------------
#### Start the containers
The AWX base container image (found in `tools/docker-compose/Dockerfile`) contains basic OS dependencies and
symbolic links into the development environment that make running the services easy. You'll first need to build the image:
Start the development containers by running the following:
(host)$ make docker-compose-build
The image will only need to be rebuilt if the requirements or OS dependencies change. A core concept about this image is that it relies
on having your local development environment mapped in.
Building the user interface
---------------------------
> AWX requires the 6.x LTS version of Node and 3.x LTS NPM
In order for the AWX user interface to load from the development environment it must be built:
(host)$ make ui-devel
```bash
(host)$ make docker-compose
```
When developing features and fixes for the user interface you can find more detail here: [UI Developer README](awx/ui/README.md)
The above utilizes the image built in the previous step, and will automatically start all required services and dependent containers. Once the containers launch, your session will be attached to the *awx* container, and you'll be able to watch log messages and events in real time. You will see messages from Django, celery, and the front end build process.
Starting up the development environment
----------------------------------------------
If you start a second terminal session, you can take a look at the running containers using the `docker ps` command. For example:
There are several ways of starting the development environment depending on your desired workflow. The easiest and most common way is with:
```bash
# List running containers
(host)$ docker ps
(host)$ make docker-compose
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aa4a75d6d77b gcr.io/ansible-tower-engineering/awx_devel:devel "/tini -- /bin/sh ..." 23 seconds ago Up 15 seconds 0.0.0.0:5555->5555/tcp, 0.0.0.0:6899-6999->6899-6999/tcp, 0.0.0.0:8013->8013/tcp, 0.0.0.0:8043->8043/tcp, 22/tcp, 0.0.0.0:8080->8080/tcp tools_awx_1
e4c0afeb548c postgres:9.6 "docker-entrypoint..." 26 seconds ago Up 23 seconds 5432/tcp tools_postgres_1
0089699d5afd tools_logstash "/docker-entrypoin..." 26 seconds ago Up 25 seconds tools_logstash_1
4d4ff0ced266 memcached:alpine "docker-entrypoint..." 26 seconds ago Up 25 seconds 0.0.0.0:11211->11211/tcp tools_memcached_1
92842acd64cd rabbitmq:3-management "docker-entrypoint..." 26 seconds ago Up 24 seconds 4369/tcp, 5671-5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp tools_rabbitmq_1
```
**NOTE**
> The Makefile assumes that the image you built is tagged with your current branch. This allows you to build images for different contexts or branches. When starting the containers, you can choose a specific branch by setting `COMPOSE_TAG=<branch name>` in your environment.
> For example, you might be working in a feature branch, but you want to run the containers using the `devel` image you built previously. To do that, start the containers using the following command: `$ COMPOSE_TAG=devel make docker-compose`
##### Wait for migrations to complete
The first time you start the environment, database migrations need to run in order to build the PostgreSQL database. It will take few moments, but eventually you will see output in your terminal session that looks like the following:
```bash
awx_1 | Operations to perform:
awx_1 | Synchronize unmigrated apps: solo, api, staticfiles, debug_toolbar, messages, channels, django_extensions, ui, rest_framework, polymorphic
awx_1 | Apply all migrations: sso, taggit, sessions, djcelery, sites, kombu_transport_django, social_auth, contenttypes, auth, conf, main
awx_1 | Synchronizing apps without migrations:
awx_1 | Creating tables...
awx_1 | Running deferred SQL...
awx_1 | Installing custom SQL...
awx_1 | Running migrations:
awx_1 | Rendering model states... DONE
awx_1 | Applying contenttypes.0001_initial... OK
awx_1 | Applying contenttypes.0002_remove_content_type_name... OK
awx_1 | Applying auth.0001_initial... OK
awx_1 | Applying auth.0002_alter_permission_name_max_length... OK
awx_1 | Applying auth.0003_alter_user_email_max_length... OK
awx_1 | Applying auth.0004_alter_user_username_opts... OK
awx_1 | Applying auth.0005_alter_user_last_login_null... OK
awx_1 | Applying auth.0006_require_contenttypes_0002... OK
awx_1 | Applying taggit.0001_initial... OK
awx_1 | Applying taggit.0002_auto_20150616_2121... OK
awx_1 | Applying main.0001_initial... OK
awx_1 | Applying main.0002_squashed_v300_release... OK
awx_1 | Applying main.0003_squashed_v300_v303_updates... OK
awx_1 | Applying main.0004_squashed_v310_release... OK
awx_1 | Applying conf.0001_initial... OK
awx_1 | Applying conf.0002_v310_copy_tower_settings... OK
...
```
Once migrations are completed, you can begin using AWX.
#### Start from the container shell
Often times you'll want to start the development environment without immediately starting all of the services in the *awx* container, and instead be taken directly to a shell. You can do this with the following:
```bash
(host)$ make docker-compose-test
```
Using `docker exec`, this will create a session in the running *awx* container, and place you at a command prompt, where you can run shell commands inside the container.
If you want to start and use the development environment, you'll first need to bootstrap it by running the following command:
```bash
(container)# /bootstrap_development.sh
```
The above will do all the setup tasks, including running database migrations, so it amy take a couple minutes.
This utilizes the image you built in the previous step and will automatically start all required services and dependent containers. You'll
be able to watch log messages and events as they come through.
Now you can start each service individually, or start all services in a pre-configured tmux session like so:
The Makefile assumes that the image you built is tagged with your current branch. This allows you to pre-build images for different contexts
but you may want to use a particular branch's image (for instance if you are developing a PR from a branch based on the integration branch):
```bash
(container)# cd /awx_devel
(container)# make server
```
(host)$ COMPOSE_TAG=devel make docker-compose
### Post Build Steps
Starting the development environment at the container shell
-----------------------------------------------------------
Before you can log in and use the system, you will need to create an admin user. Optionally, you may also want to load some demo data.
Often times you'll want to start the development environment without immediately starting all services and instead be taken directly to a shell:
##### Start a shell
(host)$ make docker-compose-test
To create the admin user, and load demo data, you first need to start a shell session on the *awx* container. In a new terminal session, use the `docker exec` command as follows to start the shell session:
From here you'll need to bootstrap the development environment before it will be usable for you. The `docker-compose` make target will
automatically do this:
```bash
(host)$ docker exec -it tools_awx_1 bash
```
This creates a session in the *awx* containers, just as if you were using `ssh`, and allows you execute commands within the running container.
(container)$ /bootstrap_development.sh
##### Create an admin user
Before you can log into AWX, you need to create an admin user. With this user you will be able to create more users, and begin configuring the server. From within the container shell, run the following command:
```bash
(container)# awx-manage createsuperuser
```
You will be prompted for a username, an email address, and a password, and you will be asked to confirm the password. The email address is not important, so just enter something that looks like an email address. Remember the username and password, as you will use them to log into the web interface for the first time.
From here you can start each service individually, or choose to start all service in a pre-configured tmux session:
##### Load demo data
You can optionally load some demo data. This will create a demo project, inventory, and job template. From within the container shell, run the following to load the data:
(container)# cd /awx_devel
(container)# make server
```bash
(container)# awx-manage create_preload_data
```
Using the development environment
---------------------------------
**NOTE**
With the development environment running there are a few optional steps to pre-populate the environment with data. If you are using the `docker-compose`
method above you'll first need a shell in the container:
> This information will persist in the database running in the `tools_postgres_1` container, until the container is removed. You may periodically need to recreate
this container, and thus the database, if the database schema changes in an upstream commit.
(host)$ docker exec -it tools_awx_1 bash
### Accessing the AWX web interface
Create a superuser account:
You can now log into the AWX web interface at [https://localhost:8043](https://localhost:8043), and access the API directly at [https://localhost:8043/api/](https://localhost:8043/api/).
(container)# awx-manage createsuperuser
Preload AWX with demo data:
To log in use the admin user and password you created above in [Create an admin user](#create-an-admin-user).
(container)# awx-manage create_preload_data
This information will persist in the database running in the `tools_postgres_1` container, until it is removed. You may periodically need to recreate
this container and database if the database schema changes in an upstream commit.
### Purging containers and images
You should now be able to visit and login to the AWX user interface at https://localhost:8043 or http://localhost:8013 if you have built the UI.
If not you can visit the API directly in your browser at: https://localhost:8043/api/ or http://localhost:8013/api/
When necessary, remove any AWX containers and images by running the following:
When working on the source code for AWX the code will auto-reload for you when changes are made, with the exception of any background tasks that run in
celery.
```bash
(host)$ make docker-clean
```
## What should I work on?
Occasionally it may be necessary to purge any containers and images that may have collected:
For feature work, take a look at the current [Enhancements](https://github.com/ansible/awx/issues?q=is%3Aissue+is%3Aopen+label%3Atype%3Aenhancement).
(host)$ make docker-clean
There are host of other shortcuts, tools, and container configurations in the Makefile designed for various purposes. Feel free to explore.
What should I work on?
======================
If it has someone assigned to it then that person is the person responsible for working the enhancement. If you feel like you could contribute then reach out to that person.
We list our specs in `/docs`. `/docs/current` are things that we are actively working on. `/docs/future` are ideas for future work and the direction we
want that work to take. Fixing bugs, translations, and updates to documentation are also appreciated.
Fixing bugs, adding translations, and updating the documentation are always appreciated, so reviewing the backlog of issues is always a good place to start.
Be aware that if you are working in a part of the codebase that is going through active development your changes may be rejected or you may be asked to
rebase them. A good idea before starting work is to have a discussion with us on IRC or the mailing list.
**NOTE**
Submitting Pull Requests
========================
> If you work in a part of the codebase that is going through active development, your changes may be rejected, or you may be asked to `rebase`. A good idea before starting work is to have a discussion with us in the `#ansible-awx` channel on irc.freenode.net, or on the [mailing list](https://groups.google.com/forum/#!forum/awx-project).
Fixes and Features for AWX will go through the Github PR interface. There are a few things that can be done to help the visibility of your change
and increase the likelihood that it will be accepted
**NOTE**
> Add UI detail to these
> If you're planning to develop features or fixes for the UI, please review the [UI Developer doc](./awx/ui/README.md).
## Submitting Pull Requests
Fixes and Features for AWX will go through the Github pull request process. Submit your pull request (PR) agains the `devel` branch.
Here are a few things you can do to help the visibility of your change, and increase the likelihood that it will be accepted:
* No issues when running linters/code checkers
* Python: flake8: `(container)/awx_devel$ make flake8`
@@ -237,44 +305,17 @@ and increase the likelihood that it will be accepted
* JavaScript: Jasmine: `(container)/awx_devel$ make ui-test-ci`
* Write tests for new functionality, update/add tests for bug fixes
* Make the smallest change possible
* Write good commit messages: https://chris.beams.io/posts/git-commit/
* Write good commit messages. See [How to write a Git commit message](https://chris.beams.io/posts/git-commit/).
It's generally a good idea to discuss features with us first by engaging us in IRC or on the mailing list, especially if you are unsure if it's a good
fit.
It's generally a good idea to discuss features with us first by engaging us in the `#ansible-awx` channel on irc.freenode.net, or on the [mailing list](https://groups.google.com/forum/#!forum/awx-project).
We like to keep our commit history clean and will require resubmission of pull requests that contain merge commits. Use `git pull --rebase` rather than
`git pull` and `git rebase` rather than `git merge`.
We like to keep our commit history clean, and will require resubmission of pull requests that contain merge commits. Use `git pull --rebase`, rather than
`git pull`, and `git rebase`, rather than `git merge`.
Sometimes it might take us a while to fully review your PR. We try to keep the `devel` branch in pretty good working order so we review requests carefuly.
Please be patient.
Sometimes it might take us a while to fully review your PR. We try to keep the `devel` branch in good working order, and so we review requests carefuly. Please be patient.
All submitted PRs will have the linter and unit tests run against them and the status reported in the PR.
All submitted PRs will have the linter and unit tests run against them, and the status reported in the PR.
Reporting Issues
================
## Reporting Issues
Use the Github issue tracker for filing bugs. In order to save time and help us respond to issues quickly, make sure to fill out as much of the issue template
as possible. Version information and an accurate reproducing scenario are critical to helping us identify the problem.
When reporting issues for the UI we also appreciate having screenshots and any error messages from the web browser's console. It's not unsual for browser extensions
and plugins to cause problems. Reporting those will also help speed up analyzing and resolving UI bugs.
For the API and backend services, please capture all of the logs that you can from the time the problem was occuring.
Don't use the issue tracker to get help on how to do something - please use the mailing list and IRC for that.
How issues are resolved
-----------------------
We triage our issues into high, medium, and low and will tag them with the relevant component (api, ui, installer, etc). We will typically focus on high priority
issues. There aren't hard and fast rules for determining the severity of an issue, but generally high priority issues have an increased likelihood of breaking
existing functionality and/or negatively impacting a large number of users.
If your issue isn't considered `high` priority then please be patient as it may take some time to get to your report.
Before opening a new issue, please use the issue search feature to see if it's already been reported. If you have any extra detail to provide then please comment.
Rather than posting a "me too" comment you might consider giving it a "thumbs up" on github.
Ansible Issue Bot
-----------------
> Fill in
We welcome your feedback, and encourage you to file an issue when you run into a problem. But before opening a new issues, we ask that you please view our [Issues guide](./ISSUES.md).

19
COPYING
View File

@@ -1,19 +0,0 @@
ANSIBLE TOWER BY RED HAT END USER LICENSE AGREEMENT
This end user license agreement (“EULA”) governs the use of the Ansible Tower software and any related updates, upgrades, versions, appearance, structure and organization (the “Ansible Tower Software”), regardless of the delivery mechanism.
1. License Grant. Subject to the terms of this EULA, Red Hat, Inc. and its affiliates (“Red Hat”) grant to you (“You”) a non-transferable, non-exclusive, worldwide, non-sublicensable, limited, revocable license to use the Ansible Tower Software for the term of the associated Red Hat Software Subscription(s) and in a quantity equal to the number of Red Hat Software Subscriptions purchased from Red Hat for the Ansible Tower Software (“License”), each as set forth on the applicable Red Hat ordering document. You acquire only the right to use the Ansible Tower Software and do not acquire any rights of ownership. Red Hat reserves all rights to the Ansible Tower Software not expressly granted to You. This License grant pertains solely to Your use of the Ansible Tower Software and is not intended to limit Your rights under, or grant You rights that supersede, the license terms of any software packages which may be made available with the Ansible Tower Software that are subject to an open source software license.
2. Intellectual Property Rights. Title to the Ansible Tower Software and each component, copy and modification, including all derivative works whether made by Red Hat, You or on Red Hat's behalf, including those made at Your suggestion and all associated intellectual property rights, are and shall remain the sole and exclusive property of Red Hat and/or it licensors. The License does not authorize You (nor may You allow any third party, specifically non-employees of Yours) to: (a) copy, distribute, reproduce, use or allow third party access to the Ansible Tower Software except as expressly authorized hereunder; (b) decompile, disassemble, reverse engineer, translate, modify, convert or apply any procedure or process to the Ansible Tower Software in order to ascertain, derive, and/or appropriate for any reason or purpose, including the Ansible Tower Software source code or source listings or any trade secret information or process contained in the Ansible Tower Software (except as permitted under applicable law); (c) execute or incorporate other software (except for approved software as appears in the Ansible Tower Software documentation or specifically approved by Red Hat in writing) into Ansible Tower Software, or create a derivative work of any part of the Ansible Tower Software; (d) remove any trademarks, trade names or titles, copyrights legends or any other proprietary marking on the Ansible Tower Software; (e) disclose the results of any benchmarking of the Ansible Tower Software (whether or not obtained with Red Hats assistance) to any third party; (f) attempt to circumvent any user limits or other license, timing or use restrictions that are built into, defined or agreed upon, regarding the Ansible Tower Software. You are hereby notified that the Ansible Tower Software may contain time-out devices, counter devices, and/or other devices intended to ensure the limits of the License will not be exceeded (“Limiting Devices”). If the Ansible Tower Software contains Limiting Devices, Red Hat will provide You materials necessary to use the Ansible Tower Software to the extent permitted. You may not tamper with or otherwise take any action to defeat or circumvent a Limiting Device or other control measure, including but not limited to, resetting the unit amount or using false host identification number for the purpose of extending any term of the License.
3. Evaluation Licenses. Unless You have purchased Ansible Tower Software Subscriptions from Red Hat or an authorized reseller under the terms of a commercial agreement with Red Hat, all use of the Ansible Tower Software shall be limited to testing purposes and not for production use (“Evaluation”). Unless otherwise agreed by Red Hat, Evaluation of the Ansible Tower Software shall be limited to an evaluation environment and the Ansible Tower Software shall not be used to manage any systems or virtual machines on networks being used in the operation of Your business or any other non-evaluation purpose. Unless otherwise agreed by Red Hat, You shall limit all Evaluation use to a single 30 day evaluation period and shall not download or otherwise obtain additional copies of the Ansible Tower Software or license keys for Evaluation.
4. Limited Warranty. Except as specifically stated in this Section 4, to the maximum extent permitted under applicable law, the Ansible Tower Software and the components are provided and licensed “as is” without warranty of any kind, expressed or implied, including the implied warranties of merchantability, non-infringement or fitness for a particular purpose. Red Hat warrants solely to You that the media on which the Ansible Tower Software may be furnished will be free from defects in materials and manufacture under normal use for a period of thirty (30) days from the date of delivery to You. Red Hat does not warrant that the functions contained in the Ansible Tower Software will meet Your requirements or that the operation of the Ansible Tower Software will be entirely error free, appear precisely as described in the accompanying documentation, or comply with regulatory requirements.
5. Limitation of Remedies and Liability. To the maximum extent permitted by applicable law, Your exclusive remedy under this EULA is to return any defective media within thirty (30) days of delivery along with a copy of Your payment receipt and Red Hat, at its option, will replace it or refund the money paid by You for the media. To the maximum extent permitted under applicable law, neither Red Hat nor any Red Hat authorized distributor will be liable to You for any incidental or consequential damages, including lost profits or lost savings arising out of the use or inability to use the Ansible Tower Software or any component, even if Red Hat or the authorized distributor has been advised of the possibility of such damages. In no event shall Red Hat's liability or an authorized distributors liability exceed the amount that You paid to Red Hat for the Ansible Tower Software during the twelve months preceding the first event giving rise to liability.
6. Export Control. In accordance with the laws of the United States and other countries, You represent and warrant that You: (a) understand that the Ansible Tower Software and its components may be subject to export controls under the U.S. Commerce Departments Export Administration Regulations (“EAR”); (b) are not located in any country listed in Country Group E:1 in Supplement No. 1 to part 740 of the EAR; (c) will not export, re-export, or transfer the Ansible Tower Software to any prohibited destination or to any end user who has been prohibited from participating in US export transactions by any federal agency of the US government; (d) will not use or transfer the Ansible Tower Software for use in connection with the design, development or production of nuclear, chemical or biological weapons, or rocket systems, space launch vehicles, or sounding rockets or unmanned air vehicle systems; (e) understand and agree that if you are in the United States and you export or transfer the Ansible Tower Software to eligible end users, you will, to the extent required by EAR Section 740.17 obtain a license for such export or transfer and will submit semi-annual reports to the Commerce Departments Bureau of Industry and Security, which include the name and address (including country) of each transferee; and (f) understand that countries including the United States may restrict the import, use, or export of encryption products (which may include the Ansible Tower Software) and agree that you shall be solely responsible for compliance with any such import, use, or export restrictions.
7. General. If any provision of this EULA is held to be unenforceable, that shall not affect the enforceability of the remaining provisions. This agreement shall be governed by the laws of the State of New York and of the United States, without regard to any conflict of laws provisions. The rights and obligations of the parties to this EULA shall not be governed by the United Nations Convention on the International Sale of Goods.
Copyright © 2015 Red Hat, Inc. All rights reserved. "Red Hat" and “Ansible Tower” are registered trademarks of Red Hat, Inc. All other trademarks are the property of their respective owners.

45
DCO_1_1.md Normal file
View File

@@ -0,0 +1,45 @@
DCO
===
All contributors must use `git commit --signoff` for any
commit to be merged, and agree that usage of --signoff constitutes
agreement with the terms of DCO 1.1, which appears below:
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```

View File

@@ -1,2 +1,468 @@
Installing AWX
==============
# Installing AWX
This document provides a guide for installing AWX.
## Table of contents
- [Getting started](#getting-started)
- [Clone the repo](#clone-the-repo)
- [AWX branding](#awx-branding)
- [Prerequisites](#prerequisites)
- [System Requirements](#system-requirements)
- [AWX Tunables](#awx-tunables)
- [Choose a deployment platform](#choose-a-deployment-platform)
- [Official vs Building Images](#official-vs-building-images)
- [OpenShift](#openshift)
- [Prerequisites](#prerequisites)
- [Deploying to Minishift](#deploying-to-minishift)
- [Pre-build steps](#pre-build-steps)
- [PostgreSQL](#postgresql)
- [Start the build](#start-the-build)
- [Post build](#post-build)
- [Accessing AWX](#accessing-awx)
- [Docker](#docker)
- [Prerequisites](#prerequisites-2)
- [Pre-build steps](#pre-build-steps-1)
- [Deploying to a remote host](#deploying-to-a-remote-host)
- [Inventory variables](#inventory-variables)
- [Docker registry](#docker-registry)
- [PostgreSQL](#postgresql-1)
- [Proxy settings](#proxy-settings)
- [Start the build](#start-the-build-1)
- [Post build](#post-build-1)
- [Accessing AWX](#accessing-awx-1)
## Getting started
### Clone the repo
If you have not already done so, you will need to clone, or create a local copy, of the [AWX repo](https://github.com/ansible/awx). For more on how to clone the repo, view [git clone help](https://git-scm.com/docs/git-clone).
Once you have a local copy, run commands within the root of the project tree.
### AWX branding
You can optionally install the AWX branding assets from the [awx-logos repo](https://github.com/ansible/awx-logos). Prior to installing, please review and agree to the [trademark guidelines](https://github.com/ansible/awx-logos/blob/master/TRADEMARKS.md).
To install the assets, clone the `awx-logos` repo so that it is next to your `awx` clone. As you progress through the installation steps, you'll be setting variables in the [inventory](./installer/inventory) file. To include the assets in the build, set `awx_official=true`.
### Prerequisites
Before you can run a deployment, you'll need the following installed in your local environment:
- [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
- [GNU Make](https://www.gnu.org/software/make/)
- [Git](https://git-scm.com/)
### System Requirements
The system that runs the AWX service will need to satisfy the following requirements
- At leasts 4GB of memory
- At least 2 cpu cores
- At least 20GB of space
- Running Docker or Openshift
### AWX Tunables
**TODO** add tunable bits
### Choose a deployment platform
We currently support running AWX as a containerized application using Docker images deployed to either an OpenShift cluster, or a standalone Docker daemon. 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.
In the sections below, you'll find deployment details and instructions for each platform. To deploy to Docker, view the [Docker section](#docker), and for OpenShift, view the [OpenShift section](#openshift).
### Official vs Building Images
When installing AWX you have the option of building your own images or using the images provided on DockerHub (see [awx_web](https://hub.docker.com/r/ansible/awx_web/) and [awx_task](https://hub.docker.com/r/ansible/awx_task/))
This is controlled by the following variables in the `inventory` file
```
dockerhub_base=ansible
dockerhub_version=latest
```
If these variables are present then all deployments will use these hosted images. If the variables are not present then the images will be built during the install.
*dockerhub_base*
> The base location on DockerHub where the images are hosted (by default this pulls container images named `ansible/awx_web:tag` and `ansible/awx_task:tag`)
*dockerhub_version*
> Multiple versions are provided. `latest` always pulls the most recent. You may also select version numbers at different granularities: 1, 1.0, 1.0.1, 1.0.0.123
## OpenShift
### Prerequisites
To complete a deployment to OpenShift, you will obviously need access to an OpenShift cluster. For demo and testing purposes, you can use [Minishift](https://github.com/minishift/minishift) to create a single node cluster running inside a virtual machine.
You will also need to have the `oc` command in your PATH. The `install.yml` playbook will call out to `oc` when logging into, and creating objects on the cluster.
#### Deploying to Minishift
Install Minishift by following the [installation guide](https://docs.openshift.org/latest/minishift/getting-started/installing.html).
The Minishift VM contains a Docker daemon, which you can use to build the AWX images. This is generally the approach you should take, and we recommend doing so. To use this instance, run the following command to setup your environment:
```bash
# Set DOCKER environment variable to point to the Minishift VM
$ eval $(minishift docker-env)
```
**Note**
> If you choose to not use the Docker instance running inside the VM, and build the images externally, you will have to enable the OpenShift cluster to access the images. This involves pushing the images to an external Docker registry, and granting the cluster access to it, or exposing the internal registry, and pushing the images into it.
### Pre-build steps
Before starting the build process, review the [inventory](./installer/inventory) file, and uncomment and provide values for the following variables found in the `[all:vars]` section:
*openshift_host*
> IP address or hostname of the OpenShift cluster. If you're using Minishift, this will be the value returned by `minishift ip`.
*awx_openshift_project*
> Name of the OpenShift project that will be created, and used as the namespace for the AWX app. Defaults to *awx*.
*awx_node_port*
> The web server port running inside the AWX pod. Defaults to *30083*.
*openshift_user*
> Username of the OpenShift user that will create the project, and deploy the application. Defaults to *developer*.
*docker_registry*
> IP address and port, or URL, for accessing a registry that the OpenShift cluster can access. Defaults to *172.30.1.1:5000*, the internal registry delivered with Minishift. This is not needed if you are using official hosted images.
n
*docker_registry_repository*
> Namespace to use when pushing and pulling images to and from the registry. Generally this will match the project name. It defaults to *awx*. This is not needed if you are using official hosted images.
*docker_registry_username*
> Username of the user that will push images to the registry. Will generally match the *openshift_user* value. Defaults to *developer*. This is not needed if you are using official hosted images.
#### PostgreSQL
AWX requires access to a PostgreSQL database, and by default, one will be created and deployed in a pod. The database is configured for persistence and will create a persistent volume claim named `postgresql`. By default it will claim 5GB from the available persistent volume pool. This can be tuned by setting a variable in the inventory file or on the command line during the `ansible-playbook` run.
ansible-playbook ... -e pg_volume_capacity=n
If you wish to use an external database, in the inventory file, set the value of `pg_hostname`, and update `pg_username`, `pg_password`, `pg_database`, and `pg_port` with the connection information. When setting `pg_hostname` the installer will assume you have configured the database in that location and will not launch the postgresql pod.
### Start the build
To start the build, you will pass two *extra* variables on the command line. The first is *openshift_password*, which is the password for the *openshift_user*, and the second is *docker_registry_password*, which is the password associated with *docker_registry_username*.
If you're using the OpenShift internal registry, then you'll pass an access token for the *docker_registry_password* value, rather than a password. The `oc whoami -t` command will generate the required token, as long as you're logged into the cluster via `oc cluster login`.
To start the build and deployment, run the following (docker_registry_password is optional if using official images):
```bash
# Start the build and deployment
$ ansible-playbook -i inventory install.yml -e openshift_password=developer -e docker_registry_password=$(oc whoami -t)
```
### Post build
After the playbook run completes, check the status of the deployment by running `oc get pods`:
```bash
# View the running pods
$ oc get pods
NAME READY STATUS RESTARTS AGE
awx-3886581826-5mv0l 4/4 Running 0 8s
postgresql-1-l85fh 1/1 Running 0 20m
```
In the above example, the name of the AWX pod is `awx-3886581826-5mv0l`. Before accessing the AWX web interface, setup tasks and database migrations need to complete. These tasks are running in the `awx_task` container inside the AWX pod. To monitor their status, tail the container's STDOUT by running the following command, replacing the AWX pod name with the pod name from your environment:
```bash
# Follow the awx_task log output
$ oc logs -f awx-3886581826-5mv0l -c awx-celery
```
You will see the following indicating that database migrations are running:
```bash
Using /etc/ansible/ansible.cfg as config file
127.0.0.1 | SUCCESS => {
"changed": false,
"db": "awx"
}
Operations to perform:
Synchronize unmigrated apps: solo, api, staticfiles, messages, channels, django_extensions, ui, rest_framework, polymorphic
Apply all migrations: sso, taggit, sessions, djcelery, sites, kombu_transport_django, social_auth, contenttypes, auth, conf, main
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Installing custom SQL...
Running migrations:
Rendering model states... DONE
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying taggit.0001_initial... OK
Applying taggit.0002_auto_20150616_2121... OK
...
```
When you see output similar to the following, you'll know that database migrations have completed, and you can access the web interface:
```bash
Python 2.7.5 (default, Nov 6 2016, 00:28:07)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> <User: admin>
>>> Default organization added.
Demo Credential, Inventory, and Job Template added.
Successfully registered instance awx-3886581826-5mv0l
(changed: True)
Creating instance group tower
Added instance awx-3886581826-5mv0l to tower
```
Once database migrations complete, the web interface will be accessible.
### Accessing AWX
The AWX web interface is running in the AWX pod, behind the `awx-web-svc` service. To view the service, and its port value, run the following command:
```bash
# View available services
$ oc get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
awx-web-svc 172.30.111.74 <nodes> 8052:30083/TCP 37m
postgresql 172.30.102.9 <none> 5432/TCP 38m
```
The deployment process creates a route, `awx-web-svc`, to expose the service. How the ingres is actually created will vary depending on your environment, and how the cluster is configured. You can view the route, and the external IP address and hostname assigned to it, by running the following command:
```bash
# View available routes
$ oc get routes
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
awx-web-svc awx-web-svc-awx.192.168.64.2.nip.io awx-web-svc http edge/Allow None
```
The above example is taken from a Minishift instance. From a web browser, use `https` to access the `HOST/PORT` value from your environment. Using the above example, the URL to access the server would be [https://awx-web-svc-awx.192.168.64.2.nip.io](https://awx-web-svc-awx.192.168.64.2.nip.io).
Once you access the AWX server, you will be prompted with a login dialog. The default administrator username is `admin`, and the password is `password`.
## Docker
### Prerequisites
You will need the following installed on the host where AWX will be deployed:
- [Docker](https://docs.docker.com/engine/installation/)
- [docker-py](https://github.com/docker/docker-py) Python module
Note: After installing Docker, the Docker service must be started.
### Pre-build steps
#### Deploying to a remote host
By default, the delivered [installer/inventory](./installer/inventory) file will deploy AWX to the local host. It is possible; however, to deploy to a remote host. The [installer/install.yml](./installer/install.yml) playbook can be used to build images on the local host, and ship the built images to, and run deployment tasks on, a remote host. To do this, modify the [installer/inventory](./installer/inventory) file, by commenting out `localhost`, and adding the remote host.
For example, suppose you wish to build images locally on your CI/CD host, and deploy them to a remote host named *awx-server*. To do this, add *awx-server* to the [installer/inventory](./installer/inventory) file, and comment out or remove `localhost`, as demonstrated by the following:
```yaml
# localhost ansible_connection=local
awx-server
[all:vars]
...
```
In the above example, image build tasks will be delegated to `localhost`, which is typically where the clone of the AWX project exists. Built images will be archived, copied to remote host, and imported into the remote Docker image cache. Tasks to start the AWX containers will then execute on the remote host.
If you choose to use the official images then the remote host will be the one to pull those images.
**Note**
> You may also want to set additional variables to control how Ansible connects to the host. For more information about this, view [Behavioral Inventory Parameters](http://docs.ansible.com/ansible/latest/intro_inventory.html#id12).
> As mentioned above, in [Prerequisites](#prerequisites-1), the prerequisites are required on the remote host.
> When deploying to a remote host, the playook does not execute tasks with the `become` option. For this reason, make sure the user that connects to the remote host has privileges to run the `docker` command. This typically means that non-privileged users need to be part of the `docker` group.
#### Inventory variables
Before starting the build process, review the [inventory](./installer/inventory) file, and uncomment and provide values for the following variables found in the `[all:vars]` section:
*postgres_data_dir*
> If you're using the default PostgreSQL container (see [PostgreSQL](#postgresql-1) below), provide a path that can be mounted to the container, and where the database can be persisted.
*host_port*
> Provide a port number that can be mapped from the Docker daemon host to the web server running inside the AWX container. Defaults to *80*.
#### Docker registry
If you wish to tag and push built images to a Docker registry, set the following variables in the inventory file:
*docker_registry*
> IP address and port, or URL, for accessing a registry.
*docker_registry_repository*
> Namespace to use when pushing and pulling images to and from the registry. Defaults to *awx*.
*docker_registry_username*
> Username of the user that will push images to the registry. Defaults to *developer*.
*docker_remove_local_images*
> Due to the way that the docker_image module behaves, images will not be pushed to a remote repository if they are present locally. Set this to delete local versions of the images that will be pushed to the remote. This will fail if containers are currently running from those images.
**Note**
> These settings are ignored if using official images
#### Proxy settings
*http_proxy*
> IP address and port, or URL, for using an http_proxy.
*https_proxy*
> IP address and port, or URL, for using an https_proxy.
*no_proxy*
> Exclude IP address or URL from the proxy.
#### PostgreSQL
AWX requires access to a PostgreSQL database, and by default, one will be created and deployed in a container, and data will be persisted to a host volume. In this scenario, you must set the value of `postgres_data_dir` to a path that can be mounted to the container. When the container is stopped, the database files will still exist in the specified path.
If you wish to use an external database, in the inventory file, set the value of `pg_hostname`, and update `pg_username`, `pg_password`, `pg_database`, and `pg_port` with the connection information.
### Start the build
If you are not pushing images to a Docker registry, start the build by running the following:
```bash
# Set the working directory to installer
$ cd installer
# Run the Ansible playbook
$ ansible-playbook -i inventory install.yml
```
If you're pushing built images to a repository, then use the `-e` option to pass the registry password as follows, replacing *password* with the password of the username assigned to `docker_registry_username` (note that you will also need to remove `dockerhub_base` and `dockerhub_version` from the inventory file):
```bash
# Set the working directory to installer
$ cd installer
# Run the Ansible playbook
$ ansible-playbook -i inventory -e docker_registry_password=password install.yml
```
### Post build
After the playbook run completes, Docker will report up to 5 running containers. If you chose to use an existing PostgresSQL database, then it will report 4. You can view the running containers using the `docker ps` command, as follows:
```bash
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e240ed8209cd awx_task:1.0.0.8 "/tini -- /bin/sh ..." 2 minutes ago Up About a minute 8052/tcp awx_task
1cfd02601690 awx_web:1.0.0.8 "/tini -- /bin/sh ..." 2 minutes ago Up About a minute 0.0.0.0:80->8052/tcp awx_web
55a552142bcd memcached:alpine "docker-entrypoint..." 2 minutes ago Up 2 minutes 11211/tcp memcached
84011c072aad rabbitmq:3 "docker-entrypoint..." 2 minutes ago Up 2 minutes 4369/tcp, 5671-5672/tcp, 25672/tcp rabbitmq
97e196120ab3 postgres:9.6 "docker-entrypoint..." 2 minutes ago Up 2 minutes 5432/tcp postgres
```
Immediately after the containers start, the *awx_task* container will perform required setup tasks, including database migrations. These tasks need to complete before the web interface can be accessed. To monitor the progress, you can follow the container's STDOUT by running the following:
```bash
# Tail the the awx_task log
$ docker logs -f awx_task
```
You will see output similar to the following:
```bash
Using /etc/ansible/ansible.cfg as config file
127.0.0.1 | SUCCESS => {
"changed": false,
"db": "awx"
}
Operations to perform:
Synchronize unmigrated apps: solo, api, staticfiles, messages, channels, django_extensions, ui, rest_framework, polymorphic
Apply all migrations: sso, taggit, sessions, djcelery, sites, kombu_transport_django, social_auth, contenttypes, auth, conf, main
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Installing custom SQL...
Running migrations:
Rendering model states... DONE
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying taggit.0001_initial... OK
Applying taggit.0002_auto_20150616_2121... OK
Applying main.0001_initial... OK
...
```
Once migrations complete, you will see the following log output, indicating that migrations have completed:
```bash
Python 2.7.5 (default, Nov 6 2016, 00:28:07)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> <User: admin>
>>> Default organization added.
Demo Credential, Inventory, and Job Template added.
Successfully registered instance awx
(changed: True)
Creating instance group tower
Added instance awx to tower
(changed: True)
...
```
### Accessing AWX
The AWX web server is accessible on the deployment host, using the *host_port* value set in the *inventory* file. The default URL is [http://localhost](http://localhost).
You will prompted with a login dialog. The default administrator username is `admin`, and the password is `password`.

87
ISSUES.md Normal file
View File

@@ -0,0 +1,87 @@
# Issues
## Reporting
Use the GitHub [issue tracker](https://github.com/ansible/awx/issues) for filing bugs. In order to save time, and help us respond to issues quickly, make sure to fill out as much of the issue template
as possible. Version information, and an accurate reproducing scenario are critical to helping us identify the problem.
Please don't use the issue tracker as a way to ask how to do something. Instead, use the [mailing list](https://groups.google.com/forum/#!forum/awx-project) , and the `#ansible-awx` channel on irc.freenode.net to get help.
Before opening a new issue, please use the issue search feature to see if what you're experiencing has already been reported. If you have any extra detail to provide, please comment. Otherwise, rather than posting a "me too" comment, please consider giving it a ["thumbs up"](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comment) to give us an indication of the severity of the problem.
### UI Issues
When reporting issues for the UI, we also appreciate having screen shots and any error messages from the web browser's console. It's not unusual for browser extensions
and plugins to cause problems. Reporting those will also help speed up analyzing and resolving UI bugs.
### API and backend issues
For the API and backend services, please capture all of the logs that you can from the time the problem occurred.
## How issues are resolved
We triage our issues into high, medium, and low, and tag them with the relevant component (e.g. api, ui, installer, etc.). We typically focus on higher priority issues first. There aren't hard and fast rules for determining the severity of an issue, but generally high priority issues have an increased likelihood of breaking existing functionality, and negatively impacting a large number of users.
If your issue isn't considered high priority, then please be patient as it may take some time to get to it.
### Issue states
`state:needs_triage` This issue has not been looked at by a person yet and still needs to be triaged. This is the initial state for all new issues/pull requests.
`state:needs_info` The issue needs more information. This could be more debug output, more specifics out the system such as version information. Any detail that is currently preventing this issue from moving forward. This should be considered a blocked state.
`state:needs_review` The the issue/pull request needs to be reviewed by other maintainers and contributors. This is usually used when there is a question out to another maintainer or when a person is less familar with an area of the code base the issue is for.
`state:needs_revision` More commonly used on pull requests, this state represents that there are changes that are being waited on.
`state:in_progress` The issue is actively being worked on and you should be in contact with who ever is assigned if you are also working on or plan to work on a similar issue.
`state:in_testing` The issue or pull request is currently being tested.
### AWX Issue Bot (awxbot)
We use an issue bot to help us label and organize incoming issues, this bot, awxbot, is a version of [ansible/ansibullbot](https://github.com/ansible/ansibullbot).
#### Overview
AWXbot performs many functions:
* Respond quickly to issues and pull requests.
* Identify the maintainers responsible for reviewing pull requests.
* Identify issues and pull request types and components (e.g. type:bug, component: api)
#### For issue submitters
The bot requires a minimal subset of information from the issue template:
* issue type
* component
* summary
If any of those items are missing your issue will still get the `needs_triage` label, but may end up being responded to slower than issues that have the complete set of information.
So please use the template whenever possible.
Currently you can expect the bot to add common labels such as `state:needs_triage`, `type:bug`, `type:enhancement`, `component:ui`, etc...
These labels are determined by the template data. Please use the template and fill it out as accurately as possible.
The `state:needs_triage` label will remain on your issue until a person has looked at it.
#### For pull request submitters
The bot requires a minimal subset of information from the pull request template:
* issue type
* component
* summary
If any of those items are missing your pull request will still get the `needs_triage` label, but may end up being responded to slower than other pull requests that have a complete set of information.
Currently you can expect awxbot to add common labels such as `state:needs_triage`, `type:bug`, `component:docs`, etc...
These labels are determined by the template data. Please use the template and fill it out as accurately as possible.
The `state:needs_triage` label will will remain on your pull request until a person has looked at it.
You can also expect the bot to CC maintainers of specific areas of the code, this will notify them that there is a pull request by placing a comment on the pull request.
The comment will look something like `CC @matburt @wwitzel3 ...`.

168
LICENSE.md Normal file
View File

@@ -0,0 +1,168 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

View File

@@ -1,4 +1,6 @@
recursive-include awx *.py
recursive-include awx *.po
recursive-include awx *.mo
recursive-include awx/static *
recursive-include awx/templates *.html
recursive-include awx/api/templates *.md *.html

View File

@@ -77,13 +77,15 @@ I18N_FLAG_FILE = .i18n_built
receiver test test_unit test_ansible 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 ui-test-saucelabs VERSION
ui-test ui-deps ui-test-ci VERSION
# remove ui build artifacts
clean-ui:
rm -rf awx/ui/static/
rm -rf awx/ui/node_modules/
rm -rf awx/ui/coverage/
rm -rf awx/ui/test/unit/reports/
rm -rf awx/ui/test/spec/reports/
rm -rf awx/ui/test/e2e/reports/
rm -rf awx/ui/client/languages/
rm -f $(UI_DEPS_FLAG_FILE)
rm -f $(UI_RELEASE_FLAG_FILE)
@@ -201,8 +203,11 @@ develop:
fi
version_file:
mkdir -p /var/lib/awx/
python -c "import awx as awx; print awx.__version__" > /var/lib/awx/.awx_version
mkdir -p /var/lib/awx/; \
if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
python -c "import awx as awx; print awx.__version__" > /var/lib/awx/.awx_version; \
# Do any one-time init tasks.
comma := ,
@@ -282,7 +287,7 @@ flower:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(PYTHON) manage.py celery flower --address=0.0.0.0 --port=5555 --broker=amqp://guest:guest@$(RABBITMQ_HOST):5672//
celery flower --address=0.0.0.0 --port=5555 --broker=amqp://guest:guest@$(RABBITMQ_HOST):5672//
collectstatic:
@if [ "$(VENV_BASE)" ]; then \
@@ -320,8 +325,7 @@ celeryd:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(PYTHON) manage.py celeryd -l DEBUG -B -Ofair --autoreload --autoscale=100,4 --schedule=$(CELERY_SCHEDULE_FILE) -Q tower_scheduler,tower_broadcast_all,$(COMPOSE_HOST),$(AWX_GROUP_QUEUES) -n celery@$(COMPOSE_HOST)
#$(PYTHON) manage.py celery multi show projects jobs default -l DEBUG -Q:projects projects -Q:jobs jobs -Q:default default -c:projects 1 -c:jobs 3 -c:default 3 -Ofair -B --schedule=$(CELERY_SCHEDULE_FILE)
celery worker -A awx -l DEBUG -B -Ofair --autoscale=100,4 --schedule=$(CELERY_SCHEDULE_FILE) -Q tower_scheduler,tower_broadcast_all,$(COMPOSE_HOST),$(AWX_GROUP_QUEUES) -n celery@$(COMPOSE_HOST)
# Run to start the zeromq callback receiver
receiver:
@@ -330,18 +334,18 @@ receiver:
fi; \
$(PYTHON) manage.py run_callback_receiver
socketservice:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(PYTHON) manage.py run_socketio_service
nginx:
nginx -g "daemon off;"
rdb:
$(PYTHON) tools/rdb.py
jupyter:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(MANAGEMENT_COMMAND) shell_plus --notebook
reports:
mkdir -p $@
@@ -362,7 +366,7 @@ pylint: reports
check: flake8 pep8 # pyflakes pylint
TEST_DIRS ?= awx/main/tests awx/conf/tests awx/sso/tests
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
# Run all API unit tests.
test: test_ansible
@if [ "$(VENV_BASE)" ]; then \
@@ -495,15 +499,14 @@ ui: clean-ui ui-devel
ui-test-ci: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run test:ci
$(NPM_BIN) --prefix awx/ui run unit
testjs_ci:
echo "Update UI unittests later" #ui-test-ci
jshint: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) run --prefix awx/ui jshint
ui-test-saucelabs: $(UI_DEPS_FLAG_FILE)
$(NPM_BIN) --prefix awx/ui run test:saucelabs
$(NPM_BIN) run --prefix awx/ui lint
# END UI TASKS
# --------------------------------------
@@ -548,6 +551,7 @@ 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
echo "__version__ = '`python setup.py --version`'" | docker exec -i tools_isolated_1 /bin/bash -c "cat > /venv/awx/lib/python2.7/site-packages/awx.py"
if [ "`docker exec -i -t tools_isolated_1 cat /root/.ssh/authorized_keys`" == "`docker exec -t tools_awx_1 cat /root/.ssh/id_rsa.pub`" ]; then \
echo "SSH keys already copied to isolated instance"; \
else \
@@ -606,11 +610,5 @@ psql-container:
docker run -it --net tools_default --rm postgres:9.4.1 sh -c 'exec psql -h "postgres" -p "5432" -U postgres'
VERSION:
echo $(VERSION_TARGET) > $@
production-openshift-image: sdist
cat installer/openshift/Dockerfile | sed "s/{{ version }}/$(VERSION_TARGET)/g" | sed "s/{{ tar }}/$(SDIST_TAR_FILE)/g" > ./Dockerfile.production
cp installer/openshift/Dockerfile.celery ./Dockerfile.celery.production
docker build -t awx_web -f ./Dockerfile.production .
docker build -t awx_task -f ./Dockerfile.celery.production .
@echo $(VERSION_TARGET) > $@
@echo "awx: $(VERSION_TARGET)"

View File

@@ -1,16 +1,46 @@
[![Devel Requirements Status](https://requires.io/github/ansible/awx/requirements.svg?branch=devel)](https://requires.io/github/ansible/awx/requirements/?branch=devel)
[![Run Status](https://api.shippable.com/projects/591c82a22f895107009e8b35/badge?branch=devel)](https://app.shippable.com/github/ansible/awx)
AWX
=============
===
AWX provides a web-based user interface, REST API and task engine built on top of
Ansible.
AWX provides a web-based user interface, REST API, and task engine built on top of [Ansible](https://github.com/ansible/ansible). It is the upstream project for [Tower](https://www.ansible.com/tower), a commercial derivative of AWX.
Resources
---------
To install AWX, please view the [Install guide](./INSTALL.md).
Refer to `CONTRIBUTING.md` to get started developing, testing and building AWX.
To learn more about using AWX, and Tower, view the [Tower docs site](http://docs.ansible.com/ansible-tower/index.html).
Refer to `INSTALL.md` to get started deploying AWX.
The AWX Project Frequently Asked Questions can be found [here](https://www.ansible.com/awx-project-faq).
Contributing
------------
- Refer to the [Contributing guide](./CONTRIBUTING.md) to get started developing, testing, and building AWX.
- All code submissions are done through pull requests against the `devel` branch.
- All contributors must use git commit --signoff for any commit to be merged, and agree that usage of --signoff constitutes agreement with the terms of [DCO 1.1](./DCO_1_1.md)
- Take care to make sure no merge commits are in the submission, and use `git rebase` vs `git merge` for this reason.
- If submitting a large code change, it's a good idea to join the `#ansible-awx` channel on irc.freenode.net, and talk about what you would like to do or add first. This not only helps everyone know what's going on, it also helps save time and effort, if the community decides some changes are needed.
Reporting Issues
----------------
If you're experiencing a problem, we encourage you to open an issue, and share your feedback. But before opening a new issue, we ask that you please take a look at our [Issues guide](./ISSUES.md).
Code of Conduct
---------------
We ask all of our community members and contributors to adhere to the [Ansible code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html). If you have questions, or need assistance, please reach out to our community team at [codeofconduct@ansible.com](mailto:codeofconduct@ansible.com)
Get Involved
------------
We welcome your feedback and ideas. Here's how to reach us:
- Join the `#ansible-awx` channel on irc.freenode.net
- Join the [mailing list](https://groups.google.com/forum/#!forum/awx-project)
- [Open an Issue](https://github.com/ansible/awx/issues)
License
-------
[Apache v2](./LICENSE.md)
Refer to `LOCALIZATION.md` for translation and localization help.

View File

@@ -1,15 +1,17 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
from __future__ import absolute_import, unicode_literals
import os
import sys
import warnings
from pkg_resources import get_distribution
from .celery import app as celery_app
__version__ = get_distribution('awx').version
__all__ = ['__version__']
__all__ = ['__version__', 'celery_app']
# Check for the presence/absence of "devonly" module to determine if running
# from a source code checkout or release packaage.

View File

@@ -17,7 +17,7 @@ from rest_framework import exceptions
from rest_framework import HTTP_HEADER_ENCODING
# AWX
from awx.main.models import UnifiedJob, AuthToken
from awx.main.models import AuthToken
logger = logging.getLogger('awx.api.authentication')
@@ -137,29 +137,3 @@ class LoggedBasicAuthentication(authentication.BasicAuthentication):
if not settings.AUTH_BASIC_ENABLED:
return
return super(LoggedBasicAuthentication, self).authenticate_header(request)
class TaskAuthentication(authentication.BaseAuthentication):
'''
Custom authentication used for views accessed by the inventory and callback
scripts when running a task.
'''
model = None
def authenticate(self, request):
auth = authentication.get_authorization_header(request).split()
if len(auth) != 2 or auth[0].lower() != 'token' or '-' not in auth[1]:
return None
pk, key = auth[1].split('-', 1)
try:
unified_job = UnifiedJob.objects.get(pk=pk, status='running')
except UnifiedJob.DoesNotExist:
return None
token = unified_job.task_auth_token
if auth[1] != token:
raise exceptions.AuthenticationFailed(_('Invalid task token'))
return (None, token)
def authenticate_header(self, request):
return 'Token'

View File

@@ -22,6 +22,7 @@ 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
from awx.main.models.rbac import RoleAncestorEntry
@@ -70,7 +71,7 @@ class TypeFilterBackend(BaseFilterBackend):
types_map[ct_type] = ct.pk
model = queryset.model
model_type = get_type_for_model(model)
if 'polymorphic_ctype' in model._meta.get_all_field_names():
if 'polymorphic_ctype' in get_all_field_names(model):
types_pks = set([v for k,v in types_map.items() if k in types])
queryset = queryset.filter(polymorphic_ctype_id__in=types_pks)
elif model_type in types:
@@ -119,7 +120,7 @@ class FieldLookupBackend(BaseFilterBackend):
'last_updated': 'last_job_run',
}.get(name, name)
if name == 'type' and 'polymorphic_ctype' in model._meta.get_all_field_names():
if name == 'type' and 'polymorphic_ctype' in get_all_field_names(model):
name = 'polymorphic_ctype'
new_parts.append('polymorphic_ctype__model')
else:
@@ -136,7 +137,7 @@ class FieldLookupBackend(BaseFilterBackend):
new_parts.pop()
new_parts.append(name_alt)
else:
field = model._meta.get_field_by_name(name)[0]
field = model._meta.get_field(name)
if isinstance(field, ForeignObjectRel) and getattr(field.field, '__prevent_search__', False):
raise PermissionDenied(_('Filtering on %s is not allowed.' % name))
elif getattr(field, '__prevent_search__', False):
@@ -268,8 +269,10 @@ class FieldLookupBackend(BaseFilterBackend):
# 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 ('cloud_credential', 'network_credential'):
key = 'extra_credentials'
if queryset.model._meta.object_name in ('JobTemplate', 'Job') and key in (
'credential', 'vault_credential', 'cloud_credential', 'network_credential'
):
key = 'credentials'
# Make legacy v1 Credential fields work for backwards compatability
# TODO: remove after API v1 deprecation period
@@ -375,7 +378,7 @@ class OrderByBackend(BaseFilterBackend):
# given the limited number of views with multiple types,
# sorting on polymorphic_ctype.model is effectively the same.
new_order_by = []
if 'polymorphic_ctype' in queryset.model._meta.get_all_field_names():
if 'polymorphic_ctype' in get_all_field_names(queryset.model):
for field in order_by:
if field == 'type':
new_order_by.append('polymorphic_ctype__model')

View File

@@ -31,6 +31,7 @@ from rest_framework import views
from awx.api.filters import FieldLookupBackend
from awx.main.models import * # noqa
from awx.main.utils import * # noqa
from awx.main.utils.db import get_all_field_names
from awx.api.serializers import ResourceAccessListElementSerializer
from awx.api.versioning import URLPathVersioning, get_request_version
from awx.api.metadata import SublistAttachDetatchMetadata
@@ -188,6 +189,7 @@ class APIView(views.APIView):
'new_in_300': getattr(self, 'new_in_300', False),
'new_in_310': getattr(self, 'new_in_310', False),
'new_in_320': getattr(self, 'new_in_320', False),
'new_in_330': getattr(self, 'new_in_330', False),
'new_in_api_v2': getattr(self, 'new_in_api_v2', False),
'deprecated': getattr(self, 'deprecated', False),
}
@@ -321,8 +323,7 @@ class ListAPIView(generics.ListAPIView, GenericAPIView):
return page
def get_description_context(self):
opts = self.model._meta
if 'username' in opts.get_all_field_names():
if 'username' in get_all_field_names(self.model):
order_field = 'username'
else:
order_field = 'name'

View File

@@ -89,7 +89,7 @@ class Metadata(metadata.SimpleMetadata):
# Special handling of inventory source_region choices that vary based on
# selected inventory source.
if field.field_name == 'source_regions':
for cp in ('azure', 'ec2', 'gce'):
for cp in ('azure_rm', 'ec2', 'gce'):
get_regions = getattr(InventorySource, 'get_%s_region_choices' % cp)
field_info['%s_region_choices' % cp] = get_regions()

View File

@@ -34,7 +34,7 @@ class ModelAccessPermission(permissions.BasePermission):
def check_get_permissions(self, request, view, obj=None):
if hasattr(view, 'parent_model'):
parent_obj = get_object_or_400(view.parent_model, pk=view.kwargs['pk'])
parent_obj = view.get_parent_object()
if not check_user_access(request.user, view.parent_model, 'read',
parent_obj):
return False
@@ -44,22 +44,26 @@ class ModelAccessPermission(permissions.BasePermission):
def check_post_permissions(self, request, view, obj=None):
if hasattr(view, 'parent_model'):
parent_obj = get_object_or_400(view.parent_model, pk=view.kwargs['pk'])
parent_obj = view.get_parent_object()
if not check_user_access(request.user, view.parent_model, 'read',
parent_obj):
return False
if hasattr(view, 'parent_key'):
if not check_user_access(request.user, view.model, 'add', {view.parent_key: parent_obj.pk}):
if not check_user_access(request.user, view.model, 'add', {view.parent_key: parent_obj}):
return False
return True
elif getattr(view, 'is_job_start', False):
elif hasattr(view, 'obj_permission_type'):
# Generic object-centric view permission check without object not needed
if not obj:
return True
return check_user_access(request.user, view.model, 'start', obj)
elif getattr(view, 'is_job_cancel', False):
if not obj:
return True
return check_user_access(request.user, view.model, 'cancel', obj)
# Permission check that happens when get_object() is called
extra_kwargs = {}
if view.obj_permission_type == 'admin':
extra_kwargs['data'] = {}
return check_user_access(
request.user, view.model, view.obj_permission_type, obj,
**extra_kwargs
)
else:
if obj:
return True

View File

@@ -48,7 +48,8 @@ class BrowsableAPIRenderer(renderers.BrowsableAPIRenderer):
obj = getattr(view, 'object', None)
if obj is None and hasattr(view, 'get_object') and hasattr(view, 'retrieve'):
try:
obj = view.get_object()
view.object = view.get_object()
obj = view.object
except Exception:
obj = None
with override_method(view, request, method) as request:

File diff suppressed because it is too large Load Diff

View File

@@ -10,4 +10,5 @@
{% if new_in_300 %}> _Added in Ansible Tower 3.0.0_{% endif %}
{% if new_in_310 %}> _New in Ansible Tower 3.1.0_{% endif %}
{% if new_in_320 %}> _New in Ansible Tower 3.2.0_{% endif %}
{% if new_in_330 %}> _New in Ansible Tower 3.3.0_{% endif %}
{% endif %}

View File

@@ -0,0 +1,12 @@
Create a schedule based on a job:
Make a POST request to this endpoint to create a schedule that launches
the job template that launched this job, and uses the same
parameters that the job was launched with. These parameters include all
"prompted" resources such as `extra_vars`, `inventory`, `limit`, etc.
Jobs that were launched with user-provided passwords cannot have a schedule
created from them.
Make a GET request for information about what those prompts are and
whether or not a schedule can be created.

View File

@@ -26,9 +26,6 @@ The response will include the following fields:
job_template (array, read-only)
* `survey_enabled`: Flag indicating whether the job_template has an enabled
survey (boolean, read-only)
* `credential_needed_to_start`: Flag indicating the presence of a credential
associated with the job template. If not then one should be supplied when
launching the job (boolean, read-only)
* `inventory_needed_to_start`: Flag indicating the presence of an inventory
associated with the job template. If not then one should be supplied when
launching the job (boolean, read-only)
@@ -36,9 +33,8 @@ The response will include the following fields:
Make a POST request to this resource to launch the job_template. If any
passwords, inventory, or extra variables (extra_vars) are required, they must
be passed via POST data, with extra_vars given as a YAML or JSON string and
escaped parentheses. If `credential_needed_to_start` is `True` then the
`credential` field is required and if the `inventory_needed_to_start` is
`True` then the `inventory` is required as well.
escaped parentheses. If the `inventory_needed_to_start` is `True` then the
`inventory` is required.
If successful, the response status code will be 201. If any required passwords
are not provided, a 400 status code will be returned. If the job cannot be

View File

@@ -1,19 +0,0 @@
ANSIBLE TOWER BY RED HAT END USER LICENSE AGREEMENT
This end user license agreement (“EULA”) governs the use of the Ansible Tower software and any related updates, upgrades, versions, appearance, structure and organization (the “Ansible Tower Software”), regardless of the delivery mechanism.
1. License Grant. Subject to the terms of this EULA, Red Hat, Inc. and its affiliates (“Red Hat”) grant to you (“You”) a non-transferable, non-exclusive, worldwide, non-sublicensable, limited, revocable license to use the Ansible Tower Software for the term of the associated Red Hat Software Subscription(s) and in a quantity equal to the number of Red Hat Software Subscriptions purchased from Red Hat for the Ansible Tower Software (“License”), each as set forth on the applicable Red Hat ordering document. You acquire only the right to use the Ansible Tower Software and do not acquire any rights of ownership. Red Hat reserves all rights to the Ansible Tower Software not expressly granted to You. This License grant pertains solely to Your use of the Ansible Tower Software and is not intended to limit Your rights under, or grant You rights that supersede, the license terms of any software packages which may be made available with the Ansible Tower Software that are subject to an open source software license.
2. Intellectual Property Rights. Title to the Ansible Tower Software and each component, copy and modification, including all derivative works whether made by Red Hat, You or on Red Hat's behalf, including those made at Your suggestion and all associated intellectual property rights, are and shall remain the sole and exclusive property of Red Hat and/or it licensors. The License does not authorize You (nor may You allow any third party, specifically non-employees of Yours) to: (a) copy, distribute, reproduce, use or allow third party access to the Ansible Tower Software except as expressly authorized hereunder; (b) decompile, disassemble, reverse engineer, translate, modify, convert or apply any procedure or process to the Ansible Tower Software in order to ascertain, derive, and/or appropriate for any reason or purpose, including the Ansible Tower Software source code or source listings or any trade secret information or process contained in the Ansible Tower Software (except as permitted under applicable law); (c) execute or incorporate other software (except for approved software as appears in the Ansible Tower Software documentation or specifically approved by Red Hat in writing) into Ansible Tower Software, or create a derivative work of any part of the Ansible Tower Software; (d) remove any trademarks, trade names or titles, copyrights legends or any other proprietary marking on the Ansible Tower Software; (e) disclose the results of any benchmarking of the Ansible Tower Software (whether or not obtained with Red Hats assistance) to any third party; (f) attempt to circumvent any user limits or other license, timing or use restrictions that are built into, defined or agreed upon, regarding the Ansible Tower Software. You are hereby notified that the Ansible Tower Software may contain time-out devices, counter devices, and/or other devices intended to ensure the limits of the License will not be exceeded (“Limiting Devices”). If the Ansible Tower Software contains Limiting Devices, Red Hat will provide You materials necessary to use the Ansible Tower Software to the extent permitted. You may not tamper with or otherwise take any action to defeat or circumvent a Limiting Device or other control measure, including but not limited to, resetting the unit amount or using false host identification number for the purpose of extending any term of the License.
3. Evaluation Licenses. Unless You have purchased Ansible Tower Software Subscriptions from Red Hat or an authorized reseller under the terms of a commercial agreement with Red Hat, all use of the Ansible Tower Software shall be limited to testing purposes and not for production use (“Evaluation”). Unless otherwise agreed by Red Hat, Evaluation of the Ansible Tower Software shall be limited to an evaluation environment and the Ansible Tower Software shall not be used to manage any systems or virtual machines on networks being used in the operation of Your business or any other non-evaluation purpose. Unless otherwise agreed by Red Hat, You shall limit all Evaluation use to a single 30 day evaluation period and shall not download or otherwise obtain additional copies of the Ansible Tower Software or license keys for Evaluation.
4. Limited Warranty. Except as specifically stated in this Section 4, to the maximum extent permitted under applicable law, the Ansible Tower Software and the components are provided and licensed “as is” without warranty of any kind, expressed or implied, including the implied warranties of merchantability, non-infringement or fitness for a particular purpose. Red Hat warrants solely to You that the media on which the Ansible Tower Software may be furnished will be free from defects in materials and manufacture under normal use for a period of thirty (30) days from the date of delivery to You. Red Hat does not warrant that the functions contained in the Ansible Tower Software will meet Your requirements or that the operation of the Ansible Tower Software will be entirely error free, appear precisely as described in the accompanying documentation, or comply with regulatory requirements.
5. Limitation of Remedies and Liability. To the maximum extent permitted by applicable law, Your exclusive remedy under this EULA is to return any defective media within thirty (30) days of delivery along with a copy of Your payment receipt and Red Hat, at its option, will replace it or refund the money paid by You for the media. To the maximum extent permitted under applicable law, neither Red Hat nor any Red Hat authorized distributor will be liable to You for any incidental or consequential damages, including lost profits or lost savings arising out of the use or inability to use the Ansible Tower Software or any component, even if Red Hat or the authorized distributor has been advised of the possibility of such damages. In no event shall Red Hat's liability or an authorized distributors liability exceed the amount that You paid to Red Hat for the Ansible Tower Software during the twelve months preceding the first event giving rise to liability.
6. Export Control. In accordance with the laws of the United States and other countries, You represent and warrant that You: (a) understand that the Ansible Tower Software and its components may be subject to export controls under the U.S. Commerce Departments Export Administration Regulations (“EAR”); (b) are not located in any country listed in Country Group E:1 in Supplement No. 1 to part 740 of the EAR; (c) will not export, re-export, or transfer the Ansible Tower Software to any prohibited destination or to any end user who has been prohibited from participating in US export transactions by any federal agency of the US government; (d) will not use or transfer the Ansible Tower Software for use in connection with the design, development or production of nuclear, chemical or biological weapons, or rocket systems, space launch vehicles, or sounding rockets or unmanned air vehicle systems; (e) understand and agree that if you are in the United States and you export or transfer the Ansible Tower Software to eligible end users, you will, to the extent required by EAR Section 740.17 obtain a license for such export or transfer and will submit semi-annual reports to the Commerce Departments Bureau of Industry and Security, which include the name and address (including country) of each transferee; and (f) understand that countries including the United States may restrict the import, use, or export of encryption products (which may include the Ansible Tower Software) and agree that you shall be solely responsible for compliance with any such import, use, or export restrictions.
7. General. If any provision of this EULA is held to be unenforceable, that shall not affect the enforceability of the remaining provisions. This agreement shall be governed by the laws of the State of New York and of the United States, without regard to any conflict of laws provisions. The rights and obligations of the parties to this EULA shall not be governed by the United Nations Convention on the International Sale of Goods.
Copyright © 2015 Red Hat, Inc. All rights reserved. "Red Hat" and “Ansible Tower” are registered trademarks of Red Hat, Inc. All other trademarks are the property of their respective owners.

View File

@@ -1,420 +0,0 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
# noqa
from django.conf.urls import include, patterns, url as original_url
def url(regex, view, kwargs=None, name=None, prefix=''):
# Set default name from view name (if a string).
if isinstance(view, basestring) and name is None:
name = view
return original_url(regex, view, kwargs, name, prefix)
organization_urls = patterns('awx.api.views',
url(r'^$', 'organization_list'),
url(r'^(?P<pk>[0-9]+)/$', 'organization_detail'),
url(r'^(?P<pk>[0-9]+)/users/$', 'organization_users_list'),
url(r'^(?P<pk>[0-9]+)/admins/$', 'organization_admins_list'),
url(r'^(?P<pk>[0-9]+)/inventories/$', 'organization_inventories_list'),
url(r'^(?P<pk>[0-9]+)/projects/$', 'organization_projects_list'),
url(r'^(?P<pk>[0-9]+)/workflow_job_templates/$', 'organization_workflow_job_templates_list'),
url(r'^(?P<pk>[0-9]+)/teams/$', 'organization_teams_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', 'organization_credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'organization_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates/$', 'organization_notification_templates_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', 'organization_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', 'organization_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', 'organization_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', 'organization_instance_groups_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'organization_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'organization_access_list'),
)
user_urls = patterns('awx.api.views',
url(r'^$', 'user_list'),
url(r'^(?P<pk>[0-9]+)/$', 'user_detail'),
url(r'^(?P<pk>[0-9]+)/teams/$', 'user_teams_list'),
url(r'^(?P<pk>[0-9]+)/organizations/$', 'user_organizations_list'),
url(r'^(?P<pk>[0-9]+)/admin_of_organizations/$', 'user_admin_of_organizations_list'),
url(r'^(?P<pk>[0-9]+)/projects/$', 'user_projects_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', 'user_credentials_list'),
url(r'^(?P<pk>[0-9]+)/roles/$', 'user_roles_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'user_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'user_access_list'),
)
project_urls = patterns('awx.api.views',
url(r'^$', 'project_list'),
url(r'^(?P<pk>[0-9]+)/$', 'project_detail'),
url(r'^(?P<pk>[0-9]+)/playbooks/$', 'project_playbooks'),
url(r'^(?P<pk>[0-9]+)/inventories/$', 'project_inventories'),
url(r'^(?P<pk>[0-9]+)/scm_inventory_sources/$', 'project_scm_inventory_sources'),
url(r'^(?P<pk>[0-9]+)/teams/$', 'project_teams_list'),
url(r'^(?P<pk>[0-9]+)/update/$', 'project_update_view'),
url(r'^(?P<pk>[0-9]+)/project_updates/$', 'project_updates_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'project_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/schedules/$', 'project_schedules_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', 'project_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', 'project_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', 'project_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'project_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'project_access_list'),
)
project_update_urls = patterns('awx.api.views',
url(r'^$', 'project_update_list'),
url(r'^(?P<pk>[0-9]+)/$', 'project_update_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', 'project_update_cancel'),
url(r'^(?P<pk>[0-9]+)/stdout/$', 'project_update_stdout'),
url(r'^(?P<pk>[0-9]+)/scm_inventory_updates/$', 'project_update_scm_inventory_updates'),
url(r'^(?P<pk>[0-9]+)/notifications/$', 'project_update_notifications_list'),
)
team_urls = patterns('awx.api.views',
url(r'^$', 'team_list'),
url(r'^(?P<pk>[0-9]+)/$', 'team_detail'),
url(r'^(?P<pk>[0-9]+)/projects/$', 'team_projects_list'),
url(r'^(?P<pk>[0-9]+)/users/$', 'team_users_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', 'team_credentials_list'),
url(r'^(?P<pk>[0-9]+)/roles/$', 'team_roles_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'team_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'team_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'team_access_list'),
)
inventory_urls = patterns('awx.api.views',
url(r'^$', 'inventory_list'),
url(r'^(?P<pk>[0-9]+)/$', 'inventory_detail'),
url(r'^(?P<pk>[0-9]+)/hosts/$', 'inventory_hosts_list'),
url(r'^(?P<pk>[0-9]+)/groups/$', 'inventory_groups_list'),
url(r'^(?P<pk>[0-9]+)/root_groups/$', 'inventory_root_groups_list'),
url(r'^(?P<pk>[0-9]+)/variable_data/$', 'inventory_variable_data'),
url(r'^(?P<pk>[0-9]+)/script/$', 'inventory_script_view'),
url(r'^(?P<pk>[0-9]+)/tree/$', 'inventory_tree_view'),
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'inventory_inventory_sources_list'),
url(r'^(?P<pk>[0-9]+)/update_inventory_sources/$', 'inventory_inventory_sources_update'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'inventory_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/job_templates/$', 'inventory_job_template_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'inventory_ad_hoc_commands_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'inventory_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'inventory_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', 'inventory_instance_groups_list'),
#url(r'^(?P<pk>[0-9]+)/single_fact/$', 'inventory_single_fact_view'),
)
host_urls = patterns('awx.api.views',
url(r'^$', 'host_list'),
url(r'^(?P<pk>[0-9]+)/$', 'host_detail'),
url(r'^(?P<pk>[0-9]+)/variable_data/$', 'host_variable_data'),
url(r'^(?P<pk>[0-9]+)/groups/$', 'host_groups_list'),
url(r'^(?P<pk>[0-9]+)/all_groups/$', 'host_all_groups_list'),
url(r'^(?P<pk>[0-9]+)/job_events/', 'host_job_events_list'),
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', 'host_job_host_summaries_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'host_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'host_inventory_sources_list'),
url(r'^(?P<pk>[0-9]+)/smart_inventories/$', 'host_smart_inventories_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'host_ad_hoc_commands_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_command_events/$', 'host_ad_hoc_command_events_list'),
#url(r'^(?P<pk>[0-9]+)/single_fact/$', 'host_single_fact_view'),
url(r'^(?P<pk>[0-9]+)/fact_versions/$', 'host_fact_versions_list'),
url(r'^(?P<pk>[0-9]+)/fact_view/$', 'host_fact_compare_view'),
url(r'^(?P<pk>[0-9]+)/insights/$', 'host_insights'),
)
group_urls = patterns('awx.api.views',
url(r'^$', 'group_list'),
url(r'^(?P<pk>[0-9]+)/$', 'group_detail'),
url(r'^(?P<pk>[0-9]+)/children/$', 'group_children_list'),
url(r'^(?P<pk>[0-9]+)/hosts/$', 'group_hosts_list'),
url(r'^(?P<pk>[0-9]+)/all_hosts/$', 'group_all_hosts_list'),
url(r'^(?P<pk>[0-9]+)/variable_data/$', 'group_variable_data'),
url(r'^(?P<pk>[0-9]+)/job_events/$', 'group_job_events_list'),
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', 'group_job_host_summaries_list'),
url(r'^(?P<pk>[0-9]+)/potential_children/$', 'group_potential_children_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'group_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', 'group_inventory_sources_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', 'group_ad_hoc_commands_list'),
#url(r'^(?P<pk>[0-9]+)/single_fact/$', 'group_single_fact_view'),
)
inventory_source_urls = patterns('awx.api.views',
url(r'^$', 'inventory_source_list'),
url(r'^(?P<pk>[0-9]+)/$', 'inventory_source_detail'),
url(r'^(?P<pk>[0-9]+)/update/$', 'inventory_source_update_view'),
url(r'^(?P<pk>[0-9]+)/inventory_updates/$', 'inventory_source_updates_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'inventory_source_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/schedules/$', 'inventory_source_schedules_list'),
url(r'^(?P<pk>[0-9]+)/groups/$', 'inventory_source_groups_list'),
url(r'^(?P<pk>[0-9]+)/hosts/$', 'inventory_source_hosts_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', 'inventory_source_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', 'inventory_source_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', 'inventory_source_notification_templates_success_list'),
)
inventory_update_urls = patterns('awx.api.views',
url(r'^$', 'inventory_update_list'),
url(r'^(?P<pk>[0-9]+)/$', 'inventory_update_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', 'inventory_update_cancel'),
url(r'^(?P<pk>[0-9]+)/stdout/$', 'inventory_update_stdout'),
url(r'^(?P<pk>[0-9]+)/notifications/$', 'inventory_update_notifications_list'),
)
inventory_script_urls = patterns('awx.api.views',
url(r'^$', 'inventory_script_list'),
url(r'^(?P<pk>[0-9]+)/$', 'inventory_script_detail'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'inventory_script_object_roles_list'),
)
credential_type_urls = patterns('awx.api.views',
url(r'^$', 'credential_type_list'),
url(r'^(?P<pk>[0-9]+)/$', 'credential_type_detail'),
url(r'^(?P<pk>[0-9]+)/credentials/$', 'credential_type_credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'credential_type_activity_stream_list'),
)
credential_urls = patterns('awx.api.views',
url(r'^$', 'credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'credential_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/$', 'credential_detail'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'credential_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'credential_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/owner_users/$', 'credential_owner_users_list'),
url(r'^(?P<pk>[0-9]+)/owner_teams/$', 'credential_owner_teams_list'),
# See also credentials resources on users/teams.
)
role_urls = patterns('awx.api.views',
url(r'^$', 'role_list'),
url(r'^(?P<pk>[0-9]+)/$', 'role_detail'),
url(r'^(?P<pk>[0-9]+)/users/$', 'role_users_list'),
url(r'^(?P<pk>[0-9]+)/teams/$', 'role_teams_list'),
url(r'^(?P<pk>[0-9]+)/parents/$', 'role_parents_list'),
url(r'^(?P<pk>[0-9]+)/children/$', 'role_children_list'),
)
job_template_urls = patterns('awx.api.views',
url(r'^$', 'job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', 'job_template_detail'),
url(r'^(?P<pk>[0-9]+)/launch/$', 'job_template_launch'),
url(r'^(?P<pk>[0-9]+)/jobs/$', 'job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/callback/$', 'job_template_callback'),
url(r'^(?P<pk>[0-9]+)/schedules/$', 'job_template_schedules_list'),
url(r'^(?P<pk>[0-9]+)/survey_spec/$', 'job_template_survey_spec'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'job_template_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', 'job_template_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', 'job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', 'job_template_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', 'job_template_instance_groups_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'job_template_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'job_template_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', 'job_template_label_list'),
)
job_urls = patterns('awx.api.views',
url(r'^$', 'job_list'),
url(r'^(?P<pk>[0-9]+)/$', 'job_detail'),
url(r'^(?P<pk>[0-9]+)/start/$', 'job_start'),
url(r'^(?P<pk>[0-9]+)/cancel/$', 'job_cancel'),
url(r'^(?P<pk>[0-9]+)/relaunch/$', 'job_relaunch'),
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', 'job_job_host_summaries_list'),
url(r'^(?P<pk>[0-9]+)/job_events/$', 'job_job_events_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'job_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/stdout/$', 'job_stdout'),
url(r'^(?P<pk>[0-9]+)/notifications/$', 'job_notifications_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', 'job_label_list'),
)
job_host_summary_urls = patterns('awx.api.views',
url(r'^(?P<pk>[0-9]+)/$', 'job_host_summary_detail'),
)
job_event_urls = patterns('awx.api.views',
url(r'^$', 'job_event_list'),
url(r'^(?P<pk>[0-9]+)/$', 'job_event_detail'),
url(r'^(?P<pk>[0-9]+)/children/$', 'job_event_children_list'),
url(r'^(?P<pk>[0-9]+)/hosts/$', 'job_event_hosts_list'),
)
ad_hoc_command_urls = patterns('awx.api.views',
url(r'^$', 'ad_hoc_command_list'),
url(r'^(?P<pk>[0-9]+)/$', 'ad_hoc_command_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', 'ad_hoc_command_cancel'),
url(r'^(?P<pk>[0-9]+)/relaunch/$', 'ad_hoc_command_relaunch'),
url(r'^(?P<pk>[0-9]+)/events/$', 'ad_hoc_command_ad_hoc_command_events_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'ad_hoc_command_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notifications/$', 'ad_hoc_command_notifications_list'),
url(r'^(?P<pk>[0-9]+)/stdout/$', 'ad_hoc_command_stdout'),
)
ad_hoc_command_event_urls = patterns('awx.api.views',
url(r'^$', 'ad_hoc_command_event_list'),
url(r'^(?P<pk>[0-9]+)/$', 'ad_hoc_command_event_detail'),
)
system_job_template_urls = patterns('awx.api.views',
url(r'^$', 'system_job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', 'system_job_template_detail'),
url(r'^(?P<pk>[0-9]+)/launch/$', 'system_job_template_launch'),
url(r'^(?P<pk>[0-9]+)/jobs/$', 'system_job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/schedules/$', 'system_job_template_schedules_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', 'system_job_template_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', 'system_job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', 'system_job_template_notification_templates_success_list'),
)
system_job_urls = patterns('awx.api.views',
url(r'^$', 'system_job_list'),
url(r'^(?P<pk>[0-9]+)/$', 'system_job_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', 'system_job_cancel'),
url(r'^(?P<pk>[0-9]+)/notifications/$', 'system_job_notifications_list'),
)
workflow_job_template_urls = patterns('awx.api.views',
url(r'^$', 'workflow_job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', 'workflow_job_template_detail'),
url(r'^(?P<pk>[0-9]+)/workflow_jobs/$', 'workflow_job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/launch/$', 'workflow_job_template_launch'),
url(r'^(?P<pk>[0-9]+)/copy/$', 'workflow_job_template_copy'),
url(r'^(?P<pk>[0-9]+)/schedules/$', 'workflow_job_template_schedules_list'),
url(r'^(?P<pk>[0-9]+)/survey_spec/$', 'workflow_job_template_survey_spec'),
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', 'workflow_job_template_workflow_nodes_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'workflow_job_template_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_any/$', 'workflow_job_template_notification_templates_any_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', 'workflow_job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', 'workflow_job_template_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', 'workflow_job_template_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', 'workflow_job_template_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', 'workflow_job_template_label_list'),
)
workflow_job_urls = patterns('awx.api.views',
url(r'^$', 'workflow_job_list'),
url(r'^(?P<pk>[0-9]+)/$', 'workflow_job_detail'),
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', 'workflow_job_workflow_nodes_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', 'workflow_job_label_list'),
url(r'^(?P<pk>[0-9]+)/cancel/$', 'workflow_job_cancel'),
url(r'^(?P<pk>[0-9]+)/relaunch/$', 'workflow_job_relaunch'),
url(r'^(?P<pk>[0-9]+)/notifications/$', 'workflow_job_notifications_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', 'workflow_job_activity_stream_list'),
)
notification_template_urls = patterns('awx.api.views',
url(r'^$', 'notification_template_list'),
url(r'^(?P<pk>[0-9]+)/$', 'notification_template_detail'),
url(r'^(?P<pk>[0-9]+)/test/$', 'notification_template_test'),
url(r'^(?P<pk>[0-9]+)/notifications/$', 'notification_template_notification_list'),
)
notification_urls = patterns('awx.api.views',
url(r'^$', 'notification_list'),
url(r'^(?P<pk>[0-9]+)/$', 'notification_detail'),
)
label_urls = patterns('awx.api.views',
url(r'^$', 'label_list'),
url(r'^(?P<pk>[0-9]+)/$', 'label_detail'),
)
workflow_job_template_node_urls = patterns('awx.api.views',
url(r'^$', 'workflow_job_template_node_list'),
url(r'^(?P<pk>[0-9]+)/$', 'workflow_job_template_node_detail'),
url(r'^(?P<pk>[0-9]+)/success_nodes/$', 'workflow_job_template_node_success_nodes_list'),
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', 'workflow_job_template_node_failure_nodes_list'),
url(r'^(?P<pk>[0-9]+)/always_nodes/$', 'workflow_job_template_node_always_nodes_list'),
)
workflow_job_node_urls = patterns('awx.api.views',
url(r'^$', 'workflow_job_node_list'),
url(r'^(?P<pk>[0-9]+)/$', 'workflow_job_node_detail'),
url(r'^(?P<pk>[0-9]+)/success_nodes/$', 'workflow_job_node_success_nodes_list'),
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', 'workflow_job_node_failure_nodes_list'),
url(r'^(?P<pk>[0-9]+)/always_nodes/$', 'workflow_job_node_always_nodes_list'),
)
schedule_urls = patterns('awx.api.views',
url(r'^$', 'schedule_list'),
url(r'^(?P<pk>[0-9]+)/$', 'schedule_detail'),
url(r'^(?P<pk>[0-9]+)/jobs/$', 'schedule_unified_jobs_list'),
)
activity_stream_urls = patterns('awx.api.views',
url(r'^$', 'activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/$', 'activity_stream_detail'),
)
instance_urls = patterns('awx.api.views',
url(r'^$', 'instance_list'),
url(r'^(?P<pk>[0-9]+)/$', 'instance_detail'),
url(r'^(?P<pk>[0-9]+)/jobs/$', 'instance_unified_jobs_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', 'instance_instance_groups_list'),
)
instance_group_urls = patterns('awx.api.views',
url(r'^$', 'instance_group_list'),
url(r'^(?P<pk>[0-9]+)/$', 'instance_group_detail'),
url(r'^(?P<pk>[0-9]+)/jobs/$', 'instance_group_unified_jobs_list'),
url(r'^(?P<pk>[0-9]+)/instances/$', 'instance_group_instance_list'),
)
v1_urls = patterns('awx.api.views',
url(r'^$', 'api_v1_root_view'),
url(r'^ping/$', 'api_v1_ping_view'),
url(r'^config/$', 'api_v1_config_view'),
url(r'^auth/$', 'auth_view'),
url(r'^authtoken/$', 'auth_token_view'),
url(r'^me/$', 'user_me_list'),
url(r'^dashboard/$', 'dashboard_view'),
url(r'^dashboard/graphs/jobs/$','dashboard_jobs_graph_view'),
url(r'^settings/', include('awx.conf.urls')),
url(r'^instances/', include(instance_urls)),
url(r'^instance_groups/', include(instance_group_urls)),
url(r'^schedules/', include(schedule_urls)),
url(r'^organizations/', include(organization_urls)),
url(r'^users/', include(user_urls)),
url(r'^projects/', include(project_urls)),
url(r'^project_updates/', include(project_update_urls)),
url(r'^teams/', include(team_urls)),
url(r'^inventories/', include(inventory_urls)),
url(r'^hosts/', include(host_urls)),
url(r'^groups/', include(group_urls)),
url(r'^inventory_sources/', include(inventory_source_urls)),
url(r'^inventory_updates/', include(inventory_update_urls)),
url(r'^inventory_scripts/', include(inventory_script_urls)),
url(r'^credentials/', include(credential_urls)),
url(r'^roles/', include(role_urls)),
url(r'^job_templates/', include(job_template_urls)),
url(r'^jobs/', include(job_urls)),
url(r'^job_host_summaries/', include(job_host_summary_urls)),
url(r'^job_events/', include(job_event_urls)),
url(r'^ad_hoc_commands/', include(ad_hoc_command_urls)),
url(r'^ad_hoc_command_events/', include(ad_hoc_command_event_urls)),
url(r'^system_job_templates/', include(system_job_template_urls)),
url(r'^system_jobs/', include(system_job_urls)),
url(r'^notification_templates/', include(notification_template_urls)),
url(r'^notifications/', include(notification_urls)),
url(r'^workflow_job_templates/',include(workflow_job_template_urls)),
url(r'^workflow_jobs/' ,include(workflow_job_urls)),
url(r'^labels/', include(label_urls)),
url(r'^workflow_job_template_nodes/', include(workflow_job_template_node_urls)),
url(r'^workflow_job_nodes/', include(workflow_job_node_urls)),
url(r'^unified_job_templates/$','unified_job_template_list'),
url(r'^unified_jobs/$', 'unified_job_list'),
url(r'^activity_stream/', include(activity_stream_urls)),
)
v2_urls = patterns('awx.api.views',
url(r'^$', 'api_v2_root_view'),
url(r'^credential_types/', include(credential_type_urls)),
url(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', 'host_ansible_facts_detail'),
url(r'^jobs/(?P<pk>[0-9]+)/extra_credentials/$', 'job_extra_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/extra_credentials/$', 'job_template_extra_credentials_list'),
)
urlpatterns = patterns('awx.api.views',
url(r'^$', 'api_root_view'),
url(r'^(?P<version>(v2))/', include(v2_urls)),
url(r'^(?P<version>(v1|v2))/', include(v1_urls))
)

7
awx/api/urls/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from __future__ import absolute_import, unicode_literals
from .urls import urlpatterns
__all__ = ['urlpatterns']

View File

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

View File

@@ -0,0 +1,29 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
AdHocCommandList,
AdHocCommandDetail,
AdHocCommandCancel,
AdHocCommandRelaunch,
AdHocCommandAdHocCommandEventsList,
AdHocCommandActivityStreamList,
AdHocCommandNotificationsList,
AdHocCommandStdout,
)
urls = [
url(r'^$', AdHocCommandList.as_view(), name='ad_hoc_command_list'),
url(r'^(?P<pk>[0-9]+)/$', AdHocCommandDetail.as_view(), name='ad_hoc_command_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', AdHocCommandCancel.as_view(), name='ad_hoc_command_cancel'),
url(r'^(?P<pk>[0-9]+)/relaunch/$', AdHocCommandRelaunch.as_view(), name='ad_hoc_command_relaunch'),
url(r'^(?P<pk>[0-9]+)/events/$', AdHocCommandAdHocCommandEventsList.as_view(), name='ad_hoc_command_ad_hoc_command_events_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', AdHocCommandActivityStreamList.as_view(), name='ad_hoc_command_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/notifications/$', AdHocCommandNotificationsList.as_view(), name='ad_hoc_command_notifications_list'),
url(r'^(?P<pk>[0-9]+)/stdout/$', AdHocCommandStdout.as_view(), name='ad_hoc_command_stdout'),
]
__all__ = ['urls']

View File

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

View File

@@ -0,0 +1,27 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
CredentialList,
CredentialActivityStreamList,
CredentialDetail,
CredentialAccessList,
CredentialObjectRolesList,
CredentialOwnerUsersList,
CredentialOwnerTeamsList,
)
urls = [
url(r'^$', CredentialList.as_view(), name='credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialActivityStreamList.as_view(), name='credential_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/$', CredentialDetail.as_view(), name='credential_detail'),
url(r'^(?P<pk>[0-9]+)/access_list/$', CredentialAccessList.as_view(), name='credential_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', CredentialObjectRolesList.as_view(), name='credential_object_roles_list'),
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'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,21 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
CredentialTypeList,
CredentialTypeDetail,
CredentialTypeCredentialList,
CredentialTypeActivityStreamList,
)
urls = [
url(r'^$', CredentialTypeList.as_view(), name='credential_type_list'),
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'),
]
__all__ = ['urls']

37
awx/api/urls/group.py Normal file
View File

@@ -0,0 +1,37 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
GroupList,
GroupDetail,
GroupChildrenList,
GroupHostsList,
GroupAllHostsList,
GroupVariableData,
GroupJobEventsList,
GroupJobHostSummariesList,
GroupPotentialChildrenList,
GroupActivityStreamList,
GroupInventorySourcesList,
GroupAdHocCommandsList,
)
urls = [
url(r'^$', GroupList.as_view(), name='group_list'),
url(r'^(?P<pk>[0-9]+)/$', GroupDetail.as_view(), name='group_detail'),
url(r'^(?P<pk>[0-9]+)/children/$', GroupChildrenList.as_view(), name='group_children_list'),
url(r'^(?P<pk>[0-9]+)/hosts/$', GroupHostsList.as_view(), name='group_hosts_list'),
url(r'^(?P<pk>[0-9]+)/all_hosts/$', GroupAllHostsList.as_view(), name='group_all_hosts_list'),
url(r'^(?P<pk>[0-9]+)/variable_data/$', GroupVariableData.as_view(), name='group_variable_data'),
url(r'^(?P<pk>[0-9]+)/job_events/$', GroupJobEventsList.as_view(), name='group_job_events_list'),
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', GroupJobHostSummariesList.as_view(), name='group_job_host_summaries_list'),
url(r'^(?P<pk>[0-9]+)/potential_children/$', GroupPotentialChildrenList.as_view(), name='group_potential_children_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', GroupActivityStreamList.as_view(), name='group_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', GroupInventorySourcesList.as_view(), name='group_inventory_sources_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', GroupAdHocCommandsList.as_view(), name='group_ad_hoc_commands_list'),
]
__all__ = ['urls']

43
awx/api/urls/host.py Normal file
View File

@@ -0,0 +1,43 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
HostList,
HostDetail,
HostVariableData,
HostGroupsList,
HostAllGroupsList,
HostJobEventsList,
HostJobHostSummariesList,
HostActivityStreamList,
HostInventorySourcesList,
HostSmartInventoriesList,
HostAdHocCommandsList,
HostAdHocCommandEventsList,
HostFactVersionsList,
HostFactCompareView,
HostInsights,
)
urls = [
url(r'^$', HostList.as_view(), name='host_list'),
url(r'^(?P<pk>[0-9]+)/$', HostDetail.as_view(), name='host_detail'),
url(r'^(?P<pk>[0-9]+)/variable_data/$', HostVariableData.as_view(), name='host_variable_data'),
url(r'^(?P<pk>[0-9]+)/groups/$', HostGroupsList.as_view(), name='host_groups_list'),
url(r'^(?P<pk>[0-9]+)/all_groups/$', HostAllGroupsList.as_view(), name='host_all_groups_list'),
url(r'^(?P<pk>[0-9]+)/job_events/', HostJobEventsList.as_view(), name='host_job_events_list'),
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', HostJobHostSummariesList.as_view(), name='host_job_host_summaries_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', HostActivityStreamList.as_view(), name='host_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', HostInventorySourcesList.as_view(), name='host_inventory_sources_list'),
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'),
]
__all__ = ['urls']

22
awx/api/urls/instance.py Normal file
View File

@@ -0,0 +1,22 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
InstanceList,
InstanceDetail,
InstanceUnifiedJobsList,
InstanceInstanceGroupsList,
)
urls = [
url(r'^$', InstanceList.as_view(), name='instance_list'),
url(r'^(?P<pk>[0-9]+)/$', InstanceDetail.as_view(), name='instance_detail'),
url(r'^(?P<pk>[0-9]+)/jobs/$', InstanceUnifiedJobsList.as_view(), name='instance_unified_jobs_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', InstanceInstanceGroupsList.as_view(),
name='instance_instance_groups_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,21 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
InstanceGroupList,
InstanceGroupDetail,
InstanceGroupUnifiedJobsList,
InstanceGroupInstanceList,
)
urls = [
url(r'^$', InstanceGroupList.as_view(), name='instance_group_list'),
url(r'^(?P<pk>[0-9]+)/$', InstanceGroupDetail.as_view(), name='instance_group_detail'),
url(r'^(?P<pk>[0-9]+)/jobs/$', InstanceGroupUnifiedJobsList.as_view(), name='instance_group_unified_jobs_list'),
url(r'^(?P<pk>[0-9]+)/instances/$', InstanceGroupInstanceList.as_view(), name='instance_group_instance_list'),
]
__all__ = ['urls']

45
awx/api/urls/inventory.py Normal file
View File

@@ -0,0 +1,45 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
InventoryList,
InventoryDetail,
InventoryHostsList,
InventoryGroupsList,
InventoryRootGroupsList,
InventoryVariableData,
InventoryScriptView,
InventoryTreeView,
InventoryInventorySourcesList,
InventoryInventorySourcesUpdate,
InventoryActivityStreamList,
InventoryJobTemplateList,
InventoryAdHocCommandsList,
InventoryAccessList,
InventoryObjectRolesList,
InventoryInstanceGroupsList,
)
urls = [
url(r'^$', InventoryList.as_view(), name='inventory_list'),
url(r'^(?P<pk>[0-9]+)/$', InventoryDetail.as_view(), name='inventory_detail'),
url(r'^(?P<pk>[0-9]+)/hosts/$', InventoryHostsList.as_view(), name='inventory_hosts_list'),
url(r'^(?P<pk>[0-9]+)/groups/$', InventoryGroupsList.as_view(), name='inventory_groups_list'),
url(r'^(?P<pk>[0-9]+)/root_groups/$', InventoryRootGroupsList.as_view(), name='inventory_root_groups_list'),
url(r'^(?P<pk>[0-9]+)/variable_data/$', InventoryVariableData.as_view(), name='inventory_variable_data'),
url(r'^(?P<pk>[0-9]+)/script/$', InventoryScriptView.as_view(), name='inventory_script_view'),
url(r'^(?P<pk>[0-9]+)/tree/$', InventoryTreeView.as_view(), name='inventory_tree_view'),
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', InventoryInventorySourcesList.as_view(), name='inventory_inventory_sources_list'),
url(r'^(?P<pk>[0-9]+)/update_inventory_sources/$', InventoryInventorySourcesUpdate.as_view(), name='inventory_inventory_sources_update'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', InventoryActivityStreamList.as_view(), name='inventory_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/job_templates/$', InventoryJobTemplateList.as_view(), name='inventory_job_template_list'),
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', InventoryAdHocCommandsList.as_view(), name='inventory_ad_hoc_commands_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', InventoryAccessList.as_view(), name='inventory_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', InventoryObjectRolesList.as_view(), name='inventory_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', InventoryInstanceGroupsList.as_view(), name='inventory_instance_groups_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,19 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
InventoryScriptList,
InventoryScriptDetail,
InventoryScriptObjectRolesList,
)
urls = [
url(r'^$', InventoryScriptList.as_view(), name='inventory_script_list'),
url(r'^(?P<pk>[0-9]+)/$', InventoryScriptDetail.as_view(), name='inventory_script_detail'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', InventoryScriptObjectRolesList.as_view(), name='inventory_script_object_roles_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,38 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
InventorySourceList,
InventorySourceDetail,
InventorySourceUpdateView,
InventorySourceUpdatesList,
InventorySourceActivityStreamList,
InventorySourceSchedulesList,
InventorySourceGroupsList,
InventorySourceHostsList,
InventorySourceNotificationTemplatesAnyList,
InventorySourceNotificationTemplatesErrorList,
InventorySourceNotificationTemplatesSuccessList,
)
urls = [
url(r'^$', InventorySourceList.as_view(), name='inventory_source_list'),
url(r'^(?P<pk>[0-9]+)/$', InventorySourceDetail.as_view(), name='inventory_source_detail'),
url(r'^(?P<pk>[0-9]+)/update/$', InventorySourceUpdateView.as_view(), name='inventory_source_update_view'),
url(r'^(?P<pk>[0-9]+)/inventory_updates/$', InventorySourceUpdatesList.as_view(), name='inventory_source_updates_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', InventorySourceActivityStreamList.as_view(), name='inventory_source_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/schedules/$', InventorySourceSchedulesList.as_view(), name='inventory_source_schedules_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_error/$', InventorySourceNotificationTemplatesErrorList.as_view(),
name='inventory_source_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', InventorySourceNotificationTemplatesSuccessList.as_view(),
name='inventory_source_notification_templates_success_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,23 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
InventoryUpdateList,
InventoryUpdateDetail,
InventoryUpdateCancel,
InventoryUpdateStdout,
InventoryUpdateNotificationsList,
)
urls = [
url(r'^$', InventoryUpdateList.as_view(), name='inventory_update_list'),
url(r'^(?P<pk>[0-9]+)/$', InventoryUpdateDetail.as_view(), name='inventory_update_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', InventoryUpdateCancel.as_view(), name='inventory_update_cancel'),
url(r'^(?P<pk>[0-9]+)/stdout/$', InventoryUpdateStdout.as_view(), name='inventory_update_stdout'),
url(r'^(?P<pk>[0-9]+)/notifications/$', InventoryUpdateNotificationsList.as_view(), name='inventory_update_notifications_list'),
]
__all__ = ['urls']

39
awx/api/urls/job.py Normal file
View File

@@ -0,0 +1,39 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
JobList,
JobDetail,
JobStart,
JobCancel,
JobRelaunch,
JobCreateSchedule,
JobJobHostSummariesList,
JobJobEventsList,
JobActivityStreamList,
JobStdout,
JobNotificationsList,
JobLabelList,
JobHostSummaryDetail,
)
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'),
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', JobJobHostSummariesList.as_view(), name='job_job_host_summaries_list'),
url(r'^(?P<pk>[0-9]+)/job_events/$', JobJobEventsList.as_view(), name='job_job_events_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', JobActivityStreamList.as_view(), name='job_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/stdout/$', JobStdout.as_view(), name='job_stdout'),
url(r'^(?P<pk>[0-9]+)/notifications/$', JobNotificationsList.as_view(), name='job_notifications_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', JobLabelList.as_view(), name='job_label_list'),
url(r'^(?P<pk>[0-9]+)/$', JobHostSummaryDetail.as_view(), name='job_host_summary_detail'),
]
__all__ = ['urls']

21
awx/api/urls/job_event.py Normal file
View File

@@ -0,0 +1,21 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
JobEventList,
JobEventDetail,
JobEventChildrenList,
JobEventHostsList,
)
urls = [
url(r'^$', JobEventList.as_view(), name='job_event_list'),
url(r'^(?P<pk>[0-9]+)/$', JobEventDetail.as_view(), name='job_event_detail'),
url(r'^(?P<pk>[0-9]+)/children/$', JobEventChildrenList.as_view(), name='job_event_children_list'),
url(r'^(?P<pk>[0-9]+)/hosts/$', JobEventHostsList.as_view(), name='job_event_hosts_list'),
]
__all__ = ['urls']

View File

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

View File

@@ -0,0 +1,46 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
JobTemplateList,
JobTemplateDetail,
JobTemplateLaunch,
JobTemplateJobsList,
JobTemplateCallback,
JobTemplateSchedulesList,
JobTemplateSurveySpec,
JobTemplateActivityStreamList,
JobTemplateNotificationTemplatesAnyList,
JobTemplateNotificationTemplatesErrorList,
JobTemplateNotificationTemplatesSuccessList,
JobTemplateInstanceGroupsList,
JobTemplateAccessList,
JobTemplateObjectRolesList,
JobTemplateLabelList,
)
urls = [
url(r'^$', JobTemplateList.as_view(), name='job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', JobTemplateDetail.as_view(), name='job_template_detail'),
url(r'^(?P<pk>[0-9]+)/launch/$', JobTemplateLaunch.as_view(), name='job_template_launch'),
url(r'^(?P<pk>[0-9]+)/jobs/$', JobTemplateJobsList.as_view(), name='job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/callback/$', JobTemplateCallback.as_view(), name='job_template_callback'),
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_error/$', JobTemplateNotificationTemplatesErrorList.as_view(),
name='job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', JobTemplateNotificationTemplatesSuccessList.as_view(),
name='job_template_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', JobTemplateInstanceGroupsList.as_view(), name='job_template_instance_groups_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', JobTemplateAccessList.as_view(), name='job_template_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', JobTemplateObjectRolesList.as_view(), name='job_template_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', JobTemplateLabelList.as_view(), name='job_template_label_list'),
]
__all__ = ['urls']

17
awx/api/urls/label.py Normal file
View File

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

View File

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

View File

@@ -0,0 +1,21 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
NotificationTemplateList,
NotificationTemplateDetail,
NotificationTemplateTest,
NotificationTemplateNotificationList,
)
urls = [
url(r'^$', NotificationTemplateList.as_view(), name='notification_template_list'),
url(r'^(?P<pk>[0-9]+)/$', NotificationTemplateDetail.as_view(), name='notification_template_detail'),
url(r'^(?P<pk>[0-9]+)/test/$', NotificationTemplateTest.as_view(), name='notification_template_test'),
url(r'^(?P<pk>[0-9]+)/notifications/$', NotificationTemplateNotificationList.as_view(), name='notification_template_notification_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,50 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
OrganizationList,
OrganizationDetail,
OrganizationUsersList,
OrganizationAdminsList,
OrganizationInventoriesList,
OrganizationProjectsList,
OrganizationWorkflowJobTemplatesList,
OrganizationTeamsList,
OrganizationCredentialList,
OrganizationActivityStreamList,
OrganizationNotificationTemplatesList,
OrganizationNotificationTemplatesAnyList,
OrganizationNotificationTemplatesErrorList,
OrganizationNotificationTemplatesSuccessList,
OrganizationInstanceGroupsList,
OrganizationObjectRolesList,
OrganizationAccessList,
)
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'),
url(r'^(?P<pk>[0-9]+)/admins/$', OrganizationAdminsList.as_view(), name='organization_admins_list'),
url(r'^(?P<pk>[0-9]+)/inventories/$', OrganizationInventoriesList.as_view(), name='organization_inventories_list'),
url(r'^(?P<pk>[0-9]+)/projects/$', OrganizationProjectsList.as_view(), name='organization_projects_list'),
url(r'^(?P<pk>[0-9]+)/workflow_job_templates/$', OrganizationWorkflowJobTemplatesList.as_view(), name='organization_workflow_job_templates_list'),
url(r'^(?P<pk>[0-9]+)/teams/$', OrganizationTeamsList.as_view(), name='organization_teams_list'),
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_error/$', OrganizationNotificationTemplatesErrorList.as_view(),
name='organization_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', OrganizationNotificationTemplatesSuccessList.as_view(),
name='organization_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', OrganizationInstanceGroupsList.as_view(), name='organization_instance_groups_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', OrganizationObjectRolesList.as_view(), name='organization_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', OrganizationAccessList.as_view(), name='organization_access_list'),
]
__all__ = ['urls']

44
awx/api/urls/project.py Normal file
View File

@@ -0,0 +1,44 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
ProjectList,
ProjectDetail,
ProjectPlaybooks,
ProjectInventories,
ProjectScmInventorySources,
ProjectTeamsList,
ProjectUpdateView,
ProjectUpdatesList,
ProjectActivityStreamList,
ProjectSchedulesList,
ProjectNotificationTemplatesAnyList,
ProjectNotificationTemplatesErrorList,
ProjectNotificationTemplatesSuccessList,
ProjectObjectRolesList,
ProjectAccessList,
)
urls = [
url(r'^$', ProjectList.as_view(), name='project_list'),
url(r'^(?P<pk>[0-9]+)/$', ProjectDetail.as_view(), name='project_detail'),
url(r'^(?P<pk>[0-9]+)/playbooks/$', ProjectPlaybooks.as_view(), name='project_playbooks'),
url(r'^(?P<pk>[0-9]+)/inventories/$', ProjectInventories.as_view(), name='project_inventories'),
url(r'^(?P<pk>[0-9]+)/scm_inventory_sources/$', ProjectScmInventorySources.as_view(), name='project_scm_inventory_sources'),
url(r'^(?P<pk>[0-9]+)/teams/$', ProjectTeamsList.as_view(), name='project_teams_list'),
url(r'^(?P<pk>[0-9]+)/update/$', ProjectUpdateView.as_view(), name='project_update_view'),
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]+)/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'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
ProjectUpdateList,
ProjectUpdateDetail,
ProjectUpdateCancel,
ProjectUpdateStdout,
ProjectUpdateScmInventoryUpdates,
ProjectUpdateNotificationsList,
)
urls = [
url(r'^$', ProjectUpdateList.as_view(), name='project_update_list'),
url(r'^(?P<pk>[0-9]+)/$', ProjectUpdateDetail.as_view(), name='project_update_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', ProjectUpdateCancel.as_view(), name='project_update_cancel'),
url(r'^(?P<pk>[0-9]+)/stdout/$', ProjectUpdateStdout.as_view(), name='project_update_stdout'),
url(r'^(?P<pk>[0-9]+)/scm_inventory_updates/$', ProjectUpdateScmInventoryUpdates.as_view(), name='project_update_scm_inventory_updates'),
url(r'^(?P<pk>[0-9]+)/notifications/$', ProjectUpdateNotificationsList.as_view(), name='project_update_notifications_list'),
]
__all__ = ['urls']

25
awx/api/urls/role.py Normal file
View File

@@ -0,0 +1,25 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
RoleList,
RoleDetail,
RoleUsersList,
RoleTeamsList,
RoleParentsList,
RoleChildrenList,
)
urls = [
url(r'^$', RoleList.as_view(), name='role_list'),
url(r'^(?P<pk>[0-9]+)/$', RoleDetail.as_view(), name='role_detail'),
url(r'^(?P<pk>[0-9]+)/users/$', RoleUsersList.as_view(), name='role_users_list'),
url(r'^(?P<pk>[0-9]+)/teams/$', RoleTeamsList.as_view(), name='role_teams_list'),
url(r'^(?P<pk>[0-9]+)/parents/$', RoleParentsList.as_view(), name='role_parents_list'),
url(r'^(?P<pk>[0-9]+)/children/$', RoleChildrenList.as_view(), name='role_children_list'),
]
__all__ = ['urls']

21
awx/api/urls/schedule.py Normal file
View File

@@ -0,0 +1,21 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
ScheduleList,
ScheduleDetail,
ScheduleUnifiedJobsList,
ScheduleCredentialsList,
)
urls = [
url(r'^$', ScheduleList.as_view(), name='schedule_list'),
url(r'^(?P<pk>[0-9]+)/$', ScheduleDetail.as_view(), name='schedule_detail'),
url(r'^(?P<pk>[0-9]+)/jobs/$', ScheduleUnifiedJobsList.as_view(), name='schedule_unified_jobs_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', ScheduleCredentialsList.as_view(), name='schedule_credentials_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,21 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
SystemJobList,
SystemJobDetail,
SystemJobCancel,
SystemJobNotificationsList,
)
urls = [
url(r'^$', SystemJobList.as_view(), name='system_job_list'),
url(r'^(?P<pk>[0-9]+)/$', SystemJobDetail.as_view(), name='system_job_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', SystemJobCancel.as_view(), name='system_job_cancel'),
url(r'^(?P<pk>[0-9]+)/notifications/$', SystemJobNotificationsList.as_view(), name='system_job_notifications_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,32 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
SystemJobTemplateList,
SystemJobTemplateDetail,
SystemJobTemplateLaunch,
SystemJobTemplateJobsList,
SystemJobTemplateSchedulesList,
SystemJobTemplateNotificationTemplatesAnyList,
SystemJobTemplateNotificationTemplatesErrorList,
SystemJobTemplateNotificationTemplatesSuccessList,
)
urls = [
url(r'^$', SystemJobTemplateList.as_view(), name='system_job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', SystemJobTemplateDetail.as_view(), name='system_job_template_detail'),
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_error/$', SystemJobTemplateNotificationTemplatesErrorList.as_view(),
name='system_job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', SystemJobTemplateNotificationTemplatesSuccessList.as_view(),
name='system_job_template_notification_templates_success_list'),
]
__all__ = ['urls']

31
awx/api/urls/team.py Normal file
View File

@@ -0,0 +1,31 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
TeamList,
TeamDetail,
TeamProjectsList,
TeamUsersList,
TeamCredentialsList,
TeamRolesList,
TeamObjectRolesList,
TeamActivityStreamList,
TeamAccessList,
)
urls = [
url(r'^$', TeamList.as_view(), name='team_list'),
url(r'^(?P<pk>[0-9]+)/$', TeamDetail.as_view(), name='team_detail'),
url(r'^(?P<pk>[0-9]+)/projects/$', TeamProjectsList.as_view(), name='team_projects_list'),
url(r'^(?P<pk>[0-9]+)/users/$', TeamUsersList.as_view(), name='team_users_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', TeamCredentialsList.as_view(), name='team_credentials_list'),
url(r'^(?P<pk>[0-9]+)/roles/$', TeamRolesList.as_view(), name='team_roles_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', TeamObjectRolesList.as_view(), name='team_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', TeamActivityStreamList.as_view(), name='team_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', TeamAccessList.as_view(), name='team_access_list'),
]
__all__ = ['urls']

123
awx/api/urls/urls.py Normal file
View File

@@ -0,0 +1,123 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
from __future__ import absolute_import, unicode_literals
from django.conf.urls import include, url
from awx.api.views import (
ApiRootView,
ApiV1RootView,
ApiV2RootView,
ApiV1PingView,
ApiV1ConfigView,
AuthView,
AuthTokenView,
UserMeList,
DashboardView,
DashboardJobsGraphView,
UnifiedJobTemplateList,
UnifiedJobList,
HostAnsibleFactsDetail,
JobCredentialsList,
JobExtraCredentialsList,
JobTemplateCredentialsList,
JobTemplateExtraCredentialsList,
)
from .organization import urls as organization_urls
from .user import urls as user_urls
from .project import urls as project_urls
from .project_update import urls as project_update_urls
from .inventory import urls as inventory_urls
from .team import urls as team_urls
from .host import urls as host_urls
from .group import urls as group_urls
from .inventory_source import urls as inventory_source_urls
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 .role import urls as role_urls
from .job_template import urls as job_template_urls
from .job import urls as job_urls
from .job_host_summary import urls as job_host_summary_urls
from .job_event import urls as job_event_urls
from .ad_hoc_command import urls as ad_hoc_command_urls
from .ad_hoc_command_event import urls as ad_hoc_command_event_urls
from .system_job_template import urls as system_job_template_urls
from .system_job import urls as system_job_urls
from .workflow_job_template import urls as workflow_job_template_urls
from .workflow_job import urls as workflow_job_urls
from .notification_template import urls as notification_template_urls
from .notification import urls as notification_urls
from .label import urls as label_urls
from .workflow_job_template_node import urls as workflow_job_template_node_urls
from .workflow_job_node import urls as workflow_job_node_urls
from .schedule import urls as schedule_urls
from .activity_stream import urls as activity_stream_urls
from .instance import urls as instance_urls
from .instance_group import urls as instance_group_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'),
url(r'^auth/$', AuthView.as_view()),
url(r'^authtoken/$', AuthTokenView.as_view(), name='auth_token_view'),
url(r'^me/$', UserMeList.as_view(), name='user_me_list'),
url(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),
url(r'^dashboard/graphs/jobs/$', DashboardJobsGraphView.as_view(), name='dashboard_jobs_graph_view'),
url(r'^settings/', include('awx.conf.urls')),
url(r'^instances/', include(instance_urls)),
url(r'^instance_groups/', include(instance_group_urls)),
url(r'^schedules/', include(schedule_urls)),
url(r'^organizations/', include(organization_urls)),
url(r'^users/', include(user_urls)),
url(r'^projects/', include(project_urls)),
url(r'^project_updates/', include(project_update_urls)),
url(r'^teams/', include(team_urls)),
url(r'^inventories/', include(inventory_urls)),
url(r'^hosts/', include(host_urls)),
url(r'^groups/', include(group_urls)),
url(r'^inventory_sources/', include(inventory_source_urls)),
url(r'^inventory_updates/', include(inventory_update_urls)),
url(r'^inventory_scripts/', include(inventory_script_urls)),
url(r'^credentials/', include(credential_urls)),
url(r'^roles/', include(role_urls)),
url(r'^job_templates/', include(job_template_urls)),
url(r'^jobs/', include(job_urls)),
url(r'^job_host_summaries/', include(job_host_summary_urls)),
url(r'^job_events/', include(job_event_urls)),
url(r'^ad_hoc_commands/', include(ad_hoc_command_urls)),
url(r'^ad_hoc_command_events/', include(ad_hoc_command_event_urls)),
url(r'^system_job_templates/', include(system_job_template_urls)),
url(r'^system_jobs/', include(system_job_urls)),
url(r'^notification_templates/', include(notification_template_urls)),
url(r'^notifications/', include(notification_urls)),
url(r'^workflow_job_templates/', include(workflow_job_template_urls)),
url(r'^workflow_jobs/', include(workflow_job_urls)),
url(r'^labels/', include(label_urls)),
url(r'^workflow_job_template_nodes/', include(workflow_job_template_node_urls)),
url(r'^workflow_job_nodes/', include(workflow_job_node_urls)),
url(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'),
url(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'),
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'),
]
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))
]

33
awx/api/urls/user.py Normal file
View File

@@ -0,0 +1,33 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
UserList,
UserDetail,
UserTeamsList,
UserOrganizationsList,
UserAdminOfOrganizationsList,
UserProjectsList,
UserCredentialsList,
UserRolesList,
UserActivityStreamList,
UserAccessList,
)
urls = [
url(r'^$', UserList.as_view(), name='user_list'),
url(r'^(?P<pk>[0-9]+)/$', UserDetail.as_view(), name='user_detail'),
url(r'^(?P<pk>[0-9]+)/teams/$', UserTeamsList.as_view(), name='user_teams_list'),
url(r'^(?P<pk>[0-9]+)/organizations/$', UserOrganizationsList.as_view(), name='user_organizations_list'),
url(r'^(?P<pk>[0-9]+)/admin_of_organizations/$', UserAdminOfOrganizationsList.as_view(), name='user_admin_of_organizations_list'),
url(r'^(?P<pk>[0-9]+)/projects/$', UserProjectsList.as_view(), name='user_projects_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', UserCredentialsList.as_view(), name='user_credentials_list'),
url(r'^(?P<pk>[0-9]+)/roles/$', UserRolesList.as_view(), name='user_roles_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', UserActivityStreamList.as_view(), name='user_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', UserAccessList.as_view(), name='user_access_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,29 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
WorkflowJobList,
WorkflowJobDetail,
WorkflowJobWorkflowNodesList,
WorkflowJobLabelList,
WorkflowJobCancel,
WorkflowJobRelaunch,
WorkflowJobNotificationsList,
WorkflowJobActivityStreamList,
)
urls = [
url(r'^$', WorkflowJobList.as_view(), name='workflow_job_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobDetail.as_view(), name='workflow_job_detail'),
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobWorkflowNodesList.as_view(), name='workflow_job_workflow_nodes_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobLabelList.as_view(), name='workflow_job_label_list'),
url(r'^(?P<pk>[0-9]+)/cancel/$', WorkflowJobCancel.as_view(), name='workflow_job_cancel'),
url(r'^(?P<pk>[0-9]+)/relaunch/$', WorkflowJobRelaunch.as_view(), name='workflow_job_relaunch'),
url(r'^(?P<pk>[0-9]+)/notifications/$', WorkflowJobNotificationsList.as_view(), name='workflow_job_notifications_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobActivityStreamList.as_view(), name='workflow_job_activity_stream_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
WorkflowJobNodeList,
WorkflowJobNodeDetail,
WorkflowJobNodeSuccessNodesList,
WorkflowJobNodeFailureNodesList,
WorkflowJobNodeAlwaysNodesList,
WorkflowJobNodeCredentialsList,
)
urls = [
url(r'^$', WorkflowJobNodeList.as_view(), name='workflow_job_node_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobNodeDetail.as_view(), name='workflow_job_node_detail'),
url(r'^(?P<pk>[0-9]+)/success_nodes/$', WorkflowJobNodeSuccessNodesList.as_view(), name='workflow_job_node_success_nodes_list'),
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobNodeFailureNodesList.as_view(), name='workflow_job_node_failure_nodes_list'),
url(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobNodeAlwaysNodesList.as_view(), name='workflow_job_node_always_nodes_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobNodeCredentialsList.as_view(), name='workflow_job_node_credentials_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,46 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
WorkflowJobTemplateList,
WorkflowJobTemplateDetail,
WorkflowJobTemplateJobsList,
WorkflowJobTemplateLaunch,
WorkflowJobTemplateCopy,
WorkflowJobTemplateSchedulesList,
WorkflowJobTemplateSurveySpec,
WorkflowJobTemplateWorkflowNodesList,
WorkflowJobTemplateActivityStreamList,
WorkflowJobTemplateNotificationTemplatesAnyList,
WorkflowJobTemplateNotificationTemplatesErrorList,
WorkflowJobTemplateNotificationTemplatesSuccessList,
WorkflowJobTemplateAccessList,
WorkflowJobTemplateObjectRolesList,
WorkflowJobTemplateLabelList,
)
urls = [
url(r'^$', WorkflowJobTemplateList.as_view(), name='workflow_job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateDetail.as_view(), name='workflow_job_template_detail'),
url(r'^(?P<pk>[0-9]+)/workflow_jobs/$', WorkflowJobTemplateJobsList.as_view(), name='workflow_job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/launch/$', WorkflowJobTemplateLaunch.as_view(), name='workflow_job_template_launch'),
url(r'^(?P<pk>[0-9]+)/copy/$', WorkflowJobTemplateCopy.as_view(), name='workflow_job_template_copy'),
url(r'^(?P<pk>[0-9]+)/schedules/$', WorkflowJobTemplateSchedulesList.as_view(), name='workflow_job_template_schedules_list'),
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_error/$', WorkflowJobTemplateNotificationTemplatesErrorList.as_view(),
name='workflow_job_template_notification_templates_error_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_success/$', WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(),
name='workflow_job_template_notification_templates_success_list'),
url(r'^(?P<pk>[0-9]+)/access_list/$', WorkflowJobTemplateAccessList.as_view(), name='workflow_job_template_access_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', WorkflowJobTemplateObjectRolesList.as_view(), name='workflow_job_template_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobTemplateLabelList.as_view(), name='workflow_job_template_label_list'),
]
__all__ = ['urls']

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from awx.api.views import (
WorkflowJobTemplateNodeList,
WorkflowJobTemplateNodeDetail,
WorkflowJobTemplateNodeSuccessNodesList,
WorkflowJobTemplateNodeFailureNodesList,
WorkflowJobTemplateNodeAlwaysNodesList,
WorkflowJobTemplateNodeCredentialsList,
)
urls = [
url(r'^$', WorkflowJobTemplateNodeList.as_view(), name='workflow_job_template_node_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateNodeDetail.as_view(), name='workflow_job_template_node_detail'),
url(r'^(?P<pk>[0-9]+)/success_nodes/$', WorkflowJobTemplateNodeSuccessNodesList.as_view(), name='workflow_job_template_node_success_nodes_list'),
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobTemplateNodeFailureNodesList.as_view(), name='workflow_job_template_node_failure_nodes_list'),
url(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobTemplateNodeAlwaysNodesList.as_view(), name='workflow_job_template_node_always_nodes_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobTemplateNodeCredentialsList.as_view(), name='workflow_job_template_node_credentials_list'),
]
__all__ = ['urls']

View File

@@ -1,4 +1,3 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
@@ -14,7 +13,7 @@ import sys
import logging
import requests
from base64 import b64encode
from collections import OrderedDict
from collections import OrderedDict, Iterable
# Django
from django.conf import settings
@@ -28,7 +27,6 @@ from django.utils.timezone import now
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.cache import never_cache
from django.template.loader import render_to_string
from django.core.servers.basehttp import FileWrapper
from django.http import HttpResponse
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
@@ -54,13 +52,15 @@ import qsstats
import ansiconv
# Python Social Auth
from social.backends.utils import load_backends
from social_core.backends.utils import load_backends
from wsgiref.util import FileWrapper
# AWX
from awx.main.tasks import send_notifications
from awx.main.access import get_user_queryset
from awx.main.ha import is_ha_environment
from awx.api.authentication import TaskAuthentication, TokenGetAuthentication
from awx.api.authentication import TokenGetAuthentication
from awx.api.filters import V1CredentialFilterBackend
from awx.api.generics import get_view_name
from awx.api.generics import * # noqa
@@ -69,7 +69,7 @@ from awx.conf.license import get_license, feature_enabled, feature_exists, Licen
from awx.main.models import * # noqa
from awx.main.utils import * # noqa
from awx.main.utils import (
callback_filter_out_ansible_extra_vars,
extract_ansible_vars,
decrypt_field,
)
from awx.main.utils.filters import SmartFilter
@@ -122,7 +122,7 @@ class WorkflowsEnforcementMixin(object):
Mixin to check that license supports workflows.
'''
def check_permissions(self, request):
if not feature_enabled('workflows') and request.method not in ('GET', 'OPTIONS'):
if not feature_enabled('workflows') and request.method not in ('GET', 'OPTIONS', 'DELETE'):
raise LicenseForbids(_('Your license does not allow use of workflows.'))
return super(WorkflowsEnforcementMixin, self).check_permissions(request)
@@ -140,7 +140,8 @@ class UnifiedJobDeletionMixin(object):
raise PermissionDenied(detail=_('Cannot delete job resource when associated workflow job is running.'))
except self.model.unified_job_node.RelatedObjectDoesNotExist:
pass
if obj.status in ACTIVE_STATES:
# Still allow deletion of new status, because these can be manually created
if obj.status in ACTIVE_STATES and obj.status != 'new':
raise PermissionDenied(detail=_("Cannot delete running job resource."))
obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
@@ -360,7 +361,7 @@ class ApiV1ConfigView(APIView):
try:
settings.LICENSE = {}
return Response(status=status.HTTP_204_NO_CONTENT)
except:
except Exception:
# FIX: Log
return Response({"error": _("Failed to remove license (%s)") % has_error}, status=status.HTTP_400_BAD_REQUEST)
@@ -606,6 +607,46 @@ class ScheduleDetail(RetrieveUpdateDestroyAPIView):
new_in_148 = True
class LaunchConfigCredentialsBase(SubListAttachDetachAPIView):
model = Credential
serializer_class = CredentialSerializer
relationship = 'credentials'
def is_valid_relation(self, parent, sub, created=False):
if not parent.unified_job_template:
return {"msg": _("Cannot assign credential when related template is null.")}
ask_mapping = parent.unified_job_template.get_ask_mapping()
if self.relationship not in ask_mapping:
return {"msg": _("Related template cannot accept {} on launch.").format(self.relationship)}
elif sub.passwords_needed:
return {"msg": _("Credential that requires user input on launch "
"cannot be used in saved launch configuration.")}
ask_field_name = ask_mapping[self.relationship]
if not getattr(parent.unified_job_template, ask_field_name):
return {"msg": _("Related template is not configured to accept credentials on launch.")}
elif sub.unique_hash() in [cred.unique_hash() for cred in parent.credentials.all()]:
return {"msg": _("This launch configuration already provides a {credential_type} credential.").format(
credential_type=sub.unique_hash(display=True))}
elif sub.pk in parent.unified_job_template.credentials.values_list('pk', flat=True):
return {"msg": _("Related template already uses {credential_type} credential.").format(
credential_type=sub.name)}
# None means there were no validation errors
return None
class ScheduleCredentialsList(LaunchConfigCredentialsBase):
parent_model = Schedule
new_in_330 = True
new_in_api_v2 = True
class ScheduleUnifiedJobsList(SubListAPIView):
model = UnifiedJob
@@ -1300,8 +1341,11 @@ class ProjectUpdateView(RetrieveAPIView):
if not project_update:
return Response({}, status=status.HTTP_400_BAD_REQUEST)
else:
data = OrderedDict()
data['project_update'] = project_update.id
data.update(ProjectUpdateSerializer(project_update, context=self.get_serializer_context()).to_representation(project_update))
headers = {'Location': project_update.get_absolute_url(request=request)}
return Response({'project_update': project_update.id},
return Response(data,
headers=headers,
status=status.HTTP_202_ACCEPTED)
else:
@@ -1325,8 +1369,8 @@ class ProjectUpdateDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
class ProjectUpdateCancel(RetrieveAPIView):
model = ProjectUpdate
obj_permission_type = 'cancel'
serializer_class = ProjectUpdateCancelSerializer
is_job_cancel = True
new_in_13 = True
def post(self, request, *args, **kwargs):
@@ -2119,7 +2163,9 @@ class HostInsights(GenericAPIView):
if res.status_code == 401:
return (dict(error=_('Unauthorized access. Please check your Insights Credential username and password.')), status.HTTP_502_BAD_GATEWAY)
elif res.status_code != 200:
return (dict(error=_('Failed to gather reports and maintenance plans from Insights API at URL {}. Server responded with {} status code and message {}').format(url, res.status_code, res.content)), status.HTTP_502_BAD_GATEWAY)
return (dict(error=_(
'Failed to gather reports and maintenance plans from Insights API at URL {}. Server responded with {} status code and message {}'
).format(url, res.status_code, res.content)), status.HTTP_502_BAD_GATEWAY)
try:
filtered_insights_content = filter_insights_api_response(res.json())
@@ -2367,82 +2413,23 @@ class InventoryScriptView(RetrieveAPIView):
model = Inventory
serializer_class = InventoryScriptSerializer
authentication_classes = [TaskAuthentication] + api_settings.DEFAULT_AUTHENTICATION_CLASSES
permission_classes = (TaskPermission,)
filter_backends = ()
def retrieve(self, request, *args, **kwargs):
obj = self.get_object()
hostname = request.query_params.get('host', '')
hostvars = bool(request.query_params.get('hostvars', ''))
show_all = bool(request.query_params.get('all', ''))
if show_all:
hosts_q = dict()
else:
hosts_q = dict(enabled=True)
if hostname:
host = get_object_or_404(obj.hosts, name=hostname, **hosts_q)
data = host.variables_dict
else:
data = OrderedDict()
if obj.variables_dict:
all_group = data.setdefault('all', OrderedDict())
all_group['vars'] = obj.variables_dict
if obj.kind == 'smart':
if len(obj.hosts.all()) == 0:
return Response({})
else:
all_group = data.setdefault('all', OrderedDict())
smart_hosts_qs = obj.hosts.all().order_by('name')
smart_hosts = list(smart_hosts_qs.values_list('name', flat=True))
all_group['hosts'] = smart_hosts
else:
# Add hosts without a group to the all group.
groupless_hosts_qs = obj.hosts.filter(groups__isnull=True, **hosts_q).order_by('name')
groupless_hosts = list(groupless_hosts_qs.values_list('name', flat=True))
if groupless_hosts:
all_group = data.setdefault('all', OrderedDict())
all_group['hosts'] = groupless_hosts
# Build in-memory mapping of groups and their hosts.
group_hosts_kw = dict(group__inventory_id=obj.id, host__inventory_id=obj.id)
if 'enabled' in hosts_q:
group_hosts_kw['host__enabled'] = hosts_q['enabled']
group_hosts_qs = Group.hosts.through.objects.filter(**group_hosts_kw)
group_hosts_qs = group_hosts_qs.order_by('host__name')
group_hosts_qs = group_hosts_qs.values_list('group_id', 'host_id', 'host__name')
group_hosts_map = {}
for group_id, host_id, host_name in group_hosts_qs:
group_hostnames = group_hosts_map.setdefault(group_id, [])
group_hostnames.append(host_name)
# Build in-memory mapping of groups and their children.
group_parents_qs = Group.parents.through.objects.filter(
from_group__inventory_id=obj.id,
to_group__inventory_id=obj.id,
)
group_parents_qs = group_parents_qs.order_by('from_group__name')
group_parents_qs = group_parents_qs.values_list('from_group_id', 'from_group__name', 'to_group_id')
group_children_map = {}
for from_group_id, from_group_name, to_group_id in group_parents_qs:
group_children = group_children_map.setdefault(to_group_id, [])
group_children.append(from_group_name)
# Now use in-memory maps to build up group info.
for group in obj.groups.all():
group_info = OrderedDict()
group_info['hosts'] = group_hosts_map.get(group.id, [])
group_info['children'] = group_children_map.get(group.id, [])
group_info['vars'] = group.variables_dict
data[group.name] = group_info
if hostvars:
data.setdefault('_meta', OrderedDict())
data['_meta'].setdefault('hostvars', OrderedDict())
for host in obj.hosts.filter(**hosts_q):
data['_meta']['hostvars'][host.name] = host.variables_dict
return Response(data)
hosts_q = dict(name=hostname)
if not show_all:
hosts_q['enabled'] = True
host = get_object_or_404(obj.hosts, **hosts_q)
return Response(host.variables_dict)
return Response(obj.get_script_data(
hostvars=bool(request.query_params.get('hostvars', '')),
show_all=show_all
))
class InventoryTreeView(RetrieveAPIView):
@@ -2495,9 +2482,9 @@ class InventoryInventorySourcesUpdate(RetrieveAPIView):
view_name = _('Inventory Sources Update')
model = Inventory
obj_permission_type = 'start'
serializer_class = InventorySourceUpdateSerializer
permission_classes = (InventoryInventorySourcesUpdatePermission,)
is_job_start = True
new_in_320 = True
def retrieve(self, request, *args, **kwargs):
@@ -2515,10 +2502,14 @@ class InventoryInventorySourcesUpdate(RetrieveAPIView):
successes = 0
failures = 0
for inventory_source in inventory.inventory_sources.exclude(source=''):
details = {'inventory_source': inventory_source.pk, 'status': None}
details = OrderedDict()
details['inventory_source'] = inventory_source.pk
details['status'] = None
if inventory_source.can_update:
update = inventory_source.update()
details.update(InventoryUpdateSerializer(update, context=self.get_serializer_context()).to_representation(update))
details['status'] = 'started'
details['inventory_update'] = inventory_source.update().id
details['inventory_update'] = update.id
successes += 1
else:
if not details.get('status'):
@@ -2647,8 +2638,8 @@ class InventorySourceUpdatesList(SubListAPIView):
class InventorySourceUpdateView(RetrieveAPIView):
model = InventorySource
obj_permission_type = 'start'
serializer_class = InventorySourceUpdateSerializer
is_job_start = True
new_in_14 = True
def post(self, request, *args, **kwargs):
@@ -2659,8 +2650,10 @@ class InventorySourceUpdateView(RetrieveAPIView):
return Response({}, status=status.HTTP_400_BAD_REQUEST)
else:
headers = {'Location': update.get_absolute_url(request=request)}
return Response(dict(inventory_update=update.id),
status=status.HTTP_202_ACCEPTED, headers=headers)
data = OrderedDict()
data['inventory_update'] = update.id
data.update(InventoryUpdateSerializer(update, context=self.get_serializer_context()).to_representation(update))
return Response(data, status=status.HTTP_202_ACCEPTED, headers=headers)
else:
return self.http_method_not_allowed(request, *args, **kwargs)
@@ -2681,8 +2674,8 @@ class InventoryUpdateDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
class InventoryUpdateCancel(RetrieveAPIView):
model = InventoryUpdate
obj_permission_type = 'cancel'
serializer_class = InventoryUpdateCancelSerializer
is_job_cancel = True
new_in_14 = True
def post(self, request, *args, **kwargs):
@@ -2711,7 +2704,7 @@ class JobTemplateList(ListCreateAPIView):
always_allow_superuser = False
capabilities_prefetch = [
'admin', 'execute',
{'copy': ['project.use', 'inventory.use', 'credential.use', 'vault_credential.use']}
{'copy': ['project.use', 'inventory.use']}
]
def post(self, request, *args, **kwargs):
@@ -2730,12 +2723,12 @@ class JobTemplateDetail(RetrieveUpdateDestroyAPIView):
always_allow_superuser = False
class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
class JobTemplateLaunch(RetrieveAPIView):
model = JobTemplate
obj_permission_type = 'start'
metadata_class = JobTypeMetadata
serializer_class = JobLaunchSerializer
is_job_start = True
always_allow_superuser = False
def update_raw_data(self, data):
@@ -2745,68 +2738,124 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
return data
extra_vars = data.pop('extra_vars', None) or {}
if obj:
for p in obj.passwords_needed_to_start:
data[p] = u''
needed_passwords = obj.passwords_needed_to_start
if needed_passwords:
data['credential_passwords'] = {}
for p in needed_passwords:
data['credential_passwords'][p] = u''
else:
data.pop('credential_passwords')
for v in obj.variables_needed_to_start:
extra_vars.setdefault(v, u'')
if extra_vars:
data['extra_vars'] = extra_vars
ask_for_vars_dict = obj._ask_for_vars_dict()
ask_for_vars_dict.pop('extra_vars')
if get_request_version(self.request) == 1: # TODO: remove in 3.3
ask_for_vars_dict.pop('extra_credentials')
for field in ask_for_vars_dict:
if not ask_for_vars_dict[field]:
modified_ask_mapping = JobTemplate.get_ask_mapping()
modified_ask_mapping.pop('extra_vars')
for field, ask_field_name in modified_ask_mapping.items():
if not getattr(obj, ask_field_name):
data.pop(field, None)
elif field == 'inventory' or field == 'credential':
elif field == 'inventory':
data[field] = getattrd(obj, "%s.%s" % (field, 'id'), None)
elif field == 'extra_credentials':
data[field] = [cred.id for cred in obj.extra_credentials.all()]
elif field == 'credentials':
data[field] = [cred.id for cred in obj.credentials.all()]
else:
data[field] = getattr(obj, field)
return data
def post(self, request, *args, **kwargs):
obj = self.get_object()
def modernize_launch_payload(self, data, obj):
'''
Steps to do simple translations of request data to support
old field structure to launch endpoint
TODO: delete this method with future API version changes
'''
ignored_fields = {}
modern_data = data.copy()
for fd in ('credential', 'vault_credential', 'inventory'):
id_fd = '{}_id'.format(fd)
if fd not in request.data and id_fd in request.data:
request.data[fd] = request.data[id_fd]
if fd not in modern_data and id_fd in modern_data:
modern_data[fd] = modern_data[id_fd]
if get_request_version(self.request) == 1 and 'extra_credentials' in request.data: # TODO: remove in 3.3
if hasattr(request.data, '_mutable') and not request.data._mutable:
request.data._mutable = True
extra_creds = request.data.pop('extra_credentials', None)
# This block causes `extra_credentials` to _always_ be ignored for
# the launch endpoint if we're accessing `/api/v1/`
if get_request_version(self.request) == 1 and 'extra_credentials' in modern_data:
extra_creds = modern_data.pop('extra_credentials', None)
if extra_creds is not None:
ignored_fields['extra_credentials'] = extra_creds
passwords = {}
serializer = self.serializer_class(instance=obj, data=request.data, context={'obj': obj, 'data': request.data, 'passwords': passwords})
# Automatically convert legacy launch credential arguments into a list of `.credentials`
if 'credentials' in modern_data and (
'credential' in modern_data or
'vault_credential' in modern_data or
'extra_credentials' in modern_data
):
raise ParseError({"error": _(
"'credentials' cannot be used in combination with 'credential', 'vault_credential', or 'extra_credentials'."
)})
if (
'credential' in modern_data or
'vault_credential' in modern_data or
'extra_credentials' in modern_data
):
# make a list of the current credentials
existing_credentials = obj.credentials.all()
new_credentials = []
for key, conditional in (
('credential', lambda cred: cred.credential_type.kind != 'ssh'),
('vault_credential', lambda cred: cred.credential_type.kind != 'vault'),
('extra_credentials', lambda cred: cred.credential_type.kind not in ('cloud', 'net'))
):
if key in modern_data:
# if a specific deprecated key is specified, remove all
# credentials of _that_ type from the list of current
# credentials
existing_credentials = filter(conditional, existing_credentials)
prompted_value = modern_data.pop(key)
# add the deprecated credential specified in the request
if not isinstance(prompted_value, Iterable) or isinstance(prompted_value, basestring):
prompted_value = [prompted_value]
# If user gave extra_credentials, special case to use exactly
# the given list without merging with JT credentials
if key == 'extra_credentials' and prompted_value:
obj._deprecated_credential_launch = True # signal to not merge credentials
new_credentials.extend(prompted_value)
# combine the list of "new" and the filtered list of "old"
new_credentials.extend([cred.pk for cred in existing_credentials])
if new_credentials:
modern_data['credentials'] = new_credentials
# credential passwords were historically provided as top-level attributes
if 'credential_passwords' not in modern_data:
modern_data['credential_passwords'] = data.copy()
return (modern_data, ignored_fields)
def post(self, request, *args, **kwargs):
obj = self.get_object()
try:
modern_data, ignored_fields = self.modernize_launch_payload(
data=request.data, obj=obj
)
except ParseError as exc:
return Response(exc.detail, status=status.HTTP_400_BAD_REQUEST)
serializer = self.serializer_class(data=modern_data, context={'template': obj})
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
_accepted_or_ignored = obj._accept_or_ignore_job_kwargs(**request.data)
prompted_fields = _accepted_or_ignored[0]
ignored_fields.update(_accepted_or_ignored[1])
ignored_fields.update(serializer._ignored_fields)
for fd, model in (
('credential', Credential),
('vault_credential', Credential),
('inventory', Inventory)):
if fd in prompted_fields and prompted_fields[fd] != getattrd(obj, '{}.pk'.format(fd), None):
new_res = get_object_or_400(model, pk=get_pk_from_dict(prompted_fields, fd))
use_role = getattr(new_res, 'use_role')
if request.user not in use_role:
raise PermissionDenied()
if not request.user.can_access(JobLaunchConfig, 'add', serializer.validated_data, template=obj):
raise PermissionDenied()
for cred in prompted_fields.get('extra_credentials', []):
new_credential = get_object_or_400(Credential, pk=cred)
if request.user not in new_credential.use_role:
raise PermissionDenied()
new_job = obj.create_unified_job(**prompted_fields)
passwords = serializer.validated_data.pop('credential_passwords', {})
new_job = obj.create_unified_job(**serializer.validated_data)
result = new_job.signal_start(**passwords)
if not result:
@@ -2815,12 +2864,36 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView):
return Response(data, status=status.HTTP_400_BAD_REQUEST)
else:
data = OrderedDict()
data['ignored_fields'] = ignored_fields
data.update(JobSerializer(new_job, context=self.get_serializer_context()).to_representation(new_job))
data['job'] = new_job.id
data['ignored_fields'] = self.sanitize_for_response(ignored_fields)
data.update(JobSerializer(new_job, context=self.get_serializer_context()).to_representation(new_job))
return Response(data, status=status.HTTP_201_CREATED)
def sanitize_for_response(self, data):
'''
Model objects cannot be serialized by DRF,
this replaces objects with their ids for inclusion in response
'''
def display_value(val):
if hasattr(val, 'id'):
return val.id
else:
return val
sanitized_data = {}
for field_name, value in data.items():
if isinstance(value, (set, list)):
sanitized_data[field_name] = []
for sub_value in value:
sanitized_data[field_name].append(display_value(sub_value))
else:
sanitized_data[field_name] = display_value(value)
return sanitized_data
class JobTemplateSchedulesList(SubListCreateAPIView):
view_name = _("Job Template Schedules")
@@ -2836,7 +2909,7 @@ class JobTemplateSchedulesList(SubListCreateAPIView):
class JobTemplateSurveySpec(GenericAPIView):
model = JobTemplate
parent_model = JobTemplate
obj_permission_type = 'admin'
serializer_class = EmptySerializer
new_in_210 = True
@@ -2923,7 +2996,6 @@ class JobTemplateSurveySpec(GenericAPIView):
class WorkflowJobTemplateSurveySpec(WorkflowsEnforcementMixin, JobTemplateSurveySpec):
model = WorkflowJobTemplate
parent_model = WorkflowJobTemplate
new_in_310 = True
@@ -2963,17 +3035,17 @@ class JobTemplateNotificationTemplatesSuccessList(SubListCreateAttachDetachAPIVi
new_in_300 = True
class JobTemplateExtraCredentialsList(SubListCreateAttachDetachAPIView):
class JobTemplateCredentialsList(SubListCreateAttachDetachAPIView):
model = Credential
serializer_class = CredentialSerializer
parent_model = JobTemplate
relationship = 'extra_credentials'
new_in_320 = True
relationship = 'credentials'
new_in_330 = True
new_in_api_v2 = True
def get_queryset(self):
# Return the full list of extra_credentials
# Return the full list of credentials
parent = self.get_parent_object()
self.check_parent_access(parent)
sublist_qs = getattrd(parent, self.relationship)
@@ -2984,15 +3056,29 @@ class JobTemplateExtraCredentialsList(SubListCreateAttachDetachAPIView):
return sublist_qs
def is_valid_relation(self, parent, sub, created=False):
current_extra_types = [
cred.credential_type.pk for cred in parent.extra_credentials.all()
]
if sub.credential_type.pk in current_extra_types:
return {'error': _('Cannot assign multiple %s credentials.' % sub.credential_type.name)}
if sub.unique_hash() in [cred.unique_hash() for cred in parent.credentials.all()]:
return {"error": _("Cannot assign multiple {credential_type} credentials.".format(
credential_type=sub.unique_hash(display=True)))}
if sub.credential_type.kind not in ('net', 'cloud'):
return super(JobTemplateCredentialsList, self).is_valid_relation(parent, sub, created)
class JobTemplateExtraCredentialsList(JobTemplateCredentialsList):
deprecated = True
new_in_320 = True
new_in_330 = False
def get_queryset(self):
sublist_qs = super(JobTemplateExtraCredentialsList, self).get_queryset()
sublist_qs = sublist_qs.filter(credential_type__kind__in=['cloud', 'net'])
return sublist_qs
def is_valid_relation(self, parent, sub, created=False):
valid = super(JobTemplateExtraCredentialsList, self).is_valid_relation(parent, sub, created)
if sub.credential_type.kind not in ('cloud', 'net'):
return {'error': _('Extra credentials must be network or cloud.')}
return super(JobTemplateExtraCredentialsList, self).is_valid_relation(parent, sub, created)
return valid
class JobTemplateLabelList(DeleteLastUnattachLabelMixin, SubListCreateAttachDetachAPIView):
@@ -3085,6 +3171,8 @@ class JobTemplateCallback(GenericAPIView):
matches.update(host_mappings[host_name])
except socket.gaierror:
pass
except UnicodeError:
pass
return matches
def get(self, request, *args, **kwargs):
@@ -3154,7 +3242,8 @@ class JobTemplateCallback(GenericAPIView):
# Everything is fine; actually create the job.
kv = {"limit": limit, "launch_type": 'callback'}
if extra_vars is not None and job_template.ask_variables_on_launch:
kv['extra_vars'] = callback_filter_out_ansible_extra_vars(extra_vars)
extra_vars_redacted, removed = extract_ansible_vars(extra_vars)
kv['extra_vars'] = extra_vars_redacted
with transaction.atomic():
job = job_template.create_job(**kv)
@@ -3221,10 +3310,20 @@ class WorkflowJobNodeDetail(WorkflowsEnforcementMixin, RetrieveAPIView):
new_in_310 = True
class WorkflowJobNodeCredentialsList(SubListAPIView):
model = Credential
serializer_class = CredentialSerializer
parent_model = WorkflowJobNode
relationship = 'credentials'
new_in_330 = True
new_in_api_v2 = True
class WorkflowJobTemplateNodeList(WorkflowsEnforcementMixin, ListCreateAPIView):
model = WorkflowJobTemplateNode
serializer_class = WorkflowJobTemplateNodeListSerializer
serializer_class = WorkflowJobTemplateNodeSerializer
new_in_310 = True
@@ -3234,21 +3333,18 @@ class WorkflowJobTemplateNodeDetail(WorkflowsEnforcementMixin, RetrieveUpdateDes
serializer_class = WorkflowJobTemplateNodeDetailSerializer
new_in_310 = True
def update_raw_data(self, data):
for fd in ['job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags']:
data[fd] = None
try:
obj = self.get_object()
data.update(obj.char_prompts)
except:
pass
return super(WorkflowJobTemplateNodeDetail, self).update_raw_data(data)
class WorkflowJobTemplateNodeCredentialsList(LaunchConfigCredentialsBase):
parent_model = WorkflowJobTemplateNode
new_in_330 = True
new_in_api_v2 = True
class WorkflowJobTemplateNodeChildrenBaseList(WorkflowsEnforcementMixin, EnforceParentRelationshipMixin, SubListCreateAttachDetachAPIView):
model = WorkflowJobTemplateNode
serializer_class = WorkflowJobTemplateNodeListSerializer
serializer_class = WorkflowJobTemplateNodeSerializer
always_allow_superuser = True
parent_model = WorkflowJobTemplateNode
relationship = ''
@@ -3366,7 +3462,6 @@ class WorkflowJobTemplateDetail(WorkflowsEnforcementMixin, RetrieveUpdateDestroy
class WorkflowJobTemplateCopy(WorkflowsEnforcementMixin, GenericAPIView):
model = WorkflowJobTemplate
parent_model = WorkflowJobTemplate
serializer_class = EmptySerializer
new_in_310 = True
@@ -3406,9 +3501,9 @@ class WorkflowJobTemplateLaunch(WorkflowsEnforcementMixin, RetrieveAPIView):
model = WorkflowJobTemplate
obj_permission_type = 'start'
serializer_class = WorkflowJobLaunchSerializer
new_in_310 = True
is_job_start = True
always_allow_superuser = False
def update_raw_data(self, data):
@@ -3426,30 +3521,28 @@ class WorkflowJobTemplateLaunch(WorkflowsEnforcementMixin, RetrieveAPIView):
def post(self, request, *args, **kwargs):
obj = self.get_object()
if not request.user.can_access(self.model, 'start', obj):
raise PermissionDenied()
serializer = self.serializer_class(instance=obj, data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
prompted_fields, ignored_fields = obj._accept_or_ignore_job_kwargs(**request.data)
prompted_fields, ignored_fields, errors = obj._accept_or_ignore_job_kwargs(**request.data)
new_job = obj.create_unified_job(**prompted_fields)
new_job.signal_start()
data = OrderedDict()
data['workflow_job'] = new_job.id
data['ignored_fields'] = ignored_fields
data.update(WorkflowJobSerializer(new_job, context=self.get_serializer_context()).to_representation(new_job))
data['workflow_job'] = new_job.id
return Response(data, status=status.HTTP_201_CREATED)
class WorkflowJobRelaunch(WorkflowsEnforcementMixin, GenericAPIView):
model = WorkflowJob
obj_permission_type = 'start'
serializer_class = EmptySerializer
is_job_start = True
new_in_310 = True
def check_object_permissions(self, request, obj):
@@ -3475,17 +3568,12 @@ class WorkflowJobRelaunch(WorkflowsEnforcementMixin, GenericAPIView):
class WorkflowJobTemplateWorkflowNodesList(WorkflowsEnforcementMixin, SubListCreateAPIView):
model = WorkflowJobTemplateNode
serializer_class = WorkflowJobTemplateNodeListSerializer
serializer_class = WorkflowJobTemplateNodeSerializer
parent_model = WorkflowJobTemplate
relationship = 'workflow_job_template_nodes'
parent_key = 'workflow_job_template'
new_in_310 = True
def update_raw_data(self, data):
for fd in ['job_type', 'job_tags', 'skip_tags', 'limit', 'skip_tags']:
data[fd] = None
return super(WorkflowJobTemplateWorkflowNodesList, self).update_raw_data(data)
def get_queryset(self):
return super(WorkflowJobTemplateWorkflowNodesList, self).get_queryset().order_by('id')
@@ -3606,8 +3694,8 @@ class WorkflowJobWorkflowNodesList(WorkflowsEnforcementMixin, SubListAPIView):
class WorkflowJobCancel(WorkflowsEnforcementMixin, RetrieveAPIView):
model = WorkflowJob
obj_permission_type = 'cancel'
serializer_class = WorkflowJobCancelSerializer
is_job_cancel = True
new_in_310 = True
def post(self, request, *args, **kwargs):
@@ -3661,8 +3749,8 @@ class SystemJobTemplateDetail(RetrieveAPIView):
class SystemJobTemplateLaunch(GenericAPIView):
model = SystemJobTemplate
obj_permission_type = 'start'
serializer_class = EmptySerializer
is_job_start = True
new_in_210 = True
def get(self, request, *args, **kwargs):
@@ -3673,7 +3761,9 @@ class SystemJobTemplateLaunch(GenericAPIView):
new_job = obj.create_unified_job(extra_vars=request.data.get('extra_vars', {}))
new_job.signal_start()
data = dict(system_job=new_job.id)
data = OrderedDict()
data['system_job'] = new_job.id
data.update(SystemJobSerializer(new_job, context=self.get_serializer_context()).to_representation(new_job))
return Response(data, status=status.HTTP_201_CREATED)
@@ -3739,6 +3829,13 @@ class JobList(ListCreateAPIView):
methods.remove('POST')
return methods
# NOTE: Remove in 3.3, switch ListCreateAPIView to ListAPIView
def post(self, request, *args, **kwargs):
if get_request_version(self.request) > 1:
return Response({"error": _("POST not allowed for Job launching in version 2 of the api")},
status=status.HTTP_405_METHOD_NOT_ALLOWED)
return super(JobList, self).post(request, *args, **kwargs)
class JobDetail(UnifiedJobDeletionMixin, RetrieveUpdateDestroyAPIView):
@@ -3754,14 +3851,26 @@ class JobDetail(UnifiedJobDeletionMixin, RetrieveUpdateDestroyAPIView):
return super(JobDetail, self).update(request, *args, **kwargs)
class JobExtraCredentialsList(SubListAPIView):
class JobCredentialsList(SubListAPIView):
model = Credential
serializer_class = CredentialSerializer
parent_model = Job
relationship = 'extra_credentials'
new_in_320 = True
relationship = 'credentials'
new_in_api_v2 = True
new_in_330 = True
class JobExtraCredentialsList(JobCredentialsList):
deprecated = True
new_in_320 = True
new_in_330 = False
def get_queryset(self):
sublist_qs = super(JobExtraCredentialsList, self).get_queryset()
sublist_qs = sublist_qs.filter(credential_type__kind__in=['cloud', 'net'])
return sublist_qs
class JobLabelList(SubListAPIView):
@@ -3788,14 +3897,21 @@ class JobActivityStreamList(ActivityStreamEnforcementMixin, SubListAPIView):
new_in_145 = True
# TODO: remove endpoint in 3.3
class JobStart(GenericAPIView):
model = Job
obj_permission_type = 'start'
serializer_class = EmptySerializer
is_job_start = True
deprecated = True
def v2_not_allowed(self):
return Response({'detail': 'Action only possible through v1 API.'},
status=status.HTTP_404_NOT_FOUND)
def get(self, request, *args, **kwargs):
if get_request_version(request) > 1:
return self.v2_not_allowed()
obj = self.get_object()
data = dict(
can_start=obj.can_start,
@@ -3806,6 +3922,8 @@ class JobStart(GenericAPIView):
return Response(data)
def post(self, request, *args, **kwargs):
if get_request_version(request) > 1:
return self.v2_not_allowed()
obj = self.get_object()
if obj.can_start:
result = obj.signal_start(**request.data)
@@ -3821,8 +3939,8 @@ class JobStart(GenericAPIView):
class JobCancel(RetrieveAPIView):
model = Job
obj_permission_type = 'cancel'
serializer_class = JobCancelSerializer
is_job_cancel = True
def post(self, request, *args, **kwargs):
obj = self.get_object()
@@ -3833,11 +3951,11 @@ class JobCancel(RetrieveAPIView):
return self.http_method_not_allowed(request, *args, **kwargs)
class JobRelaunch(RetrieveAPIView, GenericAPIView):
class JobRelaunch(RetrieveAPIView):
model = Job
obj_permission_type = 'start'
serializer_class = JobRelaunchSerializer
is_job_start = True
@csrf_exempt
@transaction.non_atomic_requests
@@ -3860,7 +3978,26 @@ class JobRelaunch(RetrieveAPIView, GenericAPIView):
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
new_job = obj.copy_unified_job()
copy_kwargs = {}
retry_hosts = request.data.get('hosts', None)
if retry_hosts and retry_hosts != 'all':
if obj.status in ACTIVE_STATES:
return Response({'hosts': _(
'Wait until job finishes before retrying on {status_value} hosts.'
).format(status_value=retry_hosts)}, status=status.HTTP_400_BAD_REQUEST)
host_qs = obj.retry_qs(retry_hosts)
if not obj.job_events.filter(event='playbook_on_stats').exists():
return Response({'hosts': _(
'Cannot retry on {status_value} hosts, playbook stats not available.'
).format(status_value=retry_hosts)}, status=status.HTTP_400_BAD_REQUEST)
retry_host_list = host_qs.values_list('name', flat=True)
if len(retry_host_list) == 0:
return Response({'hosts': _(
'Cannot relaunch because previous job had 0 {status_value} hosts.'
).format(status_value=retry_hosts)}, status=status.HTTP_400_BAD_REQUEST)
copy_kwargs['limit'] = ','.join(retry_host_list)
new_job = obj.copy_unified_job(**copy_kwargs)
result = new_job.signal_start(**request.data)
if not result:
data = dict(passwords_needed_to_start=new_job.passwords_needed_to_start)
@@ -3873,6 +4010,52 @@ class JobRelaunch(RetrieveAPIView, GenericAPIView):
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
class JobCreateSchedule(RetrieveAPIView):
model = Job
obj_permission_type = 'start'
serializer_class = JobCreateScheduleSerializer
new_in_330 = True
def post(self, request, *args, **kwargs):
obj = self.get_object()
if not obj.can_schedule:
return Response({"error": _('Information needed to schedule this job is missing.')},
status=status.HTTP_400_BAD_REQUEST)
config = obj.launch_config
if not request.user.can_access(JobLaunchConfig, 'add', {'reference_obj': obj}):
raise PermissionDenied()
# Make up a name for the schedule, guarentee that it is unique
name = 'Auto-generated schedule from job {}'.format(obj.id)
existing_names = Schedule.objects.filter(name__startswith=name).values_list('name', flat=True)
if name in existing_names:
idx = 1
alt_name = '{} - number {}'.format(name, idx)
while alt_name in existing_names:
idx += 1
alt_name = '{} - number {}'.format(name, idx)
name = alt_name
schedule = Schedule.objects.create(
name=name,
unified_job_template=obj.unified_job_template,
enabled=False,
rrule='{}Z RRULE:FREQ=MONTHLY;INTERVAL=1'.format(now().strftime('DTSTART:%Y%m%dT%H%M%S')),
extra_data=config.extra_data,
survey_passwords=config.survey_passwords,
inventory=config.inventory,
char_prompts=config.char_prompts
)
schedule.credentials.add(*config.credentials.all())
data = ScheduleSerializer(schedule, context=self.get_serializer_context()).data
headers = {'Location': schedule.get_absolute_url(request=request)}
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
class JobNotificationsList(SubListAPIView):
model = Notification
@@ -4077,8 +4260,8 @@ class AdHocCommandDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
class AdHocCommandCancel(RetrieveAPIView):
model = AdHocCommand
obj_permission_type = 'cancel'
serializer_class = AdHocCommandCancelSerializer
is_job_cancel = True
new_in_220 = True
def post(self, request, *args, **kwargs):
@@ -4093,8 +4276,8 @@ class AdHocCommandCancel(RetrieveAPIView):
class AdHocCommandRelaunch(GenericAPIView):
model = AdHocCommand
obj_permission_type = 'start'
serializer_class = AdHocCommandRelaunchSerializer
is_job_start = True
new_in_220 = True
# FIXME: Figure out why OPTIONS request still shows all fields.
@@ -4228,8 +4411,8 @@ class SystemJobDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
class SystemJobCancel(RetrieveAPIView):
model = SystemJob
obj_permission_type = 'cancel'
serializer_class = SystemJobCancelSerializer
is_job_cancel = True
new_in_210 = True
def post(self, request, *args, **kwargs):
@@ -4258,7 +4441,6 @@ class UnifiedJobTemplateList(ListAPIView):
capabilities_prefetch = [
'admin', 'execute',
{'copy': ['jobtemplate.project.use', 'jobtemplate.inventory.use',
'jobtemplate.credential.use', 'jobtemplate.vault_credential.use',
'workflowjobtemplate.organization.admin']}
]
@@ -4450,9 +4632,9 @@ class NotificationTemplateTest(GenericAPIView):
view_name = _('Notification Template Test')
model = NotificationTemplate
obj_permission_type = 'start'
serializer_class = EmptySerializer
new_in_300 = True
is_job_start = True
def post(self, request, *args, **kwargs):
obj = self.get_object()
@@ -4462,8 +4644,11 @@ class NotificationTemplateTest(GenericAPIView):
return Response({}, status=status.HTTP_400_BAD_REQUEST)
else:
send_notifications.delay([notification.id])
data = OrderedDict()
data['notification'] = notification.id
data.update(NotificationSerializer(notification, context=self.get_serializer_context()).to_representation(notification))
headers = {'Location': notification.get_absolute_url(request=request)}
return Response({"notification": notification.id},
return Response(data,
headers=headers,
status=status.HTTP_202_ACCEPTED)

23
awx/celery.py Normal file
View File

@@ -0,0 +1,23 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
try:
import awx.devonly # noqa
MODE = 'development'
except ImportError: # pragma: no cover
MODE = 'production'
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'awx.settings.%s' % MODE)
app = Celery('awx')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
if __name__ == '__main__':
app.start()

View File

@@ -53,6 +53,47 @@ class StringListField(ListField):
return super(StringListField, self).to_representation(value)
class StringListBooleanField(ListField):
default_error_messages = {
'type_error': _('Expected None, True, False, a string or list of strings but got {input_type} instead.'),
}
child = CharField()
def to_representation(self, value):
try:
if isinstance(value, (list, tuple)):
return super(StringListBooleanField, self).to_representation(value)
elif value in NullBooleanField.TRUE_VALUES:
return True
elif value in NullBooleanField.FALSE_VALUES:
return False
elif value in NullBooleanField.NULL_VALUES:
return None
elif isinstance(value, basestring):
return self.child.to_representation(value)
except TypeError:
pass
self.fail('type_error', input_type=type(value))
def to_internal_value(self, data):
try:
if isinstance(data, (list, tuple)):
return super(StringListBooleanField, self).to_internal_value(data)
elif data in NullBooleanField.TRUE_VALUES:
return True
elif data in NullBooleanField.FALSE_VALUES:
return False
elif data in NullBooleanField.NULL_VALUES:
return None
elif isinstance(data, basestring):
return self.child.run_validation(data)
except TypeError:
pass
self.fail('type_error', input_type=type(data))
class URLField(CharField):
def __init__(self, **kwargs):
@@ -83,7 +124,7 @@ class URLField(CharField):
else:
netloc = '{}@{}' % (url_parts.username, netloc)
value = urlparse.urlunsplit([url_parts.scheme, netloc, url_parts.path, url_parts.query, url_parts.fragment])
except:
except Exception:
raise # If something fails here, just fall through and let the validators check it.
super(URLField, self).run_validators(value)
@@ -100,3 +141,25 @@ class KeyValueField(DictField):
if not isinstance(value, six.string_types + six.integer_types + (float,)):
self.fail('invalid_child', input=value)
return ret
class ListTuplesField(ListField):
default_error_messages = {
'type_error': _('Expected a list of tuples of max length 2 but got {input_type} instead.'),
}
def to_representation(self, value):
if isinstance(value, (list, tuple)):
return super(ListTuplesField, self).to_representation(value)
else:
self.fail('type_error', input_type=type(value))
def to_internal_value(self, data):
if isinstance(data, list):
for x in data:
if not isinstance(x, (list, tuple)) or len(x) > 2:
self.fail('type_error', input_type=type(x))
return super(ListTuplesField, self).to_internal_value(data)
else:
self.fail('type_error', input_type=type(data))

View File

@@ -2,6 +2,8 @@
# 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
@@ -9,6 +11,7 @@ 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']
@@ -23,6 +26,13 @@ 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()
@@ -40,6 +50,7 @@ def get_licensed_features():
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()

View File

@@ -54,6 +54,13 @@ class Command(BaseCommand):
default=False,
help=_('Skip commenting out settings in files.'),
)
parser.add_argument(
'--comment-only',
action='store_true',
dest='comment_only',
default=False,
help=_('Skip migrating and only comment out settings in files.'),
)
parser.add_argument(
'--backup-suffix',
dest='backup_suffix',
@@ -67,6 +74,7 @@ class Command(BaseCommand):
self.dry_run = bool(options.get('dry_run', False))
self.skip_errors = bool(options.get('skip_errors', False))
self.no_comment = bool(options.get('no_comment', False))
self.comment_only = bool(options.get('comment_only', False))
self.backup_suffix = options.get('backup_suffix', '')
self.categories = options.get('category', None) or ['all']
self.style.HEADING = self.style.MIGRATE_HEADING
@@ -103,7 +111,7 @@ class Command(BaseCommand):
def _get_settings_file_patterns(self):
if MODE == 'development':
return [
'/etc/tower/settings.py',
'/etc/tower/settings.py',
'/etc/tower/conf.d/*.py',
os.path.join(os.path.dirname(__file__), '..', '..', '..', 'settings', 'local_*.py')
]
@@ -360,14 +368,15 @@ class Command(BaseCommand):
if filename:
self._display_diff_summary(filename, lines_added, lines_removed)
def _migrate_settings(self, registered_settings):
patterns = self._get_settings_file_patterns()
# Determine which settings need to be commented/migrated.
def _discover_settings(self, registered_settings):
if self.verbosity >= 1:
self.stdout.write(self.style.HEADING('Discovering settings to be migrated and commented:'))
# Determine which settings need to be commented/migrated.
to_migrate = collections.OrderedDict()
to_comment = collections.OrderedDict()
patterns = self._get_settings_file_patterns()
for name in registered_settings:
comment_error, migrate_error = None, None
files_to_comment = []
@@ -398,8 +407,9 @@ class Command(BaseCommand):
self._display_tbd(name, files_to_comment, migrate_value, comment_error, migrate_error)
if self.verbosity == 1 and not to_migrate and not to_comment:
self.stdout.write(' No settings found to migrate or comment!')
return (to_migrate, to_comment)
# Now migrate those settings to the database.
def _migrate(self, to_migrate):
if self.verbosity >= 1:
if self.dry_run:
self.stdout.write(self.style.HEADING('Migrating settings to database (dry-run):'))
@@ -407,6 +417,8 @@ class Command(BaseCommand):
self.stdout.write(self.style.HEADING('Migrating settings to database:'))
if not to_migrate:
self.stdout.write(' No settings to migrate!')
# Now migrate those settings to the database.
for name, db_value in to_migrate.items():
display_value = json.dumps(db_value, indent=4)
setting = Setting.objects.filter(key=name, user__isnull=True).order_by('pk').first()
@@ -422,7 +434,7 @@ class Command(BaseCommand):
setting.save(update_fields=['value'])
self._display_migrate(name, action, display_value)
# Now comment settings in settings files.
def _comment(self, to_comment):
if self.verbosity >= 1:
if bool(self.dry_run or self.no_comment):
self.stdout.write(self.style.HEADING('Commenting settings in files (dry-run):'))
@@ -430,6 +442,8 @@ class Command(BaseCommand):
self.stdout.write(self.style.HEADING('Commenting settings in files:'))
if not to_comment:
self.stdout.write(' No settings to comment!')
# Now comment settings in settings files.
if to_comment:
to_comment_patterns = []
license_file_to_comment = None
@@ -457,3 +471,10 @@ class Command(BaseCommand):
if custom_logo_file_to_comment:
diffs.extend(self._comment_custom_logo_file(dry_run=False))
self._display_comment(diffs)
def _migrate_settings(self, registered_settings):
to_migrate, to_comment = self._discover_settings(registered_settings)
if not bool(self.comment_only):
self._migrate(to_migrate)
self._comment(to_comment)

View File

@@ -74,6 +74,10 @@ class Setting(CreatedModifiedModel):
def get_cache_key(self, key):
return key
@classmethod
def get_cache_id_key(self, key):
return '{}_ID'.format(key)
import awx.conf.signals # noqa

View File

@@ -159,14 +159,14 @@ class SettingsRegistry(object):
if category_slug == 'user' and for_user:
try:
field_instance.default = original_field_instance.to_representation(getattr(self.settings, setting))
except:
except Exception:
logger.warning('Unable to retrieve default value for user setting "%s".', setting, exc_info=True)
elif not field_instance.read_only or field_instance.default is empty or field_instance.defined_in_file:
try:
field_instance.default = original_field_instance.to_representation(self.settings._awx_conf_settings._get_default(setting))
except AttributeError:
pass
except:
except Exception:
logger.warning('Unable to retrieve default value for setting "%s".', setting, exc_info=True)
# `PENDO_TRACKING_STATE` is disabled for the open source awx license

View File

@@ -16,7 +16,7 @@ class SettingSerializer(BaseSerializer):
class Meta:
model = Setting
fields = ('id', 'key', 'value')
readonly_fields = ('id', 'key', 'value')
read_only_fields = ('id', 'key', 'value')
def __init__(self, instance=None, data=serializers.empty, **kwargs):
if instance is None and data is not serializers.empty and 'key' in data:

View File

@@ -9,6 +9,7 @@ import time
import six
# Django
from django.conf import LazySettings
from django.conf import settings, UserSettingsHolder
from django.core.cache import cache as django_cache
from django.core.exceptions import ImproperlyConfigured
@@ -69,6 +70,12 @@ def _log_database_error():
pass
def filter_sensitive(registry, key, value):
if registry.is_setting_encrypted(key):
return '$encrypted$'
return value
class EncryptedCacheProxy(object):
def __init__(self, cache, registry, encrypter=None, decrypter=None):
@@ -105,9 +112,13 @@ class EncryptedCacheProxy(object):
six.text_type(value)
except UnicodeDecodeError:
value = value.decode('utf-8')
logger.debug('cache get(%r, %r) -> %r', key, empty, filter_sensitive(self.registry, key, value))
return value
def set(self, key, value, **kwargs):
def set(self, key, value, log=True, **kwargs):
if log is True:
logger.debug('cache set(%r, %r, %r)', key, filter_sensitive(self.registry, key, value),
SETTING_CACHE_TIMEOUT)
self.cache.set(
key,
self._handle_encryption(self.encrypter, key, value),
@@ -115,8 +126,13 @@ class EncryptedCacheProxy(object):
)
def set_many(self, data, **kwargs):
filtered_data = dict(
(key, filter_sensitive(self.registry, key, value))
for key, value in data.items()
)
logger.debug('cache set_many(%r, %r)', filtered_data, SETTING_CACHE_TIMEOUT)
for key, value in data.items():
self.set(key, value, **kwargs)
self.set(key, value, log=False, **kwargs)
def _handle_encryption(self, method, key, value):
TransientSetting = namedtuple('TransientSetting', ['pk', 'value'])
@@ -124,9 +140,16 @@ class EncryptedCacheProxy(object):
if value is not empty and self.registry.is_setting_encrypted(key):
# If the setting exists in the database, we'll use its primary key
# as part of the AES key when encrypting/decrypting
obj_id = self.cache.get(Setting.get_cache_id_key(key), default=empty)
if obj_id is empty:
logger.info('Efficiency notice: Corresponding id not stored in cache %s',
Setting.get_cache_id_key(key))
obj_id = getattr(self._get_setting_from_db(key), 'pk', None)
elif obj_id == SETTING_CACHE_NONE:
obj_id = None
return method(
TransientSetting(
pk=getattr(self._get_setting_from_db(key), 'pk', None),
pk=obj_id,
value=value
),
'value'
@@ -241,11 +264,13 @@ class SettingsWrapper(UserSettingsHolder):
# to indicate from the cache that the setting is not configured without
# a database lookup.
settings_to_cache = get_settings_to_cache(self.registry)
setting_ids = {}
# Load all settings defined in the database.
for setting in Setting.objects.filter(key__in=settings_to_cache.keys(), user__isnull=True).order_by('pk'):
if settings_to_cache[setting.key] != SETTING_CACHE_NOTSET:
continue
if self.registry.is_setting_encrypted(setting.key):
setting_ids[setting.key] = setting.id
try:
value = decrypt_field(setting, 'value')
except ValueError, e:
@@ -264,12 +289,18 @@ class SettingsWrapper(UserSettingsHolder):
field = self.registry.get_setting_field(key)
try:
settings_to_cache[key] = get_cache_value(field.get_default())
if self.registry.is_setting_encrypted(key):
# No database pk, so None will be passed to encryption algorithm
setting_ids[key] = SETTING_CACHE_NOTSET
except SkipField:
pass
# Generate a cache key for each setting and store them all at once.
settings_to_cache = dict([(Setting.get_cache_key(k), v) for k, v in settings_to_cache.items()])
for k, id_val in setting_ids.items():
logger.debug('Saving id in cache for encrypted setting %s, %s',
Setting.get_cache_id_key(k), id_val)
self.cache.cache.set(Setting.get_cache_id_key(k), id_val)
settings_to_cache['_awx_conf_preload_expires'] = self._awx_conf_preload_expires
logger.debug('cache set_many(%r, %r)', settings_to_cache, SETTING_CACHE_TIMEOUT)
self.cache.set_many(settings_to_cache, timeout=SETTING_CACHE_TIMEOUT)
def _get_local(self, name):
@@ -279,7 +310,6 @@ class SettingsWrapper(UserSettingsHolder):
cache_value = self.cache.get(cache_key, default=empty)
except ValueError:
cache_value = empty
logger.debug('cache get(%r, %r) -> %r', cache_key, empty, cache_value)
if cache_value == SETTING_CACHE_NOTSET:
value = empty
elif cache_value == SETTING_CACHE_NONE:
@@ -293,6 +323,7 @@ class SettingsWrapper(UserSettingsHolder):
field = self.registry.get_setting_field(name)
if value is empty:
setting = None
setting_id = None
if not field.read_only or name in (
# these two values are read-only - however - we *do* want
# to fetch their value from the database
@@ -303,6 +334,7 @@ class SettingsWrapper(UserSettingsHolder):
if setting:
if getattr(field, 'encrypted', False):
value = decrypt_field(setting, 'value')
setting_id = setting.id
else:
value = setting.value
else:
@@ -310,15 +342,17 @@ class SettingsWrapper(UserSettingsHolder):
if SETTING_CACHE_DEFAULTS:
try:
value = field.get_default()
if getattr(field, 'encrypted', False):
setting_id = SETTING_CACHE_NONE
except SkipField:
pass
# If None implies not set, convert when reading the value.
if value is None and SETTING_CACHE_NOTSET == SETTING_CACHE_NONE:
value = SETTING_CACHE_NOTSET
if cache_value != value:
logger.debug('cache set(%r, %r, %r)', cache_key,
get_cache_value(value),
SETTING_CACHE_TIMEOUT)
if setting_id:
logger.debug('Saving id in cache for encrypted setting %s', cache_key)
self.cache.cache.set(Setting.get_cache_id_key(cache_key), setting_id)
self.cache.set(cache_key, get_cache_value(value), timeout=SETTING_CACHE_TIMEOUT)
if value == SETTING_CACHE_NOTSET and not SETTING_CACHE_DEFAULTS:
try:
@@ -333,7 +367,7 @@ class SettingsWrapper(UserSettingsHolder):
return internal_value
else:
return field.run_validation(value)
except:
except Exception:
logger.warning(
'The current value "%r" for setting "%s" is invalid.',
value, name, exc_info=True)
@@ -425,3 +459,19 @@ class SettingsWrapper(UserSettingsHolder):
set_locally = Setting.objects.filter(key=setting, user__isnull=True).exists()
set_on_default = getattr(self.default_settings, 'is_overridden', lambda s: False)(setting)
return (set_locally or set_on_default)
def __getattr_without_cache__(self, name):
# Django 1.10 added an optimization to settings lookup:
# https://code.djangoproject.com/ticket/27625
# https://github.com/django/django/commit/c1b221a9b913315998a1bcec2f29a9361a74d1ac
# This change caches settings lookups on the __dict__ of the LazySettings
# object, which is not okay to do in an environment where settings can
# change in-process (the entire point of awx's custom settings implementation)
# This restores the original behavior that *does not* cache.
if self._wrapped is empty:
self._setup(name)
return getattr(self._wrapped, name)
LazySettings.__getattr__ = __getattr_without_cache__

View File

@@ -0,0 +1,43 @@
import pytest
from django.core.urlresolvers import resolve
from django.utils.six.moves.urllib.parse import urlparse
from django.contrib.auth.models import User
from rest_framework.test import (
APIRequestFactory,
force_authenticate,
)
@pytest.fixture
def normal_user():
try:
user = User.objects.get(username='conf-normal')
except User.DoesNotExist:
user = User(username='conf-normal', is_superuser=False, password='conf-normal')
user.save()
return user
@pytest.fixture
def admin():
try:
user = User.objects.get(username='conf-admin')
except User.DoesNotExist:
user = User(username='conf-admin', is_superuser=True, password='conf-admin')
user.save()
return user
@pytest.fixture
def api_request(admin):
def rf(verb, url, data=None, user=admin):
view, view_args, view_kwargs = resolve(urlparse(url)[2])
request = getattr(APIRequestFactory(), verb)(url, data=data, format='json')
if user:
force_authenticate(request, user=user)
response = view(request, *view_args, **view_kwargs)
response.render()
return response
return rf

View File

@@ -0,0 +1,350 @@
import pytest
import mock
from rest_framework import serializers
from awx.api.versioning import reverse
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
@pytest.fixture
def dummy_setting():
class context_manager(object):
def __init__(self, name, **kwargs):
self.name = name
self.kwargs = kwargs
def __enter__(self):
settings_registry.register(self.name, **(self.kwargs))
def __exit__(self, *args):
settings_registry.unregister(self.name)
return context_manager
@pytest.fixture
def dummy_validate():
class context_manager(object):
def __init__(self, category_slug, func):
self.category_slug = category_slug
self.func = func
def __enter__(self):
settings_registry.register_validate(self.category_slug, self.func)
def __exit__(self, *args):
settings_registry.unregister_validate(self.category_slug)
return context_manager
@pytest.mark.django_db
def test_non_admin_user_does_not_see_categories(api_request, dummy_setting, normal_user):
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'})
)
assert response.data['results']
response = api_request(
'get',
reverse('api:setting_category_list',
kwargs={'version': 'v2'}),
user=normal_user
)
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(
'FOO_BAR_1',
field_class=fields.IntegerField,
category='FooBar',
category_slug='foobar'
), dummy_setting(
'FOO_BAR_2',
field_class=fields.IntegerField,
category='FooBar',
category_slug='foobar'
):
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.status_code == 200
assert 'FOO_BAR_1' in response.data and response.data['FOO_BAR_1'] is None
assert 'FOO_BAR_2' in response.data and response.data['FOO_BAR_2'] is None
@pytest.mark.django_db
def test_setting_singleton_detail_invalid_retrieve(api_request, dummy_setting, normal_user):
with dummy_setting(
'FOO_BAR_1',
field_class=fields.IntegerField,
category='FooBar',
category_slug='foobar'
), dummy_setting(
'FOO_BAR_2',
field_class=fields.IntegerField,
category='FooBar',
category_slug='foobar'
):
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'barfoo'})
)
assert response.status_code == 404
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}),
user = normal_user
)
assert response.status_code == 403
@pytest.mark.django_db
def test_setting_signleton_retrieve_hierachy(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
default=0,
category='FooBar',
category_slug='foobar'
):
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == 0
s = Setting(key='FOO_BAR', value=1)
s.save()
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == 1
@pytest.mark.django_db
def test_setting_signleton_retrieve_readonly(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
read_only=True,
default=2,
category='FooBar',
category_slug='foobar'
):
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == 2
@pytest.mark.django_db
def test_setting_singleton_update(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
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': 3}
)
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == 3
api_request(
'patch',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}),
data={'FOO_BAR': 4}
)
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == 4
@pytest.mark.django_db
def test_setting_singleton_update_dont_change_readonly_fields(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
read_only=True,
default=4,
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': 5}
)
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == 4
@pytest.mark.django_db
def test_setting_singleton_update_dont_change_encripted_mark(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.CharField,
encrypted=True,
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': 'password'}
)
assert Setting.objects.get(key='FOO_BAR').value.startswith('$encrypted$')
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == '$encrypted$'
api_request(
'patch',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}),
data={'FOO_BAR': '$encrypted$'}
)
assert decrypt_field(Setting.objects.get(key='FOO_BAR'), 'value') == 'password'
api_request(
'patch',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}),
data={'FOO_BAR': 'new_pw'}
)
assert decrypt_field(Setting.objects.get(key='FOO_BAR'), 'value') == 'new_pw'
@pytest.mark.django_db
def test_setting_singleton_update_runs_custom_validate(api_request, dummy_setting, dummy_validate):
def func_raising_exception(serializer, attrs):
raise serializers.ValidationError('Error')
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
category='FooBar',
category_slug='foobar'
), dummy_validate(
'foobar', func_raising_exception
), mock.patch('awx.conf.views.handle_setting_changes'):
response = api_request(
'patch',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'}),
data={'FOO_BAR': 23}
)
assert response.status_code == 400
@pytest.mark.django_db
def test_setting_singleton_delete(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
category='FooBar',
category_slug='foobar'
), mock.patch('awx.conf.views.handle_setting_changes'):
api_request(
'delete',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert not response.data['FOO_BAR']
@pytest.mark.django_db
def test_setting_singleton_delete_no_read_only_fields(api_request, dummy_setting):
with dummy_setting(
'FOO_BAR',
field_class=fields.IntegerField,
read_only=True,
default=23,
category='FooBar',
category_slug='foobar'
), mock.patch('awx.conf.views.handle_setting_changes'):
api_request(
'delete',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
response = api_request(
'get',
reverse('api:setting_singleton_detail', kwargs={'category_slug': 'foobar'})
)
assert response.data['FOO_BAR'] == 23
@pytest.mark.django_db
def test_setting_logging_test(api_request):
with mock.patch('awx.conf.views.BaseHTTPSHandler.perform_test') as mock_func:
api_request(
'post',
reverse('api:setting_logging_test'),
data={'LOG_AGGREGATOR_HOST': 'http://foobar', 'LOG_AGGREGATOR_TYPE': 'logstash'}
)
test_arguments = mock_func.call_args[0][0]
assert test_arguments.LOG_AGGREGATOR_HOST == 'http://foobar'
assert test_arguments.LOG_AGGREGATOR_TYPE == 'logstash'
assert test_arguments.LOG_AGGREGATOR_LEVEL == 'DEBUG'

View File

@@ -0,0 +1,86 @@
import pytest
from rest_framework.fields import ValidationError
from awx.conf.fields import StringListBooleanField, ListTuplesField
class TestStringListBooleanField():
FIELD_VALUES = [
("hello", "hello"),
(("a", "b"), ["a", "b"]),
(["a", "b", 1, 3.13, "foo", "bar", "foobar"], ["a", "b", "1", "3.13", "foo", "bar", "foobar"]),
("True", True),
("TRUE", True),
("true", True),
(True, True),
("False", False),
("FALSE", False),
("false", False),
(False, False),
("", None),
("null", None),
("NULL", None),
]
FIELD_VALUES_INVALID = [
1.245,
{"a": "b"},
]
@pytest.mark.parametrize("value_in, value_known", FIELD_VALUES)
def test_to_internal_value_valid(self, value_in, value_known):
field = StringListBooleanField()
v = field.to_internal_value(value_in)
assert v == value_known
@pytest.mark.parametrize("value", FIELD_VALUES_INVALID)
def test_to_internal_value_invalid(self, value):
field = StringListBooleanField()
with pytest.raises(ValidationError) as e:
field.to_internal_value(value)
assert e.value.detail[0] == "Expected None, True, False, a string or list " \
"of strings but got {} instead.".format(type(value))
@pytest.mark.parametrize("value_in, value_known", FIELD_VALUES)
def test_to_representation_valid(self, value_in, value_known):
field = StringListBooleanField()
v = field.to_representation(value_in)
assert v == value_known
@pytest.mark.parametrize("value", FIELD_VALUES_INVALID)
def test_to_representation_invalid(self, value):
field = StringListBooleanField()
with pytest.raises(ValidationError) as e:
field.to_representation(value)
assert e.value.detail[0] == "Expected None, True, False, a string or list " \
"of strings but got {} instead.".format(type(value))
class TestListTuplesField():
FIELD_VALUES = [
([('a', 'b'), ('abc', '123')], [("a", "b"), ("abc", "123")]),
]
FIELD_VALUES_INVALID = [
("abc", type("abc")),
([('a', 'b', 'c'), ('abc', '123', '456')], type(('a',))),
(['a', 'b'], type('a')),
(123, type(123)),
]
@pytest.mark.parametrize("value_in, value_known", FIELD_VALUES)
def test_to_internal_value_valid(self, value_in, value_known):
field = ListTuplesField()
v = field.to_internal_value(value_in)
assert v == value_known
@pytest.mark.parametrize("value, t", FIELD_VALUES_INVALID)
def test_to_internal_value_invalid(self, value, t):
field = ListTuplesField()
with pytest.raises(ValidationError) as e:
field.to_internal_value(value)
assert e.value.detail[0] == "Expected a list of tuples of max length 2 " \
"but got {} instead.".format(t)

View File

@@ -264,7 +264,7 @@ def test_setting_from_db_with_unicode(settings, mocker, encrypted):
# this simulates a bug in python-memcached; see https://github.com/linsomniac/python-memcached/issues/79
value = six.u('Iñtërnâtiônàlizætiøn').encode('utf-8')
setting_from_db = mocker.Mock(key='AWX_SOME_SETTING', value=value)
setting_from_db = mocker.Mock(id=1, key='AWX_SOME_SETTING', value=value)
mocks = mocker.Mock(**{
'order_by.return_value': mocker.Mock(**{
'__iter__': lambda self: iter([setting_from_db]),
@@ -391,7 +391,20 @@ def test_charfield_properly_sets_none(settings, mocker):
)
def test_settings_use_an_encrypted_cache(settings):
def test_settings_use_cache(settings, mocker):
settings.registry.register(
'AWX_VAR',
field_class=fields.CharField,
category=_('System'),
category_slug='system'
)
settings.cache.set('AWX_VAR', 'foobar')
settings.cache.set('_awx_conf_preload_expires', 100)
# Will fail test if database is used
getattr(settings, 'AWX_VAR')
def test_settings_use_an_encrypted_cache(settings, mocker):
settings.registry.register(
'AWX_ENCRYPTED',
field_class=fields.CharField,
@@ -402,6 +415,11 @@ def test_settings_use_an_encrypted_cache(settings):
assert isinstance(settings.cache, EncryptedCacheProxy)
assert settings.cache.__dict__['encrypter'] == encrypt_field
assert settings.cache.__dict__['decrypter'] == decrypt_field
settings.cache.set('AWX_ENCRYPTED_ID', 402)
settings.cache.set('AWX_ENCRYPTED', 'foobar')
settings.cache.set('_awx_conf_preload_expires', 100)
# Will fail test if database is used
getattr(settings, 'AWX_ENCRYPTED')
def test_sensitive_cache_data_is_encrypted(settings, mocker):

View File

@@ -1,16 +1,17 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved.
# Django
from django.conf.urls import patterns
# Tower
from awx.api.urls import url
urlpatterns = patterns(
'awx.conf.views',
url(r'^$', 'setting_category_list'),
url(r'^(?P<category_slug>[a-z0-9-]+)/$', 'setting_singleton_detail'),
url(r'^logging/test/$', 'setting_logging_test'),
from django.conf.urls import url
from awx.conf.views import (
SettingCategoryList,
SettingSingletonDetail,
SettingLoggingTest,
)
urlpatterns = [
url(r'^$', SettingCategoryList.as_view(), name='setting_category_list'),
url(r'^(?P<category_slug>[a-z0-9-]+)/$', SettingSingletonDetail.as_view(), name='setting_singleton_detail'),
url(r'^logging/test/$', SettingLoggingTest.as_view(), name='setting_logging_test'),
]

View File

@@ -16,7 +16,7 @@ class argv_placeholder(object):
def __del__(self):
try:
argv_ready(sys.argv)
except:
except Exception:
pass

View File

@@ -1,3 +1,8 @@
# Copyright (c) 2017 Ansible by Red Hat
# All Rights Reserved
from __future__ import absolute_import
from collections import OrderedDict
import json
import mock
@@ -23,9 +28,9 @@ with mock.patch.dict(os.environ, {'ANSIBLE_STDOUT_CALLBACK': CALLBACK,
'ANSIBLE_CALLBACK_PLUGINS': PLUGINS}):
from ansible.cli.playbook import PlaybookCLI
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.inventory import Inventory
from ansible.inventory.manager import InventoryManager
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.vars.manager import VariableManager
# Add awx/lib to sys.path so we can use the plugin
path = os.path.abspath(os.path.join(PLUGINS, '..', '..'))
@@ -62,9 +67,8 @@ def executor(tmpdir_factory, request):
cli.parse()
options = cli.parser.parse_args(['-v'])[0]
loader = DataLoader()
variable_manager = VariableManager()
inventory = Inventory(loader=loader, variable_manager=variable_manager,
host_list=['localhost'])
variable_manager = VariableManager(loader=loader)
inventory = InventoryManager(loader=loader, sources='localhost,')
variable_manager.set_inventory(inventory)
return PlaybookExecutor(playbooks=playbook_files, inventory=inventory,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -70,14 +70,9 @@ register(
label=_('Remote Host Headers'),
help_text=_('HTTP headers and meta keys to search to determine remote host '
'name or IP. Add additional items to this list, such as '
'"HTTP_X_FORWARDED_FOR", if behind a reverse proxy.\n\n'
'Note: The headers will be searched in order and the first '
'found remote host name or IP will be used.\n\n'
'In the below example 8.8.8.7 would be the chosen IP address.\n'
'X-Forwarded-For: 8.8.8.7, 192.168.2.1, 127.0.0.1\n'
'Host: 127.0.0.1\n'
'REMOTE_HOST_HEADERS = [\'HTTP_X_FORWARDED_FOR\', '
'\'REMOTE_ADDR\', \'REMOTE_HOST\']'),
'"HTTP_X_FORWARDED_FOR", if behind a reverse proxy. '
'See the "Proxy Support" section of the Adminstrator guide for'
'more details.'),
category=_('System'),
category_slug='system',
)
@@ -88,9 +83,7 @@ register(
label=_('Proxy IP Whitelist'),
help_text=_("If Tower is behind a reverse proxy/load balancer, use this setting "
"to whitelist the proxy IP addresses from which Tower should trust "
"custom REMOTE_HOST_HEADERS header values\n"
"REMOTE_HOST_HEADERS = ['HTTP_X_FORWARDED_FOR', ''REMOTE_ADDR', 'REMOTE_HOST']\n"
"PROXY_IP_WHITELIST = ['10.0.1.100', '10.0.1.101']\n"
"custom REMOTE_HOST_HEADERS header values. "
"If this setting is an empty list (the default), the headers specified by "
"REMOTE_HOST_HEADERS will be trusted unconditionally')"),
category=_('System'),
@@ -105,7 +98,7 @@ def _load_default_license_from_file():
license_data = json.load(open(license_file))
logger.debug('Read license data from "%s".', license_file)
return license_data
except:
except Exception:
logger.warning('Could not read license from "%s".', license_file, exc_info=True)
return {}
@@ -268,7 +261,8 @@ register(
field_class=fields.IntegerField,
min_value=0,
label=_('Job Event Standard Output Maximum Display Size'),
help_text=_(u'Maximum Size of Standard Output in bytes to display for a single job or ad hoc command event. `stdout` will end with `\u2026` when truncated.'),
help_text=_(
u'Maximum Size of Standard Output in bytes to display for a single job or ad hoc command event. `stdout` will end with `\u2026` when truncated.'),
category=_('Jobs'),
category_slug='jobs',
)
@@ -311,7 +305,7 @@ register(
min_value=0,
default=0,
label=_('Default Inventory Update Timeout'),
help_text=_('Maximum time to allow inventory updates to run. Use value of 0 to indicate that no '
help_text=_('Maximum time in seconds to allow inventory updates to run. Use value of 0 to indicate that no '
'timeout should be imposed. A timeout set on an individual inventory source will override this.'),
category=_('Jobs'),
category_slug='jobs',
@@ -323,7 +317,7 @@ register(
min_value=0,
default=0,
label=_('Default Project Update Timeout'),
help_text=_('Maximum time to allow project updates to run. Use value of 0 to indicate that no '
help_text=_('Maximum time in seconds to allow project updates to run. Use value of 0 to indicate that no '
'timeout should be imposed. A timeout set on an individual project will override this.'),
category=_('Jobs'),
category_slug='jobs',
@@ -446,7 +440,7 @@ register(
register(
'LOG_AGGREGATOR_PROTOCOL',
field_class=fields.ChoiceField,
choices=['https', 'tcp', 'udp'],
choices=[('https', 'HTTPS'), ('tcp', 'TCP'), ('udp', 'UDP')],
default='https',
label=_('Logging Aggregator Protocol'),
help_text=_('Protocol used to communicate with log aggregator.'),

View File

@@ -1,8 +1,13 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
import re
from django.utils.translation import ugettext_lazy as _
CLOUD_PROVIDERS = ('azure', 'azure_rm', 'ec2', 'gce', 'rax', 'vmware', 'openstack', 'satellite6', 'cloudforms')
CLOUD_PROVIDERS = ('azure_rm', 'ec2', 'gce', 'vmware', 'openstack', 'satellite6', 'cloudforms')
SCHEDULEABLE_PROVIDERS = CLOUD_PROVIDERS + ('custom', 'scm',)
PRIVILEGE_ESCALATION_METHODS = [ ('sudo', _('Sudo')), ('su', _('Su')), ('pbrun', _('Pbrun')), ('pfexec', _('Pfexec')), ('dzdo', _('DZDO')), ('pmrun', _('Pmrun')), ('runas', _('Runas'))]
PRIVILEGE_ESCALATION_METHODS = [
('sudo', _('Sudo')), ('su', _('Su')), ('pbrun', _('Pbrun')), ('pfexec', _('Pfexec')),
('dzdo', _('DZDO')), ('pmrun', _('Pmrun')), ('runas', _('Runas'))]
ANSI_SGR_PATTERN = re.compile(r'\x1b\[[0-9;]*m')

View File

@@ -24,7 +24,7 @@ def discard_groups(message):
@channel_session
def ws_connect(message):
connect_text = {'accept':False, 'user':None}
message.reply_channel.send({"accept": True})
message.content['method'] = 'FAKE'
request = AsgiRequest(message)
@@ -35,11 +35,12 @@ def ws_connect(message):
auth_token = AuthToken.objects.get(key=token)
if auth_token.in_valid_tokens:
message.channel_session['user_id'] = auth_token.user_id
connect_text['accept'] = True
connect_text['user'] = auth_token.user_id
message.reply_channel.send({"text": json.dumps({"accept": True, "user": auth_token.user_id})})
return None
except AuthToken.DoesNotExist:
logger.error("auth_token provided was invalid.")
message.reply_channel.send({"text": json.dumps(connect_text)})
message.reply_channel.send({"close": True})
return None
@channel_session
@@ -81,7 +82,8 @@ def ws_receive(message):
if access_cls is not None:
user_access = access_cls(user)
if not user_access.get_queryset().filter(pk=oid).exists():
message.reply_channel.send({"text": json.dumps({"error": "access denied to channel {0} for resource id {1}".format(group_name, oid)})})
message.reply_channel.send({"text": json.dumps(
{"error": "access denied to channel {0} for resource id {1}".format(group_name, oid)})})
continue
current_groups.add(name)
Group(name).add(message.reply_channel)

24
awx/main/exceptions.py Normal file
View File

@@ -0,0 +1,24 @@
class AwxTaskError(Exception):
"""Base exception for errors in unified job runs"""
def __init__(self, task, message=None):
if message is None:
message = "Execution error running {}".format(task.log_format)
super(AwxTaskError, self).__init__(message)
self.task = task
class TaskCancel(AwxTaskError):
"""Canceled flag caused run_pexpect to kill the job run"""
def __init__(self, task, rc):
super(TaskCancel, self).__init__(
task, message="{} was canceled (rc={})".format(task.log_format, rc))
self.rc = rc
class TaskError(AwxTaskError):
"""Userspace error (non-zero exit code) in run_pexpect subprocess"""
def __init__(self, task, rc):
super(TaskError, self).__init__(
task, message="%s encountered an error (rc=%s), please see task stdout for details.".format(task.log_format, rc))
self.rc = rc

View File

@@ -9,6 +9,7 @@ import stat
import tempfile
import time
import logging
from distutils.version import LooseVersion as Version
from django.conf import settings
@@ -370,7 +371,24 @@ class IsolatedManager(object):
logger.warning('Isolated job {} cleanup error, output:\n{}'.format(self.instance.id, output))
@classmethod
def health_check(cls, instance_qs):
def update_capacity(cls, instance, task_result, awx_application_version):
instance.version = task_result['version']
isolated_version = instance.version.split("-", 1)[0]
cluster_version = awx_application_version.split("-", 1)[0]
if Version(cluster_version) > Version(isolated_version):
err_template = "Isolated instance {} reports version {}, cluster node is at {}, setting capacity to zero."
logger.error(err_template.format(instance.hostname, instance.version, awx_application_version))
instance.capacity = 0
else:
if instance.capacity == 0 and task_result['capacity']:
logger.warning('Isolated instance {} has re-joined.'.format(instance.hostname))
instance.capacity = int(task_result['capacity'])
instance.save(update_fields=['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
@@ -412,11 +430,7 @@ class IsolatedManager(object):
except (KeyError, IndexError):
task_result = {}
if 'capacity' in task_result:
instance.version = task_result['version']
if instance.capacity == 0 and task_result['capacity']:
logger.warning('Isolated instance {} has re-joined.'.format(instance.hostname))
instance.capacity = int(task_result['capacity'])
instance.save(update_fields=['capacity', 'version', 'modified'])
cls.update_capacity(instance, task_result, awx_application_version)
elif instance.capacity == 0:
logger.debug('Isolated instance {} previously marked as lost, could not re-join.'.format(
instance.hostname))

View File

@@ -122,7 +122,7 @@ def run_pexpect(args, cwd, env, logfile,
if cancelled_callback:
try:
canceled = cancelled_callback()
except:
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"
@@ -271,12 +271,8 @@ def __run__(private_data_dir):
if __name__ == '__main__':
__version__ = '3.2.0'
try:
import awx
__version__ = awx.__version__
except ImportError:
pass # in devel, `awx` isn't an installed package
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'])

View File

@@ -18,12 +18,12 @@ from django.db.models.signals import (
)
from django.db.models.signals import m2m_changed
from django.db import models
from django.db.models.fields.related import (
add_lazy_relation,
SingleRelatedObjectDescriptor,
ReverseSingleRelatedObjectDescriptor,
ManyRelatedObjectsDescriptor,
ReverseManyRelatedObjectsDescriptor,
from django.db.models.fields.related import add_lazy_relation
from django.db.models.fields.related_descriptors import (
ReverseOneToOneDescriptor,
ForwardManyToOneDescriptor,
ManyToManyDescriptor,
ReverseManyToOneDescriptor,
)
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -96,7 +96,7 @@ class JSONBField(upstream_JSONBField):
# https://bitbucket.org/offline/django-annoying/src/a0de8b294db3/annoying/fields.py
class AutoSingleRelatedObjectDescriptor(SingleRelatedObjectDescriptor):
class AutoSingleRelatedObjectDescriptor(ReverseOneToOneDescriptor):
"""Descriptor for access to the object from its related class."""
def __get__(self, instance, instance_type=None):
@@ -139,7 +139,7 @@ def resolve_role_field(obj, field):
raise Exception(smart_text('{} refers to a {}, not a Role'.format(field, type(obj))))
ret.append(obj.id)
else:
if type(obj) is ManyRelatedObjectsDescriptor:
if type(obj) is ManyToManyDescriptor:
for o in obj.all():
ret += resolve_role_field(o, field_components[1])
else:
@@ -179,7 +179,7 @@ def is_implicit_parent(parent_role, child_role):
return False
class ImplicitRoleDescriptor(ReverseSingleRelatedObjectDescriptor):
class ImplicitRoleDescriptor(ForwardManyToOneDescriptor):
pass
@@ -230,18 +230,18 @@ class ImplicitRoleField(models.ForeignKey):
field_name, sep, field_attr = field_name.partition('.')
field = getattr(cls, field_name)
if type(field) is ReverseManyRelatedObjectsDescriptor or \
type(field) is ManyRelatedObjectsDescriptor:
if type(field) is ReverseManyToOneDescriptor or \
type(field) is ManyToManyDescriptor:
if '.' in field_attr:
raise Exception('Referencing deep roles through ManyToMany fields is unsupported.')
if type(field) is ReverseManyRelatedObjectsDescriptor:
if type(field) is ReverseManyToOneDescriptor:
sender = field.through
else:
sender = field.related.through
reverse = type(field) is ManyRelatedObjectsDescriptor
reverse = type(field) is ManyToManyDescriptor
m2m_changed.connect(self.m2m_update(field_attr, reverse), sender, weak=False)
def m2m_update(self, field_attr, _reverse):
@@ -415,6 +415,13 @@ class JSONSchemaField(JSONBField):
return value
@JSONSchemaField.format_checker.checks('vault_id')
def format_vault_id(value):
if '@' in value:
raise jsonschema.exceptions.FormatError('@ is not an allowed character')
return True
@JSONSchemaField.format_checker.checks('ssh_private_key')
def format_ssh_private_key(value):
# Sanity check: GCE, in particular, provides JSON-encoded private
@@ -754,3 +761,22 @@ class CredentialTypeInjectorField(JSONSchemaField):
code='invalid',
params={'value': value},
)
class AskForField(models.BooleanField):
"""
Denotes whether to prompt on launch for another field on the same template
"""
def __init__(self, allows_field=None, **kwargs):
super(AskForField, self).__init__(**kwargs)
self._allows_field = allows_field
@property
def allows_field(self):
if self._allows_field is None:
try:
return self.name[len('ask_'):-len('_on_launch')]
except AttributeError:
# self.name will be set by the model metaclass, not this field
raise Exception('Corresponding allows_field cannot be accessed until model is initialized.')
return self._allows_field

View File

@@ -2,19 +2,12 @@
# All Rights Reserved
from awx.main.utils import get_licenser
from django.core.management.base import NoArgsCommand
from django.core.management.base import BaseCommand
class Command(NoArgsCommand):
"""Return 0 if licensed; 1 if unlicensed
"""
class Command(BaseCommand):
"""Returns license type, e.g., 'enterprise', 'open', 'none'"""
def handle(self, **options):
def handle(self, *args, **options):
super(Command, self).__init__()
license_info = get_licenser().validate()
if license_info['valid_key'] is True:
return 0
else:
return 1
return get_licenser().validate().get('license_type', 'none')

View File

@@ -4,29 +4,28 @@
# Python
import datetime
import logging
from optparse import make_option
# Django
from django.core.management.base import NoArgsCommand
from django.core.management.base import BaseCommand
from django.utils.timezone import now
# AWX
from awx.main.models import ActivityStream
class Command(NoArgsCommand):
class Command(BaseCommand):
'''
Management command to purge old activity stream events.
'''
help = 'Remove old activity stream events from the database'
option_list = NoArgsCommand.option_list + (
make_option('--days', dest='days', type='int', default=90, metavar='N',
help='Remove activity stream events more than N days old'),
make_option('--dry-run', dest='dry_run', action='store_true',
default=False, help='Dry run mode (show items that would '
'be removed)'),)
def add_arguments(self, parser):
parser.add_argument('--days', dest='days', type=int, default=90, metavar='N',
help='Remove activity stream events more than N days old')
parser.add_argument('--dry-run', dest='dry_run', action='store_true',
default=False, help='Dry run mode (show items that would '
'be removed)')
def init_logging(self):
log_levels = dict(enumerate([logging.ERROR, logging.INFO,
@@ -61,7 +60,7 @@ class Command(NoArgsCommand):
n_deleted_items += len(pks_to_delete)
self.logger.log(99, "Removed %d items", n_deleted_items)
def handle_noargs(self, **options):
def handle(self, *args, **options):
self.verbosity = int(options.get('verbosity', 1))
self.init_logging()
self.days = int(options.get('days', 30))

View File

@@ -4,7 +4,6 @@
# Python
import re
from dateutil.relativedelta import relativedelta
from optparse import make_option
# Django
from django.core.management.base import BaseCommand, CommandError
@@ -93,19 +92,20 @@ class CleanupFacts(object):
class Command(BaseCommand):
help = 'Cleanup facts. For each host older than the value specified, keep one fact scan for each time window (granularity).'
option_list = BaseCommand.option_list + (
make_option('--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.'),
make_option('--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.'),
make_option('--module',
dest='module',
default=None,
help='Limit cleanup to a particular module.'),)
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__()

View File

@@ -4,10 +4,9 @@
# Python
import datetime
import logging
from optparse import make_option
# Django
from django.core.management.base import NoArgsCommand, CommandError
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.utils.timezone import now
@@ -25,47 +24,47 @@ from awx.main.signals import ( # noqa
from django.db.models.signals import post_save, post_delete, m2m_changed # noqa
class Command(NoArgsCommand):
class Command(BaseCommand):
'''
Management command to cleanup old jobs and project updates.
'''
help = 'Remove old jobs, project and inventory updates from the database.'
option_list = NoArgsCommand.option_list + (
make_option('--days', dest='days', type='int', default=90, metavar='N',
help='Remove jobs/updates executed more than N days ago. Defaults to 90.'),
make_option('--dry-run', dest='dry_run', action='store_true',
default=False, help='Dry run mode (show items that would '
'be removed)'),
make_option('--jobs', dest='only_jobs', action='store_true',
default=False,
help='Remove jobs'),
make_option('--ad-hoc-commands', dest='only_ad_hoc_commands',
action='store_true', default=False,
help='Remove ad hoc commands'),
make_option('--project-updates', dest='only_project_updates',
action='store_true', default=False,
help='Remove project updates'),
make_option('--inventory-updates', dest='only_inventory_updates',
action='store_true', default=False,
help='Remove inventory updates'),
make_option('--management-jobs', default=False,
action='store_true', dest='only_management_jobs',
help='Remove management jobs'),
make_option('--notifications', dest='only_notifications',
action='store_true', default=False,
help='Remove notifications'),
make_option('--workflow-jobs', default=False,
action='store_true', dest='only_workflow_jobs',
help='Remove workflow jobs')
)
def add_arguments(self, parser):
parser.add_argument('--days', dest='days', type=int, default=90, metavar='N',
help='Remove jobs/updates executed more than N days ago. Defaults to 90.')
parser.add_argument('--dry-run', dest='dry_run', action='store_true',
default=False, help='Dry run mode (show items that would '
'be removed)')
parser.add_argument('--jobs', dest='only_jobs', action='store_true',
default=False,
help='Remove jobs')
parser.add_argument('--ad-hoc-commands', dest='only_ad_hoc_commands',
action='store_true', default=False,
help='Remove ad hoc commands')
parser.add_argument('--project-updates', dest='only_project_updates',
action='store_true', default=False,
help='Remove project updates')
parser.add_argument('--inventory-updates', dest='only_inventory_updates',
action='store_true', default=False,
help='Remove inventory updates')
parser.add_argument('--management-jobs', default=False,
action='store_true', dest='only_management_jobs',
help='Remove management jobs')
parser.add_argument('--notifications', dest='only_notifications',
action='store_true', default=False,
help='Remove notifications')
parser.add_argument('--workflow-jobs', default=False,
action='store_true', dest='only_workflow_jobs',
help='Remove workflow jobs')
def cleanup_jobs(self):
#jobs_qs = Job.objects.exclude(status__in=('pending', 'running'))
#jobs_qs = jobs_qs.filter(created__lte=self.cutoff)
skipped, deleted = 0, 0
for job in Job.objects.all():
jobs = Job.objects.filter(created__lt=self.cutoff)
for job in jobs.iterator():
job_display = '"%s" (%d host summaries, %d events)' % \
(unicode(job),
job.job_host_summaries.count(), job.job_events.count())
@@ -73,21 +72,20 @@ class Command(NoArgsCommand):
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s job %s', action_text, job.status, job_display)
skipped += 1
elif job.created >= self.cutoff:
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, job_display)
skipped += 1
else:
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, job_display)
if not self.dry_run:
job.delete()
deleted += 1
skipped += Job.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_ad_hoc_commands(self):
skipped, deleted = 0, 0
for ad_hoc_command in AdHocCommand.objects.all():
ad_hoc_commands = AdHocCommand.objects.filter(created__lt=self.cutoff)
for ad_hoc_command in ad_hoc_commands.iterator():
ad_hoc_command_display = '"%s" (%d events)' % \
(unicode(ad_hoc_command),
ad_hoc_command.ad_hoc_command_events.count())
@@ -95,21 +93,20 @@ class Command(NoArgsCommand):
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s ad hoc command %s', action_text, ad_hoc_command.status, ad_hoc_command_display)
skipped += 1
elif ad_hoc_command.created >= self.cutoff:
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, ad_hoc_command_display)
skipped += 1
else:
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, ad_hoc_command_display)
if not self.dry_run:
ad_hoc_command.delete()
deleted += 1
skipped += AdHocCommand.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_project_updates(self):
skipped, deleted = 0, 0
for pu in ProjectUpdate.objects.all():
project_updates = ProjectUpdate.objects.filter(created__lt=self.cutoff)
for pu in project_updates.iterator():
pu_display = '"%s" (type %s)' % (unicode(pu), unicode(pu.launch_type))
if pu.status in ('pending', 'waiting', 'running'):
action_text = 'would skip' if self.dry_run else 'skipping'
@@ -119,21 +116,20 @@ class Command(NoArgsCommand):
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, pu_display)
skipped += 1
elif pu.created >= self.cutoff:
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, pu_display)
skipped += 1
else:
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, pu_display)
if not self.dry_run:
pu.delete()
deleted += 1
skipped += ProjectUpdate.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_inventory_updates(self):
skipped, deleted = 0, 0
for iu in InventoryUpdate.objects.all():
inventory_updates = InventoryUpdate.objects.filter(created__lt=self.cutoff)
for iu in inventory_updates.iterator():
iu_display = '"%s" (source %s)' % (unicode(iu), unicode(iu.source))
if iu.status in ('pending', 'waiting', 'running'):
action_text = 'would skip' if self.dry_run else 'skipping'
@@ -143,36 +139,33 @@ class Command(NoArgsCommand):
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, iu_display)
skipped += 1
elif iu.created >= self.cutoff:
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, iu_display)
skipped += 1
else:
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, iu_display)
if not self.dry_run:
iu.delete()
deleted += 1
skipped += InventoryUpdate.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_management_jobs(self):
skipped, deleted = 0, 0
for sj in SystemJob.objects.all():
system_jobs = SystemJob.objects.filter(created__lt=self.cutoff)
for sj in system_jobs.iterator():
sj_display = '"%s" (type %s)' % (unicode(sj), unicode(sj.job_type))
if sj.status in ('pending', 'waiting', 'running'):
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s system_job %s', action_text, sj.status, sj_display)
skipped += 1
elif sj.created >= self.cutoff:
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, sj_display)
skipped += 1
else:
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, sj_display)
if not self.dry_run:
sj.delete()
deleted += 1
skipped += SystemJob.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def init_logging(self):
@@ -187,7 +180,8 @@ class Command(NoArgsCommand):
def cleanup_workflow_jobs(self):
skipped, deleted = 0, 0
for workflow_job in WorkflowJob.objects.all():
workflow_jobs = WorkflowJob.objects.filter(created__lt=self.cutoff)
for workflow_job in workflow_jobs.iterator():
workflow_job_display = '"{}" ({} nodes)'.format(
unicode(workflow_job),
workflow_job.workflow_nodes.count())
@@ -195,21 +189,20 @@ class Command(NoArgsCommand):
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s job %s', action_text, workflow_job.status, workflow_job_display)
skipped += 1
elif workflow_job.created >= self.cutoff:
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, workflow_job_display)
skipped += 1
else:
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, workflow_job_display)
if not self.dry_run:
workflow_job.delete()
deleted += 1
skipped += WorkflowJob.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
def cleanup_notifications(self):
skipped, deleted = 0, 0
for notification in Notification.objects.all():
notifications = Notification.objects.filter(created__lt=self.cutoff)
for notification in notifications.iterator():
notification_display = '"{}" (started {}, {} type, {} sent)'.format(
unicode(notification), unicode(notification.created),
notification.notification_type, notification.notifications_sent)
@@ -217,20 +210,18 @@ class Command(NoArgsCommand):
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s notification %s', action_text, notification.status, notification_display)
skipped += 1
elif notification.created >= self.cutoff:
action_text = 'would skip' if self.dry_run else 'skipping'
self.logger.debug('%s %s', action_text, notification_display)
skipped += 1
else:
action_text = 'would delete' if self.dry_run else 'deleting'
self.logger.info('%s %s', action_text, notification_display)
if not self.dry_run:
notification.delete()
deleted += 1
skipped += Notification.objects.filter(created__gte=self.cutoff).count()
return skipped, deleted
@transaction.atomic
def handle_noargs(self, **options):
def handle(self, *args, **options):
self.verbosity = int(options.get('verbosity', 1))
self.init_logging()
self.days = int(options.get('days', 90))
@@ -255,3 +246,4 @@ class Command(NoArgsCommand):
self.logger.log(99, '%s: %d would be deleted, %d would be skipped.', m.replace('_', ' '), deleted, skipped)
else:
self.logger.log(99, '%s: %d deleted, %d skipped.', m.replace('_', ' '), deleted, skipped)

View File

@@ -45,10 +45,10 @@ class Command(BaseCommand):
inventory=i,
variables="ansible_connection: local",
created_by=superuser)
JobTemplate.objects.create(name='Demo Job Template',
playbook='hello_world.yml',
project=p,
inventory=i,
credential=c)
jt = JobTemplate.objects.create(name='Demo Job Template',
playbook='hello_world.yml',
project=p,
inventory=i)
jt.credentials.add(c)
print('Default organization added.')
print('Demo Credential, Inventory, and Job Template added.')

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved
from optparse import make_option
import subprocess
import warnings
@@ -17,13 +16,17 @@ class Command(BaseCommand):
Deprovision a Tower cluster node
"""
option_list = BaseCommand.option_list + (
make_option('--hostname', dest='hostname', type='string',
help='Hostname used during provisioning'),
make_option('--name', dest='name', type='string',
help='(PENDING DEPRECIATION) Hostname used during provisioning'),
help = (
'Remove instance from the database. '
'Specify `--hostname` to use this command.'
)
def add_arguments(self, parser):
parser.add_argument('--hostname', dest='hostname', type=str,
help='Hostname used during provisioning')
parser.add_argument('--name', dest='name', type=str,
help='(PENDING DEPRECIATION) Hostname used during provisioning')
@transaction.atomic
def handle(self, *args, **options):
# TODO: remove in 3.3

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