Compare commits

...

713 Commits

Author SHA1 Message Date
Kersom
dac26e5e91 Merge pull request #11979 from nixocio/ui_move_boolean
Move AWX_MOUNT_ISOLATED_PATHS_ON_K8S to be closer to other booleans
2022-03-30 14:14:40 -04:00
nixocio
3b1a626fa9 Move AWX_MOUNT_ISOLATED_PATHS_ON_K8S to be closer to other booleans
Move AWX_MOUNT_ISOLATED_PATHS_ON_K8S to be closer to other booleans on
the layout.
2022-03-30 13:27:20 -04:00
Shane McDonald
35907fdf51 Merge pull request #11977 from shanemcd/handle-missing-devel-images
Tweaks to devel_images workflow
2022-03-30 09:45:35 -04:00
Shane McDonald
3513956cd6 Merge pull request #11972 from JoelKle/patch-1
[bugfix] credential_plugin tss.py (Thycotic Secret Server) return only value of secret
2022-03-30 09:33:54 -04:00
Shane McDonald
3ed65ce39e Only run devel_images workflow for devel branch in awx repo 2022-03-30 09:24:22 -04:00
Alan Rominger
73e02e745a Patches to make jobs robust to database restarts (#11905)
* Simple patches to make jobs robust to database restarts

* Add some wait time before retrying loop due to DB error

* Apply dispatcher downtime setting to job updates, fix dispatcher bug

This resolves a bug where the pg_is_down property
  never had the right value
  the loop is normally stuck in the conn.events() iterator
  so it never recognized successful database interactions
  this lead to serial database outages terminating jobs

New setting for allowable PG downtime is shared with task code
  any calls to update_model will use _max_attempts parameter
  to make it align with the patience time that the dispatcher
  respects when consuming new events

* To avoid restart loops, handle DB errors on startup with prejudice

* If reconnect consistently fails, exit with non-zero code
2022-03-30 09:14:20 -04:00
Shane McDonald
91df8ab0f7 Do not fail devel_images workflow if initial images are missing 2022-03-30 09:10:50 -04:00
Shane McDonald
ef0f6ca248 Merge pull request #11955 from shanemcd/fail-better
Increase resiliency when application crashes
2022-03-30 08:58:26 -04:00
Satoe Imaishi
4ecce81c51 Merge pull request #11971 from simaishi/add_setuptools_scm_toml
Add setuptools_scm[toml] and pkgconfig to requirements file
2022-03-30 06:51:18 +09:00
Satoe Imaishi
823e4cb11a Add license files for pkgconfig, setuptools-scm and tomli 2022-03-29 16:57:12 -04:00
Alan Rominger
28fa90e9e5 Only allow provision_instances without options to be used on k8s 2022-03-29 16:24:06 -04:00
Alan Rominger
3d22c8ae91 Merge pull request #11968 from AlanCoding/cleanup_tweaks
Minor tweaks to ansible-runner cleanup task arguments
2022-03-29 15:00:33 -04:00
John Westcott IV
e2135b8d68 Collection meta runtime updates (#11952)
* Update runtime.yml
* Extending test_completness to include meta/runtime.yml and adding remaining missing modules from runtime.yml

Co-authored-by: quasd <quasd@users.noreply.github.com>
2022-03-29 14:24:06 -04:00
Alan Rominger
fe5736dc7f Specifically abort the reaper if instance not registered 2022-03-29 14:08:58 -04:00
Shane McDonald
b36af5dfb3 Update help text for provision_instance command 2022-03-29 14:08:58 -04:00
Shane McDonald
4446434e5b Ensure stop signals are forwarded to the correct processes 2022-03-29 14:08:56 -04:00
Shane McDonald
39905b33cd Replace tini with dumb-init
dumb-init is more actively maintained, available on pypi, and already used for both upstream and downstream EEs
2022-03-29 14:08:09 -04:00
Shane McDonald
dbdc529d4a Fix race condition causing rsyslog to crash 2022-03-29 14:08:07 -04:00
Shane McDonald
0cbc802cf4 Use the same settings on each supervisor entry
I didnt see a reason for the weird inconsistencies here.
2022-03-29 14:07:54 -04:00
Shane McDonald
b04747676c Provision the instance before booting anything
There was a race condition because the callback reciever tried to run this code:

  File "/awx_devel/awx/main/management/commands/run_callback_receiver.py", line 31, in handle
    CallbackBrokerWorker(),
  File "/awx_devel/awx/main/dispatch/worker/callback.py", line 49, in __init__
    self.subsystem_metrics = s_metrics.Metrics(auto_pipe_execute=False)
  File "/awx_devel/awx/main/analytics/subsystem_metrics.py", line 156, in __init__
    self.instance_name = Instance.objects.me().hostname

Before get_or_register was being called by the dispatcher.
2022-03-29 14:07:49 -04:00
Alex Corey
5297a87ad4 Merge pull request #11970 from jtmelhorn/devel
Joboutput Search: Put Event Dropdown Options in Alpha Order #11807
2022-03-29 13:10:25 -04:00
Joel
bd907425a9 return only value of secret 2022-03-29 10:33:53 +02:00
Satoe Imaishi
229ed53c0e Add setuptools_scm[toml] and pkgconfig, xmlsec's build dep 2022-03-29 01:57:44 -04:00
Alan Rominger
f17ceca7a0 Add in default value to unit tests 2022-03-28 22:39:59 -04:00
Alan Rominger
deac08ba8a Add regression test for overly agressive cleanup behavior 2022-03-28 22:23:33 -04:00
Seth Foster
e0082f4c76 Merge pull request #11945 from fosterseth/fix_create_partition_already_exists_error
Handle error for create_partition
2022-03-28 18:13:29 -04:00
Justin
bed0443b18 Joboutput Search: Put Event Dropdown Options in Alpha Order #11807
Put Event Options in Alpha order.

Signed-off-by: Justin Melhorn <jtmelhorn@gmail.com>
2022-03-28 16:50:44 -04:00
Seth Foster
24152555c5 Handle error for create_partition
Occasionally the create_partition will error with,
relation "main_projectupdateevent_20220323_19" already exists

This change wraps the db command into a try except block with its
own transaction
2022-03-28 16:37:50 -04:00
Amol Gautam
56f51eebce Merge pull request #11956 from amolgautam25/credential_plugin
setting environment variables for credential plugins
2022-03-28 13:02:19 -04:00
Jeff Bradberry
6c1adade25 Merge pull request #11947 from jbradberry/django-3.2-upgrade
Remove the out-of-band JSONField migration
2022-03-28 12:02:53 -04:00
kialam
ec5e677635 Merge pull request #11938 from kialam/mesh-viz-unit-tests
Mesh viz unit tests
2022-03-28 08:44:19 -07:00
Alex Corey
327cae056e Merge pull request #11829 from AlexSCorey/11478-StartofJobOutputDevDocs
Adds outline for JobOutput documentation.
2022-03-28 11:22:21 -04:00
Alex Corey
7a11470817 Adds outline for JobOutput documentation. 2022-03-28 10:58:05 -04:00
Alan Rominger
85ec83c3fd Minor tweaks to ansible-runner cleanup task arguments 2022-03-28 10:52:09 -04:00
Alex Corey
1679102204 Merge pull request #11946 from nixocio/ui_cred_type
Add credential type filter
2022-03-28 10:03:56 -04:00
Kersom
7601531d82 Merge pull request #11965 from nixocio/ui_b_style
Small style update
2022-03-28 10:02:59 -04:00
Sarah Akus
56ab1c2f0a Merge pull request #11958 from AlexSCorey/UpdatesPF
Updates PF to bring in the DrownActionToggle component
2022-03-25 20:27:25 -04:00
nixocio
f309054637 Small style update
Small style update to make a bit more consistent.
2022-03-25 15:39:22 -04:00
Amol Gautam
8efed4ef62 Adding awx_task_env as wrapper while invoking backend 2022-03-25 10:16:30 -04:00
Shane McDonald
e4c85a5790 Merge pull request #11957 from lucas-benedito/fix_hardcode_tmp_models_ha
fixed hardcode tmp ha.py
2022-03-25 09:57:02 -04:00
lucas-benedito
8af2214979 Merge branch 'ansible:devel' into fix_hardcode_tmp_models_ha 2022-03-25 14:28:29 +01:00
Lucas Dias
01ce3440eb added os.path and module import 2022-03-25 14:26:00 +01:00
Shane McDonald
b6573ec2e2 Merge pull request #11961 from shanemcd/respect-system-tmp
Respect system configured tmp directory
2022-03-25 08:13:53 -04:00
Jeff Bradberry
d54838cd94 Remove the out-of-band migration
that was turning all old JSONFields into a jsonb type database column.
The use of JSONBlob makes this unnecessary.
2022-03-24 15:21:59 -04:00
Jeff Bradberry
e3f3ab224a Replace all previously text-based json fields with JSONBlob
This JSONBlob field type is a wrapper around Django's new generic
JSONField, but with the database column type forced to be text.  This
should behave close enough to our old wrapper around
django-jsonfield's JSONField and will avoid needing to do the
out-of-band database migration.
2022-03-24 15:21:54 -04:00
Shane McDonald
c06ced93f7 Merge pull request #11933 from AlanCoding/settingify
Add setting for notification job status retry loop
2022-03-24 13:55:39 -04:00
Shane McDonald
ea59e895af Respect system configured tmp directory 2022-03-24 13:51:02 -04:00
Alex Corey
fb7a8dfd16 Updates PF to bring in the DrownActionToggle component 2022-03-24 13:17:25 -04:00
Lucas Dias
18b1440d7c fixed hardcode tmp ha.py 2022-03-24 17:59:43 +01:00
John Westcott IV
593eebf062 Adding awx_ as well as tower_ variable names for webhooks (#11925)
Adding utility to ease testing webhooks from command line
Modifying all variables to use a constants list of variable names
2022-03-24 11:58:15 -04:00
John Westcott IV
fcdff8bdfb Fixing pre-commit.sh for OS X (#11953) 2022-03-24 11:39:29 -04:00
John Westcott IV
b9cdd6f2c8 Adding ability to run user level pre-commit hooks (#11923)
* Adding ability to run user level pre-commit hooks
* Adding pre-commit docs in CONTRIBUTING.md
2022-03-24 10:58:14 -04:00
Shane McDonald
270497eda1 Kill all control plane processes if one of them fails to boot 2022-03-23 18:40:23 -04:00
Shane McDonald
dbcdb825b0 Remove awx-config-watcher from kube dev env 2022-03-23 18:37:16 -04:00
nixocio
6c28f4b204 Add credential type filter
Add credential type filter

See: https://github.com/ansible/awx/issues/11930
2022-03-23 16:44:50 -04:00
Shane McDonald
7b2b979c1b Merge pull request #11941 from shanemcd/update-devel-image-refs
Update some references to our development images
2022-03-23 15:57:18 -04:00
Shane McDonald
e87c9d8811 Fix command in build_awx_image.md 2022-03-23 15:40:49 -04:00
Alex Corey
7d04737a65 Merge pull request #11934 from mabashian/5707-proj-field-label
Fix Source Control Type label in project form
2022-03-23 11:32:30 -04:00
Shane McDonald
99056e3697 Update some references to our development images 2022-03-23 11:31:11 -04:00
Shane McDonald
c110101cb1 Merge pull request #11787 from liortamari/hashicorp-vault-kubernetes-auth
Add Hashicorp Vault Kubernetes authentication method
2022-03-23 11:02:38 -04:00
Shane McDonald
aa6129fda0 Merge pull request #11932 from shanemcd/gha-devel-images
Migrate all development image builds to GHA
2022-03-23 10:28:48 -04:00
Shane McDonald
1d181757e8 Migrate all development image builds to GHA
- This also moves the development image from quay.io to ghcr.io.
- These changes will need to be backported to all of our supported branches.
2022-03-23 10:03:55 -04:00
Sarah Akus
4fa8b6ded8 Merge pull request #11788 from AlexSCorey/10281-OutputHostFilters
Fixes search drop down items for job output search
2022-03-23 09:45:01 -04:00
Alex Corey
79afdfd1a6 Fixes search drop down items for job output search 2022-03-23 09:26:49 -04:00
Kia Lam
7702abb368 Add unit tests for Topology View. 2022-03-22 15:31:27 -07:00
Shane McDonald
3d6a49ce7c Merge pull request #11937 from ansible/shanemcd-patch-1
Stop adding needs_triage label every time an issue is edited
2022-03-22 14:04:46 -04:00
Shane McDonald
f823049f55 Stop adding needs_triage label every time an issue is edited 2022-03-22 13:08:34 -04:00
Seth Foster
b608b73110 Merge pull request #11927 from fosterseth/fix_subsystem_metrics_sync_in_async
Fix subsystem metrics sync-only operation in async context
2022-03-22 11:55:05 -04:00
mabashian
12c36d279e Fix Source Control Type label in project form 2022-03-22 09:35:37 -04:00
Chris Meyers
59bd73bff8 add setting for notification job status retry loop
* We trigger notifications when the callback receiver processes the
playbook_on_stats event. This is the last event in ansible-playbook and
the process should exist very shortly after this event is emitted. The
trouble comes in with the isolated node feature. There is a management
playbook that runs periodically that pulls the events from the remote
node. It's possible that the management playbooks runs, gets the
playbook_on_stats event, but does not see that the playbook is finished
running. Therefore the job status is still seen as 'running' BUT we have
kicked of the notification for the job. The notification worker will
enter a loop waiting on the job to enter the finished state. In this
case the time it takes for the job to enter the finished state can be
long, roughly 2 * the management playbook run time.
* This new setting allows the user to increase the time that the
notification spends waiting for the job to enter the finished state.
2022-03-22 09:20:14 -04:00
Shane McDonald
afbd9f04d7 Merge pull request #11748 from john-westcott-iv/github_workflows_on_all_releases
Chaning workflow to run on all release branches
2022-03-22 09:06:50 -04:00
liortamari
26fb5a0bd7 Merge branch 'ansible:devel' into hashicorp-vault-kubernetes-auth 2022-03-22 14:07:15 +02:00
Seth Foster
acebff7be1 Fix sync-only operation in async context 2022-03-21 14:37:10 -04:00
John Westcott IV
45bd143c07 Fixing import of projects issue due to local_path (#11889) 2022-03-21 14:04:47 -04:00
Jeff Bradberry
aa46a7fe06 Merge pull request #11924 from jbradberry/awxkit-support-inventory-labels
Support the new Inventory.labels in awxkit / awx-cli
2022-03-21 10:19:42 -04:00
Shane McDonald
07d0eedb0a Merge pull request #11875 from shanemcd/url-prefixing-collection
Make our collection work with prefixed API endpoints
2022-03-21 08:09:08 -04:00
Kersom
9aae2a11f2 Add related job templates to a couple of screens (#11890)
Add related job templates to a couple of screens. Credential and
Inventory.

Also refactor the component already in place for Projects to be in sync
with the Job Templates screen.

See: https://github.com/ansible/awx/issues/5867
2022-03-18 20:52:50 +00:00
Jeff Bradberry
51021f380b Support the new Inventory.labels in awxkit / awx-cli 2022-03-18 14:24:49 -04:00
Shane McDonald
7818a479ee Merge pull request #11880 from kurokobo/operator_version
fix: add OPERATOR_VERSION as build-arg to pass the version to operator
2022-03-18 11:20:20 -04:00
Alan Rominger
799bac4066 Merge pull request #11860 from AlanCoding/hybrid_artifacts
Do not remove artifacts for local work
2022-03-18 10:37:06 -04:00
Tiago Góes
41b3ad1b83 Merge pull request #11917 from nixocio/ui_survey_issue
Fix credential encrypted
2022-03-18 10:44:39 -03:00
nixocio
c912dd4e76 Fix credential encrypted
Display credential as encrypted.

See: https://github.com/ansible/awx/issues/11915
2022-03-17 16:37:44 -04:00
Tiago Góes
3ec9bacb30 Merge pull request #11913 from keithjgrant/9041-page-titles
display current page name in document title
2022-03-17 17:32:00 -03:00
Keith J. Grant
13db49aab7 display current page name in document title 2022-03-17 11:26:20 -07:00
Jeff Bradberry
ac6a82eee4 Merge pull request #11654 from jbradberry/django-3.2-upgrade
Django 3.2 upgrade
2022-03-17 10:34:22 -04:00
Tiago Góes
546fc24a0a Merge pull request #11839 from nixocio/ui_issue_11718_backup
Add several changes to Instance Groups
2022-03-15 18:11:01 -03:00
Alan Rominger
f99820a391 Merge pull request #11898 from AlanCoding/hop_node_lost_found
Only clear hop node errors if they were lost before, not lost now
2022-03-15 13:03:33 -04:00
Shane McDonald
873875af84 Merge pull request #11909 from JamieSlome/patch-1
Create SECURITY.md
2022-03-15 10:38:54 -04:00
Jamie Slome
fcb1c4823e Create SECURITY.md 2022-03-15 13:59:42 +00:00
Kersom
a1203e6fec Merge pull request #11902 from keithjgrant/error-detail-formatting
add line wrap formatting to ErrorDetail
2022-03-15 08:30:12 -04:00
Alan Rominger
2321f06c8a Only clear hop node errors if they were lost before, not lost now 2022-03-14 16:04:55 -04:00
nixocio
ce8b9750c9 Add several changes to Instance Groups
Add several changes to API and UI related to Instance Groups.

* Update summary_fields for DEFAULT_CONTROL_PLANE_QUEUE_NAME, and
  DEFAULT_EXECUTION_QUEUE_NAME. Rely on API validation for those fields.

* Fix Instance Group list RBAC

* Add validation for a couple of fields on the Instance Groups endpoint
	1. is_container_group
	2. policy_instance_percentage
	3. policy_instance_list

See: https://github.com/ansible/awx/issues/11130
Also: https://github.com/ansible/awx/issues/11718
2022-03-14 14:55:59 -04:00
Jeff Bradberry
574e3ed6ef Fix the signature of RADIUSBackend.get_django_user
to match what django-radius is now expecting.
2022-03-14 13:19:57 -04:00
Jeff Bradberry
584514766d Disable our wrapping of the Django settings during migrations
This will hopefully get us past the unfortunate check against the
HostMetric table, which doesn't exist when you are upgrading from 3.8
to 4.x.

Additionally, guard against AUTH_LDAP_GROUP_TYPE not being in settings
for conf migration 0006.
2022-03-14 13:19:57 -04:00
Jeff Bradberry
eb8a1fec49 Make API queries involving json fields cast the fields to text
This restores compatibility with the way it previously worked -- we
never supported proper json operator queries through the API.
2022-03-14 13:19:57 -04:00
Jeff Bradberry
38ccea0f1f Fix up warnings
- the default auto-increment primary key field type is now
  configurable, and Django's check command issues a warning if you are
  just assuming the historical behavior of using AutoField.

- Django 3.2 brings in automatic AppConfig discovery, so all of our
  explicit `default_app_config = ...` assignments in __init__.py
  modules are no longer needed, and raise a RemovedInDjango41Warning.
2022-03-14 13:19:57 -04:00
Jeff Bradberry
5d000c37d6 Deal with breaking tests for 3.2
- Instantiating an abstract model raises a TypeError
2022-03-14 13:19:57 -04:00
Jeff Bradberry
1803c5bdb4 Fix up usage of django-guid
It has replaced the class-based middleware, everything is
function-based now.
2022-03-14 13:19:57 -04:00
Jeff Bradberry
23e700a1ef Upgrade to Django 3.2
- upgrades
  - Django 3.2.12
  - pytz 2021.3 (from 2019.3)
  - oauthlib 3.2.0 (from 3.1.0)
  - requests-oauthlib 1.3.1 (from 1.3.0)
  - django-guid 3.2.1 (from 2.2.1)
  - django-solo 2.0.0 (from 1.1.3)
  - django-taggit 2.1.0 (from 1.2.0)
  - netaddr 0.8.0 (from 0.7.19)
  - pyrad 2.4 (from 2.3)
  - django-radius devel (from 1.3.3)
  - future devel (from 0.16.0)

- django-guid, django-solo, and django-taggit are upgraded to fix the
  AppConfig deprecation warning.  FIXME: django-guid devel has the
  fix, but it hasn't been released yet.

- Released versions of django-radius have a hard-coded pin to
  future==0.16.0, which has a Python warning due to an improperly
  escaped character.  This is fixed in future devel, so for now we are
  pinning to references to the git repos.

- netaddr had a bunch of Python syntax and deprecation warnings
2022-03-14 13:19:53 -04:00
Keith J. Grant
7114b9fa11 add line wrap formatting to ErrorDetail 2022-03-14 09:29:02 -07:00
Tiago Góes
2e4d866f69 Merge pull request #11897 from kialam/add-csp-for-web-worker
Add d3 to CSP.
2022-03-14 11:43:13 -03:00
Tiago Góes
f1cc808429 Merge pull request #11882 from nixocio/api_issue_11622
Add validation for hop nodes
2022-03-14 11:15:26 -03:00
Sarah Akus
30a39e1d1b Merge pull request #11885 from marshmalien/11729-job-details-deleted-text
Add deleted details to job detail view
2022-03-14 10:14:08 -04:00
Sarah Akus
22ad7244fa Merge pull request #11896 from AlanCoding/pod1_standup
Move location of AWX_ISOLATION_SHOW_PATHS so it is editable
2022-03-11 15:39:28 -05:00
Tiago
5be901c044 fix CSP rules 2022-03-11 15:51:35 -03:00
Kia Lam
2c073ae488 Add d3 to CSP. 2022-03-11 08:50:28 -08:00
Alan Rominger
d4a4ba7fdb Move location of AWX_ISOLATION_SHOW_PATHS so it is editable 2022-03-11 11:08:04 -05:00
Sarah Akus
3b8a0fcd95 Merge pull request #11858 from keithjgrant/11409-empty-job-output
add JobOutput screens for empty content
2022-03-11 09:14:53 -05:00
kialam
d02cef9d92 Merge pull request #11501 from kialam/add-mesh-viz
Add mesh visualizer
2022-03-10 11:48:03 -08:00
John Westcott IV
bc783b8f94 Enabling export of applications through awxkit (#11887) 2022-03-10 13:49:18 -05:00
John Westcott IV
4de27117e8 Adding option to enable and configure an OpenLDAP server next to AWX (#11843) 2022-03-10 10:29:04 -05:00
Sarah Akus
49bcf2e211 Merge pull request #11693 from AlexSCorey/5576-host_count_case_sensitivity
Fixes case sensitive host count
2022-03-09 15:55:48 -05:00
Alex Corey
f52ef6e967 Fixes case sensitive host count 2022-03-09 15:36:05 -05:00
Alan Rominger
99bbc347ec Fill in errors for hop nodes when Last Seen is out of date, and clear them when not (#11714)
* Process unresponsive and newly responsive hop nodes

* Use more natural way to zero hop node capacity, add test

* Use warning as opposed to warn for log messages
2022-03-09 13:21:32 -05:00
nixocio
53185a4ea5 Add validation for hop nodes
Add validation for hop nodes

See: https://github.com/ansible/awx/issues/11622
2022-03-09 11:04:12 -05:00
Kia Lam
23f6fae27a Add data-cy to content loader; move simulatioWorker to /util directory. 2022-03-09 07:36:04 -08:00
Marliana Lara
4b7e3620ca Add deleted details to job detail view 2022-03-09 10:25:21 -05:00
Kia Lam
e4f0153a7d Remove import statements from web worker file. 2022-03-09 06:58:43 -08:00
kurokobo
80947e2b32 fix: add OPERATOR_VERSION as build-arg to pass the version to operator 2022-03-09 22:32:38 +09:00
Kia Lam
8bf9dd038e Address review feedback. 2022-03-08 12:58:04 -08:00
Keith J. Grant
4080007ced JobOutput: add 'waiting for job' and 'no results found' messages 2022-03-08 12:35:47 -08:00
Kia Lam
7a6fd2623e Move web worker out of /screens directory. 2022-03-08 12:34:05 -08:00
Kia Lam
079eed2b9e Mock web worker. 2022-03-08 10:13:47 -08:00
Marliana Lara
4c9d028a35 Disable checkbox while job is running in project and inventory source lists (#11841) 2022-03-08 13:04:35 -05:00
Shane McDonald
bd5c304a50 Make our collection work with prefixed API endpoints
I caught this when trying to add test coverage for https://github.com/ansible/awx/pull/11342
2022-03-08 12:05:50 -05:00
Shane McDonald
123a3a22c9 Merge pull request #11859 from shanemcd/dev-env-test
Add a CI check for the development environment
2022-03-08 11:12:45 -05:00
Tiago Góes
82d91f8dbd Merge pull request #11830 from marshmalien/fix-duplicate-keys-subscription-modal
Add unique row id to subscription modal list items
2022-03-08 11:48:58 -03:00
Alan Rominger
cd86310562 Do not remove artifacts for local work 2022-03-08 09:07:09 -05:00
Shane McDonald
f04d7733bb Add a CI check for the development environment 2022-03-08 09:00:30 -05:00
Shane McDonald
b2fe1c46ee Fix playbook error when files do not exist.
I was seeing "Failed to template loop_control.label: 'dict object' has no attribute 'path'"
2022-03-08 08:18:05 -05:00
Jeff Bradberry
676b8f6d8f Implement an out-of-band migration to change the json fields 2022-03-07 18:11:36 -05:00
Jeff Bradberry
028f09002f Fix the cleanup_jobs management command
It previously depended on a private Django internal class that changed
with Django 3.1.

I've switched here instead to disabling the django-polymorphic
accessors to get the underlying UnifiedJob object for a Job, which due
to the way they implement those was resulting in N+1 behavior on
deletes.  This gets us back most of the way to the performance gains
we achieved with the custom collector class.  See
https://github.com/django-polymorphic/django-polymorphic/issues/198.
2022-03-07 18:11:36 -05:00
Jeff Bradberry
0500512c3c Fix up deprecation warning about get_response for middleware
It will no longer be allowed to be None by Django 4.0
2022-03-07 18:11:36 -05:00
Jeff Bradberry
1e625ed58b Fix up deprecation warning about re_path() replacing urls() 2022-03-07 18:11:36 -05:00
Jeff Bradberry
e620bef2a5 Fix Django 3.1 deprecation removal problems
- FieldDoesNotExist now has to be imported from django.core.exceptions
- Django docs specifically say not to import
  django.conf.global_settings, which now has the side-effect of
  triggering one of the check errors
2022-03-07 18:11:36 -05:00
Jeff Bradberry
05142a779d Replace all usage of customized json fields with the Django builtin
The event_data field on event models, however, is getting an
overridden version that retains the underlying text data type for the
column, to avoid a heavy data migration on those tables.

Also, certain of the larger tables are getting these fields with the
NOT NULL constraint turned off, to avoid a long migration.

Remove the django.utils.six monkey patch we did at the beginning of
the upgrade.
2022-03-07 18:11:36 -05:00
Jeff Bradberry
65d17fb316 Upgrade to Django 3.1
- upgrades
  - Django 3.1.14
  - djangorestframework 3.13.1 (from 3.12.1)
  - djangorestframework-yaml 2.0.0 (from 1.0.3)
  - django-polymorphic 3.1.0 (from 2.1.2)
  - social-auth-core 4.2.0 (from 3.3.1)
  - social-auth-app-django 5.0.0 (from 3.1.0)
  - django-auth-ldap 4.0.0 (from 2.1.0)
  - django-crum 0.7.9 (from 0.7.5)

- django-jsonfield is removed
2022-03-07 18:11:36 -05:00
Jeff Bradberry
faa12880a9 Squash a few deprecation warnings
- inspect.getargspec() -> inspect.getfullargspec()
- register pytest.mark.fixture_args
- replace use of DRF's deprecated NullBooleanField
- fix some usage of naive datetimes in the tests
- fix some strings with backslashes that ought to be raw strings
2022-03-07 18:11:36 -05:00
Jeff Bradberry
9b6fa55433 Deal with breaking tests for 3.1
- Django's PostgreSQL JSONField wraps values in a JsonAdapter, so deal
  with that when it happens.  This goes away in Django 3.1.
- Setting related *_id fields clears the actual relation field, so
  trying to fake objects for tests is a problem
- Instance.objects.me() was inappropriately creating stub objects
  every time while running tests, but some of our tests now create
  real db objects. Ditch that logic and use a proper fixture where needed.
- awxkit tox.ini was pinned at Python 3.8
2022-03-07 18:11:36 -05:00
Jeff Bradberry
b852baaa39 Fix up logger .warn() calls to use .warning() instead
This is a usage that was deprecated in Python 3.0.
2022-03-07 18:11:36 -05:00
Jeff Bradberry
a3a216f91f Fix up new Django 3.0 deprecations
Mostly text based: force/smart_text, ugettext_*
2022-03-07 18:11:36 -05:00
Bill Nottingham
efff85bc1f Fix wsbroadcast for django 3.0+ async
From https://docs.djangoproject.com/en/3.0/topics/async/#asgiref.sync.sync_to_async
2022-03-07 18:11:36 -05:00
Jeff Bradberry
df61d1a59c Upgrade to Django 3.0
- upgrades
  - Django 3.0.14
  - django-jsonfield 1.4.1 (from 1.2.0)
  - django-oauth-toolkit 1.4.1 (from 1.1.3)
    - Stopping here because later versions have changes to the
      underlying model to support OpenID Connect.  Presumably this can
      be dealt with via a migration in our project.
  - django-guid 2.2.1 (from 2.2.0)
  - django-debug-toolbar 3.2.4 (from 1.11.1)
  - python3-saml 1.13.0 (from 1.9.0)
  - xmlsec 1.3.12 (from 1.3.3)

- Remove our project's use of django.utils.six in favor of directly
  using six, in awx.sso.fields.

- Temporarily monkey patch six back in as django.utils.six, since
  django-jsonfield makes use of that import, and is no longer being
  updated.  Hopefully we can do away with this dependency with the new
  generalized JSONField brought in with Django 3.1.

- Force a json decoder to be used with all instances of JSONField
  brought in by django-jsonfield.  This deals with the 'cast to text'
  problem noted previously in our UPGRADE_BLOCKERS.

- Remove the validate_uris validator from the OAuth2Application in
  migration 0025, per the UPGRADE_BLOCKERS, and remove that note.

- Update the TEMPLATES setting to satisfy Django Debug Toolbar.  It
  requires at least one entry that has APP_DIRS=True, and as near as I
  can tell our custom OPTIONS.loaders setting was effectively doing
  the same thing as Django's own machinery if this setting is set.
2022-03-07 18:11:36 -05:00
Shane McDonald
4450b11e61 Merge pull request #11844 from AlanCoding/shane_forward
Adopt changes to AWX_ISOLATION_SHOW_PATHS for trust store
2022-03-07 16:28:42 -05:00
Shane McDonald
9f021b780c Move default show paths to production.py
This breaks the dev env
2022-03-07 16:08:58 -05:00
Shane McDonald
7df66eff5e Merge pull request #11855 from Spredzy/addpackaging
requirements: Add packaging deps following runner upgrade
2022-03-07 15:23:19 -05:00
Yanis Guenane
6e5cde0b05 requirements: Add packaging deps following runner upgrade 2022-03-07 20:51:11 +01:00
Marliana Lara
a65948de69 Add unique row id to subscription modal list items 2022-03-07 13:31:03 -05:00
Marliana Lara
0d0a8fdc9a Merge pull request #11850 from marshmalien/11626-hide-user-only-access-roles
Remove user_only roles from User and Team permission modal
2022-03-07 12:12:31 -05:00
Shane McDonald
a5b888c193 Add default container mounts to AWX_ISOLATION_SHOW_PATHS 2022-03-07 11:45:23 -05:00
Jeff Bradberry
32cc8e1a63 Merge pull request #11845 from jbradberry/awxkit-import-role-precedence
Expand out the early membership role assignment
2022-03-07 11:21:48 -05:00
Jeff Bradberry
69ea456cf6 Expand out the early membership role assignment
The Member role can derive from e.g. the Org Admin role, so basically
all organization and team roles should be assigned first, so that RBAC
conditions are met when assigning later roles.
2022-03-07 09:30:10 -05:00
Alan Rominger
e02e91adaa Merge pull request #11837 from AlanCoding/thread_key_error
Move model and settings operations out of threaded code
2022-03-05 14:55:13 -05:00
Alan Rominger
264c508c80 Move model and settings operations out of threaded code
This is to avoid references to settings in threads,
  this is known to create problems when caches expire
  this leads to KeyError in environments with heavy load
2022-03-04 15:31:12 -05:00
Kersom
c6209df1e0 Api issue float (#11757)
* Fix integer/float errors in survey

* Add SURVEY_TYPE_MAPPING to constants

Add SURVEY_TYPE_MAPPING to constants, and replace usage in a couple of
files.

Co-authored-by: Alexander Komarov <akomarov.me@gmail.com>
2022-03-04 14:03:17 -05:00
Marliana Lara
a155f5561f Remove user_only roles from User and Team permission modal 2022-03-04 13:56:03 -05:00
Shane McDonald
0eac63b844 Merge pull request #11836 from nixocio/ui_ci_matrix
Split UI tests run
2022-03-04 11:50:28 -05:00
Sarah Akus
d07c2973e0 Merge pull request #11792 from marshmalien/8321-job-list-schedule-name
Add schedule detail to job list expanded view
2022-03-04 11:46:45 -05:00
nixocio
f1efc578cb Split UI test run
Split UI test run

See: https://github.com/ansible/awx/issues/10678
2022-03-03 16:22:32 -05:00
Seth Foster
0b486762fa Merge pull request #11840 from fosterseth/meta_vars_priority
load job meta vars after JT extra vars
2022-03-03 13:13:34 -05:00
Alan Rominger
17756f0e72 Add job execution environment image to analytics data (#11835)
* Add job execution environment image to analytics data

* Add EE image to UJT analytics data

* Bump the unified job templates table
2022-03-03 11:13:11 -05:00
Alan Rominger
128400bfb5 Add resolved_action to analytics event data (#11816)
* Add resolved_action to analytics event data

* Bump collector version
2022-03-03 10:11:54 -05:00
Seth Foster
de1df8bf28 load job meta vars after JT extra vars 2022-03-02 14:42:47 -05:00
Alex Corey
fe01f13edb Merge pull request #11790 from AlexSCorey/11712-SelectRelatedQuery
Use select_related on db queries to reduce db calls
2022-03-02 11:33:45 -05:00
Kia Lam
4040e09cb8 Remove setTimeout and old comment from MeshGraph.js. 2022-03-01 16:25:12 -08:00
Shane McDonald
3b6cd18283 Merge pull request #11834 from shanemcd/automate-galaxy-and-pypi
Automate publishing to galaxy and pypi
2022-03-01 16:22:39 -05:00
Keith Grant
4f505486e3 Add Toast messages when resources are copied (#11758)
* create useToast hook

* add copy success toast message to credentials/inventories

* add Toast tests

* add copy success toast to template/ee/project lists

* move Toast type to types.js
2022-03-01 15:59:24 -05:00
Shane McDonald
f6e18bbf06 Publish to galaxy and pypi in promote workflow 2022-03-01 15:42:13 -05:00
liortamary
bbf6484e89 fix code review comments: Add support for Kubernetes authentication method in Hashicorp Vault secret lookup 2022-03-01 21:21:28 +02:00
Marcelo Moreira de Mello
a988ad0c4e Merge pull request #11659 from ansible/expose_isolate_path_k8s
Allow isolated paths as hostPath volume @ k8s/ocp/container groups
2022-03-01 10:52:36 -05:00
Shane McDonald
a815e94209 Merge pull request #11737 from ansible/update-minikube-docs
update minkube docs with steps for using custom operator
2022-03-01 07:49:21 -05:00
Shane McDonald
650bee1dea Merge pull request #11749 from rh-dluong/fix-ocp-cred-desc
Fixed doc string for Container Groups credential type
2022-03-01 07:48:37 -05:00
Shane McDonald
80c188586c Merge pull request #11798 from john-westcott-iv/saml_attr_lists
SAML superuse/auditor working with lists
2022-03-01 07:42:35 -05:00
Shane McDonald
b5cf8f9326 Merge pull request #11819 from shanemcd/transmitter-future
Reimplement transmitter thread as future
2022-03-01 07:33:26 -05:00
Marliana Lara
1aefd39782 Show deleted detail for deleted schedules 2022-02-28 15:51:36 -05:00
Marliana Lara
8c21a2aa9e Add schedule detail to job list expanded view 2022-02-28 14:59:03 -05:00
Shane McDonald
2df3ca547b Reimplement transmitter thread as future
This avoids the need for an explicit `.join()`, and removes the need for the TransmitterThread wrapper class.
2022-02-28 11:21:53 -05:00
Marcelo Moreira de Mello
8645147292 Renamed scontext variable to mount_options 2022-02-28 10:22:24 -05:00
Marliana Lara
169da866f3 Add UI unit tests to job settings 2022-02-28 10:22:24 -05:00
Marcelo Moreira de Mello
5e8107621e Allow isolated paths as hostPath volume @ k8s/ocp/container groups 2022-02-28 10:22:20 -05:00
Alan Rominger
eb52095670 Fix bug where translated strings will cause log error to error (#11813)
* Fix bug where translated strings will cause log error to error

* Use force_str for ensuring string
2022-02-28 08:38:01 -05:00
John Westcott IV
cb57752903 Changing session cookie name and added a way for clients to know what the name is #11413 (#11679)
* Changing session cookie name and added a way for clients to know what the key name is
* Adding session information to docs
* Fixing how awxkit gets the session id header
2022-02-27 07:27:25 -05:00
liortamary
b870659fd9 run black: Add support for Kubernetes authentication method in Hashicorp Vault secret lookup 2022-02-26 18:33:36 +02:00
Shane McDonald
895c05a84a Merge pull request #11808 from john-westcott-iv/fix_minicube
Chaning API version from v1beta1 to v1
2022-02-24 16:32:21 -05:00
John Westcott IV
4d47f24dd4 Chaning API version from v1beta1 to v1 2022-02-24 11:17:36 -05:00
Elijah DeLee
4bd6c2a804 set max dispatch workers to same as max forks
Right now, without this, we end up with a different number for max_workers than max_forks. For example, on a control node with 16 Gi of RAM,
  max_mem_capacity  w/ 100 MB/fork = (16*1024)/100 --> 164
  max_workers = 5 * 16 --> 80

This means we would allow that control node to control up to 164 jobs, but all jobs after the 80th job will be stuck in `waiting` waiting for a dispatch worker to free up to run the job.
2022-02-24 10:53:54 -05:00
Shane McDonald
48fa947692 Merge pull request #11756 from shanemcd/ipv6-podman
Enable Podman ipv6 support by default
2022-02-24 09:58:20 -05:00
Shane McDonald
88f66d5c51 Enable Podman ipv6 support by default 2022-02-24 08:51:51 -05:00
Kia Lam
fd135caed5 Offload simulation calculation to web worker. 2022-02-23 18:54:18 -08:00
Kia Lam
7fbab6760e Small layout adjustment. 2022-02-23 12:37:20 -08:00
Marcelo Moreira de Mello
e9a8175fd7 Merge pull request #11702 from ansible/fact_insights_mount_issues
Do not mount /etc/redhat-access-insights into EEs
2022-02-23 14:44:10 -05:00
Marcelo Moreira de Mello
0d75a25bf0 Do not mount /etc/redhat-access-insights into EEs
Sharing the /etc/redhat-access-insights is no longer
required for EEs. Furthermore, this fixes a SELinux issue
when launching multiple jobs with concurrency and fact_caching enabled.

i.e:
lsetxattr /etc/redhat-access-insights: operation not permitted
2022-02-23 14:12:33 -05:00
Tiago Góes
6af294e9a4 Merge pull request #11794 from jainnikhil30/fix_credential_types_drop_down
Allow more than 400 credential types in drop down while adding new credential
2022-02-23 16:08:28 -03:00
Elijah DeLee
38f50f014b fix missing job lifecycle messages (#11801)
we were missing these messages for control type jobs that call start_task earlier than other types of jobs
2022-02-23 13:56:25 -05:00
Alex Corey
a394f11d07 Resolves occassions where missing table data moves items to the left (#11772) 2022-02-23 11:36:20 -05:00
Kersom
3ab73ddf84 Fix TypeError when running a command on a host in a smart inventory (#11768)
Fix TypeError when running a command on a host in a smart inventory

See: https://github.com/ansible/awx/issues/11611
2022-02-23 10:32:27 -05:00
John Westcott IV
c7a1fb67d0 SAML superuse/auditor now searching all fields in a list instead of just the first 2022-02-23 09:35:11 -05:00
nixocio
afb8be4f0b Refactor fetch of credential types
Refactor fetch of credential types
2022-02-23 09:29:23 -05:00
Nikhil Jain
dc2a392f4c forgot to run prettier earlier 2022-02-23 12:09:51 +05:30
Nikhil Jain
61323c7f85 allow more than 400 credential types in drop down while adding new credential 2022-02-23 11:30:55 +05:30
Kia Lam
7ebf6b77e5 Disable zoom controls until mesh layout is finalized. 2022-02-22 13:45:30 -08:00
Alex Corey
fa47e48a15 Fixes broken link from User to UserOrg (#11759) 2022-02-22 16:34:30 -05:00
Kia Lam
fee47fe347 Vertically center node type symbols on Firefox. 2022-02-22 09:36:57 -08:00
Kia Lam
039c038cd7 Move zoom methods into a hook. 2022-02-22 09:36:43 -08:00
liortamary
dd99a25db0 unittest: Add support for Kubernetes authentication method in Hashicorp Vault secret lookup
Signed-off-by: liortamary <lior.tamary@houzz.com>
2022-02-22 17:53:34 +02:00
liortamary
85791f730c Add support for Kubernetes authentication method in Hashicorp Vault secret lookup
Signed-off-by: liortamary <lior.tamary@houzz.com>
2022-02-22 13:04:58 +02:00
Kersom
eb859b9812 Fix TypeError when running a command on a host in a smart inventory (#11768)
Fix TypeError when running a command on a host in a smart inventory

See: https://github.com/ansible/awx/issues/11611
2022-02-21 16:34:31 -05:00
Kersom
7cf0523561 Display roles for organization listed when using non-English web browser (#11762)
Display roles for organization listed when using non-English web browser
2022-02-21 15:53:32 -05:00
Alex Corey
aae2e3f835 Merge pull request #11785 from ansible/dependabot/npm_and_yarn/awx/ui/url-parse-1.5.9
Bump url-parse from 1.5.3 to 1.5.9 in /awx/ui
2022-02-21 14:02:17 -05:00
liortamary
e0ce4c49f3 Add support for Kubernetes authentication method in Hashicorp Vault secret lookup
Signed-off-by: liortamary <lior.tamary@houzz.com>
2022-02-21 17:41:14 +02:00
dependabot[bot]
a60a65cd2a Bump url-parse from 1.5.3 to 1.5.9 in /awx/ui
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.9.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.9)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 15:06:19 +00:00
Kersom
b7d0ec53e8 Merge pull request #11776 from nixocio/ui_ternary
Use ternary rather than &&
2022-02-17 18:24:09 -05:00
Kia Lam
ef5cd66494 Excise disable-lint rules. 2022-02-17 13:58:16 -08:00
Kia Lam
0d1898e72d Add error screen. 2022-02-17 13:26:31 -08:00
nixocio
f20cd8c203 Use ternary rather than &&
Use ternary rather than && to avoid display 0.
2022-02-17 15:34:03 -05:00
Kia Lam
8993dc706a Redirect to Instances/{nodeId}/details page. 2022-02-17 10:53:27 -08:00
Kia Lam
af18453691 Use 100% height. 2022-02-17 10:21:48 -08:00
kialam
c102bf05af Update awx/ui/src/screens/TopologyView/MeshGraph.js
Co-authored-by: Tiago Góes <tiago.goes2009@gmail.com>
2022-02-17 10:21:48 -08:00
Kia Lam
b1570302bc Refactor: move constants and helper functions into their own files. 2022-02-17 10:21:48 -08:00
Kia Lam
69a42b1a89 Some lint fixes; fix routesConfig unit test. 2022-02-17 10:21:48 -08:00
Kia Lam
272e012626 Add new loading screen placeholder. 2022-02-17 10:21:47 -08:00
Kia Lam
d785f30c5f Fix JSX errors. 2022-02-17 10:21:47 -08:00
Kia Lam
9854f8a6ab Use alpha decay percentage instead of absolute value for loading screen. 2022-02-17 10:21:47 -08:00
Kia Lam
4235bf67f8 Truncate long host names in graph, show full name in tooltip. 2022-02-17 10:21:47 -08:00
Kia Lam
a6bc0d4222 Add loading screen. 2022-02-17 10:21:47 -08:00
Kia Lam
b859c3360d Add zoom to fit. 2022-02-17 10:21:47 -08:00
Kia Lam
391907c41e Add reset zoom button. 2022-02-17 10:21:47 -08:00
Kia Lam
04a550cc67 Hook up zoom in, zoom out buttons. 2022-02-17 10:21:46 -08:00
Kia Lam
cf459dc4e8 Remove placeholder label text. 2022-02-17 10:21:46 -08:00
Kia Lam
afebcc574d Add icons to header; randomly generate data. 2022-02-17 10:21:46 -08:00
Kia Lam
f3474f0811 Add legend toggle to header. 2022-02-17 10:21:46 -08:00
Kia Lam
7378952a8b Add opaque bg to tooltip and legend. 2022-02-17 10:21:46 -08:00
Kia Lam
3cfab418d1 Fix zoom on scroll. 2022-02-17 10:21:46 -08:00
Kia Lam
8090cd3032 WIP new mesh layout based on QE feedback. 2022-02-17 10:21:46 -08:00
Kia Lam
cd54d560b3 Update layout; fix multiple renders happening on page load. 2022-02-17 10:21:46 -08:00
Tiago
9fc92ccc52 add data-cy attr 2022-02-17 10:21:46 -08:00
Kia Lam
b8674a3f8c Use PF colors for nodes. 2022-02-17 10:21:46 -08:00
Kia Lam
07ccce9845 Zoom in/out on entire SVG canvas. 2022-02-17 10:21:46 -08:00
Kia Lam
0c8c69f04a Add RBAC for /topology_view endpoint. 2022-02-17 10:21:46 -08:00
Kia Lam
5856f805fc Add debounce to resize event; link to node details. 2022-02-17 10:21:46 -08:00
Kia Lam
73a5802c11 Lint. 2022-02-17 10:21:45 -08:00
Kia Lam
826a069be0 Highlight immediate siblings on hover. 2022-02-17 10:21:45 -08:00
Kia Lam
1246b14e7e WIP add network visualizer to Controller UI. 2022-02-17 10:21:45 -08:00
Tiago Góes
1ed0b70601 Merge pull request #11764 from ansible/filter_hopcontrol_from_associatemodal
filter out both hop and control nodes instead of just one or the other
2022-02-17 14:48:59 -03:00
Shane McDonald
c3621f1e89 Merge pull request #11742 from kdelee/drop_unused_capacity_tracking
drop unused logic in task manager
2022-02-17 09:46:00 -05:00
Shane McDonald
7de86fc4b4 Merge pull request #11747 from AlanCoding/loop_label
Add loop label with docker-compose playbook
2022-02-17 09:45:03 -05:00
Shane McDonald
963948b5c8 Merge pull request #11767 from simaishi/rekey_existing
Allow rekey with an existing key
2022-02-17 09:39:05 -05:00
Shane McDonald
d9749e8975 Merge pull request #11734 from shanemcd/fix-image-push
Fix image push when overriding awx_image_tag
2022-02-17 07:21:29 -05:00
Julen Landa Alustiza
f6e4e53728 Merge pull request #11766 from Zokormazo/collection-pep8
pep8 E231 fix for awx_collection
2022-02-17 13:21:23 +01:00
Julen Landa Alustiza
98adb196ea pep8 E231 fix for awx_collection
Signed-off-by: Julen Landa Alustiza <jlanda@redhat.com>
2022-02-17 09:34:48 +01:00
Rebeccah
6b60edbe5d filter out both hop and control nodes instead of just one or the other 2022-02-16 18:32:41 -05:00
Satoe Imaishi
9d6de42f48 Allow rekey with an existing key
(cherry picked from commit 0c6440b46756f02a669d87e461faa4abc5bab8e6)
2022-02-16 17:58:22 -05:00
Tiago Góes
a94a602ccd Merge pull request #11746 from AlexSCorey/11744-fixValidatorBug
Fixes validator console error, and routing issue in Instance Groups Branch
2022-02-16 12:28:43 -03:00
dluong
301818003d Fixed doc string for Container Groups credential type 2022-02-15 16:10:28 -05:00
John Westcott IV
50d52c31e2 Chaning workflow to run on all release branches 2022-02-15 15:32:27 -05:00
Elijah DeLee
799968460d Fixup conversion of memory and cpu settings to support k8s resource request format (#11725)
fix memory and cpu settings to suport k8s resource request format

* fix conversion of memory setting to bytes

This setting has not been getting set by default, and needed some fixing
up to be compatible with setting the memory in the same way as we set it
in the operator, as well as with other changes from last year which
assume that ansible runner is returning memory in bytes.

This way we can start setting this setting in the operator, and get a
more accurate reflection of how much memory is available to the control
pod in k8s.

On platforms where services are all sharing memory, we deduct a
penalty from the memory available. On k8s we don't need to do this
because the web, redis, and task containers each have memory
allocated to them.

* Support CPU setting expressed in units used by k8s

This setting has not been getting set by default, and needed some fixing
up to be compatible with setting the CPU resource request/limits in the
same way as we set it in the resource requests/limits.

This way we can start setting this setting in the
operator, and get a more accurate reflection of how much cpu is
available to the control pod in k8s.

Because cpu on k8s can be partial cores, migrate cpu field to decimal.

k8s does not allow granularity of less than 100m (equivalent to 0.1 cores), so only
store up to 1 decimal place.

fix analytics to deal with decimal cpu

need to use DjangoJSONEncoder when Decimal fields in data passed to
json.dumps
2022-02-15 14:08:24 -05:00
Alex Corey
170d95aa3c Fixes validator console error, and routing issue in Instance Groups branch 2022-02-15 13:07:36 -05:00
Alan Rominger
fe7a2fe229 Add loop label with docker-compose playbook 2022-02-15 13:05:59 -05:00
Amol Gautam
3f08e26881 Merge pull request #11571 from amolgautam25/tasks-refactor-2
Added new class for  Ansible Runner Callbacks
2022-02-15 10:31:32 -05:00
Elijah DeLee
921b2bfb28 drop unused logic in task manager
There is no current need or use to keep a seperate dependency graph for
each instance group. In the interest of making it clearer what the
current code does, eliminate this superfluous complication.

We are no longer ever referencing any accounting of instance group
capacity, instead we only look
at capacity on intances.
2022-02-14 16:15:03 -05:00
Alex Corey
9af2c92795 Merge pull request #11691 from AlexSCorey/11634-ContaineGroupNameFix
Fixes erroneous disabling of name input field on container and instance group forms
2022-02-14 16:14:32 -05:00
Alex Corey
dabae456d9 Merge pull request #11653 from AlexSCorey/11588-TopLevelInstances
Adds top level instances list
2022-02-14 16:06:55 -05:00
Alex Corey
c40785b6eb Fixes erroneous disabling of name input field on container and instance group forms 2022-02-14 15:47:50 -05:00
Alex Corey
e2e80313ac Refactor the health check button 2022-02-14 15:35:25 -05:00
Alex Corey
14a99a7b9e resolves advanced search button 2022-02-14 15:35:24 -05:00
Alex Corey
50e8c299c6 Adds top level instances list 2022-02-14 15:35:24 -05:00
Alex Corey
326d12382f Adds Inventory labels (#11558)
* Adds inventory labels end point

* Adds label field to inventory form
2022-02-14 15:14:08 -05:00
Kersom
1de9dddd21 Merge pull request #11724 from nixocio/ui_issue_11708
Bump node to LTS version
2022-02-14 13:11:57 -05:00
nixocio
87b1f0d0de Bump node to LTS version
Bump node to LTS version
2022-02-14 12:41:11 -05:00
Elijah DeLee
dd6cf19c39 update steps for using custom operator
Updating this to use the new make commands in the operator repo
2022-02-14 11:01:30 -05:00
Kersom
f085afd92f Merge pull request #11592 from nixocio/ui_issue_11017_utils
Modify usage of ansible_facts on advanced search
2022-02-14 10:30:45 -05:00
Elijah DeLee
604cbc1737 Consume control capacity (#11665)
* Select control node before start task

Consume capacity on control nodes for controlling tasks and consider
remainging capacity on control nodes before selecting them.

This depends on the requirement that control and hybrid nodes should all
be in the instance group named 'controlplane'. Many tests do not satisfy that
requirement. I'll update the tests in another commit.

* update tests to use controlplane

We don't start any tasks if we don't have a controlplane instance group

Due to updates to fixtures, update tests to set node type and capacity
explicitly so they get expected result.

* Fixes for accounting of control capacity consumed

Update method is used to account for currently consumed capacity for
instance groups in the in-memory capacity tracking data structure we initialize in
after_lock_init and then update via calculate_capacity_consumed (both in
task_manager.py)

Also update fit_task_to_instance to consider control impact on instances

Trust that these functions do the right thing looking for a
node with capacity, and cut out redundant check for the whole group's
capacity per Alan's reccomendation.

* Refactor now redundant code

Deal with control type tasks before we loop over the preferred instance
groups, which cuts out the need for some redundant logic.

Also, fix a bug where I was missing assigning the execution node in one case!

* set job explanation on tasks that need capacity

move the job explanation for jobs that need capacity to a function
so we can re-use it in the three places we need it.

* project updates always run on the controlplane

Instance group ordering makes no sense on project updates because they
always need to run on the control plane.

Also, since hybrid nodes should always run the control processes for the
jobs running on them as execution nodes, account for this when looking for a
execution node.

* fix misleading message

the variables and wording were both misleading, fix to be more accurate
description in the two different cases where this log may be emitted.

* use settings correctly

use settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME instead of a hardcoded
name
cache the controlplane_ig object during the after lock init to avoid
an uneccesary query
eliminate mistakenly duplicated AWX_CONTROL_PLANE_TASK_IMPACT and use
only AWX_CONTROL_NODE_TASK_IMPACT

* add test for control capacity consumption

add test to verify that when there are 2 jobs and only capacity for one
that one will move into waiting and the other stays in pending

* add test for hybrid node capacity consumption

assert that the hybrid node is used for both control and execution and
capacity is deducted correctly

* add test for task.capacity_type = control

Test that control type tasks have the right capacity consumed and
get assigned to the right instance group

Also fix lint in the tests

* jobs_running not accurate for control nodes

We can either NOT use "idle instances" for control nodes, or we need
to update the jobs_running property on the Instance model to count
jobs where the node is the controller_node.

I didn't do that because it may be an expensive query, and it would be
hard to make it match with jobs_running on the InstanceGroup which
filters on tasks assigned to the instance group.

This change chooses to stop considering "idle" control nodes an option,
since we can't acurrately identify them.

The way things are without any change, is we are continuing to over consume capacity on control nodes
because this method sees all control nodes as "idle" at the beginning
of the task manager run, and then only counts jobs started in that run
in the in-memory tracking. So jobs which last over a number of task
manager runs build up consuming capacity, which is accurately reported
via Instance.consumed_capacity

* Reduce default task impact for control nodes

This is something we can experiment with as far as what users
want at install time, but start with just 1 for now.

* update capacity docs

Describe usage of the new setting and the concept of control impact.

Co-authored-by: Alan Rominger <arominge@redhat.com>
Co-authored-by: Rebeccah <rhunter@redhat.com>
2022-02-14 10:13:22 -05:00
Shane McDonald
60b6faff19 Merge pull request #11655 from ivarmu/devel
Let an organization admin to add new users to it's tower organization
2022-02-12 19:35:51 -05:00
Shane McDonald
e70059ed6b Fix image push when overriding awx_image_tag 2022-02-12 13:34:46 -05:00
Rebeccah Hunter
b26c1c16b9 Merge pull request #11728 from ansible/node_state_unhealthy_to_error
[mesh viz] change the term unhealthy to error
2022-02-11 16:02:43 -05:00
Rebeccah
c2bf9d94be change the term unhealthy to error 2022-02-11 15:42:33 -05:00
Brandon Sharp
ea09adbbf3 Add await to handleLaunch (#11649)
* Add async to handleLaunch

* Fix package-lock

Co-authored-by: Wambugu  Kironji <wkironji@redhat.com>
2022-02-11 13:40:20 -05:00
Seth Foster
9d0de57fae Merge pull request #11717 from fosterseth/emit_event_detail_metrics
Add metric for number of events emitted over websocket broadcast
2022-02-11 12:52:16 -05:00
nixocio
da733538c4 Modify usage of ansible_facts on advanced search
Modify usage of ansible_facts on advanced search, once `ansible_facts`
key is selected render a text input allowing the user to type special
query expected for ansible_facts.

This change will add more flexibility to the usage of ansible_facts when
creating a smart inventory.

See: https://github.com/ansible/awx/issues/11017
2022-02-11 10:24:04 -05:00
Seth Foster
6db7cea148 variable name changes 2022-02-10 10:57:00 -05:00
Seth Foster
3993aa9524 Add metric for number of events emitted over websocket broadcast 2022-02-09 21:57:01 -05:00
Alex Corey
6f9d4d89cd Adds credential password step to ad hoc commands wizard (#11598) 2022-02-09 15:59:50 -05:00
Amol Gautam
443bdc1234 Decoupled callback functions from BaseTask Class
--- Removed all callback functions from 'jobs.py' and put them in a new file '/awx/main/tasks/callback.py'
--- Modified Unit tests unit moved
--- Moved 'update_model' from jobs.py to /awx/main/utils/update_model.py
2022-02-09 13:46:32 -05:00
Ivan Aragonés Muniesa
9cd43d044e let an organization admin to add new users to it's tower organization 2022-02-09 18:59:53 +01:00
Kersom
f8e680867b Merge pull request #11710 from nixocio/ui_npm_audit
Run npm audit fix
2022-02-09 12:48:54 -05:00
Rebeccah Hunter
96a5540083 Merge pull request #11632 from ansible/minikube-docs-part-2
update minikube dev env docs with newer keywords for instantiate-awx-deployment.yml
2022-02-09 11:44:43 -05:00
Shane McDonald
750e1bd80a Merge pull request #11342 from shanemcd/custom-uwsgi-mount-path
Allow for running AWX at non-root path (URL prefixing)
2022-02-09 10:37:04 -05:00
Jeff Bradberry
a12f161be5 Merge pull request #11711 from jbradberry/firehose-with-partitioning
Fix the firehose job creation script
2022-02-09 10:07:47 -05:00
Jeff Bradberry
04568ea830 Fix the firehose job creation script
to account for the changes made due to the job event table partitioning work.
2022-02-09 09:49:17 -05:00
nixocio
3be0b527d6 Run npm audit fix
Run npm audit fix

See: https://github.com/ansible/awx/issues/11709
2022-02-09 09:03:20 -05:00
Kersom
afc0732a32 Merge pull request #11568 from nixocio/ui_rs5
Bump react scripts to 5.0
2022-02-09 07:49:43 -05:00
nixocio
9703fb06fc Bump react scripts to 5.0
Bump react scripts to 5.0

See: https://github.com/ansible/awx/issues/11543

Bump eslint

Bump eslint and related plugins

Add @babe/core

Add @babe/core remove babel/core.

Rename .eslintrc to .eslintrc.json

Rename .eslintrc to .eslintrc.json

Add extra plugin

Move babe-plugin-macro as dev dependencies

Move babe-plugin-macro as dev dependencies

Add preset-react

Add preset-react

Fixing lint errors

Fixing lint errors

Run eslint --fix

Run eslint --fix

Turn no-restricted-exports off

Turn no-restricted-exports off

Revert "Run eslint --fix"

This reverts commit e760885b6c199f2ca18091088cb79bfa77c1d3ed.

Run --fix

Run --fix

Fix lint errors

Also bump specificity of Select CSS border component to avoid bug of
missing borders.

Also update API tests related to lincenses.
2022-02-08 11:12:51 -05:00
Shane McDonald
54cbf13219 Merge pull request #11696 from sean-m-sullivan/awx_collection_role_update_v2
add execution_environment_admin to role module
2022-02-08 10:12:00 -05:00
Shane McDonald
6774a12c67 Merge pull request #11694 from shanemcd/scoped-schema
Scope schema.json to target branch
2022-02-08 09:48:08 -05:00
Sean Sullivan
94e53d988b add execution adminitrator to role module 2022-02-08 09:44:50 -05:00
Shane McDonald
22d47ea8c4 Update port binding for UI dev tooling
Jake says "Folks sometimes run the ui dev server independently of the tools_awx container"

Co-authored-by: Jake McDermott <9753817+jakemcdermott@users.noreply.github.com>
2022-02-08 08:33:21 -05:00
Sarah Akus
73bba00cc6 Merge pull request #11670 from keithjgrant/11628-missing-job-output
Display all job type events in job output
2022-02-07 18:04:18 -05:00
Shane McDonald
6ed429ada2 Scope api schema.json to target branch 2022-02-07 17:54:01 -05:00
Keith J. Grant
d2c2d459c4 display all job type events in job output 2022-02-07 14:48:39 -08:00
John Westcott IV
c8b906ffb7 Workflow changes (#11692)
Modifying workflows to install python for make commands
Squashing CI tasks to remove repeated steps
Modifying pre-commit.sh to not fail if there are no python file changes
2022-02-07 15:42:35 -05:00
Shane McDonald
264f1d6638 Merge pull request #11685 from shanemcd/skip-pytest-7.0.0
Skip pytest 7.0.0
2022-02-04 16:09:42 -05:00
Shane McDonald
16c7908adc Skip pytest 7.0.0
A test was failing with:

    from importlib.readers import FileReader
E   ModuleNotFoundError: No module named 'importlib.readers'
2022-02-04 15:48:18 -05:00
Sarabraj Singh
c9d05d7d4a Merge pull request #11474 from sarabrajsingh/supervisord-rsyslog-event-listener-buff
adding event handler specific to when awx-rsyslog throws PROCESS_LOG_STDERR
2022-02-04 11:59:51 -05:00
Sarabraj Singh
ec7e4488dc adding event handler specific to when awx-rsyslog throws PROCESS_LOG_STDERR errors based on 4XX http errors; increased clarity in stderr log messages; removed useless None intializations 2022-02-04 11:18:45 -05:00
Alex Corey
72f440acf5 Merge pull request #11675 from AlexSCorey/11630-WrongtooltipDocs
Fix tooltip documentation in settings
2022-02-04 10:23:11 -05:00
Alan Rominger
21bf698c81 Merge pull request #11617 from AlanCoding/task_job_id
Fix error on timeout with non-job types
2022-02-04 09:41:25 -05:00
Shane McDonald
489ee30e54 Simplify code that generates named URLS 2022-02-03 19:00:07 -05:00
Shane McDonald
2abab0772f Bind port for UI live reload tooling in development environmentt
This allows for running:

```
docker exec -ti tools_awx_1 npm --prefix=awx/ui start
```
2022-02-03 19:00:07 -05:00
Shane McDonald
0bca0fabaa Fix bug in named url middleware when running at non-root path
The most notable change here is the removal of the conditional in
process_request. I don't know why we were preferring REQUEST_URI over
PATH_INFO. When the app is running at /, they are always the same as far as I
can tell. However, when using SCRIPT_NAME, this was incorrectly setting path and
path_info to /myprefix/myprefix/.
2022-02-03 19:00:07 -05:00
Shane McDonald
93ac3fea43 Make UI work when not running at root path 2022-02-03 19:00:07 -05:00
Shane McDonald
c72b71a43a Use relative paths for UI assets
Found at https://create-react-app.dev/docs/deployment/#serving-the-same-build-from-different-paths
2022-02-03 19:00:07 -05:00
Shane McDonald
9e8c40598c Allow for overriding UWSGI mount path
This is just one piece of the puzzle as I try to add support for URL prefixing.
2022-02-03 19:00:07 -05:00
Shane McDonald
4ded4afb7d Move production UWSGI config to a file 2022-02-03 19:00:07 -05:00
Seth Foster
801c45da6d Merge pull request #11681 from fosterseth/fix_cleanup_named_pipe
remove any named pipes before unzipping artifacts
2022-02-03 15:43:05 -05:00
srinathman
278b356a18 Update saml.md (#11663)
* Update saml.md

- Updated link to python documentation
- Added instructions for superadmin permissions

Co-authored-by: John Westcott IV <john.westcott.iv@redhat.com>
2022-02-03 13:33:50 -05:00
Shane McDonald
a718e01dbf Merge pull request #11676 from shanemcd/automate-labels
Automate labels with GHA
2022-02-03 10:53:15 -05:00
Shane McDonald
8e6cdde861 Automate labels 2022-02-03 09:45:00 -05:00
Alex Corey
62b0c2b647 Fix tooltip documentation 2022-02-02 16:18:41 -05:00
Seth Foster
1cd30ceb31 remove any named pipes before unzipping artifacts 2022-02-02 15:54:31 -05:00
Shane McDonald
15c7a3f85b Merge pull request #11673 from ansible/fix_dockerfile_kube_dev_deps
Includes gettext on build-deps for multi-stage builds
2022-02-02 15:31:54 -05:00
Alex Corey
d977aff8cf Merge pull request #11668 from nixocio/ui_issue_11582
Fix typerror cannot read property of null
2022-02-02 14:46:04 -05:00
Marcelo Moreira de Mello
e3b44c3950 Includes gettext on build-deps for multi-stage builds 2022-02-02 14:12:27 -05:00
nixocio
ba035efc91 Fix typerror cannot read property of null
```
> x = null
null
> x?.contains
undefined
> x.contains
Uncaught TypeError: Cannot read property 'contains' of null
```

See: https://github.com/ansible/awx/issues/11582
2022-02-02 13:54:37 -05:00
Sarah Akus
76cfd7784a Merge pull request #11517 from AlexSCorey/11236-ExpandCollapseAll
Adds expand collapse all functionality on job output page.
2022-02-02 09:43:13 -05:00
Alex Corey
3e6875ce1d Adds expand collapse all functionality on job output page. 2022-02-02 09:26:08 -05:00
Shane McDonald
1ab7aa0fc4 Merge pull request #11662 from simaishi/remove_tower_setup_script
Remove ansible-tower-setup script
2022-02-01 15:25:00 -05:00
Shane McDonald
5950e0bfcb Merge pull request #11643 from john-westcott-iv/github_meta_changes
GitHub meta changes
2022-02-01 13:15:40 -05:00
Satoe Imaishi
ac540d3d3f Remove tower-setup script - no longer used 2022-02-01 12:51:02 -05:00
Rebeccah Hunter
848ddc5f3e Merge pull request #10912 from rh-dluong/add_org_alias_to_org_mapping
Add organization_alias to Org Mapping as intended
2022-02-01 11:44:48 -05:00
Marliana Lara
30d1d63813 Add wf node list item info popover (#11587) 2022-02-01 11:10:24 -05:00
dluong
9781a9094f Added functionality to where user can add organization alias to org mapping so that the user doesn't have to match the saml attr exactly as the org name 2022-02-01 09:46:37 -05:00
Kersom
ab3de5898d Merge pull request #11646 from jainnikhil30/fix_jobs_id
add job id to the jobs details page
2022-02-01 08:45:51 -05:00
Nikhil Jain
7ff8a3764b add job id to the jobs details page 2022-02-01 10:34:02 +05:30
Tiago Góes
32d6d746b3 Merge pull request #11638 from jakemcdermott/fix-prompted-inventory-role-level
Only display usable inventories for launch prompt
2022-01-31 17:48:28 -03:00
Shane McDonald
ecf9a0827d Merge pull request #11618 from fosterseth/ps_in_dev_image
Install ps in dev image
2022-01-31 12:42:59 -05:00
John Westcott IV
a9a7fac308 Removing the Installer option in issues and pr templates 2022-01-31 10:56:59 -05:00
Alan Rominger
54b5884943 Merge pull request #11642 from AlanCoding/new_black_rule
Fix newly-added black rules
2022-01-31 10:01:50 -05:00
John Westcott IV
1fb38137dc Adding Collection and Installer category to issues/prs 2022-01-30 14:01:25 -05:00
John Westcott IV
2d6192db75 Adding triage label to any new issue 2022-01-30 13:59:37 -05:00
Jeff Bradberry
9ecceb4a1e Merge pull request #11639 from jbradberry/fix-updater-script
Deal properly with comments in requirements_git.txt
2022-01-30 10:16:22 -05:00
Alan Rominger
6b25fcaa80 Fix newly-added black rules 2022-01-29 23:17:58 -05:00
Jeff Bradberry
c5c83a4240 Deal properly with comments in requirements_git.txt
The updater.sh script was expecting that _every_ line in this file was
a repo reference.
2022-01-28 17:30:42 -05:00
Jake McDermott
5e0eb5ab97 Only display usable inventories for launch prompt 2022-01-28 16:13:19 -05:00
Alan Rominger
2de5ffc8d9 Merge pull request #11627 from AlanCoding/fast_heartbeat
Prevent duplicate query in local health check
2022-01-28 13:19:56 -05:00
Elijah DeLee
3b2fe39a0a update another part of minikube dev env docs
vars in ansible/instantiate-awx-deployment.yml in awx-operator repo appear to have been updated, because when we used the `tower_...` vars, they did not apply
2022-01-27 23:31:20 -05:00
Alan Rominger
285ff080d0 Prevent duplicate query in local health check 2022-01-27 15:27:07 -05:00
Jeff Bradberry
627bde9e9e Merge pull request #11614 from jbradberry/register_peers_warn_2cycles
Only do a warning on 2-cycles for the register_peers command
2022-01-27 10:25:19 -05:00
Shane McDonald
ef7d5e6004 Merge pull request #11621 from ansible/update-minikube-dev-env-docs
Update minikube dev environment docs
2022-01-27 09:56:50 -05:00
Elijah DeLee
598c8a1c4d Update minikube docs
Replace reference to a non-existent playbook with current directions from awx-operator
Also add some tips about how to interact with the deployment
2022-01-27 08:37:14 -05:00
Seth Foster
b3c20ee0ae Install ps in dev image 2022-01-26 18:12:52 -05:00
Alan Rominger
cd8d382038 Fix error on timeout with non-job types 2022-01-26 17:00:59 -05:00
Shane McDonald
b678d61318 Merge pull request #11569 from zjzh/devel
Update ad_hoc_commands.py
2022-01-26 16:51:30 -05:00
Brian Coca
43c8231f7d fix deprecated indentation and type (#11599)
* fix deprecated indentation and type

This was breaking docs build for any plugins that used this fragment

fixes #10776
2022-01-26 16:10:02 -05:00
Shane McDonald
db401e0daa Merge pull request #11616 from shanemcd/hostname
Install hostname in dev image
2022-01-26 15:04:07 -05:00
Shane McDonald
675d4c5f2b Install hostname in dev image 2022-01-26 14:39:57 -05:00
Jeff Bradberry
fdbf3ed279 Only do a warning on 2-cycles for the register_peers command
It has no way of knowing whether a later command will fix the
situation, and this will come up in the installer.  Let's just trust
the pre-flight checks.
2022-01-26 11:50:57 -05:00
Shane McDonald
5660f9ac59 Merge pull request #11514 from shanemcd/python39
Upgrade to Python 3.9
2022-01-26 10:59:14 -05:00
Alex Corey
546e63aa4c Merge pull request #11581 from AlexSCorey/UpdateReleaseNotes
Adds more detail to the AWX release notes
2022-01-26 10:43:52 -05:00
Alex Corey
ddbd143793 Adds more detail to the AWX release notes 2022-01-26 09:52:40 -05:00
Shane McDonald
35ba321546 Unpin virtualenv version 2022-01-25 17:41:38 -05:00
Shane McDonald
2fe7fe30f8 Remove epel
This doesnt seem to be needed anymore
2022-01-25 17:39:42 -05:00
Alan Rominger
8d4d1d594b Merge pull request #11608 from AlanCoding/mount_awx_devel
Mount awx_devel in execution nodes for developer utility
2022-01-25 16:42:56 -05:00
Alan Rominger
c86fafbd7e Mount awx_devel in execution nodes for developer utility 2022-01-25 12:28:26 -05:00
Jeff Bradberry
709c439afc Merge pull request #11591 from ansible/enable-hop-nodes-endpoints
Turn off the filtering of hop nodes from the Instance endpoints
2022-01-25 12:03:23 -05:00
Sarah Akus
4cdc88e4bb Merge pull request #11534 from marshmalien/7678-inv-sync-link
Link from sync status icon to prefiltered list of inventory source sync jobs
2022-01-25 12:03:09 -05:00
Jeff Bradberry
7c550a76a5 Make sure to filter out control-plane nodes in inspect_execution_nodes
Also, make sure that the cluster host doesn't get marked as lost by
this machinery.
2022-01-25 11:06:20 -05:00
Marcelo Moreira de Mello
cfabbcaaf6 Merge pull request #11602 from ansible/avoid_project_updates_on_create_preload_data
Avoid Project..get_or_create() in create_preload_data
2022-01-24 18:20:29 -05:00
Marcelo Moreira de Mello
7ae6286152 Avoid Project..get_or_create() in create_preload_data
Django ORM method get_or_create() does not call save() directly,
but it calls the create() [1].

The create method ignores the skip_update=True option, which then
will trigger a project update, however the EE was not yet created
in the database.

To avoid this problem, we just check the existence of the default
project and creates it with save(skip_update=True) manually.
2022-01-24 17:59:29 -05:00
Jeff Bradberry
fd9c28c960 Adjust register_queue command to not allow hop nodes to be added 2022-01-24 17:40:55 -05:00
Jeff Bradberry
fa9ee96f7f Adjust the list_instances command to show hop nodes
with appropriate attributes removed or added.
2022-01-24 17:22:12 -05:00
Jeff Bradberry
334c33ca07 Handle receptorctl advertisements for hop nodes
counting it towards their heartbeat.  Also, leave off the link to the
health check endpoint from hop node Instances.
2022-01-24 16:51:45 -05:00
Keith Grant
85cc67fb4e Update status icons (#11561)
* update StatusLabels on job detail

* change StatusIcon to use PF circle icons

* change status icon to status label on host event modal

* update status label on wf job output

* update tests for status label changes

* fix default status icon color
2022-01-24 14:01:02 -05:00
Shane McDonald
af9eb7c374 Update timezone test 2022-01-24 12:21:28 -05:00
Shane McDonald
44968cc01e Upgrade to Python 3.9 2022-01-24 12:21:20 -05:00
Shane McDonald
af69b25eaa Merge pull request #11332 from shanemcd/bump-deps
Security-related updates for some Python dependencies.
2022-01-24 12:13:53 -05:00
Shane McDonald
eb33b95083 Merge pull request #11548 from shanemcd/revert-11428
Revert "Make awx-python script available in k8s app images"
2022-01-24 12:10:01 -05:00
Marcelo Moreira de Mello
aa9124e072 Merge pull request #11566 from ansible/expose_isolate_path_podman_O
Support user customization of EE mount options and mount paths
2022-01-21 22:41:23 -05:00
Marcelo Moreira de Mello
c086fad945 Added verbosity to molecule logs 2022-01-21 21:30:49 -05:00
Marcelo Moreira de Mello
0fef88c358 Support user customization of container mount options and mount paths 2022-01-21 17:12:32 -05:00
Jeff Bradberry
56f8f8d3f4 Turn off the filtering of hop nodes from the Instance endpoints
except for the health check.
2022-01-21 15:19:59 -05:00
John Westcott IV
5bced09fc5 Handeling different types of response.data (#11576) 2022-01-21 15:16:09 -05:00
Jake McDermott
b4e9ff7ce0 Merge pull request #11573 from nixocio/ui_rename_files
Rename remaining .jsx files to .js
2022-01-21 10:55:06 -05:00
Alex Corey
208cbabb31 Merge pull request #11580 from jakemcdermott/readme-update-templates-2
Update ui dev readme
2022-01-21 10:50:01 -05:00
Jake McDermott
2fb5cfd55d Update ui dev readme 2022-01-21 10:31:35 -05:00
Jake McDermott
582036ba45 Merge pull request #11579 from jakemcdermott/readme-update-templates
Update ui dev readme, templates
2022-01-21 10:12:50 -05:00
Jake McDermott
e06f9f5438 Update ui dev readme, templates 2022-01-21 09:55:54 -05:00
nixocio
461876da93 Rename remaining .jsx files to .js
Rename remaining .jsx files to .js
2022-01-20 14:17:32 -05:00
Alan Rominger
4f1c662691 Merge pull request #11570 from AlanCoding/keycloak_docs
Minor docs tweaks for keycloak setup
2022-01-20 11:52:21 -05:00
Alan Rominger
9abd4e05d0 Minor docs tweaks for keycloak setup 2022-01-20 11:01:32 -05:00
Elijah DeLee
faba64890e Merge pull request #11559 from kdelee/pending_container_group_jobs_take2
Add resource requests to default podspec
2022-01-20 09:54:20 -05:00
Alan Rominger
add54bfd0b Merge pull request #11472 from AlanCoding/process_ident
Pass new ansible-runner parameters to reduce number of artifacts we don't need on file system
2022-01-20 09:48:44 -05:00
zzj
16d39bb72b Update ad_hoc_commands.py
refactoring code with set comprehension which is more concise and efficient
2022-01-20 18:50:33 +08:00
John Westcott IV
e63ce9ed08 Api 4XX error msg customization #1236 (#11527)
* Adding API_400_ERROR_LOG_FORMAT setting
* Adding functional tests for API_400_ERROR_LOG_FORMAT
Co-authored-by: nixocio <nixocio@gmail.com>
2022-01-19 11:16:21 -05:00
Kersom
60831cae88 Merge pull request #11539 from nixocio/api_issue_11523
Update ping endpoint to use last_seen
2022-01-19 10:40:02 -05:00
Kersom
97cf46eaa9 Merge pull request #11556 from nixocio/ui_bump_node_npm
Bump node and npm versions inside container
2022-01-19 09:58:30 -05:00
Shane McDonald
381e75b913 Merge pull request #11562 from ansible/avoid_dups_create_preload_data
Avoid duplicated entries when calling create_preload_data
2022-01-18 19:00:43 -05:00
Shane McDonald
7bd516a16c Skip project update 2022-01-18 18:40:58 -05:00
Marcelo Moreira de Mello
3dd01cde89 Avoid duplicated entries when calling create_preload_data 2022-01-18 18:07:26 -05:00
Kersom
495394084d Fix null on workflowjobtemplate (#11522)
Fix null on workflowjobtemplate

See: https://github.com/ansible/awx/issues/11284
2022-01-18 16:54:00 -05:00
Alan Rominger
2609ee5ed0 Delete artifact dir after transmit phase is finished 2022-01-18 14:51:40 -05:00
John Westcott IV
da930ce276 Fixing token documentation (#11550) 2022-01-18 14:21:17 -05:00
Elijah DeLee
987924cbda Add resource requests to default podspec
Extend the timeout, assuming that we want to let the kubernetes scheduler
start containers when it wants to start them. This allows us to make
resource requests knowing that when some jobs queue up waiting for
resources, they will not get reaped in as short of a
timeout.
2022-01-18 13:34:39 -05:00
Alan Rominger
8fac1c18c8 Make task logic use consistent artifact dir location 2022-01-18 13:00:39 -05:00
Alan Rominger
eb64fde885 Pass ident to "process" cmd and disable stdout file
This requires corresponding ansible-runner changes
  which are only available in devel branch
  to do this, requirements are changed
  to install ansible-runner devel as it did before

Revert "Use ansible-runner 2.1.1 build"

This reverts commit f0ede01017.

Add back in change from updater.sh that we want to keep
2022-01-18 13:00:39 -05:00
nixocio
b1e9537499 Bump node and npm versions inside container
Bump node and npm versions inside container

Prepating to bump react scripts to 5.0.

See: https://github.com/ansible/awx/issues/11543
2022-01-17 20:33:47 -05:00
Shane McDonald
9d636cad29 Revert "Make awx-python script available in k8s app images"
This reverts commit 88bbd43314.
2022-01-15 10:38:50 -05:00
Alan Rominger
696c0b0055 Merge pull request #11503 from AlanCoding/no_version
Remove unused ansible version method
2022-01-14 22:15:15 -05:00
Jeff Bradberry
6e030fd62f Merge pull request #11546 from jbradberry/remove-instance-activecount
Remove the Instance.objects.active_count() method
2022-01-14 16:46:01 -05:00
Jeff Bradberry
bb14a95076 Remove the Instance.objects.active_count() method
Literally nothing uses it.  The similar Host.objects.active_count()
method seems to be what is actually important for licensing.
2022-01-14 16:21:41 -05:00
Alan Rominger
9664aed1f2 Remove unused ansible version method 2022-01-14 14:55:35 -05:00
Amol Gautam
6dda5f477e Merge pull request #11544 from AlanCoding/another_rule
Respect linter rule F811 about trivial re-definition
2022-01-14 14:05:41 -05:00
Alan Rominger
72cd73ca71 Update to cover stuff from tasks.py changes 2022-01-14 13:42:24 -05:00
Alan Rominger
02e18cf919 Fix more F811 linter violations 2022-01-14 13:23:05 -05:00
Alan Rominger
82671680e3 Respect linter rule F811 for trivial re-definition 2022-01-14 13:23:04 -05:00
Amol Gautam
bff49f2a5f Merge pull request #11528 from amolgautam25/tasks-refactor-1
Refactored 'tasks.py' file  into a package
2022-01-14 12:16:32 -05:00
Marcelo Moreira de Mello
59d582ce83 Merge pull request #11530 from ansible/dont_expose_k8s_api_token_by_default
Don't expose serviceAccount token on default pod spec
2022-01-14 12:04:14 -05:00
Amol Gautam
a4a3ba65d7 Refactored tasks.py to a package
--- Added 3 new sub-package : awx.main.tasks.system , awx.main.tasks.jobs , awx.main.tasks.receptor
--- Modified the functional tests and unit tests accordingly
2022-01-14 11:55:41 -05:00
Kersom
11f4b64229 Modify how manual subform is displayed for projects (#11509)
Modify how manual subform is displayed for projects - Do not rely on
label that could be translated, rely on the value.

See: https://github.com/ansible/awx/issues/11505
2022-01-14 11:19:10 -05:00
Jeff Bradberry
b76029fac3 Merge pull request #11538 from jbradberry/fix-exact-removals-for-register-peers
Fix the logic for register_peers --exact
2022-01-14 09:42:51 -05:00
nixocio
3d45f31536 Update ping endpoint to use last_seen
Update ping endpoint to use last_seen, instead of `modified` on
instances `heartbeat`.

See: https://github.com/ansible/awx/issues/11523
2022-01-13 16:46:40 -05:00
Jeff Bradberry
ade00c70e5 Merge pull request #11537 from jbradberry/enhancements-for-meshviz-endpoint
Enhancements for meshviz endpoint
2022-01-13 16:42:21 -05:00
Jeff Bradberry
82dca5336d Fix the logic for register_peers --exact
- correctly calculate the extraneous peers
- allow --exact to take an empty set of arguments, to remove all peers
2022-01-13 15:41:45 -05:00
Jeff Bradberry
8c33d0ecbd Add the mesh_visualizer resource to awxkit 2022-01-13 15:01:54 -05:00
Jeff Bradberry
dea5fd1a9d Fix a problem with IsSystemAdminOrAuditor for anonymous users
It was raising an error, but should really show the message about not
being authenticated.
2022-01-13 14:44:50 -05:00
Jeff Bradberry
6a131f70f0 Require System Admin or Auditor permissions to access the mesh visualizer 2022-01-13 14:13:17 -05:00
Alex Corey
d33a0d5dde Merge pull request #11454 from AlexSCorey/ReceptorEndPoints
Creates end point and beginning of serializer for receptor mesh
2022-01-13 11:51:34 -05:00
Marliana Lara
11cc7e37e1 Add prefiltered link to inventory source sync jobs 2022-01-13 11:48:40 -05:00
Jeff Bradberry
7e6cb7ecc9 Merge pull request #11533 from jbradberry/fix-register-peers-exact-typo
Fix the loop variable name for the register_peers --exact flag
2022-01-13 11:28:15 -05:00
Jeff Bradberry
807c58dc36 Fix the loop variable name for the register_peers --exact flag 2022-01-13 11:05:26 -05:00
Marcelo Moreira de Mello
1517f2d910 Don't expose serviceAccount token on default pod spec 2022-01-12 23:47:24 -05:00
Alan Rominger
b0c59ee330 Merge pull request #11375 from AlanCoding/missing_image_error_devel
Fail with specific error message if protected image is not available
2022-01-12 11:05:17 -05:00
Jeff Bradberry
1ff52bab56 Merge pull request #11520 from jbradberry/fix-register-peers
In register_peers, only check non-empty flags for the 1-cycle check
2022-01-11 16:52:53 -05:00
Jeff Bradberry
7a9fca7f77 In register_peers, only check non-empty flags for the 1-cycle check 2022-01-11 16:16:33 -05:00
Alex Corey
dea53a0dba Creates end point and serializer for receptor mesh 2022-01-11 10:57:57 -05:00
Jeff Bradberry
db999b82ed Merge pull request #11431 from jbradberry/receptor-mesh-models
Modify Instance and introduce InstanceLink
2022-01-11 10:55:54 -05:00
John Westcott IV
c92468062d SAML user attribute flags issue #5303 (PR #11430)
* Adding SAML option in SAML configuration to specify system auditor and system superusers by role or attribute
* Adding keycloak container and documentation on how to start keycloak alongside AWX (including configuration of both)
2022-01-10 16:52:44 -05:00
Seth Foster
4de0f09c85 Merge pull request #11515 from fosterseth/revert_debug_level
Revert "Remove unnecessary DEBUG logger level settings (#11441)"
2022-01-10 16:38:33 -05:00
Jeff Bradberry
9c9c1b4d3b register_peers will now raise errors if you attempt to reverse or loop 2022-01-10 15:48:17 -05:00
Jeff Bradberry
5ffe91f069 Add a new --exact parameter to register_peers 2022-01-10 15:12:04 -05:00
Jeff Bradberry
63867518ee Add a new parameter --disconnect to register_peers
To allow links between Receptor nodes to be removed from the database.
2022-01-10 14:15:58 -05:00
Sarah Akus
53ff99e391 Merge pull request #11513 from marshmalien/10241-test-locator
Add test locators to OUIA-compliant components
2022-01-10 13:10:08 -05:00
Shane McDonald
c035c12c0a Merge pull request #11380 from sean-m-sullivan/new_name
add new name to multiple modules
2022-01-11 01:42:55 +08:00
Shane McDonald
6e39a02e99 Merge pull request #11504 from sean-m-sullivan/devel
add better error and documentation on labels
2022-01-11 01:42:13 +08:00
Seth Foster
956638e564 Revert "Remove unnecessary DEBUG logger level settings (#11441)"
This reverts commit 8126f734e3.
2022-01-10 11:46:19 -05:00
Jeff Bradberry
37907ad348 Register the hop & execution nodes and all node links 2022-01-10 11:37:19 -05:00
Jeff Bradberry
386aa898ec Remove the make init target
we want to fold that in to bootstrap_environment.sh.
2022-01-10 11:37:19 -05:00
Jeff Bradberry
f1c5da7026 Remove the auto-discovery feature 2022-01-10 11:37:19 -05:00
Jeff Bradberry
fc2a5224ef Add error messages to the new register_peers command 2022-01-10 11:37:19 -05:00
Jeff Bradberry
ce5aefd3d8 Capture hop nodes and links in the automatic discovery machinery
Also, make sure that the control service is turned on in the dev
environment's hop node, so that it shows up in the Advertisements
list.
2022-01-10 11:37:13 -05:00
Marliana Lara
b2124dffb5 Add test locators to OUIA-compliant components 2022-01-07 14:39:18 -05:00
Christian Adams
25eaace4be Merge pull request #11508 from tchellomello/awx-config-watcher-dies-ocp
Disable awx-config-watcher for k8s images
2022-01-07 10:01:19 -05:00
sean-m-ssullivan
bb8efbcc82 add new name to multiple modules 2022-01-05 22:33:51 -05:00
sean-m-sullivan
e0bd5ad041 add better error and documentation on labels 2022-01-05 20:09:02 -05:00
Marcelo Moreira de Mello
69ec49d0e9 Disable awx-config-watcher on OCP 2022-01-05 17:02:14 -05:00
Alan Rominger
8126f734e3 Remove unnecessary DEBUG logger level settings (#11441)
* Remove unnecessary DEBUG logger level settings
2022-01-05 14:44:57 -05:00
nixocio
f2aaa6778c Add warning message for K8S deployment
Add warning message for K8S deployment
2022-01-05 11:32:59 -05:00
Sarah Akus
4fd5b01a83 Merge pull request #11324 from keithjgrant/10655-duplicate-api-requests
Reduce duplicate fetches after saving inventory group
2022-01-04 11:42:37 -05:00
Jeff Bradberry
1747a844fc Merge pull request #11485 from jbradberry/fix-broken-events-analytics
Fix a problem with the events_table analytics collectors
2022-01-04 11:30:26 -05:00
Kersom
afc210a70d Merge pull request #11489 from nixocio/ui_issue_11452
Fix relaunch of jobs
2022-01-04 08:34:50 -05:00
Keith J. Grant
f63003f982 don't navigate to inventory group details on edit cancel 2021-12-21 13:22:59 -08:00
Keith J. Grant
e89037dd77 reduce duplicate fetches after saving inventory group 2021-12-21 13:22:59 -08:00
nixocio
ab6e650e9c Fix relaunch of jobs
Events were passed to `handleRelaunch` and those events structure were
not parseable to JSON - breaking the relaunch of jobs. React 17 changes
made this bug visible.

Also, remove withRouter from LaunchButton.

See: https://github.com/ansible/awx/issues/11452
2021-12-21 14:39:34 -05:00
Jeff Bradberry
2ed246cb61 Fix a problem with the events_table analytics collectors
The switch to using jsonb objects instead of json broke the use of
json_to_record in the raw sql in the _events_table function.
2021-12-20 14:03:24 -05:00
Jeff Bradberry
4449555abe Add a new register_peers management command
and alter provision_instance to accept hop nodes.
2021-12-20 09:56:48 -05:00
Jeff Bradberry
f340f491dc Control the visibility and use of hop node Instances
- the list, detail, and health check API views should not include them
- the Instance-InstanceGroup association views should not allow them
  to be changed
- the ping view excludes them
- list_instances management command excludes them
- Instance.set_capacity_value sets hop nodes to 0 capacity
- TaskManager will exclude them from the nodes available for job execution
- TaskManager.reap_jobs_from_orphaned_instances will consider hop nodes
  to be an orphaned instance
- The apply_cluster_membership_policies task will not manipulate hop nodes
- get_broadcast_hosts will ignore hop nodes
- active_count also will ignore hop nodes
2021-12-17 14:30:28 -05:00
Jeff Bradberry
c8f1e714e1 Capture hop nodes and the peer links between nodes 2021-12-17 14:30:18 -05:00
Sarah Akus
ddc428532f Merge pull request #11470 from rebeccahhh/devel
Jobs page filter status with OR operator
2021-12-16 16:45:47 -05:00
Jeff Bradberry
3414cae677 Merge pull request #11471 from jbradberry/failure-notification-fallback-explanation
Only update the job_explanation on error if there wasn't already one
2021-12-16 11:10:38 -05:00
Wambugu “Innocent” Kironji
9d6972c6ce Merge pull request #11459 from marshmalien/5456-insights-system-settings
Update label and display of "Last gathered entries..." setting
2021-12-15 16:58:18 -05:00
Marliana Lara
0566a0f1d6 Update label and display of "Last gathered entries..." setting 2021-12-15 15:59:43 -05:00
Jeff Bradberry
de0561dcc2 Only update the job_explanation on error if there wasn't already one 2021-12-15 15:24:04 -05:00
Rebeccah
a9f4f53f92 change logical ANDs into logical ORs for filtering based on status in the JobsList 2021-12-15 15:15:33 -05:00
Elijah DeLee
5fdfd4114a Merge pull request #11395 from kdelee/override_default_container_group_pod_spec
Allow setting default execution group pod spec
2021-12-15 13:57:47 -05:00
Jeff Bradberry
b195f9da44 Merge pull request #11384 from jbradberry/failure-notification-on-error
Make sure to fire off failure notifications on error
2021-12-15 13:47:10 -05:00
Tiago Góes
1205d71f4b Merge pull request #11466 from tiagodread/restore-locator-2
Restore locator removed
2021-12-15 11:10:26 -03:00
Tiago
3f762a6476 restore locator removed 2021-12-15 10:55:02 -03:00
Tiago Góes
4aa403c122 Merge pull request #11465 from tiagodread/restore-locator
Restore locator removed
2021-12-14 18:57:22 -03:00
Tiago
a13070a8da restore locator removed 2021-12-14 18:39:10 -03:00
Wambugu “Innocent” Kironji
b63b171653 Merge pull request #11447 from nixocio/ui_issue_7561
Add email as default search key user lists
2021-12-14 16:29:10 -05:00
Alan Rominger
7219f8fed8 Merge pull request #11462 from AlanCoding/forgot_this
Add the cancel_callback to system job interface
2021-12-14 14:17:47 -05:00
Alan Rominger
b6a5f834d6 Merge pull request #11408 from amolgautam25/receptor_tech_debt
Removing time.sleep(3)
2021-12-14 11:54:49 -05:00
Alan Rominger
99b9d53bbb Add the cancel_callback to system job interface 2021-12-14 10:50:39 -05:00
Alex Corey
edca19a697 Merge pull request #11402 from AlexSCorey/upgradePF
Updates patternfly dependencies
2021-12-13 11:02:01 -05:00
Jake McDermott
c13d721062 Merge pull request #11435 from jakemcdermott/fix-vaulted-ee-cred
Handle exception for credential input checks in calling function
2021-12-13 10:10:23 -05:00
Kersom
d2f316c484 Merge pull request #11443 from nixocio/ui_issue_11442
Fix extra requests when creating WorkFlowJobTemplate
2021-12-13 09:12:27 -05:00
nixocio
70e832d4db Fix extra requests when creating WorkFlowJobTemplate
Fix extra requests when creating WorkFlowJobTemplate

See: https://github.com/ansible/awx/issues/11442
2021-12-13 08:19:24 -05:00
Alan Rominger
21895bd09b Merge pull request #11448 from AlanCoding/revert_again
Revert "cancel job if receptor no longer knows about the work item"
2021-12-10 16:35:12 -05:00
Alan Rominger
411ef5f9e8 Revert "cancel job if receptor no longer knows about the work item"
This reverts commit 2a11bb4f3b.
2021-12-10 16:18:44 -05:00
nixocio
f6282b9a09 Add email as default search key user lists
Add email as default search key user lists

See: https://github.com/ansible/awx/issues/7561
2021-12-10 16:06:38 -05:00
Elijah DeLee
e10030b73d Allow setting default execution group pod spec
This will allow us to control the default container group created via settings, meaning
we could set this in the operator and the default container group would get created with it applied.

We need this for https://github.com/ansible/awx-operator/issues/242

Deepmerge the default podspec and the override

With out this, providing the `spec` for the podspec would override everything
contained, which ends up including the container used, which is not desired

Also, use the same deepmerge function def, as the code seems to be copypasted from
the utils
2021-12-10 15:02:45 -05:00
Jeff Needle
cdf14158b4 Merge pull request #11436 from AlexSCorey/sync
Pulling in upstream changes
2021-12-10 14:48:59 -05:00
Alex Corey
f310e672b0 Merge pull request #11247 from AlexSCorey/11227-fix
Removes disassociate button on details view and fine tunes disassociate button on list view
2021-12-10 10:30:30 -05:00
Keith Grant
675d0d28d2 Job Output expand/collapse take 2 (#11312) 2021-12-09 14:08:31 -05:00
Alex Corey
4c2fd056ef updated patternfly 2021-12-09 12:09:58 -05:00
Sarah Akus
a259e48377 Merge pull request #11414 from AlexSCorey/upgradeReact
Upgrade react
2021-12-09 09:53:35 -05:00
ansible-translation-bot
095c586172 UI translation strings for release_4.1 branch
* Correct syntax errors & add back lost last line for messages.po
  * Manually sort through es & nl translated strings
  * Mnaually sort through french strings and correct syntax errors

Signed-off-by: Christian M. Adams <chadams@redhat.com>
2021-12-08 15:57:08 -05:00
Jeff Bradberry
c9c198b54b Fix the problems with the api-schema tests against Tower
- add the appropriate release branch to the branches list
- add a fallback to the `docker pull` command
2021-12-08 15:57:08 -05:00
Jim Ladd
2a11bb4f3b cancel job if receptor no longer knows about the work item
lint
2021-12-08 15:57:02 -05:00
Shane McDonald
35bac50962 Ensure docker pull commands fail gracefully 2021-12-08 15:51:14 -05:00
jakemcdermott
366d2c1d97 Handle exception for credential input checks in calling function 2021-12-08 12:09:20 -05:00
Jake McDermott
9a930cbd95 Merge pull request #10935 from jakemcdermott/remove-sleep
Remove sleep from tests
2021-12-08 11:14:36 -05:00
Jake McDermott
03277513a9 Remove sleep from tests 2021-12-08 10:55:30 -05:00
Alan Rominger
1b0fca8026 Merge pull request #11386 from AlanCoding/logs_on_the_fire
Remove dev-only log filters and downgrade periodic logs
2021-12-07 16:13:45 -05:00
Christian Adams
c9cf5b78c5 Merge pull request #11428 from rooftopcellist/fix-k8s-image-build
Make awx-python script available in k8s app images
2021-12-07 14:36:31 -05:00
Alan Rominger
d6679a1e9b Respect dynamic log setting for console, downgrade exit log 2021-12-07 14:35:03 -05:00
Alan Rominger
b721a4b361 Remove dev-only log filters and downgrade periodic logs 2021-12-07 14:35:02 -05:00
Christian M. Adams
88bbd43314 Make awx-python script available in k8s app images 2021-12-07 13:48:32 -05:00
Tiago Góes
fb1c97cdc1 Merge pull request #11311 from nixocio/ui_no_more_classes
Convert last class components to functional components
2021-12-07 14:57:47 -03:00
Kersom
f5ae8a0a4c Merge pull request #11377 from nixocio/ui_sonic_tests
Update how ui tests are invoked on CI
2021-12-07 09:42:34 -05:00
nixocio
1994eaa406 Convert last class components to functional components
Convert last class components to functional components
2021-12-07 09:19:49 -05:00
nixocio
510b40a776 Update how ui tests are invoked on CI
Update how ui tests are invoked on CI as an attempt to speed up test
run.
2021-12-07 09:18:32 -05:00
Alex Corey
f37b070965 Upgrades React 2021-12-06 14:36:08 -05:00
Alex Corey
41385261f3 Resolves disassociate button for instances 2021-12-06 11:32:12 -05:00
Alan Rominger
19b4849345 Merge pull request #11394 from notok/cfg_from_template_branch
Load ansible.cfg from the branch specified on job template
2021-12-06 11:09:36 -05:00
notok
76283bd299 Load ansible.cfg from the branch specified on job template
Load ansible.cfg from the branch specified on job template (i.e. the same branch that the playbook exists), not from the branch set in the "project".

Signed-off-by: notok <noto.kazufumi@gmail.com>
2021-12-03 20:36:07 +09:00
Amol Gautam
2e4cda74c8 Removing time.sleep(3) 2021-12-02 15:41:46 -05:00
Alan Rominger
5512b71e16 Merge pull request #11412 from AlanCoding/cookie_revert
Revert "Set SESSION_COOKIE_NAME by default"
2021-12-02 11:00:56 -05:00
Alan Rominger
97b60c43b7 Merge pull request #11385 from AlanCoding/my_cluster_host
Do not overwrite file-based CLUSTER_HOST_ID written by installer
2021-12-02 10:53:59 -05:00
Alan Rominger
35b62f8526 Revert "Set SESSION_COOKIE_NAME by default"
This reverts commit 59c6f35b0b.
2021-12-01 17:51:47 -05:00
Kersom
a15a3f005c Merge pull request #11278 from nixocio/ui_bump
Bump Browserslist version
2021-12-01 09:26:19 -05:00
Alan Rominger
776c4a988a Do not overwrite file-based CLUSTER_HOST_ID written by installer 2021-11-30 20:15:10 -05:00
Jeff Bradberry
c419969253 Make sure to fire off failure notifications on error
where the error is unrelated to Ansible, thus is not caught by the
usual methods.
2021-11-23 13:25:08 -05:00
Jake McDermott
ba324c73ce Merge pull request #11378 from ansible/update-dev-env-readme
Update example command for running test container
2021-11-19 16:09:37 -05:00
Jake McDermott
4a5dc78331 Update example command for running test container 2021-11-19 15:44:51 -05:00
Kersom
55dc9dfb54 Merge pull request #11355 from nixocio/ui_issue_11352
Linkify instance/container groups job template details
2021-11-19 14:59:31 -05:00
nixocio
23a8191bb5 Bump Browserslist version
Bump Browserslist version to remove warning.

See: https://github.com/browserslist/browserslist#browsers-data-updating
2021-11-19 14:53:01 -05:00
nixocio
c665caaf35 Linkify instance/container groups job template
Linkify instance/container groups job template

See: https://github.com/ansible/awx/issues/11352
2021-11-19 14:23:11 -05:00
Alan Rominger
099efb883d Allow customizing the receptor image in the development environment (#11374)
* Allow for customizing the receptor image

* Hook in receptor image to docker-compose template

* Fix missing -e to pass into Dockerfile playbook

* Add some docs
2021-11-19 14:00:23 -05:00
Sarah Akus
44237426df Merge pull request #11353 from nixocio/ui_node_delete
Identify node to be deleted on workflow
2021-11-19 12:32:27 -05:00
Alan Rominger
eeefd19ad3 Fail with specific error message if protected image is not available locally 2021-11-19 11:52:54 -05:00
nixocio
47ae6e7a5a Identify node to be deleted on workflow
Identify node to be deleted on workflow. If there is an alias show the
alias if no alias is available show the node name.

See: https://github.com/ansible/awx/issues/11351
2021-11-19 10:55:19 -05:00
Shane McDonald
03ed6e9755 Merge pull request #11371 from shanemcd/document-release-process
Document release process
2021-11-19 18:43:53 +08:00
Shane McDonald
8d4e7f0a82 Document release process 2021-11-19 08:28:48 +00:00
Shane McDonald
7fdf491c05 Merge pull request #11369 from shanemcd/lets-automate-everything
Automate the rest of our release process
2021-11-19 11:37:58 +08:00
Shane McDonald
ef1563283e An automated stage / promotion release process 2021-11-19 02:22:45 +00:00
Shane McDonald
a206d79851 Merge pull request #11368 from shanemcd/downstream-changes
A few more downstream fixes
2021-11-19 09:46:21 +08:00
Satoe Imaishi
42c9c0a06b Use receptor 1.1.1 build 2021-11-19 01:11:35 +00:00
Satoe Imaishi
f0ede01017 Use ansible-runner 2.1.1 build 2021-11-19 01:11:19 +00:00
Alan Rominger
d67007f777 Move only_transmit_kwargs calculation out of thread 2021-11-19 01:11:18 +00:00
nixocio
83d81e3788 Upgrade has-ansi 2021-11-19 01:10:36 +00:00
Shane McDonald
e789e16289 Merge pull request #11348 from pabelanger/temp/sessionname
Set SESSION_COOKIE_NAME by default
2021-11-19 08:33:07 +08:00
Bianca Henderson
61c9683aa6 Merge pull request #11269 from AlexSCorey/1741-SlackNotifications
Users can send slack notification to a thread
2021-11-18 14:28:28 -05:00
Sarah Akus
ee9d1356b2 Merge pull request #11354 from nixocio/ui_issue_11350
Update search keys
2021-11-17 14:56:46 -05:00
Alex Corey
f92a49fda9 Adds ability to send slack notification to a thread, updates tooltip in ui, and adds test button to notification details view 2021-11-17 14:04:32 -05:00
nixocio
3dc6a055ac Update search keys
Update search keys.

See: https://github.com/ansible/awx/issues/11350
2021-11-16 15:32:50 -05:00
Kersom
229f0d97f9 Merge pull request #11307 from jakemcdermott/default-template-search-labels
Add labels to default template search
2021-11-16 15:14:55 -05:00
Christian Adams
7cc530f950 Merge pull request #11145 from aperigault/devel
fix french typos
2021-11-16 11:23:18 -05:00
aperigault
2ef840ce12 Fix encrypted translation 2021-11-16 16:27:27 +01:00
Antony Perigault
a372d8d1d5 fix french typos 2021-11-16 16:27:27 +01:00
Shane McDonald
aad150cf1d Pin rsa package to latest version 2021-11-16 09:02:11 +00:00
Shane McDonald
be13a11dd5 Merge pull request #11344 from Akasurde/typo
Misc typo fix
2021-11-16 16:52:30 +08:00
Paul Belanger
59c6f35b0b Set SESSION_COOKIE_NAME by default
Make sure to use a different session cookie name then the default, to
avoid overlapping cookies with other django apps that might be running.

Signed-off-by: Paul Belanger <pabelanger@redhat.com>
2021-11-15 12:59:07 -05:00
Abhijeet Kasurde
37e45c5e7c Misc typo fix
Changed 'controler' to 'controller'

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-11-15 16:24:21 +05:30
Shane McDonald
39370f1eab Security-related updates for some Python dependencies. 2021-11-14 08:45:49 +00:00
Shane McDonald
aec7ac6ebd Merge pull request #11341 from shanemcd/fix-image-builds
Fix official image builds
2021-11-13 14:31:26 +08:00
Shane McDonald
f6e63d0917 Fix official image builds
I broke everything in https://github.com/ansible/awx/pull/11242.

These changes were necessary in order to run `awx-manage collectstatic` without a running database.
2021-11-13 06:07:37 +00:00
Rebeccah Hunter
0ae67edaba Merge pull request #11267 from ziegenberg/add-tests-for-webhook-notifications
Add unit tests for webhook notifications
2021-11-11 09:55:38 -05:00
Shane McDonald
481f6435ee Merge pull request #11327 from shanemcd/downstream-changes
Pull in downstream changes
2021-11-11 11:09:22 +08:00
chris meyers
d0c5c3d3cf add work_unit_id to job lifecycle 2021-11-10 08:50:16 +08:00
chris meyers
9f8250bd47 add events to job lifecycle
* Note in the job lifecycle when the controller_node and execution_node
  are chosen. This event occurs most commonly in the task manager with a
  couple of exceptions that happen when we dynamically create dependenct
  jobs on the fly in tasks.py
2021-11-10 08:50:16 +08:00
Alan Rominger
3a3fffb2dd Fixed error dropped on floor - save receptor detail when it applies 2021-11-10 08:50:16 +08:00
nixocio
4cfa4eaf8e Update validators for Misc Auth Edit
* Update SharedFields to use number validator instead of integer
* Use number validation for SESSIONS_PER_USER

See: https://github.com/ansible/tower/issues/5396
2021-11-10 08:50:16 +08:00
Kersom
abb1125a2c Display host name for Associate Modal (#5407)
Display host name for Associate Modal

See: https://github.com/ansible/awx/issues/11256
2021-11-10 08:50:16 +08:00
Alan Rominger
a2acbe9fe6 Fix incorrect (changed: True) frequent in OCP task logs 2021-11-10 08:50:16 +08:00
Alex Corey
cab8c690d2 Adds instances to aactivty stream 2021-11-10 08:50:16 +08:00
Alan Rominger
0d1f8a06ce Revert default EE authfile support for inventory_import 2021-11-10 08:50:15 +08:00
Alan Rominger
d42fe921db Re-order authfile option to make inventory import command work 2021-11-10 08:50:15 +08:00
Kersom
db7fb81855 Fix login redirect (#5386)
Allows the user to visit login page when the login redirect url is set.

Also, redirects to login page once logging out and there is session from
a SAML available.

See: https://github.com/ansible/awx/issues/11012
2021-11-10 08:50:15 +08:00
Jeff Bradberry
d3c695b853 Clean up some scar tissue left behind
by the initial use of the black code formatter.
2021-11-10 08:50:15 +08:00
Jeff Bradberry
010c3ab0b8 Fix a typo in inventory_import
ExecutionEnvironment.credential got shortened to .cred.
2021-11-10 08:50:15 +08:00
Bianca Henderson
58cdbca5cf Update error message to be more accurate 2021-11-10 08:50:15 +08:00
Bianca Henderson
8275082896 Update error messages for when exceptions are caught 2021-11-10 08:50:14 +08:00
Bianca Henderson
d79da1ef9f Catch exceptions that might pop up when releasing work units 2021-11-10 08:50:14 +08:00
Jeff Bradberry
a9636426b8 Make the inventory_import command respect the default EE and credential 2021-11-10 08:50:14 +08:00
Alan Rominger
329caad681 In admin reaper skip work units w/o params 2021-11-10 08:50:14 +08:00
Alan Rominger
ecb84e090c Revert "Merge pull request #5354 from ansible/jobs_killed_via_receptor_should_get_reaped"
This reverts commit 8736858d80, reversing
changes made to 84e77c9db9.
2021-11-10 08:50:14 +08:00
nixocio
8e9fc14b0e Fix SAML variables default values
Fix SAML variables default values

See: https://github.com/ansible/tower/issues/5372
2021-11-10 08:50:14 +08:00
Jim Ladd
0f77ca605d add unit tests 2021-11-10 08:50:14 +08:00
Jim Ladd
231fcc8178 drop lines picked up during merge resolution 2021-11-10 08:50:13 +08:00
Alan Rominger
2839091b22 Avoid extra check if we have job_explanation 2021-11-10 08:50:13 +08:00
Alan Rominger
47e67481b3 Avoid reaping tentative jobs 2021-11-10 08:50:13 +08:00
Alan Rominger
55059b015f Avoid resultsock shutdown before reading from it 2021-11-10 08:50:13 +08:00
Alan Rominger
eb6c58682d Alternative for reaping lost jobs, in work unit reaper 2021-11-10 08:50:13 +08:00
Jim Ladd
26055de772 cancel job if receptor no longer knows about the work item 2021-11-10 08:50:13 +08:00
Jim Ladd
ebb4581595 update exception log message to be descriptive
.. instead of surfacing exception
2021-11-10 08:50:12 +08:00
Jim Ladd
d1fecc11c9 when releasing receptor work, do so in try/except 2021-11-10 08:50:12 +08:00
Jeff Bradberry
056247a34a Adjust Instance-InstanceGroup tests to show that the ActivityStream is captured 2021-11-10 08:50:12 +08:00
Jeff Bradberry
7010015e8a Change the ActivityStream registration for InstanceGroups
to include the m2m fields.  Also to avoid spamminess, disable the
activity stream on the apply_cluster_membership_policies task.
2021-11-10 08:50:12 +08:00
Jeff Bradberry
62d50d27be Update a couple of the existing tests 2021-11-10 08:50:12 +08:00
Jeff Bradberry
1e5231d68b Enable ActivityStream capture for Instances 2021-11-10 08:50:12 +08:00
Seth Foster
e04efad3c0 tools_receptor_1 should use whatever awx_devel tag that tools_awx_1 is using 2021-11-10 08:50:11 +08:00
Alan Rominger
e54db3ce50 Gracefully handle receptorctl RuntimeError in health check 2021-11-10 08:50:11 +08:00
Alan Rominger
77076dbd67 Reduce the number of triggers for execution node health checks 2021-11-10 08:50:11 +08:00
Alan Rominger
6f20a798ab Allow testing a single hybrid instance like the good old days 2021-11-10 08:50:11 +08:00
Alex Corey
0d3a22bbc3 Fixes erroneous validation 2021-11-10 08:50:11 +08:00
Alan Rominger
f34c96ecf5 Error handling when node is missing from mesh for jobs and checks 2021-11-10 08:50:11 +08:00
nixocio
206c85778e Do not show control instances as option to be associated
Do not show control instances as option to be associated to user defined
instance groups.

See: https://github.com/ansible/tower/issues/5339
2021-11-10 08:50:11 +08:00
Marcelo Moreira de Mello
d6b4b9f973 Added node_type on awx-manage list_instances commmand
(cherry picked from commit 683145e3eaa8b13da59bc51e57dff98f25d3554d)
2021-11-10 08:50:10 +08:00
chris meyers
3065e29deb avoid work_results and work release race
* Unsure exactly why this happens but there seems to be a race condition
  related to the time window between Receptor work_results and work
  release. This sleep extends that window and hopefully avoids the race
  condition.
2021-11-10 08:50:10 +08:00
Bianca Henderson
481047bed8 Change log level from 'warning' to 'exception' 2021-11-10 08:50:10 +08:00
Bianca Henderson
f72292cce2 Move error handling into try/catch block 2021-11-10 08:50:10 +08:00
Alan Rominger
7b35902d33 Respect settings to keep files and work units
Add new logic to cleanup orphaned work units
  from administrative tasks

Remove noisy log which is often irrelevant
  about running-cleanup-on-execution-nodes
  we already have other logs for this
2021-11-10 08:50:10 +08:00
Shane McDonald
1660900914 Dont fail CI when pre-built images arent available
CI will build the image from scratch if the pre-build image is not available
2021-11-10 08:50:08 +08:00
kialam
a7be25ce8b Merge pull request #11282 from kialam/upgrade-d3-to-v7
Upgrade d3 to v7.
2021-11-04 14:06:23 -07:00
Tiago Góes
54b5ba08b8 Merge pull request #11259 from tiagodread/update-e2e-script
Fix e2e tests workflow
2021-11-04 13:06:38 -03:00
jakemcdermott
0fb8d48074 Add labels to default template search 2021-11-04 10:35:24 -04:00
Rebeccah Hunter
b5fac4157d Merge pull request #11281 from ziegenberg/update-docs-to-include-openssl-as-requirement
add OpenSSL to the list of prerequisites
2021-11-01 13:02:52 -04:00
Bianca Henderson
9e61949f9f Merge pull request #11263 from ziegenberg/fix-documentation-link-to-debugging
fix link to debugging documentation
2021-11-01 11:53:01 -04:00
Daniel Ziegenberg
6c5640798f fix link to debugging documentation
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-30 18:45:46 +02:00
Bianca Henderson
03222197a3 Merge pull request #11270 from ziegenberg/update-slack-sdk
Update dependency slackclient to slack_sdk
2021-10-29 17:33:29 -04:00
Alan Rominger
12f417d0a3 Merge pull request #11286 from StarryInternet/enpaul-multiuse-mesh
Skip additional instance checks on unrecognized hosts
2021-10-29 15:09:33 -04:00
Ethan Paul
c77aaece1d Skip additional instance checks on unrecognized hosts
Skip checking the health of a mesh instance when the instance is not registered
with the application. This prevents encountering an 'UnbouncLocalError' when
running the application attached to a multi-use Receptor mesh network

Signed-off-by: Ethan Paul <24588726+enpaul@users.noreply.github.com>
2021-10-29 14:06:36 -04:00
Shane McDonald
25140c9072 Merge pull request #11288 from bhavenst/devel
Fix dev build (docker-compose) problems
2021-10-28 12:54:13 -04:00
Bryan Havenstein
3a636c29ab Fix dev build (docker-compose) problems
Prevent deletion of nginx user by entrypoint.sh
 - Fixes: https://github.com/ansible/awx/issues/9552

Enable fuse-overlayfs in all images - native overlay not supported until kernel 5.13+
 - Fixes: https://github.com/ansible/awx/issues/10099

Refs:
https://www.redhat.com/sysadmin/podman-rootless-overlay
https://www.redhat.com/en/blog/working-container-storage-library-and-tools-red-hat-enterprise-linux
2021-10-27 15:55:57 -06:00
Kia Lam
a11d5ccd37 Add missing UI license file. 2021-10-27 10:58:31 -07:00
Daniel Ziegenberg
f6e7937f74 Add unit tests for webhook notifications
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-27 17:33:37 +02:00
Rebeccah Hunter
e447b667e5 Merge pull request #11246 from ziegenberg/fix-http-headers-for-rocketchat-notifications
Use the AWX HTTP client headers for rocketchat notifications
2021-10-27 10:20:58 -04:00
Kia Lam
24c635e9bc Fix unit tests. 2021-10-26 14:48:58 -07:00
Kia Lam
2ad4dcd741 Upgrade d3 to v7. 2021-10-26 12:07:15 -07:00
Daniel Ziegenberg
f5cd9e0799 add OpenSSL to the list of prerequisites
For running `make docker-compose` a working version of openssl is
required for successfully generating Private RSA key for signing work.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-26 17:14:00 +02:00
Daniel Ziegenberg
e7064868b4 updates the implementation of the slack backend for notifications
Use the slack_sdk instead of the deprecated slackclient. Because according to the official documentation:
>  The slackclient PyPI project is in maintenance mode now and slack-sdk project is the successor.
With this commit one UPGRADE BLOCKER from requirements/requirements.in is removed. Als the license for slack_sdk
is updated and unit tests for slack notifications backend are added.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-26 16:41:10 +02:00
Daniel Ziegenberg
65cbbf15c9 Use the AWX HTTP client headers for rocketchat notifications
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-20 13:14:30 +02:00
Tiago
a325509e1e Fix e2e check 2021-10-19 15:23:43 -03:00
Jake McDermott
69ae731898 Merge pull request #11258 from ansible/jakemcdermott-include-jsconfig
Add jsconfig to frontend container
2021-10-19 14:02:54 -04:00
Jake McDermott
3452dee1b0 Add jsconfig to frontend container
The eslint and jsconfig files are needed to start the dev server.

Without the jsconfig, the ui development server can't resolve src 
modules and will fail to start.
2021-10-19 12:05:15 -04:00
Shane McDonald
64b337e3c6 Dont re-run CI after merging PRs into devel 2021-10-19 11:24:28 -04:00
Bianca Henderson
5df9655fe3 Merge pull request #11252 from beeankha/update_version_makefile_target
Update/Add Targets that Acquire AWX Version
2021-10-19 10:59:48 -04:00
Shane McDonald
f3669f3be6 Fix make install_collection
The version obtained from setuptools_scm is not compatible with ansible-galaxy collection install.
2021-10-19 10:26:23 -04:00
Shane McDonald
61eb99c46d Merge pull request #11253 from beeankha/collections_docs_fix_pt2
Update auth_plugin Doc Extension File to Fix Malformed Collections Docs
2021-10-18 18:07:41 -04:00
Bianca Henderson
f74a14e34f Update auth_plugin doc extension to fix malformed Collections docs 2021-10-18 11:08:17 -04:00
Shane McDonald
517f1d7991 Merge pull request #9491 from sezanzeb/awxkit-credential-file
making the cli use AWXKIT_CREDENTIAL_FILE
2021-10-13 19:05:56 -04:00
Bianca Henderson
25e69885d0 Merge pull request #11198 from sean-m-sullivan/name_or_id_workflow_node
update to allow use of id for unified job template
2021-10-13 15:19:02 -04:00
Shane McDonald
60a357eda1 Merge pull request #10906 from oweel/10829-idle_timeout_setting
Added idle_timeout setting to job settings
2021-10-13 13:16:53 -04:00
Cesar Francisco San Nicolas Martinez
d74679a5f9 Merge pull request #11244 from ansible/CFSNM-fix-minor-typo
Update test_ha.py
2021-10-13 17:04:34 +02:00
Chris Meyers
73a865073d Merge pull request #11241 from chrismeyersfsu/fix-missing-project-updates
Fix missing project updates
2021-10-13 11:03:44 -04:00
Cesar Francisco San Nicolas Martinez
4ff8c28fe4 Update test_ha.py
Fixed minor typo in node type
2021-10-13 16:46:58 +02:00
Shane McDonald
4ab2539c8a Merge pull request #11242 from shanemcd/awx-operator-ci-check
Add awx-operator CI check
2021-10-13 10:28:23 -04:00
Tiago Góes
459eb3903e Merge pull request #11208 from AlexSCorey/7741-GroupAdvanceSearchKeys
Groups Advanced Search Keys
2021-10-13 10:32:26 -03:00
chris meyers
611a537b55 add missing create partition for scm backed inv
* This will resolve missing project update job events issue
2021-10-13 07:51:40 -04:00
Shane McDonald
3a74cc5a74 Add awx-operator CI check 2021-10-12 18:59:24 -04:00
Shane McDonald
f1520e1a70 Allow for building headless mode
This will only be used in CI and maybe other places where we dont need a UI
2021-10-12 18:59:24 -04:00
Shane McDonald
727b4668c2 yamllint: ignore some gitignore'd directories 2021-10-12 18:59:24 -04:00
Shane McDonald
1287e001d8 yamllint: disable truthy rule
This rule feels very anti-Ansible
2021-10-12 18:59:23 -04:00
Shane McDonald
c9b53cf975 Refactor image_build and image_push roles
Primary changes are:

- Generalized variable names (remove "docker")
- Add explicit "push" variable rather than checking if the "registry" variable is defined.
- Allow for passing in version as build arg
2021-10-12 18:59:13 -04:00
chris meyers
64811d0b6b fix python black lint requirements 2021-10-12 17:09:30 -04:00
Alan Rominger
74af187568 Fix Makefile conditional used for docker-refresh (#11238) 2021-10-12 13:52:52 -04:00
sean-m-ssullivan
a28c023cf1 update to allow use of id for unified job template 2021-10-12 13:06:30 -04:00
Shane McDonald
cdf7fd64b2 Merge pull request #11230 from no-12/devel
Fix survey update with job_template module
2021-10-11 17:23:57 -04:00
Shane McDonald
84ffa4a5b7 Merge pull request #11189 from nntrn/pgsql-12
Change pgsql version from 10 to 12 in template for dockerfile role
2021-10-11 15:41:18 -04:00
Shane McDonald
326a43de11 Merge pull request #11231 from CastawayEGR/fix-awx-collection-spelling
fix spelling of Vault
2021-10-11 15:37:20 -04:00
Amol Gautam
07f193d8d6 Merge pull request #11226 from amolgautam25/K8s_signed_work
Changed Work Submission parameter for K8s work
2021-10-11 13:03:28 -04:00
Amol Gautam
f79a57c3e2 Changed Work Submission parameter for K8s work 2021-10-11 08:10:26 -07:00
Michael Tipton
f8319fcd02 fix spelling of Vault 2021-10-09 23:46:16 -04:00
Nico Ohnezat
815ef4c9c9 related #11229 consider previous set json_output changed in
controller_api

job_template module sets self.json_output['changed'] to true before calling create_or_update_if_needed.

Signed-off-by: Nico Ohnezat <nico@no-12.net>
2021-10-08 23:59:12 +02:00
kialam
d1800aa6d0 Merge pull request #11218 from kialam/revert-pf-upgrade
Roll back PF deps upgrade to re-enable select input typing.
2021-10-08 11:38:55 -07:00
Wambugu “Innocent” Kironji
dda940344e Merge pull request #11209 from kialam/fix-job-list-refresh
Pass configurable qs to fetchJobsById function.
2021-10-08 13:18:53 -04:00
Kersom
1fffeb430c Merge pull request #11216 from AlexSCorey/11214-DisableDefaultInstanceDelete
Disable default instance delete
2021-10-08 12:48:23 -04:00
Jeff Bradberry
7d0bbd0a4c Merge pull request #11225 from jbradberry/revert-iso-group-removal
Revert removing the old isolated groups
2021-10-08 12:38:03 -04:00
Jeff Bradberry
15fd22681d Revert removing the old isolated groups
In 4.1+ / AAP 2.1+, isolated groups should be converted into plain
instance groups, and it's desirable for the old ones to stick around
since they'll likely be tied to a bunch of job templates.  We do not
want to make the users have to reconstruct those relationships.
2021-10-08 11:53:21 -04:00
Chris Meyers
6a2826b91c Merge pull request #11088 from saito-hideki/issue/10879
Fixed Org mapping behavior with SAML when Ansible Galaxy cred does not exist
2021-10-08 10:48:11 -04:00
Jim Ladd
112111c7f9 Merge pull request #10904 from jladdjr/do_not_collect_artifact_data
do not collect artifact_data when gathering analytics
2021-10-07 22:46:00 -07:00
Alan Rominger
ed8498f43f Change search location for job private data (#11217) 2021-10-07 20:33:57 -04:00
Kia Lam
77a5bb9069 Roll back PF deps upgrade to re-enable select input typing. 2021-10-07 15:36:14 -07:00
Alex Corey
37f86803f7 Disables name field for default and controlplan instance groups 2021-10-07 15:36:25 -04:00
Tiago Góes
160858b051 Merge pull request #11206 from nixocio/ui_update
Upgrade a few ui dependencies
2021-10-07 15:55:50 -03:00
Kia Lam
68f44c01ea Rely on default qs value. 2021-10-07 09:52:33 -07:00
Alex Corey
bef8d7426f Groups Advanced search keys, and removes Clear all filters text after advanced search 2021-10-07 10:08:06 -04:00
nixocio
c758f079cd Upgrade a few ui dependencies
Upgrade axios, and ansi-to-html.
2021-10-06 22:14:59 -04:00
Shane McDonald
7e404b7c19 Merge pull request #11199 from shanemcd/auto-version
Remove VERSION files, obtain version from git tags.
2021-10-06 20:14:06 -04:00
Kia Lam
4b7faea552 Remove comments and linter-disable. 2021-10-06 13:18:47 -07:00
Sarah Akus
4ddd391033 Merge pull request #11168 from AlexSCorey/11103-AllowJinjaOnSettings
Sufrace ALLOW_JINJA_IN_EXTRA_VARS on the job settings page
2021-10-06 15:59:28 -04:00
Alan Rominger
e52416fd47 Report single node clusters as non-ha (#11212)
* Report single node clusters as non-ha

* Move test file so we can make it use the database

* Update unit test to accomidate different node types
2021-10-06 10:50:18 -04:00
Shane McDonald
f67a2d2f46 Make setup.py compatible with older pythons
This caused some annoying downstream failures I'd rather not fix right now.
2021-10-05 19:11:03 -04:00
Shane McDonald
fcdda8d7a7 Remove old test comparing VERSION files 2021-10-05 19:11:03 -04:00
Shane McDonald
1f0b936e82 Remove VERSION files, obtain version from git tags. 2021-10-05 19:11:00 -04:00
Alan Rominger
b70793db5c Consolidate cleanup actions under new ansible-runner worker cleanup command (#11160)
* Primary development of integrating runner cleanup command

* Fixup image cleanup signals and their tests

* Use alphabetical sort to solve the cluster coordination problem

* Update test to new pattern

* Clarity edits to interface with ansible-runner cleanup method

* Another change corresponding to ansible-runner CLI updates

* Fix incomplete implementation of receptor remote cleanup

* Share receptor utils code between worker_info and cleanup

* Complete task logging from calling runner cleanup command

* Wrap up unit tests and some contract changes that fall out of those

* Fix bug in CLI construction

* Fix queryset filter bug
2021-10-05 16:32:03 -04:00
Kia Lam
0f044f6c21 Pass configurable qs to fetchJobsById function. 2021-10-05 13:04:37 -07:00
Amol Gautam
4c205dfde9 Merge pull request #11133 from amolgautam25/receptor_work_sign
AWX dev environment changes for receptor work signing feature
2021-10-05 14:57:58 -04:00
Tiago Góes
d58d460119 Merge pull request #11173 from mabashian/hub-to-controller
Adds support for pre-filling EE add form name, description, and image from query params
2021-10-05 15:57:31 -03:00
Amol Gautam
24a6edef9e AWX dev environment changes for receptor work signing feature
-- Updated devel build to take most recent receptor binary
-- Added signWork parameter when sedning job to receptor
-- Modified docker-compose tasks to generate RSA key pair to use for work-signing
-- Modified docker-compose templates and jinja templates for implementing work-sign
-- Modified Firewall rules on the receptor jinja config

Add firewall rules to dev env
2021-10-05 11:41:34 -07:00
Kersom
a5485096ac Merge pull request #11200 from nixocio/ui_update_unit_tests
Update unit-tests
2021-10-05 14:29:07 -04:00
Kersom
60a5ccf70b Merge pull request #11201 from nixocio/ui_remove_console
Remove console.log
2021-10-05 14:28:42 -04:00
Marliana Lara
d93a7c2997 Reset form values when query params change 2021-10-05 13:10:33 -04:00
Alan Rominger
af5f8e8a4a Always set project sync execution_node to current host (#11204) 2021-10-05 13:08:40 -04:00
nixocio
1596c855ff Remove console.log
Remove console.log
2021-10-05 11:26:03 -04:00
nixocio
f45dd7a748 Update unit-tests
Update unit-tests mocked values, as attempt to mitigate CI failures.
2021-10-05 11:16:42 -04:00
Shane McDonald
a036363e85 Merge pull request #11195 from shanemcd/update-pip-and-setuptools
Update pip and setuptools
2021-10-04 18:50:51 -04:00
Shane McDonald
4aceea41fd Update licensce test to work with newer pip 2021-10-04 17:41:48 -04:00
Shane McDonald
7bbfcbaefd Update dev requirements to work with setuptools 58 2021-10-04 16:24:16 -04:00
Elijah DeLee
18eaa9bb92 Merge pull request #11166 from ansible/receptorctl-status-sosreport
get receptorctl status for sosreport
2021-10-04 16:13:37 -04:00
Tiago Góes
6826d5444b Merge pull request #11183 from AlexSCorey/11170-fix
Fixes Instance Group tooltip
2021-10-04 15:35:03 -03:00
Alex Corey
622ec69216 fixes tooltip 2021-10-04 14:17:13 -04:00
Shane McDonald
d38c109d49 Update pip and setuptools 2021-10-04 13:07:16 -04:00
Tiago Góes
a31b2d0259 Merge pull request #11192 from AlexSCorey/11191-fix
Fixes delete message
2021-10-04 12:39:19 -03:00
Tiago Góes
b13c076881 Merge pull request #11148 from AlexSCorey/11105-UpdatePF
Updates PF dependencies, and Instance Toggle labels
2021-10-04 12:29:36 -03:00
Alex Corey
c429a55382 Fixes delete message 2021-10-04 10:58:48 -04:00
Alex Corey
20c4b21c39 Sufrace ALLOW_JINJA_IN_EXTRA_VARS on the job settings page 2021-10-04 10:24:26 -04:00
Elijah DeLee
d3289dc688 fix typo in comment in tools/sosreport/controller.py 2021-10-04 09:45:11 -04:00
annie tran
685c0b844e Change pgsql version from 10 to 12 in template for dockerfile role 2021-10-04 06:34:16 -05:00
Shane McDonald
57c9b14198 Fix docker-compose targets 2021-10-03 13:40:26 -04:00
mabashian
d0a13cb12a Adds test coverage for parsing and prefilling form fields from query params on EE add form 2021-09-29 16:59:16 -04:00
mabashian
71c72f74a1 Add support for name and description query params on ee add 2021-09-29 16:45:07 -04:00
mabashian
ad24fe7017 Remove cred from potential hub params 2021-09-29 13:57:27 -04:00
mabashian
e5578a8ef3 Fix bad merge conflict resolution 2021-09-29 13:55:30 -04:00
Elijah DeLee
3a40d5e243 get receptorctl status for sosreport
I presume the logs also get collected from journalctl but I'm not sure
2021-09-29 11:24:49 -04:00
Marliana Lara
8e34898b4e Redirect with query params and update EE form with hub image data 2021-09-29 11:22:56 -04:00
Alex Corey
0b0d049071 Updates PF dependencies, and Instance Toggle labels 2021-09-27 17:26:39 -04:00
Hideki Saito
9e74ac24fa Fixed Org mapping behavior with SAML when Ansible Galaxy cred does not exist
- Fixes #10879
- Fixes ansible/tower#5061

Signed-off-by: Hideki Saito <saito@fgrep.org>
2021-09-16 23:25:50 +09:00
sezanzeb
cbe612baa5 add credential file support
Signed-off-by: sezanzeb <proxima@sezanzeb.de>
2021-09-12 17:58:49 +02:00
Alexander Komarov
899d36b2c9 Fix tests 2021-08-19 15:20:52 +05:00
Alexander Komarov
530977d6b3 Set default value is 0 for idle_timeout 2021-08-19 15:18:38 +05:00
Alexander Komarov
aa682fa2c9 Add idle_timeout setting to job settings 2021-08-19 14:48:29 +05:00
Jim Ladd
e3893b1887 do not collect artifact_data when gathering analytics
- also, store event_data in jsonb object
- .. in order to have data structure that supports '-' operator
2021-08-17 14:55:16 -07:00
932 changed files with 52076 additions and 47025 deletions

View File

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

View File

@@ -16,7 +16,7 @@ https://www.ansible.com/security
<!-- Pick the area of AWX for this issue, you can have multiple, delete the rest: --> <!-- Pick the area of AWX for this issue, you can have multiple, delete the rest: -->
- API - API
- UI - UI
- Installer - Collection
##### SUMMARY ##### SUMMARY
<!-- Briefly describe the problem. --> <!-- Briefly describe the problem. -->

View File

@@ -1,26 +1,24 @@
--- ---
name: Bug Report name: Bug Report
description: Create a report to help us improve description: Create a report to help us improve
labels:
- bug
body: body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Issues are for **concrete, actionable bugs and feature requests** only. For debugging help or technical support, please use: Issues are for **concrete, actionable bugs and feature requests** only. For debugging help or technical support, please use:
- The #ansible-awx channel on irc.libera.chat - The #ansible-awx channel on irc.libera.chat
- https://groups.google.com/forum/#!forum/awx-project - The awx project mailing list, https://groups.google.com/forum/#!forum/awx-project
- type: checkboxes - type: checkboxes
id: terms id: terms
attributes: attributes:
label: Please confirm the following label: Please confirm the following
options: options:
- label: I agree to follow this project's [code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html). - label: I agree to follow this project's [code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
required: true required: true
- label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates. - label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
required: true required: true
- label: I understand that AWX is open source software provided for free and that I am not entitled to status updates or other assurances. - label: I understand that AWX is open source software provided for free and that I might not receive a timely response.
required: true required: true
- type: textarea - type: textarea
@@ -39,6 +37,15 @@ body:
validations: validations:
required: true required: true
- type: checkboxes
id: components
attributes:
label: Select the relevant components
options:
- label: UI
- label: API
- label: Docs
- type: dropdown - type: dropdown
id: awx-install-method id: awx-install-method
attributes: attributes:

View File

@@ -25,6 +25,7 @@ the change does.
<!--- Name of the module/plugin/module/task --> <!--- Name of the module/plugin/module/task -->
- API - API
- UI - UI
- Collection
##### AWX VERSION ##### AWX VERSION
<!--- Paste verbatim output from `make VERSION` between quotes below --> <!--- Paste verbatim output from `make VERSION` between quotes below -->

12
.github/issue_labeler.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
needs_triage:
- '.*'
"type:bug":
- "Please confirm the following"
"type:enhancement":
- "Feature Idea"
"component:ui":
- "\\[X\\] UI"
"component:api":
- "\\[X\\] API"
"component:docs":
- "\\[X\\] Docs"

14
.github/pr_labeler.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
"component:api":
- any: ['awx/**/*', '!awx/ui/*']
"component:ui":
- any: ['awx/ui/**/*']
"component:docs":
- any: ['docs/**/*']
"component:cli":
- any: ['awxkit/**/*']
"component:collection":
- any: ['awx_collection/**/*']

View File

@@ -4,64 +4,51 @@ env:
BRANCH: ${{ github.base_ref || 'devel' }} BRANCH: ${{ github.base_ref || 'devel' }}
on: on:
pull_request: pull_request:
push:
branches: [devel]
jobs: jobs:
api-test: common-tests:
name: ${{ matrix.tests.name }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
packages: write packages: write
contents: read contents: read
strategy:
fail-fast: false
matrix:
tests:
- name: api-test
command: /start_tests.sh
label: Run API Tests
- name: api-lint
command: /var/lib/awx/venv/awx/bin/tox -e linters
label: Run API Linters
- name: api-swagger
command: /start_tests.sh swagger
label: Generate API Reference
- name: awx-collection
command: /start_tests.sh test_collection_all
label: Run Collection Tests
- name: api-schema
label: Check API Schema
command: /start_tests.sh detect-schema-change SCHEMA_DIFF_BASE_BRANCH=${{ github.event.pull_request.base.ref }}
- name: ui-lint
label: Run UI Linters
command: make ui-lint
- name: ui-test-screens
label: Run UI Screens Tests
command: make ui-test-screens
- name: ui-test-general
label: Run UI General Tests
command: make ui-test-general
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Log in to registry - name: Get python version from Makefile
run: | run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache - name: Install python ${{ env.py_version }}
run: | uses: actions/setup-python@v2
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} with:
python-version: ${{ env.py_version }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Run API Tests
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh
api-lint:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Run API Linters
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /var/lib/awx/venv/awx/bin/tox -e linters
api-swagger:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry - name: Log in to registry
run: | run: |
@@ -73,105 +60,78 @@ jobs:
- name: Build image - name: Build image
run: | run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Generate API Reference - name: ${{ matrix.texts.label }}
run: | run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \ docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh swagger --workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} ${{ matrix.tests.command }}
awx-collection: dev-env:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Get python version from Makefile
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
- name: Install python ${{ env.py_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.py_version }}
- name: Log in to registry - name: Log in to registry
run: | run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache - name: Pre-pull image to warm build cache
run: | run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Run Collection Tests
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh test_collection_all
api-schema:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Check API Schema
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh detect-schema-change
ui-lint:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
- name: Build image - name: Build image
run: | run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Run UI Linters - name: Run smoke test
run: | run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \ export DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }}
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} make ui-lint export COMPOSE_TAG=${{ env.BRANCH }}
ui-test: ansible-playbook tools/docker-compose/ansible/smoke-test.yml -e repo_dir=$(pwd) -v
awx-operator:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps: steps:
- uses: actions/checkout@v2 - name: Checkout awx
uses: actions/checkout@v2
with:
path: awx
- name: Log in to registry - name: Checkout awx-operator
run: | uses: actions/checkout@v2
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin with:
repository: ansible/awx-operator
path: awx-operator
- name: Pre-pull image to warm build cache - name: Install playbook dependencies
run: | run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} python3 -m pip install docker
- name: Build image - name: Build AWX image
working-directory: awx
run: | run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build ansible-playbook -v tools/ansible/build.yml \
-e headless=yes \
-e awx_image=awx \
-e awx_image_tag=ci \
-e ansible_python_interpreter=$(which python3)
- name: Run UI Tests - name: Run test deployment with awx-operator
working-directory: awx-operator
run: | run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \ python3 -m pip install -r molecule/requirements.txt
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} make ui-test ansible-galaxy collection install -r molecule/requirements.yml
sudo rm -f $(which kustomize)
make kustomize
KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule -v test -s kind
env:
AWX_TEST_IMAGE: awx
AWX_TEST_VERSION: ci

View File

@@ -1,30 +0,0 @@
---
name: Push Development Image
on:
push:
branches:
- devel
jobs:
push:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
- name: Build image
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make docker-compose-build
- name: Push image
run: |
docker push ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}

43
.github/workflows/devel_images.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
---
name: Build/Push Development Images
on:
push:
branches:
- devel
- release_*
jobs:
push:
if: endsWith(github.repository, '/awx') || startsWith(github.ref, 'refs/heads/release_')
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v2
- name: Get python version from Makefile
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
- name: Install python ${{ env.py_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.py_version }}
- name: Log in to registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} || :
docker pull ghcr.io/${{ github.repository_owner }}/awx_kube_devel:${GITHUB_REF##*/} || :
- name: Build images
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make docker-compose-build
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make awx-kube-dev-build
- name: Push image
run: |
docker push ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
docker push ghcr.io/${{ github.repository_owner }}/awx_kube_devel:${GITHUB_REF##*/}

View File

@@ -18,6 +18,14 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Get python version from Makefile
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
- name: Install python ${{ env.py_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.py_version }}
- name: Install system deps - name: Install system deps
run: sudo apt-get install -y gettext run: sudo apt-get install -y gettext
@@ -85,7 +93,7 @@ jobs:
-e CYPRESS_baseUrl="https://$AWX_IP:8043" \ -e CYPRESS_baseUrl="https://$AWX_IP:8043" \
-e CYPRESS_AWX_E2E_USERNAME=admin \ -e CYPRESS_AWX_E2E_USERNAME=admin \
-e CYPRESS_AWX_E2E_PASSWORD='password' \ -e CYPRESS_AWX_E2E_PASSWORD='password' \
-e COMMAND="npm run cypress-gha" \ -e COMMAND="npm run cypress-concurrently-gha" \
-v /dev/shm:/dev/shm \ -v /dev/shm:/dev/shm \
-v $PWD:/e2e \ -v $PWD:/e2e \
-w /e2e \ -w /e2e \

21
.github/workflows/label_issue.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Label Issue
on:
issues:
types:
- opened
- reopened
jobs:
triage:
runs-on: ubuntu-latest
name: Label Issue
steps:
- name: Label Issue
uses: github/issue-labeler@v2.4.1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
not-before: 2021-12-07T07:00:00Z
configuration-path: .github/issue_labeler.yml
enable-versioned-regex: 0

20
.github/workflows/label_pr.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Label PR
on:
pull_request_target:
types:
- opened
- reopened
- synchronize
jobs:
triage:
runs-on: ubuntu-latest
name: Label PR
steps:
- name: Label PR
uses: actions/labeler@v3
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/pr_labeler.yml

73
.github/workflows/promote.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
---
name: Promote Release
on:
release:
types: [published]
jobs:
promote:
runs-on: ubuntu-latest
steps:
- name: Checkout awx
uses: actions/checkout@v2
- name: Get python version from Makefile
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
- name: Install python ${{ env.py_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.py_version }}
- name: Install dependencies
run: |
python${{ env.py_version }} -m pip install wheel twine
- name: Set official collection namespace
run: echo collection_namespace=awx >> $GITHUB_ENV
if: ${{ github.repository_owner == 'ansible' }}
- name: Set unofficial collection namespace
run: echo collection_namespace=${{ github.repository_owner }} >> $GITHUB_ENV
if: ${{ github.repository_owner != 'ansible' }}
- name: Build collection and publish to galaxy
run: |
COLLECTION_NAMESPACE=${{ env.collection_namespace }} make build_collection
ansible-galaxy collection publish \
--token=${{ secrets.GALAXY_TOKEN }} \
awx_collection_build/${{ env.collection_namespace }}-awx-${{ github.event.release.tag_name }}.tar.gz
- name: Set official pypi info
run: echo pypi_repo=pypi >> $GITHUB_ENV
if: ${{ github.repository_owner == 'ansible' }}
- name: Set unofficial pypi info
run: echo pypi_repo=testpypi >> $GITHUB_ENV
if: ${{ github.repository_owner != 'ansible' }}
- name: Build awxkit and upload to pypi
run: |
cd awxkit && python3 setup.py bdist_wheel
twine upload \
-r ${{ env.pypi_repo }} \
-u ${{ secrets.PYPI_USERNAME }} \
-p ${{ secrets.PYPI_PASSWORD }} \
dist/*
- name: Log in to GHCR
run: |
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Log in to Quay
run: |
echo ${{ secrets.QUAY_TOKEN }} | docker login quay.io -u ${{ secrets.QUAY_USER }} --password-stdin
- name: Re-tag and promote awx image
run: |
docker pull ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }}
docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:${{ github.event.release.tag_name }}
docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:latest
docker push quay.io/${{ github.repository }}:${{ github.event.release.tag_name }}
docker push quay.io/${{ github.repository }}:latest

View File

@@ -1,56 +0,0 @@
name: Release AWX
on:
workflow_dispatch:
inputs:
version:
description: 'Version'
required: true
default: ''
confirm:
description: 'Are you sure? Set this to yes.'
required: true
default: 'no'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: "Verify inputs"
run: |
set -e
if [[ ${{ github.event.inputs.confirm }} != "yes" ]]; then
>&2 echo "Confirm must be 'yes'"
exit 1
fi
if [[ ${{ github.event.inputs.version }} == "" ]]; then
>&2 echo "Set version to continue."
exit 1
fi
exit 0
- name: Generate changelog
uses: shanemcd/simple-changelog-generator@v1
id: changelog
with:
repo: "${{ github.repository }}"
- name: Write changelog to file
run: |
cat << 'EOF' > /tmp/changelog
${{ steps.changelog.outputs.changelog }}
EOF
- name: Release AWX
run: |
ansible-playbook -v tools/ansible/release.yml \
-e changelog_path=/tmp/changelog \
-e version=${{ github.event.inputs.version }} \
-e github_token=${{ secrets.GITHUB_TOKEN }} \
-e repo=${{ github.repository }}

132
.github/workflows/stage.yml vendored Normal file
View File

@@ -0,0 +1,132 @@
---
name: Stage Release
on:
workflow_dispatch:
inputs:
version:
description: 'AWX version.'
required: true
default: ''
operator_version:
description: 'Operator version. Leave blank to skip staging awx-operator.'
default: ''
confirm:
description: 'Are you sure? Set this to yes.'
required: true
default: 'no'
jobs:
stage:
runs-on: ubuntu-latest
permissions:
packages: write
contents: write
steps:
- name: Verify inputs
run: |
set -e
if [[ ${{ github.event.inputs.confirm }} != "yes" ]]; then
>&2 echo "Confirm must be 'yes'"
exit 1
fi
if [[ ${{ github.event.inputs.version }} == "" ]]; then
>&2 echo "Set version to continue."
exit 1
fi
exit 0
- name: Checkout awx
uses: actions/checkout@v2
with:
path: awx
- name: Get python version from Makefile
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
- name: Install python ${{ env.py_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.py_version }}
- name: Checkout awx-logos
uses: actions/checkout@v2
with:
repository: ansible/awx-logos
path: awx-logos
- name: Checkout awx-operator
uses: actions/checkout@v2
with:
repository: ${{ github.repository_owner }}/awx-operator
path: awx-operator
- name: Install playbook dependencies
run: |
python3 -m pip install docker
- name: Build and stage AWX
working-directory: awx
run: |
ansible-playbook -v tools/ansible/build.yml \
-e registry=ghcr.io \
-e registry_username=${{ github.actor }} \
-e registry_password=${{ secrets.GITHUB_TOKEN }} \
-e awx_image=${{ github.repository }} \
-e awx_version=${{ github.event.inputs.version }} \
-e ansible_python_interpreter=$(which python3) \
-e push=yes \
-e awx_official=yes
- name: Build and stage awx-operator
working-directory: awx-operator
run: |
BUILD_ARGS="--build-arg DEFAULT_AWX_VERSION=${{ github.event.inputs.version }} \
--build-arg OPERATOR_VERSION=${{ github.event.inputs.operator_version }}" \
IMAGE_TAG_BASE=ghcr.io/${{ github.repository_owner }}/awx-operator \
VERSION=${{ github.event.inputs.operator_version }} make docker-build docker-push
- name: Run test deployment with awx-operator
working-directory: awx-operator
run: |
python3 -m pip install -r molecule/requirements.txt
ansible-galaxy collection install -r molecule/requirements.yml
sudo rm -f $(which kustomize)
make kustomize
KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule test -s kind
env:
AWX_TEST_IMAGE: ${{ github.repository }}
AWX_TEST_VERSION: ${{ github.event.inputs.version }}
- name: Generate changelog
uses: shanemcd/simple-changelog-generator@v1
id: changelog
with:
repo: "${{ github.repository }}"
- name: Write changelog to file
run: |
cat << 'EOF' > /tmp/awx-changelog
${{ steps.changelog.outputs.changelog }}
EOF
- name: Create draft release for AWX
working-directory: awx
run: |
ansible-playbook -v tools/ansible/stage.yml \
-e changelog_path=/tmp/awx-changelog \
-e repo=${{ github.repository }} \
-e awx_image=ghcr.io/${{ github.repository }} \
-e version=${{ github.event.inputs.version }} \
-e github_token=${{ secrets.GITHUB_TOKEN }}
- name: Create draft release for awx-operator
if: ${{ github.event.inputs.operator_version != '' }}
working-directory: awx
run: |
ansible-playbook tools/ansible/stage.yml \
-e version=${{ github.event.inputs.operator_version }} \
-e repo=${{ github.repository_owner }}/awx-operator \
-e github_token=${{ secrets.AWX_OPERATOR_RELEASE_TOKEN }}

View File

@@ -4,6 +4,7 @@ on:
push: push:
branches: branches:
- devel - devel
- release_**
jobs: jobs:
push: push:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -13,13 +14,21 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Get python version from Makefile
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
- name: Install python ${{ env.py_version }}
uses: actions/setup-python@v2
with:
python-version: ${{ env.py_version }}
- name: Log in to registry - name: Log in to registry
run: | run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Pre-pull image to warm build cache - name: Pre-pull image to warm build cache
run: | run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} || :
- name: Build image - name: Build image
run: | run: |
@@ -38,6 +47,6 @@ jobs:
run: | run: |
ansible localhost -c local, -m command -a "{{ ansible_python_interpreter + ' -m pip install boto3'}}" ansible localhost -c local, -m command -a "{{ ansible_python_interpreter + ' -m pip install boto3'}}"
ansible localhost -c local -m aws_s3 \ ansible localhost -c local -m aws_s3 \
-a 'src=${{ github.workspace }}/schema.json bucket=awx-public-ci-files object=schema.json mode=put permission=public-read' -a "src=${{ github.workspace }}/schema.json bucket=awx-public-ci-files object=${GITHUB_REF##*/}/schema.json mode=put permission=public-read"

5
.gitignore vendored
View File

@@ -7,6 +7,9 @@ reference-schema.json
.tags .tags
.tags1 .tags1
# User level pre-commit hooks
pre-commit-user
# Tower # Tower
awx-dev awx-dev
awx/settings/local_*.py* awx/settings/local_*.py*
@@ -42,6 +45,7 @@ tools/docker-compose/_build
tools/docker-compose/_sources tools/docker-compose/_sources
tools/docker-compose/overrides/ tools/docker-compose/overrides/
tools/docker-compose-minikube/_sources tools/docker-compose-minikube/_sources
tools/docker-compose/keycloak.awx.realm.json
# Tower setup playbook testing # Tower setup playbook testing
setup/test/roles/postgresql setup/test/roles/postgresql
@@ -58,6 +62,7 @@ __pycache__
/dist /dist
/*.egg-info /*.egg-info
*.py[c,o] *.py[c,o]
/.eggs
# JavaScript # JavaScript
/Gruntfile.js /Gruntfile.js

View File

@@ -6,8 +6,11 @@ ignore: |
# vault files # vault files
awx/main/tests/data/ansible_utils/playbooks/valid/vault.yml awx/main/tests/data/ansible_utils/playbooks/valid/vault.yml
awx/ui/test/e2e/tests/smoke-vars.yml awx/ui/test/e2e/tests/smoke-vars.yml
awx/ui/node_modules
tools/docker-compose/_sources
extends: default extends: default
rules: rules:
line-length: disable line-length: disable
truthy: disable

View File

@@ -17,6 +17,7 @@ Have questions about this document or anything not covered here? Come chat with
- [Building API Documentation](#building-api-documentation) - [Building API Documentation](#building-api-documentation)
- [Accessing the AWX web interface](#accessing-the-awx-web-interface) - [Accessing the AWX web interface](#accessing-the-awx-web-interface)
- [Purging containers and images](#purging-containers-and-images) - [Purging containers and images](#purging-containers-and-images)
- [Pre commit hooks](#pre-commit-hooks)
- [What should I work on?](#what-should-i-work-on) - [What should I work on?](#what-should-i-work-on)
- [Submitting Pull Requests](#submitting-pull-requests) - [Submitting Pull Requests](#submitting-pull-requests)
- [PR Checks run by Zuul](#pr-checks-run-by-zuul) - [PR Checks run by Zuul](#pr-checks-run-by-zuul)
@@ -104,13 +105,21 @@ When necessary, remove any AWX containers and images by running the following:
(host)$ make docker-clean (host)$ make docker-clean
``` ```
### Pre commit hooks
When you attempt to perform a `git commit` there will be a pre-commit hook that gets run before the commit is allowed to your local repository. For example, python's [black](https://pypi.org/project/black/) will be run to test the formatting of any python files.
While you can use environment variables to skip the pre-commit hooks GitHub will run similar tests and prevent merging of PRs if the tests do not pass.
If you would like to add additional commit hooks for your own usage you can create a directory in the root of the repository called `pre-commit-user`. Any executable file in that directory will be executed as part of the pre-commit hooks. If any of the pre-commit checks fail the commit will be halted. For your convenience in user scripts, a variable called `CHANGED_FILES` will be set with any changed files present in the commit.
## What should I work on? ## What should I work on?
For feature work, take a look at the current [Enhancements](https://github.com/ansible/awx/issues?q=is%3Aissue+is%3Aopen+label%3Atype%3Aenhancement). For feature work, take a look at the current [Enhancements](https://github.com/ansible/awx/issues?q=is%3Aissue+is%3Aopen+label%3Atype%3Aenhancement).
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. 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.
Fixing bugs, adding translations, and updating the documentation are always appreciated, so reviewing the backlog of issues is always a good place to start. For extra information on debugging tools, see [Debugging](https://github.com/ansible/awx/blob/devel/docs/debugging.md). Fixing bugs, adding translations, and updating the documentation are always appreciated, so reviewing the backlog of issues is always a good place to start. For extra information on debugging tools, see [Debugging](./docs/debugging/).
**NOTE** **NOTE**

122
Makefile
View File

@@ -1,29 +1,34 @@
PYTHON ?= python3.8 PYTHON ?= python3.9
PYTHON_VERSION = $(shell $(PYTHON) -c "from distutils.sysconfig import get_python_version; print(get_python_version())")
OFFICIAL ?= no OFFICIAL ?= no
NODE ?= node NODE ?= node
NPM_BIN ?= npm NPM_BIN ?= npm
CHROMIUM_BIN=/tmp/chrome-linux/chrome CHROMIUM_BIN=/tmp/chrome-linux/chrome
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
MANAGEMENT_COMMAND ?= awx-manage MANAGEMENT_COMMAND ?= awx-manage
VERSION := $(shell cat VERSION) VERSION := $(shell $(PYTHON) setup.py --version)
COLLECTION_VERSION := $(shell $(PYTHON) setup.py --version | cut -d . -f 1-3)
# NOTE: This defaults the container image version to the branch that's active # NOTE: This defaults the container image version to the branch that's active
COMPOSE_TAG ?= $(GIT_BRANCH) COMPOSE_TAG ?= $(GIT_BRANCH)
COMPOSE_HOST ?= $(shell hostname)
MAIN_NODE_TYPE ?= hybrid MAIN_NODE_TYPE ?= hybrid
# If set to true docker-compose will also start a keycloak instance
KEYCLOAK ?= false
# If set to true docker-compose will also start an ldap instance
LDAP ?= false
VENV_BASE ?= /var/lib/awx/venv VENV_BASE ?= /var/lib/awx/venv
DEV_DOCKER_TAG_BASE ?= quay.io/awx DEV_DOCKER_TAG_BASE ?= ghcr.io/ansible
DEVEL_IMAGE_NAME ?= $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) DEVEL_IMAGE_NAME ?= $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
RECEPTOR_IMAGE ?= quay.io/ansible/receptor:devel
# Python packages to install only from source (not from binary wheels) # Python packages to install only from source (not from binary wheels)
# Comma separated list # Comma separated list
SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio
# These should be upgraded in the AWX and Ansible venv before attempting # These should be upgraded in the AWX and Ansible venv before attempting
# to install the actual requirements # to install the actual requirements
VENV_BOOTSTRAP ?= pip==19.3.1 setuptools==41.6.0 wheel==0.36.2 VENV_BOOTSTRAP ?= pip==21.2.4 setuptools==58.2.0 setuptools_scm[toml]==6.4.2 wheel==0.36.2
NAME ?= awx NAME ?= awx
@@ -40,7 +45,7 @@ I18N_FLAG_FILE = .i18n_built
receiver test test_unit test_coverage coverage_html \ receiver test test_unit test_coverage coverage_html \
dev_build release_build sdist \ dev_build release_build sdist \
ui-release ui-devel \ ui-release ui-devel \
VERSION docker-compose-sources \ VERSION PYTHON_VERSION docker-compose-sources \
.git/hooks/pre-commit .git/hooks/pre-commit
clean-tmp: clean-tmp:
@@ -142,24 +147,6 @@ version_file:
fi; \ fi; \
$(PYTHON) -c "import awx; print(awx.__version__)" > /var/lib/awx/.awx_version; \ $(PYTHON) -c "import awx; print(awx.__version__)" > /var/lib/awx/.awx_version; \
# Do any one-time init tasks.
comma := ,
init:
if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(MANAGEMENT_COMMAND) provision_instance --hostname=$(COMPOSE_HOST) --node_type=$(MAIN_NODE_TYPE); \
$(MANAGEMENT_COMMAND) register_queue --queuename=controlplane --instance_percent=100;\
$(MANAGEMENT_COMMAND) register_queue --queuename=default --instance_percent=100;
if [ ! -f /etc/receptor/certs/awx.key ]; then \
rm -f /etc/receptor/certs/*; \
receptor --cert-init commonname="AWX Test CA" bits=2048 outcert=/etc/receptor/certs/ca.crt outkey=/etc/receptor/certs/ca.key; \
for node in $(RECEPTOR_MUTUAL_TLS); do \
receptor --cert-makereq bits=2048 commonname="$$node test cert" dnsname=$$node nodeid=$$node outreq=/etc/receptor/certs/$$node.csr outkey=/etc/receptor/certs/$$node.key; \
receptor --cert-signreq req=/etc/receptor/certs/$$node.csr cacert=/etc/receptor/certs/ca.crt cakey=/etc/receptor/certs/ca.key outcert=/etc/receptor/certs/$$node.crt verify=yes; \
done; \
fi
# Refresh development environment after pulling new code. # Refresh development environment after pulling new code.
refresh: clean requirements_dev version_file develop migrate refresh: clean requirements_dev version_file develop migrate
@@ -280,17 +267,16 @@ api-lint:
awx-link: awx-link:
[ -d "/awx_devel/awx.egg-info" ] || $(PYTHON) /awx_devel/setup.py egg_info_dev [ -d "/awx_devel/awx.egg-info" ] || $(PYTHON) /awx_devel/setup.py egg_info_dev
cp -f /tmp/awx.egg-link /var/lib/awx/venv/awx/lib/python$(PYTHON_VERSION)/site-packages/awx.egg-link cp -f /tmp/awx.egg-link /var/lib/awx/venv/awx/lib/$(PYTHON)/site-packages/awx.egg-link
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
PYTEST_ARGS ?= -n auto
# Run all API unit tests. # Run all API unit tests.
test: test:
if [ "$(VENV_BASE)" ]; then \ if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \ . $(VENV_BASE)/awx/bin/activate; \
fi; \ fi; \
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS) PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider $(PYTEST_ARGS) $(TEST_DIRS)
cmp VERSION awxkit/VERSION || "VERSION and awxkit/VERSION *must* match"
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3 cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
awx-manage check_migrations --dry-run --check -n 'missing_migration_file' awx-manage check_migrations --dry-run --check -n 'missing_migration_file'
@@ -321,13 +307,19 @@ symlink_collection:
mkdir -p ~/.ansible/collections/ansible_collections/$(COLLECTION_NAMESPACE) # in case it does not exist mkdir -p ~/.ansible/collections/ansible_collections/$(COLLECTION_NAMESPACE) # in case it does not exist
ln -s $(shell pwd)/awx_collection $(COLLECTION_INSTALL) ln -s $(shell pwd)/awx_collection $(COLLECTION_INSTALL)
build_collection: awx_collection_build: $(shell find awx_collection -type f)
ansible-playbook -i localhost, awx_collection/tools/template_galaxy.yml -e collection_package=$(COLLECTION_PACKAGE) -e collection_namespace=$(COLLECTION_NAMESPACE) -e collection_version=$(VERSION) -e '{"awx_template_version":false}' ansible-playbook -i localhost, awx_collection/tools/template_galaxy.yml \
-e collection_package=$(COLLECTION_PACKAGE) \
-e collection_namespace=$(COLLECTION_NAMESPACE) \
-e collection_version=$(COLLECTION_VERSION) \
-e '{"awx_template_version":false}'
ansible-galaxy collection build awx_collection_build --force --output-path=awx_collection_build ansible-galaxy collection build awx_collection_build --force --output-path=awx_collection_build
build_collection: awx_collection_build
install_collection: build_collection install_collection: build_collection
rm -rf $(COLLECTION_INSTALL) rm -rf $(COLLECTION_INSTALL)
ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(VERSION).tar.gz ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(COLLECTION_VERSION).tar.gz
test_collection_sanity: install_collection test_collection_sanity: install_collection
cd $(COLLECTION_INSTALL) && ansible-test sanity cd $(COLLECTION_INSTALL) && ansible-test sanity
@@ -378,9 +370,9 @@ clean-ui:
rm -rf $(UI_BUILD_FLAG_FILE) rm -rf $(UI_BUILD_FLAG_FILE)
awx/ui/node_modules: awx/ui/node_modules:
NODE_OPTIONS=--max-old-space-size=4096 $(NPM_BIN) --prefix awx/ui --loglevel warn ci NODE_OPTIONS=--max-old-space-size=6144 $(NPM_BIN) --prefix awx/ui --loglevel warn ci
$(UI_BUILD_FLAG_FILE): $(UI_BUILD_FLAG_FILE): awx/ui/node_modules
$(PYTHON) tools/scripts/compilemessages.py $(PYTHON) tools/scripts/compilemessages.py
$(NPM_BIN) --prefix awx/ui --loglevel warn run compile-strings $(NPM_BIN) --prefix awx/ui --loglevel warn run compile-strings
$(NPM_BIN) --prefix awx/ui --loglevel warn run build $(NPM_BIN) --prefix awx/ui --loglevel warn run build
@@ -392,7 +384,9 @@ $(UI_BUILD_FLAG_FILE):
cp -r awx/ui/build/static/media/* awx/public/static/media cp -r awx/ui/build/static/media/* awx/public/static/media
touch $@ touch $@
ui-release: awx/ui/node_modules $(UI_BUILD_FLAG_FILE)
ui-release: $(UI_BUILD_FLAG_FILE)
ui-devel: awx/ui/node_modules ui-devel: awx/ui/node_modules
@$(MAKE) -B $(UI_BUILD_FLAG_FILE) @$(MAKE) -B $(UI_BUILD_FLAG_FILE)
@@ -410,8 +404,17 @@ ui-lint:
ui-test: ui-test:
$(NPM_BIN) --prefix awx/ui install $(NPM_BIN) --prefix awx/ui install
$(NPM_BIN) run --prefix awx/ui test -- --coverage --maxWorkers=4 --watchAll=false $(NPM_BIN) run --prefix awx/ui test
ui-test-screens:
$(NPM_BIN) --prefix awx/ui install
$(NPM_BIN) run --prefix awx/ui pretest
$(NPM_BIN) run --prefix awx/ui test-screens --runInBand
ui-test-general:
$(NPM_BIN) --prefix awx/ui install
$(NPM_BIN) run --prefix awx/ui pretest
$(NPM_BIN) run --prefix awx/ui/ test-general --runInBand
# Build a pip-installable package into dist/ with a timestamped version number. # Build a pip-installable package into dist/ with a timestamped version number.
dev_build: dev_build:
@@ -421,10 +424,17 @@ dev_build:
release_build: release_build:
$(PYTHON) setup.py release_build $(PYTHON) setup.py release_build
dist/$(SDIST_TAR_FILE): ui-release VERSION HEADLESS ?= no
ifeq ($(HEADLESS), yes)
dist/$(SDIST_TAR_FILE):
else
dist/$(SDIST_TAR_FILE): $(UI_BUILD_FLAG_FILE)
endif
$(PYTHON) setup.py $(SDIST_COMMAND) $(PYTHON) setup.py $(SDIST_COMMAND)
ln -sf $(SDIST_TAR_FILE) dist/awx.tar.gz
sdist: dist/$(SDIST_TAR_FILE) sdist: dist/$(SDIST_TAR_FILE)
echo $(HEADLESS)
@echo "#############################################" @echo "#############################################"
@echo "Artifacts:" @echo "Artifacts:"
@echo dist/$(SDIST_TAR_FILE) @echo dist/$(SDIST_TAR_FILE)
@@ -450,19 +460,22 @@ docker-compose-sources: .git/hooks/pre-commit
ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/sources.yml \ ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/sources.yml \
-e awx_image=$(DEV_DOCKER_TAG_BASE)/awx_devel \ -e awx_image=$(DEV_DOCKER_TAG_BASE)/awx_devel \
-e awx_image_tag=$(COMPOSE_TAG) \ -e awx_image_tag=$(COMPOSE_TAG) \
-e receptor_image=$(RECEPTOR_IMAGE) \
-e control_plane_node_count=$(CONTROL_PLANE_NODE_COUNT) \ -e control_plane_node_count=$(CONTROL_PLANE_NODE_COUNT) \
-e execution_node_count=$(EXECUTION_NODE_COUNT) \ -e execution_node_count=$(EXECUTION_NODE_COUNT) \
-e minikube_container_group=$(MINIKUBE_CONTAINER_GROUP) -e minikube_container_group=$(MINIKUBE_CONTAINER_GROUP) \
-e enable_keycloak=$(KEYCLOAK) \
-e enable_ldap=$(LDAP)
docker-compose: docker-auth awx/projects docker-compose-sources docker-compose: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans docker-compose -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans
docker-compose-credential-plugins: docker-auth awx/projects docker-compose-sources docker-compose-credential-plugins: awx/projects docker-compose-sources
echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m" echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m"
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/docker-credential-plugins-override.yml up --no-recreate awx_1 --remove-orphans docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/docker-credential-plugins-override.yml up --no-recreate awx_1 --remove-orphans
docker-compose-test: docker-auth awx/projects docker-compose-sources docker-compose-test: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports awx_1 /bin/bash docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports awx_1 /bin/bash
docker-compose-runtest: awx/projects docker-compose-sources docker-compose-runtest: awx/projects docker-compose-sources
@@ -471,8 +484,9 @@ docker-compose-runtest: awx/projects docker-compose-sources
docker-compose-build-swagger: awx/projects docker-compose-sources docker-compose-build-swagger: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports --no-deps awx_1 /start_tests.sh swagger docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports --no-deps awx_1 /start_tests.sh swagger
SCHEMA_DIFF_BASE_BRANCH ?= devel
detect-schema-change: genschema detect-schema-change: genschema
curl https://s3.amazonaws.com/awx-public-ci-files/schema.json -o reference-schema.json curl https://s3.amazonaws.com/awx-public-ci-files/$(SCHEMA_DIFF_BASE_BRANCH)/schema.json -o reference-schema.json
# Ignore differences in whitespace with -b # Ignore differences in whitespace with -b
diff -u -b reference-schema.json schema.json diff -u -b reference-schema.json schema.json
@@ -487,15 +501,15 @@ docker-compose-container-group-clean:
# Base development image build # Base development image build
docker-compose-build: docker-compose-build:
ansible-playbook tools/ansible/dockerfile.yml -e build_dev=True ansible-playbook tools/ansible/dockerfile.yml -e build_dev=True -e receptor_image=$(RECEPTOR_IMAGE)
DOCKER_BUILDKIT=1 docker build -t $(DEVEL_IMAGE_NAME) \ DOCKER_BUILDKIT=1 docker build -t $(DEVEL_IMAGE_NAME) \
--build-arg BUILDKIT_INLINE_CACHE=1 \ --build-arg BUILDKIT_INLINE_CACHE=1 \
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) . --cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) .
docker-clean: docker-clean:
$(foreach container_id,$(shell docker ps -f name=tools_awx -aq && docker ps -f name=tools_receptor -aq),docker stop $(container_id); docker rm -f $(container_id);) $(foreach container_id,$(shell docker ps -f name=tools_awx -aq && docker ps -f name=tools_receptor -aq),docker stop $(container_id); docker rm -f $(container_id);)
if [ $(shell docker images | grep "awx_devel") ]; then \ if [ "$(shell docker images | grep awx_devel)" ]; then \
docker images | grep "awx_devel" | awk '{print $$3}' | xargs docker rmi --force; \ docker images | grep awx_devel | awk '{print $$3}' | xargs docker rmi --force; \
fi fi
docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
@@ -504,10 +518,10 @@ docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
docker-refresh: docker-clean docker-compose docker-refresh: docker-clean docker-compose
# Docker Development Environment with Elastic Stack Connected # Docker Development Environment with Elastic Stack Connected
docker-compose-elk: docker-auth awx/projects docker-compose-sources docker-compose-elk: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
docker-compose-cluster-elk: docker-auth awx/projects docker-compose-sources docker-compose-cluster-elk: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link-cluster.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link-cluster.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
prometheus: prometheus:
@@ -530,18 +544,23 @@ psql-container:
VERSION: VERSION:
@echo "awx: $(VERSION)" @echo "awx: $(VERSION)"
PYTHON_VERSION:
@echo "$(PYTHON)" | sed 's:python::'
Dockerfile: tools/ansible/roles/dockerfile/templates/Dockerfile.j2 Dockerfile: tools/ansible/roles/dockerfile/templates/Dockerfile.j2
ansible-playbook tools/ansible/dockerfile.yml ansible-playbook tools/ansible/dockerfile.yml -e receptor_image=$(RECEPTOR_IMAGE)
Dockerfile.kube-dev: tools/ansible/roles/dockerfile/templates/Dockerfile.j2 Dockerfile.kube-dev: tools/ansible/roles/dockerfile/templates/Dockerfile.j2
ansible-playbook tools/ansible/dockerfile.yml \ ansible-playbook tools/ansible/dockerfile.yml \
-e dockerfile_name=Dockerfile.kube-dev \ -e dockerfile_name=Dockerfile.kube-dev \
-e kube_dev=True \ -e kube_dev=True \
-e template_dest=_build_kube_dev -e template_dest=_build_kube_dev \
-e receptor_image=$(RECEPTOR_IMAGE)
awx-kube-dev-build: Dockerfile.kube-dev awx-kube-dev-build: Dockerfile.kube-dev
docker build -f Dockerfile.kube-dev \ DOCKER_BUILDKIT=1 docker build -f Dockerfile.kube-dev \
--build-arg BUILDKIT_INLINE_CACHE=1 \ --build-arg BUILDKIT_INLINE_CACHE=1 \
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_kube_devel:$(COMPOSE_TAG) \
-t $(DEV_DOCKER_TAG_BASE)/awx_kube_devel:$(COMPOSE_TAG) . -t $(DEV_DOCKER_TAG_BASE)/awx_kube_devel:$(COMPOSE_TAG) .
@@ -563,3 +582,6 @@ messages:
. $(VENV_BASE)/awx/bin/activate; \ . $(VENV_BASE)/awx/bin/activate; \
fi; \ fi; \
$(PYTHON) manage.py makemessages -l $(LANG) --keep-pot $(PYTHON) manage.py makemessages -l $(LANG) --keep-pot
print-%:
@echo $($*)

3
SECURITY.md Normal file
View File

@@ -0,0 +1,3 @@
For all security related bugs, email security@ansible.com instead of using this issue tracker and you will receive a prompt response.
For more information on the Ansible community's practices regarding responsible disclosure, see https://www.ansible.com/security

View File

@@ -1 +0,0 @@
19.4.0

View File

@@ -36,7 +36,6 @@ else:
from django.db.backends.utils import names_digest from django.db.backends.utils import names_digest
from django.db import connection from django.db import connection
if HAS_DJANGO is True: if HAS_DJANGO is True:
# See upgrade blocker note in requirements/README.md # See upgrade blocker note in requirements/README.md
@@ -151,7 +150,7 @@ def manage():
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
# enforce the postgres version is equal to 12. if not, then terminate program with exit code of 1 # enforce the postgres version is equal to 12. if not, then terminate program with exit code of 1
if not MODE == 'development': if not os.getenv('SKIP_PG_VERSION_CHECK', False) and not MODE == 'development':
if (connection.pg_version // 10000) < 12: if (connection.pg_version // 10000) < 12:
sys.stderr.write("Postgres version 12 is required\n") sys.stderr.write("Postgres version 12 is required\n")
sys.exit(1) sys.exit(1)

View File

@@ -6,7 +6,7 @@ import logging
# Django # Django
from django.conf import settings from django.conf import settings
from django.utils.encoding import smart_text from django.utils.encoding import smart_str
# Django REST Framework # Django REST Framework
from rest_framework import authentication from rest_framework import authentication
@@ -24,7 +24,7 @@ class LoggedBasicAuthentication(authentication.BasicAuthentication):
ret = super(LoggedBasicAuthentication, self).authenticate(request) ret = super(LoggedBasicAuthentication, self).authenticate(request)
if ret: if ret:
username = ret[0].username if ret[0] else '<none>' username = ret[0].username if ret[0] else '<none>'
logger.info(smart_text(u"User {} performed a {} to {} through the API".format(username, request.method, request.path))) logger.info(smart_str(u"User {} performed a {} to {} through the API".format(username, request.method, request.path)))
return ret return ret
def authenticate_header(self, request): def authenticate_header(self, request):
@@ -45,7 +45,7 @@ class LoggedOAuth2Authentication(OAuth2Authentication):
user, token = ret user, token = ret
username = user.username if user else '<none>' username = user.username if user else '<none>'
logger.info( logger.info(
smart_text(u"User {} performed a {} to {} through the API using OAuth 2 token {}.".format(username, request.method, request.path, token.pk)) smart_str(u"User {} performed a {} to {} through the API using OAuth 2 token {}.".format(username, request.method, request.path, token.pk))
) )
setattr(user, 'oauth_scopes', [x for x in token.scope.split() if x]) setattr(user, 'oauth_scopes', [x for x in token.scope.split() if x])
return ret return ret

View File

@@ -1,6 +1,6 @@
# Django # Django
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework import serializers from rest_framework import serializers

View File

@@ -2,7 +2,7 @@
# All Rights Reserved. # All Rights Reserved.
# Django # Django
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
@@ -13,7 +13,7 @@ class ActiveJobConflict(ValidationError):
def __init__(self, active_jobs): def __init__(self, active_jobs):
# During APIException.__init__(), Django Rest Framework # During APIException.__init__(), Django Rest Framework
# turn everything in self.detail into string by using force_text. # turn everything in self.detail into string by using force_str.
# Declare detail afterwards circumvent this behavior. # Declare detail afterwards circumvent this behavior.
super(ActiveJobConflict, self).__init__() super(ActiveJobConflict, self).__init__()
self.detail = {"error": _("Resource is being used by running jobs."), "active_jobs": active_jobs} self.detail = {"error": _("Resource is being used by running jobs."), "active_jobs": active_jobs}

View File

@@ -2,7 +2,7 @@
# All Rights Reserved. # All Rights Reserved.
# Django # Django
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
# Django REST Framework # Django REST Framework
@@ -28,13 +28,17 @@ class NullFieldMixin(object):
return (is_empty_value, data) return (is_empty_value, data)
class BooleanNullField(NullFieldMixin, serializers.NullBooleanField): class BooleanNullField(NullFieldMixin, serializers.BooleanField):
""" """
Custom boolean field that allows null and empty string as False values. Custom boolean field that allows null and empty string as False values.
""" """
def __init__(self, **kwargs):
kwargs['allow_null'] = True
super().__init__(**kwargs)
def to_internal_value(self, data): def to_internal_value(self, data):
return bool(super(BooleanNullField, self).to_internal_value(data)) return bool(super().to_internal_value(data))
class CharNullField(NullFieldMixin, serializers.CharField): class CharNullField(NullFieldMixin, serializers.CharField):
@@ -47,7 +51,7 @@ class CharNullField(NullFieldMixin, serializers.CharField):
super(CharNullField, self).__init__(**kwargs) super(CharNullField, self).__init__(**kwargs)
def to_internal_value(self, data): def to_internal_value(self, data):
return super(CharNullField, self).to_internal_value(data or u'') return super(CharNullField, self).to_internal_value(data or '')
class ChoiceNullField(NullFieldMixin, serializers.ChoiceField): class ChoiceNullField(NullFieldMixin, serializers.ChoiceField):
@@ -60,7 +64,7 @@ class ChoiceNullField(NullFieldMixin, serializers.ChoiceField):
super(ChoiceNullField, self).__init__(**kwargs) super(ChoiceNullField, self).__init__(**kwargs)
def to_internal_value(self, data): def to_internal_value(self, data):
return super(ChoiceNullField, self).to_internal_value(data or u'') return super(ChoiceNullField, self).to_internal_value(data or '')
class VerbatimField(serializers.Field): class VerbatimField(serializers.Field):

View File

@@ -7,15 +7,15 @@ import json
from functools import reduce from functools import reduce
# Django # Django
from django.core.exceptions import FieldError, ValidationError from django.core.exceptions import FieldError, ValidationError, FieldDoesNotExist
from django.db import models from django.db import models
from django.db.models import Q, CharField, IntegerField, BooleanField from django.db.models import Q, CharField, IntegerField, BooleanField, TextField, JSONField
from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields.related import ForeignObjectRel, ManyToManyField, ForeignKey from django.db.models.fields.related import ForeignObjectRel, ManyToManyField, ForeignKey
from django.db.models.functions import Cast
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.utils.encoding import force_text from django.utils.encoding import force_str
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework.exceptions import ParseError, PermissionDenied from rest_framework.exceptions import ParseError, PermissionDenied
@@ -185,16 +185,14 @@ class FieldLookupBackend(BaseFilterBackend):
return (field_list[-1], new_lookup) return (field_list[-1], new_lookup)
def to_python_related(self, value): def to_python_related(self, value):
value = force_text(value) value = force_str(value)
if value.lower() in ('none', 'null'): if value.lower() in ('none', 'null'):
return None return None
else: else:
return int(value) return int(value)
def value_to_python_for_field(self, field, value): def value_to_python_for_field(self, field, value):
if isinstance(field, models.NullBooleanField): if isinstance(field, models.BooleanField):
return to_python_boolean(value, allow_none=True)
elif isinstance(field, models.BooleanField):
return to_python_boolean(value) return to_python_boolean(value)
elif isinstance(field, (ForeignObjectRel, ManyToManyField, GenericForeignKey, ForeignKey)): elif isinstance(field, (ForeignObjectRel, ManyToManyField, GenericForeignKey, ForeignKey)):
try: try:
@@ -244,6 +242,8 @@ class FieldLookupBackend(BaseFilterBackend):
new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name)) new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name))
return value, new_lookups, needs_distinct return value, new_lookups, needs_distinct
else: else:
if isinstance(field, JSONField):
new_lookup = new_lookup.replace(field.name, f'{field.name}_as_txt')
value = self.value_to_python_for_field(field, value) value = self.value_to_python_for_field(field, value)
return value, new_lookup, needs_distinct return value, new_lookup, needs_distinct
@@ -293,7 +293,7 @@ class FieldLookupBackend(BaseFilterBackend):
search_filter_relation = 'AND' search_filter_relation = 'AND'
values = reduce(lambda list1, list2: list1 + list2, [i.split(',') for i in values]) values = reduce(lambda list1, list2: list1 + list2, [i.split(',') for i in values])
for value in values: for value in values:
search_value, new_keys, _ = self.value_to_python(queryset.model, key, force_text(value)) search_value, new_keys, _ = self.value_to_python(queryset.model, key, force_str(value))
assert isinstance(new_keys, list) assert isinstance(new_keys, list)
search_filters[search_value] = new_keys search_filters[search_value] = new_keys
# by definition, search *only* joins across relations, # by definition, search *only* joins across relations,
@@ -325,6 +325,9 @@ class FieldLookupBackend(BaseFilterBackend):
value, new_key, distinct = self.value_to_python(queryset.model, key, value) value, new_key, distinct = self.value_to_python(queryset.model, key, value)
if distinct: if distinct:
needs_distinct = True needs_distinct = True
if '_as_txt' in new_key:
fname = next(item for item in new_key.split('__') if item.endswith('_as_txt'))
queryset = queryset.annotate(**{fname: Cast(fname[:-7], output_field=TextField())})
if q_chain: if q_chain:
chain_filters.append((q_not, new_key, value)) chain_filters.append((q_not, new_key, value))
elif q_or: elif q_or:

View File

@@ -10,18 +10,18 @@ import urllib.parse
# Django # Django
from django.conf import settings from django.conf import settings
from django.contrib.auth import views as auth_views
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import FieldDoesNotExist
from django.db import connection from django.db import connection
from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields.related import OneToOneRel from django.db.models.fields.related import OneToOneRel
from django.http import QueryDict from django.http import QueryDict
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.encoding import smart_text from django.utils.encoding import smart_str
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import views as auth_views
# Django REST Framework # Django REST Framework
from rest_framework.exceptions import PermissionDenied, AuthenticationFailed, ParseError, NotAcceptable, UnsupportedMediaType from rest_framework.exceptions import PermissionDenied, AuthenticationFailed, ParseError, NotAcceptable, UnsupportedMediaType
@@ -44,6 +44,7 @@ from awx.main.views import ApiErrorView
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
from awx.api.versioning import URLPathVersioning from awx.api.versioning import URLPathVersioning
from awx.api.metadata import SublistAttachDetatchMetadata, Metadata from awx.api.metadata import SublistAttachDetatchMetadata, Metadata
from awx.conf import settings_registry
__all__ = [ __all__ = [
'APIView', 'APIView',
@@ -92,17 +93,18 @@ class LoggedLoginView(auth_views.LoginView):
ret = super(LoggedLoginView, self).post(request, *args, **kwargs) ret = super(LoggedLoginView, self).post(request, *args, **kwargs)
current_user = getattr(request, 'user', None) current_user = getattr(request, 'user', None)
if request.user.is_authenticated: if request.user.is_authenticated:
logger.info(smart_text(u"User {} logged in from {}".format(self.request.user.username, request.META.get('REMOTE_ADDR', None)))) logger.info(smart_str(u"User {} logged in from {}".format(self.request.user.username, request.META.get('REMOTE_ADDR', None))))
ret.set_cookie('userLoggedIn', 'true') ret.set_cookie('userLoggedIn', 'true')
current_user = UserSerializer(self.request.user) current_user = UserSerializer(self.request.user)
current_user = smart_text(JSONRenderer().render(current_user.data)) current_user = smart_str(JSONRenderer().render(current_user.data))
current_user = urllib.parse.quote('%s' % current_user, '') current_user = urllib.parse.quote('%s' % current_user, '')
ret.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None) ret.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None)
ret.setdefault('X-API-Session-Cookie-Name', getattr(settings, 'SESSION_COOKIE_NAME', 'awx_sessionid'))
return ret return ret
else: else:
if 'username' in self.request.POST: if 'username' in self.request.POST:
logger.warn(smart_text(u"Login failed for user {} from {}".format(self.request.POST.get('username'), request.META.get('REMOTE_ADDR', None)))) logger.warning(smart_str(u"Login failed for user {} from {}".format(self.request.POST.get('username'), request.META.get('REMOTE_ADDR', None))))
ret.status_code = 401 ret.status_code = 401
return ret return ret
@@ -208,12 +210,27 @@ class APIView(views.APIView):
return response return response
if response.status_code >= 400: if response.status_code >= 400:
status_msg = "status %s received by user %s attempting to access %s from %s" % ( msg_data = {
response.status_code, 'status_code': response.status_code,
request.user, 'user_name': request.user,
request.path, 'url_path': request.path,
request.META.get('REMOTE_ADDR', None), 'remote_addr': request.META.get('REMOTE_ADDR', None),
) }
if type(response.data) is dict:
msg_data['error'] = response.data.get('error', response.status_text)
elif type(response.data) is list:
msg_data['error'] = ", ".join(list(map(lambda x: x.get('error', response.status_text), response.data)))
else:
msg_data['error'] = response.status_text
try:
status_msg = getattr(settings, 'API_400_ERROR_LOG_FORMAT').format(**msg_data)
except Exception as e:
if getattr(settings, 'API_400_ERROR_LOG_FORMAT', None):
logger.error("Unable to format API_400_ERROR_LOG_FORMAT setting, defaulting log message: {}".format(e))
status_msg = settings_registry.get_setting_field('API_400_ERROR_LOG_FORMAT').get_default().format(**msg_data)
if hasattr(self, '__init_request_error__'): if hasattr(self, '__init_request_error__'):
response = self.handle_exception(self.__init_request_error__) response = self.handle_exception(self.__init_request_error__)
if response.status_code == 401: if response.status_code == 401:
@@ -221,6 +238,7 @@ class APIView(views.APIView):
logger.info(status_msg) logger.info(status_msg)
else: else:
logger.warning(status_msg) logger.warning(status_msg)
response = super(APIView, self).finalize_response(request, response, *args, **kwargs) response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
time_started = getattr(self, 'time_started', None) time_started = getattr(self, 'time_started', None)
response['X-API-Product-Version'] = get_awx_version() response['X-API-Product-Version'] = get_awx_version()
@@ -374,8 +392,8 @@ class GenericAPIView(generics.GenericAPIView, APIView):
if hasattr(self.model._meta, "verbose_name"): if hasattr(self.model._meta, "verbose_name"):
d.update( d.update(
{ {
'model_verbose_name': smart_text(self.model._meta.verbose_name), 'model_verbose_name': smart_str(self.model._meta.verbose_name),
'model_verbose_name_plural': smart_text(self.model._meta.verbose_name_plural), 'model_verbose_name_plural': smart_str(self.model._meta.verbose_name_plural),
} }
) )
serializer = self.get_serializer() serializer = self.get_serializer()
@@ -506,8 +524,8 @@ class SubListAPIView(ParentMixin, ListAPIView):
d = super(SubListAPIView, self).get_description_context() d = super(SubListAPIView, self).get_description_context()
d.update( d.update(
{ {
'parent_model_verbose_name': smart_text(self.parent_model._meta.verbose_name), 'parent_model_verbose_name': smart_str(self.parent_model._meta.verbose_name),
'parent_model_verbose_name_plural': smart_text(self.parent_model._meta.verbose_name_plural), 'parent_model_verbose_name_plural': smart_str(self.parent_model._meta.verbose_name_plural),
} }
) )
return d return d
@@ -817,7 +835,7 @@ class ResourceAccessList(ParentMixin, ListAPIView):
def trigger_delayed_deep_copy(*args, **kwargs): def trigger_delayed_deep_copy(*args, **kwargs):
from awx.main.tasks import deep_copy_model_obj from awx.main.tasks.system import deep_copy_model_obj
connection.on_commit(lambda: deep_copy_model_obj.delay(*args, **kwargs)) connection.on_commit(lambda: deep_copy_model_obj.delay(*args, **kwargs))

View File

@@ -6,11 +6,12 @@ from uuid import UUID
# Django # Django
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db.models import JSONField
from django.db.models.fields import PositiveIntegerField, BooleanField from django.db.models.fields import PositiveIntegerField, BooleanField
from django.db.models.fields.related import ForeignKey from django.db.models.fields.related import ForeignKey
from django.http import Http404 from django.http import Http404
from django.utils.encoding import force_text, smart_text from django.utils.encoding import force_str, smart_str
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework import exceptions from rest_framework import exceptions
@@ -22,7 +23,7 @@ from rest_framework.request import clone_request
# AWX # AWX
from awx.api.fields import ChoiceNullField from awx.api.fields import ChoiceNullField
from awx.main.fields import JSONField, ImplicitRoleField from awx.main.fields import ImplicitRoleField
from awx.main.models import NotificationTemplate from awx.main.models import NotificationTemplate
from awx.main.utils.execution_environments import get_default_pod_spec from awx.main.utils.execution_environments import get_default_pod_spec
@@ -53,7 +54,7 @@ class Metadata(metadata.SimpleMetadata):
for attr in text_attrs: for attr in text_attrs:
value = getattr(field, attr, None) value = getattr(field, attr, None)
if value is not None and value != '': if value is not None and value != '':
field_info[attr] = force_text(value, strings_only=True) field_info[attr] = force_str(value, strings_only=True)
placeholder = getattr(field, 'placeholder', serializers.empty) placeholder = getattr(field, 'placeholder', serializers.empty)
if placeholder is not serializers.empty: if placeholder is not serializers.empty:
@@ -77,7 +78,7 @@ class Metadata(metadata.SimpleMetadata):
} }
if field.field_name in field_help_text: if field.field_name in field_help_text:
opts = serializer.Meta.model._meta.concrete_model._meta opts = serializer.Meta.model._meta.concrete_model._meta
verbose_name = smart_text(opts.verbose_name) verbose_name = smart_str(opts.verbose_name)
field_info['help_text'] = field_help_text[field.field_name].format(verbose_name) field_info['help_text'] = field_help_text[field.field_name].format(verbose_name)
if field.field_name == 'type': if field.field_name == 'type':

View File

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

View File

@@ -5,7 +5,7 @@ import json
# Django # Django
from django.conf import settings from django.conf import settings
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework import parsers from rest_framework import parsers

View File

@@ -4,8 +4,6 @@
# Python # Python
import logging import logging
from django.conf import settings
# Django REST Framework # Django REST Framework
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
from rest_framework import permissions from rest_framework import permissions
@@ -243,20 +241,13 @@ class IsSystemAdminOrAuditor(permissions.BasePermission):
""" """
def has_permission(self, request, view): def has_permission(self, request, view):
if not request.user: if not (request.user and request.user.is_authenticated):
return False return False
if request.method == 'GET': if request.method == 'GET':
return request.user.is_superuser or request.user.is_system_auditor return request.user.is_superuser or request.user.is_system_auditor
return request.user.is_superuser return request.user.is_superuser
class InstanceGroupTowerPermission(ModelAccessPermission):
def has_object_permission(self, request, view, obj):
if request.method == 'DELETE' and obj.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
return False
return super(InstanceGroupTowerPermission, self).has_object_permission(request, view, obj)
class WebhookKeyPermission(permissions.BasePermission): class WebhookKeyPermission(permissions.BasePermission):
def has_object_permission(self, request, view, obj): def has_object_permission(self, request, view, obj):
return request.user.can_access(view.model, 'admin', obj, request.data) return request.user.can_access(view.model, 'admin', obj, request.data)

View File

@@ -25,8 +25,8 @@ from django.contrib.auth.password_validation import validate_password as django_
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils.encoding import force_text from django.utils.encoding import force_str
from django.utils.text import capfirst from django.utils.text import capfirst
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.functional import cached_property from django.utils.functional import cached_property
@@ -57,6 +57,7 @@ from awx.main.models import (
Host, Host,
Instance, Instance,
InstanceGroup, InstanceGroup,
InstanceLink,
Inventory, Inventory,
InventorySource, InventorySource,
InventoryUpdate, InventoryUpdate,
@@ -96,7 +97,7 @@ from awx.main.models import (
) )
from awx.main.models.base import VERBOSITY_CHOICES, NEW_JOB_TYPE_CHOICES from awx.main.models.base import VERBOSITY_CHOICES, NEW_JOB_TYPE_CHOICES
from awx.main.models.rbac import get_roles_on_resource, role_summary_fields_generator from awx.main.models.rbac import get_roles_on_resource, role_summary_fields_generator
from awx.main.fields import ImplicitRoleField, JSONBField from awx.main.fields import ImplicitRoleField
from awx.main.utils import ( from awx.main.utils import (
get_type_for_model, get_type_for_model,
get_model_for_type, get_model_for_type,
@@ -356,7 +357,7 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
} }
choices = [] choices = []
for t in self.get_types(): for t in self.get_types():
name = _(type_name_map.get(t, force_text(get_model_for_type(t)._meta.verbose_name).title())) name = _(type_name_map.get(t, force_str(get_model_for_type(t)._meta.verbose_name).title()))
choices.append((t, name)) choices.append((t, name))
return choices return choices
@@ -378,19 +379,22 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
def _get_related(self, obj): def _get_related(self, obj):
return {} if obj is None else self.get_related(obj) return {} if obj is None else self.get_related(obj)
def _generate_named_url(self, url_path, obj, node): def _generate_friendly_id(self, obj, node):
url_units = url_path.split('/')
reset_counters() reset_counters()
named_url = node.generate_named_url(obj) return node.generate_named_url(obj)
url_units[4] = named_url
return '/'.join(url_units)
def get_related(self, obj): def get_related(self, obj):
res = OrderedDict() res = OrderedDict()
view = self.context.get('view', None) view = self.context.get('view', None)
if view and (hasattr(view, 'retrieve') or view.request.method == 'POST') and type(obj) in settings.NAMED_URL_GRAPH: if view and (hasattr(view, 'retrieve') or view.request.method == 'POST') and type(obj) in settings.NAMED_URL_GRAPH:
original_url = self.get_url(obj) original_path = self.get_url(obj)
res['named_url'] = self._generate_named_url(original_url, obj, settings.NAMED_URL_GRAPH[type(obj)]) path_components = original_path.lstrip('/').rstrip('/').split('/')
friendly_id = self._generate_friendly_id(obj, settings.NAMED_URL_GRAPH[type(obj)])
path_components[-1] = friendly_id
new_path = '/' + '/'.join(path_components) + '/'
res['named_url'] = new_path
if getattr(obj, 'created_by', None): if getattr(obj, 'created_by', None):
res['created_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.created_by.pk}) res['created_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.created_by.pk})
if getattr(obj, 'modified_by', None): if getattr(obj, 'modified_by', None):
@@ -641,7 +645,7 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
v2.extend(e) v2.extend(e)
else: else:
v2.append(e) v2.append(e)
d[k] = list(map(force_text, v2)) d[k] = list(map(force_str, v2))
raise ValidationError(d) raise ValidationError(d)
return attrs return attrs
@@ -861,7 +865,7 @@ class UnifiedJobSerializer(BaseSerializer):
if 'elapsed' in ret: if 'elapsed' in ret:
if obj and obj.pk and obj.started and not obj.finished: if obj and obj.pk and obj.started and not obj.finished:
td = now() - obj.started td = now() - obj.started
ret['elapsed'] = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / (10 ** 6 * 1.0) ret['elapsed'] = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / (10**6 * 1.0)
ret['elapsed'] = float(ret['elapsed']) ret['elapsed'] = float(ret['elapsed'])
# Because this string is saved in the db in the source language, # Because this string is saved in the db in the source language,
# it must be marked for translation after it is pulled from the db, not when set # it must be marked for translation after it is pulled from the db, not when set
@@ -1259,6 +1263,12 @@ class OAuth2ApplicationSerializer(BaseSerializer):
activity_stream=self.reverse('api:o_auth2_application_activity_stream_list', kwargs={'pk': obj.pk}), activity_stream=self.reverse('api:o_auth2_application_activity_stream_list', kwargs={'pk': obj.pk}),
) )
) )
if obj.organization_id:
res.update(
dict(
organization=self.reverse('api:organization_detail', kwargs={'pk': obj.organization_id}),
)
)
return res return res
def get_modified(self, obj): def get_modified(self, obj):
@@ -1639,7 +1649,25 @@ class BaseSerializerWithVariables(BaseSerializer):
return vars_validate_or_raise(value) return vars_validate_or_raise(value)
class InventorySerializer(BaseSerializerWithVariables): class LabelsListMixin(object):
def _summary_field_labels(self, obj):
label_list = [{'id': x.id, 'name': x.name} for x in obj.labels.all()[:10]]
if has_model_field_prefetched(obj, 'labels'):
label_ct = len(obj.labels.all())
else:
if len(label_list) < 10:
label_ct = len(label_list)
else:
label_ct = obj.labels.count()
return {'count': label_ct, 'results': label_list}
def get_summary_fields(self, obj):
res = super(LabelsListMixin, self).get_summary_fields(obj)
res['labels'] = self._summary_field_labels(obj)
return res
class InventorySerializer(LabelsListMixin, BaseSerializerWithVariables):
show_capabilities = ['edit', 'delete', 'adhoc', 'copy'] show_capabilities = ['edit', 'delete', 'adhoc', 'copy']
capabilities_prefetch = ['admin', 'adhoc', {'copy': 'organization.inventory_admin'}] capabilities_prefetch = ['admin', 'adhoc', {'copy': 'organization.inventory_admin'}]
@@ -1680,6 +1708,7 @@ class InventorySerializer(BaseSerializerWithVariables):
object_roles=self.reverse('api:inventory_object_roles_list', kwargs={'pk': obj.pk}), object_roles=self.reverse('api:inventory_object_roles_list', kwargs={'pk': obj.pk}),
instance_groups=self.reverse('api:inventory_instance_groups_list', kwargs={'pk': obj.pk}), instance_groups=self.reverse('api:inventory_instance_groups_list', kwargs={'pk': obj.pk}),
copy=self.reverse('api:inventory_copy', kwargs={'pk': obj.pk}), copy=self.reverse('api:inventory_copy', kwargs={'pk': obj.pk}),
labels=self.reverse('api:inventory_label_list', kwargs={'pk': obj.pk}),
) )
) )
if obj.organization: if obj.organization:
@@ -1695,7 +1724,7 @@ class InventorySerializer(BaseSerializerWithVariables):
def validate_host_filter(self, host_filter): def validate_host_filter(self, host_filter):
if host_filter: if host_filter:
try: try:
for match in JSONBField.get_lookups().keys(): for match in models.JSONField.get_lookups().keys():
if match == 'exact': if match == 'exact':
# __exact is allowed # __exact is allowed
continue continue
@@ -1824,11 +1853,11 @@ class HostSerializer(BaseSerializerWithVariables):
if port < 1 or port > 65535: if port < 1 or port > 65535:
raise ValueError raise ValueError
except ValueError: except ValueError:
raise serializers.ValidationError(_(u'Invalid port specification: %s') % force_text(port)) raise serializers.ValidationError(_(u'Invalid port specification: %s') % force_str(port))
return name, port return name, port
def validate_name(self, value): def validate_name(self, value):
name = force_text(value or '') name = force_str(value or '')
# Validate here only, update in main validate method. # Validate here only, update in main validate method.
host, port = self._get_host_port_from_name(name) host, port = self._get_host_port_from_name(name)
return value return value
@@ -1842,13 +1871,13 @@ class HostSerializer(BaseSerializerWithVariables):
return vars_validate_or_raise(value) return vars_validate_or_raise(value)
def validate(self, attrs): def validate(self, attrs):
name = force_text(attrs.get('name', self.instance and self.instance.name or '')) name = force_str(attrs.get('name', self.instance and self.instance.name or ''))
inventory = attrs.get('inventory', self.instance and self.instance.inventory or '') inventory = attrs.get('inventory', self.instance and self.instance.inventory or '')
host, port = self._get_host_port_from_name(name) host, port = self._get_host_port_from_name(name)
if port: if port:
attrs['name'] = host attrs['name'] = host
variables = force_text(attrs.get('variables', self.instance and self.instance.variables or '')) variables = force_str(attrs.get('variables', self.instance and self.instance.variables or ''))
vars_dict = parse_yaml_or_json(variables) vars_dict = parse_yaml_or_json(variables)
vars_dict['ansible_ssh_port'] = port vars_dict['ansible_ssh_port'] = port
attrs['variables'] = json.dumps(vars_dict) attrs['variables'] = json.dumps(vars_dict)
@@ -1921,7 +1950,7 @@ class GroupSerializer(BaseSerializerWithVariables):
return res return res
def validate(self, attrs): def validate(self, attrs):
name = force_text(attrs.get('name', self.instance and self.instance.name or '')) name = force_str(attrs.get('name', self.instance and self.instance.name or ''))
inventory = attrs.get('inventory', self.instance and self.instance.inventory or '') inventory = attrs.get('inventory', self.instance and self.instance.inventory or '')
if Host.objects.filter(name=name, inventory=inventory).exists(): if Host.objects.filter(name=name, inventory=inventory).exists():
raise serializers.ValidationError(_('A Host with that name already exists.')) raise serializers.ValidationError(_('A Host with that name already exists.'))
@@ -2749,24 +2778,6 @@ class OrganizationCredentialSerializerCreate(CredentialSerializerCreate):
fields = ('*', '-user', '-team') fields = ('*', '-user', '-team')
class LabelsListMixin(object):
def _summary_field_labels(self, obj):
label_list = [{'id': x.id, 'name': x.name} for x in obj.labels.all()[:10]]
if has_model_field_prefetched(obj, 'labels'):
label_ct = len(obj.labels.all())
else:
if len(label_list) < 10:
label_ct = len(label_list)
else:
label_ct = obj.labels.count()
return {'count': label_ct, 'results': label_list}
def get_summary_fields(self, obj):
res = super(LabelsListMixin, self).get_summary_fields(obj)
res['labels'] = self._summary_field_labels(obj)
return res
class JobOptionsSerializer(LabelsListMixin, BaseSerializer): class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
class Meta: class Meta:
fields = ( fields = (
@@ -2833,8 +2844,8 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
if not project: if not project:
raise serializers.ValidationError({'project': _('This field is required.')}) raise serializers.ValidationError({'project': _('This field is required.')})
playbook_not_found = bool( playbook_not_found = bool(
(project and project.scm_type and (not project.allow_override) and playbook and force_text(playbook) not in project.playbook_files) (project and project.scm_type and (not project.allow_override) and playbook and force_str(playbook) not in project.playbook_files)
or (project and not project.scm_type and playbook and force_text(playbook) not in project.playbooks) # manual or (project and not project.scm_type and playbook and force_str(playbook) not in project.playbooks) # manual
) )
if playbook_not_found: if playbook_not_found:
raise serializers.ValidationError({'playbook': _('Playbook not found for project.')}) raise serializers.ValidationError({'playbook': _('Playbook not found for project.')})
@@ -3623,7 +3634,7 @@ class LaunchConfigurationBaseSerializer(BaseSerializer):
job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None) job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
limit = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None) limit = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
skip_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None) skip_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
diff_mode = serializers.NullBooleanField(required=False, default=None) diff_mode = serializers.BooleanField(required=False, allow_null=True, default=None)
verbosity = serializers.ChoiceField(allow_null=True, required=False, default=None, choices=VERBOSITY_CHOICES) verbosity = serializers.ChoiceField(allow_null=True, required=False, default=None, choices=VERBOSITY_CHOICES)
exclude_errors = () exclude_errors = ()
@@ -4767,6 +4778,28 @@ class ScheduleSerializer(LaunchConfigurationBaseSerializer, SchedulePreviewSeria
return super(ScheduleSerializer, self).validate(attrs) return super(ScheduleSerializer, self).validate(attrs)
class InstanceLinkSerializer(BaseSerializer):
class Meta:
model = InstanceLink
fields = ('source', 'target')
source = serializers.SlugRelatedField(slug_field="hostname", read_only=True)
target = serializers.SlugRelatedField(slug_field="hostname", read_only=True)
class InstanceNodeSerializer(BaseSerializer):
class Meta:
model = Instance
fields = ('id', 'hostname', 'node_type', 'node_state')
node_state = serializers.SerializerMethodField()
def get_node_state(self, obj):
if not obj.enabled:
return "disabled"
return "error" if obj.errors else "healthy"
class InstanceSerializer(BaseSerializer): class InstanceSerializer(BaseSerializer):
consumed_capacity = serializers.SerializerMethodField() consumed_capacity = serializers.SerializerMethodField()
@@ -4810,7 +4843,8 @@ class InstanceSerializer(BaseSerializer):
res['jobs'] = self.reverse('api:instance_unified_jobs_list', kwargs={'pk': obj.pk}) res['jobs'] = self.reverse('api:instance_unified_jobs_list', kwargs={'pk': obj.pk})
res['instance_groups'] = self.reverse('api:instance_instance_groups_list', kwargs={'pk': obj.pk}) res['instance_groups'] = self.reverse('api:instance_instance_groups_list', kwargs={'pk': obj.pk})
if self.context['request'].user.is_superuser or self.context['request'].user.is_system_auditor: if self.context['request'].user.is_superuser or self.context['request'].user.is_system_auditor:
res['health_check'] = self.reverse('api:instance_health_check', kwargs={'pk': obj.pk}) if obj.node_type != 'hop':
res['health_check'] = self.reverse('api:instance_health_check', kwargs={'pk': obj.pk})
return res return res
def get_consumed_capacity(self, obj): def get_consumed_capacity(self, obj):
@@ -4822,6 +4856,11 @@ class InstanceSerializer(BaseSerializer):
else: else:
return float("{0:.2f}".format(((float(obj.capacity) - float(obj.consumed_capacity)) / (float(obj.capacity))) * 100)) return float("{0:.2f}".format(((float(obj.capacity) - float(obj.consumed_capacity)) / (float(obj.capacity))) * 100))
def validate(self, attrs):
if self.instance.node_type == 'hop':
raise serializers.ValidationError(_('Hop node instances may not be changed.'))
return attrs
class InstanceHealthCheckSerializer(BaseSerializer): class InstanceHealthCheckSerializer(BaseSerializer):
class Meta: class Meta:
@@ -4908,6 +4947,9 @@ class InstanceGroupSerializer(BaseSerializer):
return res return res
def validate_policy_instance_list(self, value): def validate_policy_instance_list(self, value):
if self.instance and self.instance.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
if self.instance.policy_instance_list != value:
raise serializers.ValidationError(_('%s instance group policy_instance_list may not be changed.' % self.instance.name))
for instance_name in value: for instance_name in value:
if value.count(instance_name) > 1: if value.count(instance_name) > 1:
raise serializers.ValidationError(_('Duplicate entry {}.').format(instance_name)) raise serializers.ValidationError(_('Duplicate entry {}.').format(instance_name))
@@ -4918,6 +4960,11 @@ class InstanceGroupSerializer(BaseSerializer):
return value return value
def validate_policy_instance_percentage(self, value): def validate_policy_instance_percentage(self, value):
if self.instance and self.instance.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
if value != self.instance.policy_instance_percentage:
raise serializers.ValidationError(
_('%s instance group policy_instance_percentage may not be changed from the initial value set by the installer.' % self.instance.name)
)
if value and self.instance and self.instance.is_container_group: if value and self.instance and self.instance.is_container_group:
raise serializers.ValidationError(_('Containerized instances may not be managed via the API')) raise serializers.ValidationError(_('Containerized instances may not be managed via the API'))
return value return value
@@ -4936,6 +4983,13 @@ class InstanceGroupSerializer(BaseSerializer):
return value return value
def validate_is_container_group(self, value):
if self.instance and self.instance.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
if value != self.instance.is_container_group:
raise serializers.ValidationError(_('%s instance group is_container_group may not be changed.' % self.instance.name))
return value
def validate_credential(self, value): def validate_credential(self, value):
if value and not value.kubernetes: if value and not value.kubernetes:
raise serializers.ValidationError(_('Only Kubernetes credentials can be associated with an Instance Group')) raise serializers.ValidationError(_('Only Kubernetes credentials can be associated with an Instance Group'))
@@ -5003,6 +5057,7 @@ class ActivityStreamSerializer(BaseSerializer):
('credential_type', ('id', 'name', 'description', 'kind', 'managed')), ('credential_type', ('id', 'name', 'description', 'kind', 'managed')),
('ad_hoc_command', ('id', 'name', 'status', 'limit')), ('ad_hoc_command', ('id', 'name', 'status', 'limit')),
('workflow_approval', ('id', 'name', 'unified_job_id')), ('workflow_approval', ('id', 'name', 'unified_job_id')),
('instance', ('id', 'hostname')),
] ]
return field_list return field_list
@@ -5049,7 +5104,7 @@ class ActivityStreamSerializer(BaseSerializer):
try: try:
return json.loads(obj.changes) return json.loads(obj.changes)
except Exception: except Exception:
logger.warn("Error deserializing activity stream json changes") logger.warning("Error deserializing activity stream json changes")
return {} return {}
def get_object_association(self, obj): def get_object_association(self, obj):

View File

@@ -0,0 +1 @@
Make a GET request to this resource to obtain a list all Receptor Nodes and their links.

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
AdHocCommandList, AdHocCommandList,
@@ -16,14 +16,14 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', AdHocCommandList.as_view(), name='ad_hoc_command_list'), re_path(r'^$', AdHocCommandList.as_view(), name='ad_hoc_command_list'),
url(r'^(?P<pk>[0-9]+)/$', AdHocCommandDetail.as_view(), name='ad_hoc_command_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/stdout/$', AdHocCommandStdout.as_view(), name='ad_hoc_command_stdout'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
CredentialList, CredentialList,
@@ -18,16 +18,16 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', CredentialList.as_view(), name='credential_list'), re_path(r'^$', CredentialList.as_view(), name='credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialActivityStreamList.as_view(), name='credential_activity_stream_list'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/owner_teams/$', CredentialOwnerTeamsList.as_view(), name='credential_owner_teams_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', CredentialCopy.as_view(), name='credential_copy'), re_path(r'^(?P<pk>[0-9]+)/copy/$', CredentialCopy.as_view(), name='credential_copy'),
url(r'^(?P<pk>[0-9]+)/input_sources/$', CredentialInputSourceSubList.as_view(), name='credential_input_source_sublist'), re_path(r'^(?P<pk>[0-9]+)/input_sources/$', CredentialInputSourceSubList.as_view(), name='credential_input_source_sublist'),
url(r'^(?P<pk>[0-9]+)/test/$', CredentialExternalTest.as_view(), name='credential_external_test'), re_path(r'^(?P<pk>[0-9]+)/test/$', CredentialExternalTest.as_view(), name='credential_external_test'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

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

View File

@@ -1,17 +1,17 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import CredentialTypeList, CredentialTypeDetail, CredentialTypeCredentialList, CredentialTypeActivityStreamList, CredentialTypeExternalTest from awx.api.views import CredentialTypeList, CredentialTypeDetail, CredentialTypeCredentialList, CredentialTypeActivityStreamList, CredentialTypeExternalTest
urls = [ urls = [
url(r'^$', CredentialTypeList.as_view(), name='credential_type_list'), re_path(r'^$', CredentialTypeList.as_view(), name='credential_type_list'),
url(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'), re_path(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,4 +1,4 @@
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
ExecutionEnvironmentList, ExecutionEnvironmentList,
@@ -10,11 +10,11 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', ExecutionEnvironmentList.as_view(), name='execution_environment_list'), re_path(r'^$', ExecutionEnvironmentList.as_view(), name='execution_environment_list'),
url(r'^(?P<pk>[0-9]+)/$', ExecutionEnvironmentDetail.as_view(), name='execution_environment_detail'), re_path(r'^(?P<pk>[0-9]+)/$', ExecutionEnvironmentDetail.as_view(), name='execution_environment_detail'),
url(r'^(?P<pk>[0-9]+)/unified_job_templates/$', ExecutionEnvironmentJobTemplateList.as_view(), name='execution_environment_job_template_list'), re_path(r'^(?P<pk>[0-9]+)/unified_job_templates/$', ExecutionEnvironmentJobTemplateList.as_view(), name='execution_environment_job_template_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', ExecutionEnvironmentCopy.as_view(), name='execution_environment_copy'), re_path(r'^(?P<pk>[0-9]+)/copy/$', ExecutionEnvironmentCopy.as_view(), name='execution_environment_copy'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', ExecutionEnvironmentActivityStreamList.as_view(), name='execution_environment_activity_stream_list'), re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', ExecutionEnvironmentActivityStreamList.as_view(), name='execution_environment_activity_stream_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
GroupList, GroupList,
@@ -20,18 +20,18 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', GroupList.as_view(), name='group_list'), re_path(r'^$', GroupList.as_view(), name='group_list'),
url(r'^(?P<pk>[0-9]+)/$', GroupDetail.as_view(), name='group_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', GroupAdHocCommandsList.as_view(), name='group_ad_hoc_commands_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
HostList, HostList,
@@ -20,18 +20,18 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', HostList.as_view(), name='host_list'), re_path(r'^$', HostList.as_view(), name='host_list'),
url(r'^(?P<pk>[0-9]+)/$', HostDetail.as_view(), name='host_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/ad_hoc_command_events/$', HostAdHocCommandEventsList.as_view(), name='host_ad_hoc_command_events_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
InventoryList, InventoryList,
@@ -20,28 +20,30 @@ from awx.api.views import (
InventoryAccessList, InventoryAccessList,
InventoryObjectRolesList, InventoryObjectRolesList,
InventoryInstanceGroupsList, InventoryInstanceGroupsList,
InventoryLabelList,
InventoryCopy, InventoryCopy,
) )
urls = [ urls = [
url(r'^$', InventoryList.as_view(), name='inventory_list'), re_path(r'^$', InventoryList.as_view(), name='inventory_list'),
url(r'^(?P<pk>[0-9]+)/$', InventoryDetail.as_view(), name='inventory_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/instance_groups/$', InventoryInstanceGroupsList.as_view(), name='inventory_instance_groups_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', InventoryCopy.as_view(), name='inventory_copy'), re_path(r'^(?P<pk>[0-9]+)/labels/$', InventoryLabelList.as_view(), name='inventory_label_list'),
re_path(r'^(?P<pk>[0-9]+)/copy/$', InventoryCopy.as_view(), name='inventory_copy'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
InventorySourceList, InventorySourceList,
@@ -20,26 +20,26 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', InventorySourceList.as_view(), name='inventory_source_list'), re_path(r'^$', InventorySourceList.as_view(), name='inventory_source_list'),
url(r'^(?P<pk>[0-9]+)/$', InventorySourceDetail.as_view(), name='inventory_source_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/schedules/$', InventorySourceSchedulesList.as_view(), name='inventory_source_schedules_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', InventorySourceCredentialsList.as_view(), name='inventory_source_credentials_list'), re_path(r'^(?P<pk>[0-9]+)/credentials/$', InventorySourceCredentialsList.as_view(), name='inventory_source_credentials_list'),
url(r'^(?P<pk>[0-9]+)/groups/$', InventorySourceGroupsList.as_view(), name='inventory_source_groups_list'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/hosts/$', InventorySourceHostsList.as_view(), name='inventory_source_hosts_list'),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_started/$', r'^(?P<pk>[0-9]+)/notification_templates_started/$',
InventorySourceNotificationTemplatesStartedList.as_view(), InventorySourceNotificationTemplatesStartedList.as_view(),
name='inventory_source_notification_templates_started_list', name='inventory_source_notification_templates_started_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_error/$', r'^(?P<pk>[0-9]+)/notification_templates_error/$',
InventorySourceNotificationTemplatesErrorList.as_view(), InventorySourceNotificationTemplatesErrorList.as_view(),
name='inventory_source_notification_templates_error_list', name='inventory_source_notification_templates_error_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_success/$', r'^(?P<pk>[0-9]+)/notification_templates_success/$',
InventorySourceNotificationTemplatesSuccessList.as_view(), InventorySourceNotificationTemplatesSuccessList.as_view(),
name='inventory_source_notification_templates_success_list', name='inventory_source_notification_templates_success_list',

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
InventoryUpdateList, InventoryUpdateList,
@@ -15,13 +15,13 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', InventoryUpdateList.as_view(), name='inventory_update_list'), re_path(r'^$', InventoryUpdateList.as_view(), name='inventory_update_list'),
url(r'^(?P<pk>[0-9]+)/$', InventoryUpdateDetail.as_view(), name='inventory_update_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/notifications/$', InventoryUpdateNotificationsList.as_view(), name='inventory_update_notifications_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', InventoryUpdateCredentialsList.as_view(), name='inventory_update_credentials_list'), re_path(r'^(?P<pk>[0-9]+)/credentials/$', InventoryUpdateCredentialsList.as_view(), name='inventory_update_credentials_list'),
url(r'^(?P<pk>[0-9]+)/events/$', InventoryUpdateEventsList.as_view(), name='inventory_update_events_list'), re_path(r'^(?P<pk>[0-9]+)/events/$', InventoryUpdateEventsList.as_view(), name='inventory_update_events_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
JobList, JobList,
@@ -20,18 +20,18 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', JobList.as_view(), name='job_list'), re_path(r'^$', JobList.as_view(), name='job_list'),
url(r'^(?P<pk>[0-9]+)/$', JobDetail.as_view(), name='job_detail'), re_path(r'^(?P<pk>[0-9]+)/$', JobDetail.as_view(), name='job_detail'),
url(r'^(?P<pk>[0-9]+)/cancel/$', JobCancel.as_view(), name='job_cancel'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/$', JobHostSummaryDetail.as_view(), name='job_host_summary_detail'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,13 +1,13 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import JobEventDetail, JobEventChildrenList from awx.api.views import JobEventDetail, JobEventChildrenList
urls = [ urls = [
url(r'^(?P<pk>[0-9]+)/$', JobEventDetail.as_view(), name='job_event_detail'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/children/$', JobEventChildrenList.as_view(), name='job_event_children_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import include, url from django.urls import include, re_path
from awx.api.views import ( from awx.api.views import (
JobTemplateList, JobTemplateList,
@@ -25,36 +25,36 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', JobTemplateList.as_view(), name='job_template_list'), re_path(r'^$', JobTemplateList.as_view(), name='job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', JobTemplateDetail.as_view(), name='job_template_detail'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/jobs/$', JobTemplateJobsList.as_view(), name='job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/slice_workflow_jobs/$', JobTemplateSliceWorkflowJobsList.as_view(), name='job_template_slice_workflow_jobs_list'), re_path(r'^(?P<pk>[0-9]+)/slice_workflow_jobs/$', JobTemplateSliceWorkflowJobsList.as_view(), name='job_template_slice_workflow_jobs_list'),
url(r'^(?P<pk>[0-9]+)/callback/$', JobTemplateCallback.as_view(), name='job_template_callback'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', JobTemplateActivityStreamList.as_view(), name='job_template_activity_stream_list'),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_started/$', r'^(?P<pk>[0-9]+)/notification_templates_started/$',
JobTemplateNotificationTemplatesStartedList.as_view(), JobTemplateNotificationTemplatesStartedList.as_view(),
name='job_template_notification_templates_started_list', name='job_template_notification_templates_started_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_error/$', r'^(?P<pk>[0-9]+)/notification_templates_error/$',
JobTemplateNotificationTemplatesErrorList.as_view(), JobTemplateNotificationTemplatesErrorList.as_view(),
name='job_template_notification_templates_error_list', name='job_template_notification_templates_error_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_success/$', r'^(?P<pk>[0-9]+)/notification_templates_success/$',
JobTemplateNotificationTemplatesSuccessList.as_view(), JobTemplateNotificationTemplatesSuccessList.as_view(),
name='job_template_notification_templates_success_list', name='job_template_notification_templates_success_list',
), ),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', JobTemplateInstanceGroupsList.as_view(), name='job_template_instance_groups_list'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/labels/$', JobTemplateLabelList.as_view(), name='job_template_label_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', JobTemplateCopy.as_view(), name='job_template_copy'), re_path(r'^(?P<pk>[0-9]+)/copy/$', JobTemplateCopy.as_view(), name='job_template_copy'),
url(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'job_templates'}), re_path(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'job_templates'}),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
NotificationTemplateList, NotificationTemplateList,
@@ -13,11 +13,11 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', NotificationTemplateList.as_view(), name='notification_template_list'), re_path(r'^$', NotificationTemplateList.as_view(), name='notification_template_list'),
url(r'^(?P<pk>[0-9]+)/$', NotificationTemplateDetail.as_view(), name='notification_template_detail'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/notifications/$', NotificationTemplateNotificationList.as_view(), name='notification_template_notification_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', NotificationTemplateCopy.as_view(), name='notification_template_copy'), re_path(r'^(?P<pk>[0-9]+)/copy/$', NotificationTemplateCopy.as_view(), name='notification_template_copy'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
OAuth2ApplicationList, OAuth2ApplicationList,
@@ -15,13 +15,13 @@ from awx.api.views import (
urls = [ urls = [
url(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'), re_path(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
url(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'), re_path(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
url(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='o_auth2_application_token_list'), re_path(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='o_auth2_application_token_list'),
url(r'^applications/(?P<pk>[0-9]+)/activity_stream/$', OAuth2ApplicationActivityStreamList.as_view(), name='o_auth2_application_activity_stream_list'), re_path(r'^applications/(?P<pk>[0-9]+)/activity_stream/$', OAuth2ApplicationActivityStreamList.as_view(), name='o_auth2_application_activity_stream_list'),
url(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'), re_path(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
url(r'^tokens/(?P<pk>[0-9]+)/$', OAuth2TokenDetail.as_view(), name='o_auth2_token_detail'), re_path(r'^tokens/(?P<pk>[0-9]+)/$', OAuth2TokenDetail.as_view(), name='o_auth2_token_detail'),
url(r'^tokens/(?P<pk>[0-9]+)/activity_stream/$', OAuth2TokenActivityStreamList.as_view(), name='o_auth2_token_activity_stream_list'), re_path(r'^tokens/(?P<pk>[0-9]+)/activity_stream/$', OAuth2TokenActivityStreamList.as_view(), name='o_auth2_token_activity_stream_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -4,7 +4,7 @@ from datetime import timedelta
from django.utils.timezone import now from django.utils.timezone import now
from django.conf import settings from django.conf import settings
from django.conf.urls import url from django.urls import re_path
from oauthlib import oauth2 from oauthlib import oauth2
from oauth2_provider import views from oauth2_provider import views
@@ -35,10 +35,10 @@ class TokenView(views.TokenView):
urls = [ urls = [
url(r'^$', ApiOAuthAuthorizationRootView.as_view(), name='oauth_authorization_root_view'), re_path(r'^$', ApiOAuthAuthorizationRootView.as_view(), name='oauth_authorization_root_view'),
url(r"^authorize/$", views.AuthorizationView.as_view(), name="authorize"), re_path(r"^authorize/$", views.AuthorizationView.as_view(), name="authorize"),
url(r"^token/$", TokenView.as_view(), name="token"), re_path(r"^token/$", TokenView.as_view(), name="token"),
url(r"^revoke_token/$", views.RevokeTokenView.as_view(), name="revoke-token"), re_path(r"^revoke_token/$", views.RevokeTokenView.as_view(), name="revoke-token"),
] ]

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
OrganizationList, OrganizationList,
@@ -30,44 +30,44 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', OrganizationList.as_view(), name='organization_list'), re_path(r'^$', OrganizationList.as_view(), name='organization_list'),
url(r'^(?P<pk>[0-9]+)/$', OrganizationDetail.as_view(), name='organization_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/inventories/$', OrganizationInventoriesList.as_view(), name='organization_inventories_list'),
url(r'^(?P<pk>[0-9]+)/execution_environments/$', OrganizationExecutionEnvironmentsList.as_view(), name='organization_execution_environments_list'), re_path(r'^(?P<pk>[0-9]+)/execution_environments/$', OrganizationExecutionEnvironmentsList.as_view(), name='organization_execution_environments_list'),
url(r'^(?P<pk>[0-9]+)/projects/$', OrganizationProjectsList.as_view(), name='organization_projects_list'), re_path(r'^(?P<pk>[0-9]+)/projects/$', OrganizationProjectsList.as_view(), name='organization_projects_list'),
url(r'^(?P<pk>[0-9]+)/job_templates/$', OrganizationJobTemplatesList.as_view(), name='organization_job_templates_list'), re_path(r'^(?P<pk>[0-9]+)/job_templates/$', OrganizationJobTemplatesList.as_view(), name='organization_job_templates_list'),
url(r'^(?P<pk>[0-9]+)/workflow_job_templates/$', OrganizationWorkflowJobTemplatesList.as_view(), name='organization_workflow_job_templates_list'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/notification_templates/$', OrganizationNotificationTemplatesList.as_view(), name='organization_notification_templates_list'),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_started/$', r'^(?P<pk>[0-9]+)/notification_templates_started/$',
OrganizationNotificationTemplatesStartedList.as_view(), OrganizationNotificationTemplatesStartedList.as_view(),
name='organization_notification_templates_started_list', name='organization_notification_templates_started_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_error/$', r'^(?P<pk>[0-9]+)/notification_templates_error/$',
OrganizationNotificationTemplatesErrorList.as_view(), OrganizationNotificationTemplatesErrorList.as_view(),
name='organization_notification_templates_error_list', name='organization_notification_templates_error_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_success/$', r'^(?P<pk>[0-9]+)/notification_templates_success/$',
OrganizationNotificationTemplatesSuccessList.as_view(), OrganizationNotificationTemplatesSuccessList.as_view(),
name='organization_notification_templates_success_list', name='organization_notification_templates_success_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_approvals/$', r'^(?P<pk>[0-9]+)/notification_templates_approvals/$',
OrganizationNotificationTemplatesApprovalList.as_view(), OrganizationNotificationTemplatesApprovalList.as_view(),
name='organization_notification_templates_approvals_list', name='organization_notification_templates_approvals_list',
), ),
url(r'^(?P<pk>[0-9]+)/instance_groups/$', OrganizationInstanceGroupsList.as_view(), name='organization_instance_groups_list'), re_path(r'^(?P<pk>[0-9]+)/instance_groups/$', OrganizationInstanceGroupsList.as_view(), name='organization_instance_groups_list'),
url(r'^(?P<pk>[0-9]+)/galaxy_credentials/$', OrganizationGalaxyCredentialsList.as_view(), name='organization_galaxy_credentials_list'), re_path(r'^(?P<pk>[0-9]+)/galaxy_credentials/$', OrganizationGalaxyCredentialsList.as_view(), name='organization_galaxy_credentials_list'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', OrganizationObjectRolesList.as_view(), name='organization_object_roles_list'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/access_list/$', OrganizationAccessList.as_view(), name='organization_access_list'),
url(r'^(?P<pk>[0-9]+)/applications/$', OrganizationApplicationList.as_view(), name='organization_applications_list'), re_path(r'^(?P<pk>[0-9]+)/applications/$', OrganizationApplicationList.as_view(), name='organization_applications_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
ProjectList, ProjectList,
@@ -24,30 +24,32 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', ProjectList.as_view(), name='project_list'), re_path(r'^$', ProjectList.as_view(), name='project_list'),
url(r'^(?P<pk>[0-9]+)/$', ProjectDetail.as_view(), name='project_detail'), re_path(r'^(?P<pk>[0-9]+)/$', ProjectDetail.as_view(), name='project_detail'),
url(r'^(?P<pk>[0-9]+)/playbooks/$', ProjectPlaybooks.as_view(), name='project_playbooks'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/schedules/$', ProjectSchedulesList.as_view(), name='project_schedules_list'),
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', ProjectNotificationTemplatesErrorList.as_view(), name='project_notification_templates_error_list'), re_path(
url( r'^(?P<pk>[0-9]+)/notification_templates_error/$', ProjectNotificationTemplatesErrorList.as_view(), name='project_notification_templates_error_list'
),
re_path(
r'^(?P<pk>[0-9]+)/notification_templates_success/$', r'^(?P<pk>[0-9]+)/notification_templates_success/$',
ProjectNotificationTemplatesSuccessList.as_view(), ProjectNotificationTemplatesSuccessList.as_view(),
name='project_notification_templates_success_list', name='project_notification_templates_success_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_started/$', r'^(?P<pk>[0-9]+)/notification_templates_started/$',
ProjectNotificationTemplatesStartedList.as_view(), ProjectNotificationTemplatesStartedList.as_view(),
name='project_notification_templates_started_list', name='project_notification_templates_started_list',
), ),
url(r'^(?P<pk>[0-9]+)/object_roles/$', ProjectObjectRolesList.as_view(), name='project_object_roles_list'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/access_list/$', ProjectAccessList.as_view(), name='project_access_list'),
url(r'^(?P<pk>[0-9]+)/copy/$', ProjectCopy.as_view(), name='project_copy'), re_path(r'^(?P<pk>[0-9]+)/copy/$', ProjectCopy.as_view(), name='project_copy'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
ProjectUpdateList, ProjectUpdateList,
@@ -15,13 +15,13 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', ProjectUpdateList.as_view(), name='project_update_list'), re_path(r'^$', ProjectUpdateList.as_view(), name='project_update_list'),
url(r'^(?P<pk>[0-9]+)/$', ProjectUpdateDetail.as_view(), name='project_update_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/notifications/$', ProjectUpdateNotificationsList.as_view(), name='project_update_notifications_list'),
url(r'^(?P<pk>[0-9]+)/events/$', ProjectUpdateEventsList.as_view(), name='project_update_events_list'), re_path(r'^(?P<pk>[0-9]+)/events/$', ProjectUpdateEventsList.as_view(), name='project_update_events_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,18 +1,18 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import RoleList, RoleDetail, RoleUsersList, RoleTeamsList, RoleParentsList, RoleChildrenList from awx.api.views import RoleList, RoleDetail, RoleUsersList, RoleTeamsList, RoleParentsList, RoleChildrenList
urls = [ urls = [
url(r'^$', RoleList.as_view(), name='role_list'), re_path(r'^$', RoleList.as_view(), name='role_list'),
url(r'^(?P<pk>[0-9]+)/$', RoleDetail.as_view(), name='role_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/children/$', RoleChildrenList.as_view(), name='role_children_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
SystemJobTemplateList, SystemJobTemplateList,
@@ -16,22 +16,22 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', SystemJobTemplateList.as_view(), name='system_job_template_list'), re_path(r'^$', SystemJobTemplateList.as_view(), name='system_job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', SystemJobTemplateDetail.as_view(), name='system_job_template_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/schedules/$', SystemJobTemplateSchedulesList.as_view(), name='system_job_template_schedules_list'),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_started/$', r'^(?P<pk>[0-9]+)/notification_templates_started/$',
SystemJobTemplateNotificationTemplatesStartedList.as_view(), SystemJobTemplateNotificationTemplatesStartedList.as_view(),
name='system_job_template_notification_templates_started_list', name='system_job_template_notification_templates_started_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_error/$', r'^(?P<pk>[0-9]+)/notification_templates_error/$',
SystemJobTemplateNotificationTemplatesErrorList.as_view(), SystemJobTemplateNotificationTemplatesErrorList.as_view(),
name='system_job_template_notification_templates_error_list', name='system_job_template_notification_templates_error_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_success/$', r'^(?P<pk>[0-9]+)/notification_templates_success/$',
SystemJobTemplateNotificationTemplatesSuccessList.as_view(), SystemJobTemplateNotificationTemplatesSuccessList.as_view(),
name='system_job_template_notification_templates_success_list', name='system_job_template_notification_templates_success_list',

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
TeamList, TeamList,
@@ -17,15 +17,15 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', TeamList.as_view(), name='team_list'), re_path(r'^$', TeamList.as_view(), name='team_list'),
url(r'^(?P<pk>[0-9]+)/$', TeamDetail.as_view(), name='team_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/access_list/$', TeamAccessList.as_view(), name='team_access_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -3,7 +3,7 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from django.conf import settings from django.conf import settings
from django.conf.urls import include, url from django.urls import include, re_path
from awx.api.generics import LoggedLoginView, LoggedLogoutView from awx.api.generics import LoggedLoginView, LoggedLogoutView
from awx.api.views import ( from awx.api.views import (
@@ -28,6 +28,7 @@ from awx.api.views import (
OAuth2TokenList, OAuth2TokenList,
ApplicationOAuth2TokenList, ApplicationOAuth2TokenList,
OAuth2ApplicationDetail, OAuth2ApplicationDetail,
MeshVisualizer,
) )
from awx.api.views.metrics import MetricsView from awx.api.views.metrics import MetricsView
@@ -73,77 +74,78 @@ from .workflow_approval import urls as workflow_approval_urls
v2_urls = [ v2_urls = [
url(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'), re_path(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'),
url(r'^credential_types/', include(credential_type_urls)), re_path(r'^credential_types/', include(credential_type_urls)),
url(r'^credential_input_sources/', include(credential_input_source_urls)), re_path(r'^credential_input_sources/', include(credential_input_source_urls)),
url(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'), re_path(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'),
url(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'), re_path(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'),
url(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'), re_path(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'),
url(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'), re_path(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'), re_path(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
url(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'), re_path(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
url(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'), re_path(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
url(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='application_o_auth2_token_list'), re_path(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='application_o_auth2_token_list'),
url(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'), re_path(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
url(r'^', include(oauth2_urls)), re_path(r'^', include(oauth2_urls)),
url(r'^metrics/$', MetricsView.as_view(), name='metrics_view'), re_path(r'^metrics/$', MetricsView.as_view(), name='metrics_view'),
url(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'), re_path(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'),
url(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'), re_path(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'),
url(r'^config/subscriptions/$', ApiV2SubscriptionView.as_view(), name='api_v2_subscription_view'), re_path(r'^config/subscriptions/$', ApiV2SubscriptionView.as_view(), name='api_v2_subscription_view'),
url(r'^config/attach/$', ApiV2AttachView.as_view(), name='api_v2_attach_view'), re_path(r'^config/attach/$', ApiV2AttachView.as_view(), name='api_v2_attach_view'),
url(r'^auth/$', AuthView.as_view()), re_path(r'^auth/$', AuthView.as_view()),
url(r'^me/$', UserMeList.as_view(), name='user_me_list'), re_path(r'^me/$', UserMeList.as_view(), name='user_me_list'),
url(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'), re_path(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),
url(r'^dashboard/graphs/jobs/$', DashboardJobsGraphView.as_view(), name='dashboard_jobs_graph_view'), re_path(r'^dashboard/graphs/jobs/$', DashboardJobsGraphView.as_view(), name='dashboard_jobs_graph_view'),
url(r'^settings/', include('awx.conf.urls')), re_path(r'^mesh_visualizer/', MeshVisualizer.as_view(), name='mesh_visualizer_view'),
url(r'^instances/', include(instance_urls)), re_path(r'^settings/', include('awx.conf.urls')),
url(r'^instance_groups/', include(instance_group_urls)), re_path(r'^instances/', include(instance_urls)),
url(r'^schedules/', include(schedule_urls)), re_path(r'^instance_groups/', include(instance_group_urls)),
url(r'^organizations/', include(organization_urls)), re_path(r'^schedules/', include(schedule_urls)),
url(r'^users/', include(user_urls)), re_path(r'^organizations/', include(organization_urls)),
url(r'^execution_environments/', include(execution_environment_urls)), re_path(r'^users/', include(user_urls)),
url(r'^projects/', include(project_urls)), re_path(r'^execution_environments/', include(execution_environment_urls)),
url(r'^project_updates/', include(project_update_urls)), re_path(r'^projects/', include(project_urls)),
url(r'^teams/', include(team_urls)), re_path(r'^project_updates/', include(project_update_urls)),
url(r'^inventories/', include(inventory_urls)), re_path(r'^teams/', include(team_urls)),
url(r'^hosts/', include(host_urls)), re_path(r'^inventories/', include(inventory_urls)),
url(r'^groups/', include(group_urls)), re_path(r'^hosts/', include(host_urls)),
url(r'^inventory_sources/', include(inventory_source_urls)), re_path(r'^groups/', include(group_urls)),
url(r'^inventory_updates/', include(inventory_update_urls)), re_path(r'^inventory_sources/', include(inventory_source_urls)),
url(r'^credentials/', include(credential_urls)), re_path(r'^inventory_updates/', include(inventory_update_urls)),
url(r'^roles/', include(role_urls)), re_path(r'^credentials/', include(credential_urls)),
url(r'^job_templates/', include(job_template_urls)), re_path(r'^roles/', include(role_urls)),
url(r'^jobs/', include(job_urls)), re_path(r'^job_templates/', include(job_template_urls)),
url(r'^job_host_summaries/', include(job_host_summary_urls)), re_path(r'^jobs/', include(job_urls)),
url(r'^job_events/', include(job_event_urls)), re_path(r'^job_host_summaries/', include(job_host_summary_urls)),
url(r'^ad_hoc_commands/', include(ad_hoc_command_urls)), re_path(r'^job_events/', include(job_event_urls)),
url(r'^ad_hoc_command_events/', include(ad_hoc_command_event_urls)), re_path(r'^ad_hoc_commands/', include(ad_hoc_command_urls)),
url(r'^system_job_templates/', include(system_job_template_urls)), re_path(r'^ad_hoc_command_events/', include(ad_hoc_command_event_urls)),
url(r'^system_jobs/', include(system_job_urls)), re_path(r'^system_job_templates/', include(system_job_template_urls)),
url(r'^notification_templates/', include(notification_template_urls)), re_path(r'^system_jobs/', include(system_job_urls)),
url(r'^notifications/', include(notification_urls)), re_path(r'^notification_templates/', include(notification_template_urls)),
url(r'^workflow_job_templates/', include(workflow_job_template_urls)), re_path(r'^notifications/', include(notification_urls)),
url(r'^workflow_jobs/', include(workflow_job_urls)), re_path(r'^workflow_job_templates/', include(workflow_job_template_urls)),
url(r'^labels/', include(label_urls)), re_path(r'^workflow_jobs/', include(workflow_job_urls)),
url(r'^workflow_job_template_nodes/', include(workflow_job_template_node_urls)), re_path(r'^labels/', include(label_urls)),
url(r'^workflow_job_nodes/', include(workflow_job_node_urls)), re_path(r'^workflow_job_template_nodes/', include(workflow_job_template_node_urls)),
url(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'), re_path(r'^workflow_job_nodes/', include(workflow_job_node_urls)),
url(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'), re_path(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'),
url(r'^activity_stream/', include(activity_stream_urls)), re_path(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'),
url(r'^workflow_approval_templates/', include(workflow_approval_template_urls)), re_path(r'^activity_stream/', include(activity_stream_urls)),
url(r'^workflow_approvals/', include(workflow_approval_urls)), re_path(r'^workflow_approval_templates/', include(workflow_approval_template_urls)),
re_path(r'^workflow_approvals/', include(workflow_approval_urls)),
] ]
app_name = 'api' app_name = 'api'
urlpatterns = [ urlpatterns = [
url(r'^$', ApiRootView.as_view(), name='api_root_view'), re_path(r'^$', ApiRootView.as_view(), name='api_root_view'),
url(r'^(?P<version>(v2))/', include(v2_urls)), re_path(r'^(?P<version>(v2))/', include(v2_urls)),
url(r'^login/$', LoggedLoginView.as_view(template_name='rest_framework/login.html', extra_context={'inside_login_context': True}), name='login'), re_path(r'^login/$', LoggedLoginView.as_view(template_name='rest_framework/login.html', extra_context={'inside_login_context': True}), name='login'),
url(r'^logout/$', LoggedLogoutView.as_view(next_page='/api/', redirect_field_name='next'), name='logout'), re_path(r'^logout/$', LoggedLogoutView.as_view(next_page='/api/', redirect_field_name='next'), name='logout'),
url(r'^o/', include(oauth2_root_urls)), re_path(r'^o/', include(oauth2_root_urls)),
] ]
if settings.SETTINGS_MODULE == 'awx.settings.development': if settings.SETTINGS_MODULE == 'awx.settings.development':
from awx.api.swagger import SwaggerSchemaView from awx.api.swagger import SwaggerSchemaView
urlpatterns += [url(r'^swagger/$', SwaggerSchemaView.as_view(), name='swagger_view')] urlpatterns += [re_path(r'^swagger/$', SwaggerSchemaView.as_view(), name='swagger_view')]

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
UserList, UserList,
@@ -21,20 +21,20 @@ from awx.api.views import (
) )
urls = [ urls = [
url(r'^$', UserList.as_view(), name='user_list'), re_path(r'^$', UserList.as_view(), name='user_list'),
url(r'^(?P<pk>[0-9]+)/$', UserDetail.as_view(), name='user_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/access_list/$', UserAccessList.as_view(), name='user_access_list'),
url(r'^(?P<pk>[0-9]+)/applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'), re_path(r'^(?P<pk>[0-9]+)/applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
url(r'^(?P<pk>[0-9]+)/tokens/$', OAuth2UserTokenList.as_view(), name='o_auth2_token_list'), re_path(r'^(?P<pk>[0-9]+)/tokens/$', OAuth2UserTokenList.as_view(), name='o_auth2_token_list'),
url(r'^(?P<pk>[0-9]+)/authorized_tokens/$', UserAuthorizedTokenList.as_view(), name='user_authorized_token_list'), re_path(r'^(?P<pk>[0-9]+)/authorized_tokens/$', UserAuthorizedTokenList.as_view(), name='user_authorized_token_list'),
url(r'^(?P<pk>[0-9]+)/personal_tokens/$', UserPersonalTokenList.as_view(), name='user_personal_token_list'), re_path(r'^(?P<pk>[0-9]+)/personal_tokens/$', UserPersonalTokenList.as_view(), name='user_personal_token_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,10 +1,10 @@
from django.conf.urls import url from django.urls import re_path
from awx.api.views import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver from awx.api.views import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver
urlpatterns = [ urlpatterns = [
url(r'^webhook_key/$', WebhookKeyView.as_view(), name='webhook_key'), re_path(r'^webhook_key/$', WebhookKeyView.as_view(), name='webhook_key'),
url(r'^github/$', GithubWebhookReceiver.as_view(), name='webhook_receiver_github'), re_path(r'^github/$', GithubWebhookReceiver.as_view(), name='webhook_receiver_github'),
url(r'^gitlab/$', GitlabWebhookReceiver.as_view(), name='webhook_receiver_gitlab'), re_path(r'^gitlab/$', GitlabWebhookReceiver.as_view(), name='webhook_receiver_gitlab'),
] ]

View File

@@ -1,16 +1,16 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import WorkflowApprovalList, WorkflowApprovalDetail, WorkflowApprovalApprove, WorkflowApprovalDeny from awx.api.views import WorkflowApprovalList, WorkflowApprovalDetail, WorkflowApprovalApprove, WorkflowApprovalDeny
urls = [ urls = [
url(r'^$', WorkflowApprovalList.as_view(), name='workflow_approval_list'), re_path(r'^$', WorkflowApprovalList.as_view(), name='workflow_approval_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalDetail.as_view(), name='workflow_approval_detail'), re_path(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalDetail.as_view(), name='workflow_approval_detail'),
url(r'^(?P<pk>[0-9]+)/approve/$', WorkflowApprovalApprove.as_view(), name='workflow_approval_approve'), re_path(r'^(?P<pk>[0-9]+)/approve/$', WorkflowApprovalApprove.as_view(), name='workflow_approval_approve'),
url(r'^(?P<pk>[0-9]+)/deny/$', WorkflowApprovalDeny.as_view(), name='workflow_approval_deny'), re_path(r'^(?P<pk>[0-9]+)/deny/$', WorkflowApprovalDeny.as_view(), name='workflow_approval_deny'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
WorkflowJobList, WorkflowJobList,
@@ -16,14 +16,14 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', WorkflowJobList.as_view(), name='workflow_job_list'), re_path(r'^$', WorkflowJobList.as_view(), name='workflow_job_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobDetail.as_view(), name='workflow_job_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobActivityStreamList.as_view(), name='workflow_job_activity_stream_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
WorkflowJobNodeList, WorkflowJobNodeList,
@@ -14,12 +14,12 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', WorkflowJobNodeList.as_view(), name='workflow_job_node_list'), re_path(r'^$', WorkflowJobNodeList.as_view(), name='workflow_job_node_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobNodeDetail.as_view(), name='workflow_job_node_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobNodeCredentialsList.as_view(), name='workflow_job_node_credentials_list'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import include, url from django.urls import include, re_path
from awx.api.views import ( from awx.api.views import (
WorkflowJobTemplateList, WorkflowJobTemplateList,
@@ -24,39 +24,39 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', WorkflowJobTemplateList.as_view(), name='workflow_job_template_list'), re_path(r'^$', WorkflowJobTemplateList.as_view(), name='workflow_job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateDetail.as_view(), name='workflow_job_template_detail'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_started/$', r'^(?P<pk>[0-9]+)/notification_templates_started/$',
WorkflowJobTemplateNotificationTemplatesStartedList.as_view(), WorkflowJobTemplateNotificationTemplatesStartedList.as_view(),
name='workflow_job_template_notification_templates_started_list', name='workflow_job_template_notification_templates_started_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_error/$', r'^(?P<pk>[0-9]+)/notification_templates_error/$',
WorkflowJobTemplateNotificationTemplatesErrorList.as_view(), WorkflowJobTemplateNotificationTemplatesErrorList.as_view(),
name='workflow_job_template_notification_templates_error_list', name='workflow_job_template_notification_templates_error_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_success/$', r'^(?P<pk>[0-9]+)/notification_templates_success/$',
WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(), WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(),
name='workflow_job_template_notification_templates_success_list', name='workflow_job_template_notification_templates_success_list',
), ),
url( re_path(
r'^(?P<pk>[0-9]+)/notification_templates_approvals/$', r'^(?P<pk>[0-9]+)/notification_templates_approvals/$',
WorkflowJobTemplateNotificationTemplatesApprovalList.as_view(), WorkflowJobTemplateNotificationTemplatesApprovalList.as_view(),
name='workflow_job_template_notification_templates_approvals_list', name='workflow_job_template_notification_templates_approvals_list',
), ),
url(r'^(?P<pk>[0-9]+)/access_list/$', WorkflowJobTemplateAccessList.as_view(), name='workflow_job_template_access_list'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobTemplateLabelList.as_view(), name='workflow_job_template_label_list'),
url(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'workflow_job_templates'}), re_path(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'workflow_job_templates'}),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc. # Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
from django.conf.urls import url from django.urls import re_path
from awx.api.views import ( from awx.api.views import (
WorkflowJobTemplateNodeList, WorkflowJobTemplateNodeList,
@@ -15,13 +15,13 @@ from awx.api.views import (
urls = [ urls = [
url(r'^$', WorkflowJobTemplateNodeList.as_view(), name='workflow_job_template_node_list'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(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'), re_path(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobTemplateNodeCredentialsList.as_view(), name='workflow_job_template_node_credentials_list'),
url(r'^(?P<pk>[0-9]+)/create_approval_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'), re_path(r'^(?P<pk>[0-9]+)/create_approval_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'),
] ]
__all__ = ['urls'] __all__ = ['urls']

View File

@@ -29,7 +29,7 @@ from django.views.decorators.csrf import csrf_exempt
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.http import HttpResponse from django.http import HttpResponse
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
@@ -62,7 +62,7 @@ import pytz
from wsgiref.util import FileWrapper from wsgiref.util import FileWrapper
# AWX # AWX
from awx.main.tasks import send_notifications, update_inventory_computed_fields from awx.main.tasks.system import send_notifications, update_inventory_computed_fields
from awx.main.access import get_user_queryset, HostAccess from awx.main.access import get_user_queryset, HostAccess
from awx.api.generics import ( from awx.api.generics import (
APIView, APIView,
@@ -105,7 +105,6 @@ from awx.api.permissions import (
ProjectUpdatePermission, ProjectUpdatePermission,
InventoryInventorySourcesUpdatePermission, InventoryInventorySourcesUpdatePermission,
UserPermission, UserPermission,
InstanceGroupTowerPermission,
VariableDataPermission, VariableDataPermission,
WorkflowApprovalPermission, WorkflowApprovalPermission,
IsSystemAdminOrAuditor, IsSystemAdminOrAuditor,
@@ -113,7 +112,7 @@ from awx.api.permissions import (
from awx.api import renderers from awx.api import renderers
from awx.api import serializers from awx.api import serializers
from awx.api.metadata import RoleMetadata from awx.api.metadata import RoleMetadata
from awx.main.constants import ACTIVE_STATES from awx.main.constants import ACTIVE_STATES, SURVEY_TYPE_MAPPING
from awx.main.scheduler.dag_workflow import WorkflowDAG from awx.main.scheduler.dag_workflow import WorkflowDAG
from awx.api.views.mixin import ( from awx.api.views.mixin import (
ControlledByScmMixin, ControlledByScmMixin,
@@ -157,8 +156,10 @@ from awx.api.views.inventory import ( # noqa
InventoryAccessList, InventoryAccessList,
InventoryObjectRolesList, InventoryObjectRolesList,
InventoryJobTemplateList, InventoryJobTemplateList,
InventoryLabelList,
InventoryCopy, InventoryCopy,
) )
from awx.api.views.mesh_visualizer import MeshVisualizer # noqa
from awx.api.views.root import ( # noqa from awx.api.views.root import ( # noqa
ApiRootView, ApiRootView,
ApiOAuthAuthorizationRootView, ApiOAuthAuthorizationRootView,
@@ -171,6 +172,7 @@ from awx.api.views.root import ( # noqa
) )
from awx.api.views.webhooks import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver # noqa from awx.api.views.webhooks import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver # noqa
from awx.api.pagination import UnifiedJobEventPagination from awx.api.pagination import UnifiedJobEventPagination
from awx.main.utils import set_environ
logger = logging.getLogger('awx.api.views') logger = logging.getLogger('awx.api.views')
@@ -406,6 +408,8 @@ class InstanceInstanceGroupsList(InstanceGroupMembershipMixin, SubListCreateAtta
def is_valid_relation(self, parent, sub, created=False): def is_valid_relation(self, parent, sub, created=False):
if parent.node_type == 'control': if parent.node_type == 'control':
return {'msg': _(f"Cannot change instance group membership of control-only node: {parent.hostname}.")} return {'msg': _(f"Cannot change instance group membership of control-only node: {parent.hostname}.")}
if parent.node_type == 'hop':
return {'msg': _(f"Cannot change instance group membership of hop node: {parent.hostname}.")}
return None return None
@@ -416,6 +420,10 @@ class InstanceHealthCheck(GenericAPIView):
serializer_class = serializers.InstanceHealthCheckSerializer serializer_class = serializers.InstanceHealthCheckSerializer
permission_classes = (IsSystemAdminOrAuditor,) permission_classes = (IsSystemAdminOrAuditor,)
def get_queryset(self):
# FIXME: For now, we don't have a good way of checking the health of a hop node.
return super().get_queryset().exclude(node_type='hop')
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
obj = self.get_object() obj = self.get_object()
data = self.get_serializer(data=request.data).to_representation(obj) data = self.get_serializer(data=request.data).to_representation(obj)
@@ -425,7 +433,7 @@ class InstanceHealthCheck(GenericAPIView):
obj = self.get_object() obj = self.get_object()
if obj.node_type == 'execution': if obj.node_type == 'execution':
from awx.main.tasks import execution_node_health_check from awx.main.tasks.system import execution_node_health_check
runner_data = execution_node_health_check(obj.hostname) runner_data = execution_node_health_check(obj.hostname)
obj.refresh_from_db() obj.refresh_from_db()
@@ -435,7 +443,7 @@ class InstanceHealthCheck(GenericAPIView):
if extra_field in runner_data: if extra_field in runner_data:
data[extra_field] = runner_data[extra_field] data[extra_field] = runner_data[extra_field]
else: else:
from awx.main.tasks import cluster_node_health_check from awx.main.tasks.system import cluster_node_health_check
if settings.CLUSTER_HOST_ID == obj.hostname: if settings.CLUSTER_HOST_ID == obj.hostname:
cluster_node_health_check(obj.hostname) cluster_node_health_check(obj.hostname)
@@ -472,7 +480,6 @@ class InstanceGroupDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAP
name = _("Instance Group Detail") name = _("Instance Group Detail")
model = models.InstanceGroup model = models.InstanceGroup
serializer_class = serializers.InstanceGroupSerializer serializer_class = serializers.InstanceGroupSerializer
permission_classes = (InstanceGroupTowerPermission,)
def update_raw_data(self, data): def update_raw_data(self, data):
if self.get_object().is_container_group: if self.get_object().is_container_group:
@@ -503,6 +510,8 @@ class InstanceGroupInstanceList(InstanceGroupMembershipMixin, SubListAttachDetac
def is_valid_relation(self, parent, sub, created=False): def is_valid_relation(self, parent, sub, created=False):
if sub.node_type == 'control': if sub.node_type == 'control':
return {'msg': _(f"Cannot change instance group membership of control-only node: {sub.hostname}.")} return {'msg': _(f"Cannot change instance group membership of control-only node: {sub.hostname}.")}
if sub.node_type == 'hop':
return {'msg': _(f"Cannot change instance group membership of hop node: {sub.hostname}.")}
return None return None
@@ -1547,8 +1556,9 @@ class CredentialExternalTest(SubDetailAPIView):
backend_kwargs[field_name] = value backend_kwargs[field_name] = value
backend_kwargs.update(request.data.get('metadata', {})) backend_kwargs.update(request.data.get('metadata', {}))
try: try:
obj.credential_type.plugin.backend(**backend_kwargs) with set_environ(**settings.AWX_TASK_ENV):
return Response({}, status=status.HTTP_202_ACCEPTED) obj.credential_type.plugin.backend(**backend_kwargs)
return Response({}, status=status.HTTP_202_ACCEPTED)
except requests.exceptions.HTTPError as exc: except requests.exceptions.HTTPError as exc:
message = 'HTTP {}'.format(exc.response.status_code) message = 'HTTP {}'.format(exc.response.status_code)
return Response({'inputs': message}, status=status.HTTP_400_BAD_REQUEST) return Response({'inputs': message}, status=status.HTTP_400_BAD_REQUEST)
@@ -2458,8 +2468,6 @@ class JobTemplateSurveySpec(GenericAPIView):
obj_permission_type = 'admin' obj_permission_type = 'admin'
serializer_class = serializers.EmptySerializer serializer_class = serializers.EmptySerializer
ALLOWED_TYPES = {'text': str, 'textarea': str, 'password': str, 'multiplechoice': str, 'multiselect': str, 'integer': int, 'float': float}
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
obj = self.get_object() obj = self.get_object()
return Response(obj.display_survey_spec()) return Response(obj.display_survey_spec())
@@ -2530,17 +2538,17 @@ class JobTemplateSurveySpec(GenericAPIView):
# Type-specific validation # Type-specific validation
# validate question type <-> default type # validate question type <-> default type
qtype = survey_item["type"] qtype = survey_item["type"]
if qtype not in JobTemplateSurveySpec.ALLOWED_TYPES: if qtype not in SURVEY_TYPE_MAPPING:
return Response( return Response(
dict( dict(
error=_("'{survey_item[type]}' in survey question {idx} is not one of '{allowed_types}' allowed question types.").format( error=_("'{survey_item[type]}' in survey question {idx} is not one of '{allowed_types}' allowed question types.").format(
allowed_types=', '.join(JobTemplateSurveySpec.ALLOWED_TYPES.keys()), **context allowed_types=', '.join(SURVEY_TYPE_MAPPING.keys()), **context
) )
), ),
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
if 'default' in survey_item and survey_item['default'] != '': if 'default' in survey_item and survey_item['default'] != '':
if not isinstance(survey_item['default'], JobTemplateSurveySpec.ALLOWED_TYPES[qtype]): if not isinstance(survey_item['default'], SURVEY_TYPE_MAPPING[qtype]):
type_label = 'string' type_label = 'string'
if qtype in ['integer', 'float']: if qtype in ['integer', 'float']:
type_label = qtype type_label = qtype

View File

@@ -8,7 +8,7 @@ import logging
from django.conf import settings from django.conf import settings
from django.db.models import Q from django.db.models import Q
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
@@ -16,17 +16,21 @@ from rest_framework.response import Response
from rest_framework import status from rest_framework import status
# AWX # AWX
from awx.main.models import ( from awx.main.models import ActivityStream, Inventory, JobTemplate, Role, User, InstanceGroup, InventoryUpdateEvent, InventoryUpdate
ActivityStream,
Inventory, from awx.main.models.label import Label
JobTemplate,
Role, from awx.api.generics import (
User, ListCreateAPIView,
InstanceGroup, RetrieveUpdateDestroyAPIView,
InventoryUpdateEvent, SubListAPIView,
InventoryUpdate, SubListAttachDetachAPIView,
ResourceAccessList,
CopyAPIView,
DeleteLastUnattachLabelMixin,
SubListCreateAttachDetachAPIView,
) )
from awx.api.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView, SubListAPIView, SubListAttachDetachAPIView, ResourceAccessList, CopyAPIView
from awx.api.serializers import ( from awx.api.serializers import (
InventorySerializer, InventorySerializer,
@@ -35,6 +39,7 @@ from awx.api.serializers import (
InstanceGroupSerializer, InstanceGroupSerializer,
InventoryUpdateEventSerializer, InventoryUpdateEventSerializer,
JobTemplateSerializer, JobTemplateSerializer,
LabelSerializer,
) )
from awx.api.views.mixin import RelatedJobsPreventDeleteMixin, ControlledByScmMixin from awx.api.views.mixin import RelatedJobsPreventDeleteMixin, ControlledByScmMixin
@@ -152,6 +157,30 @@ class InventoryJobTemplateList(SubListAPIView):
return qs.filter(inventory=parent) return qs.filter(inventory=parent)
class InventoryLabelList(DeleteLastUnattachLabelMixin, SubListCreateAttachDetachAPIView, SubListAPIView):
model = Label
serializer_class = LabelSerializer
parent_model = Inventory
relationship = 'labels'
def post(self, request, *args, **kwargs):
# If a label already exists in the database, attach it instead of erroring out
# that it already exists
if 'id' not in request.data and 'name' in request.data and 'organization' in request.data:
existing = Label.objects.filter(name=request.data['name'], organization_id=request.data['organization'])
if existing.exists():
existing = existing[0]
request.data['id'] = existing.id
del request.data['name']
del request.data['organization']
if Label.objects.filter(inventory_labels=self.kwargs['pk']).count() > 100:
return Response(
dict(msg=_('Maximum number of labels for {} reached.'.format(self.parent_model._meta.verbose_name_raw))), status=status.HTTP_400_BAD_REQUEST
)
return super(InventoryLabelList, self).post(request, *args, **kwargs)
class InventoryCopy(CopyAPIView): class InventoryCopy(CopyAPIView):
model = Inventory model = Inventory

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2018 Red Hat, Inc.
# All Rights Reserved.
from django.utils.translation import gettext_lazy as _
from awx.api.generics import APIView, Response
from awx.api.permissions import IsSystemAdminOrAuditor
from awx.api.serializers import InstanceLinkSerializer, InstanceNodeSerializer
from awx.main.models import InstanceLink, Instance
class MeshVisualizer(APIView):
name = _("Mesh Visualizer")
permission_classes = (IsSystemAdminOrAuditor,)
swagger_topic = "System Configuration"
def get(self, request, format=None):
data = {
'nodes': InstanceNodeSerializer(Instance.objects.all(), many=True).data,
'links': InstanceLinkSerializer(InstanceLink.objects.select_related('target', 'source'), many=True).data,
}
return Response(data)

View File

@@ -5,7 +5,7 @@
import logging import logging
# Django # Django
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework.response import Response from rest_framework.response import Response

View File

@@ -8,7 +8,7 @@ from django.db.models import Count
from django.db import transaction from django.db import transaction
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework.permissions import SAFE_METHODS from rest_framework.permissions import SAFE_METHODS
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied

View File

@@ -7,7 +7,7 @@ import logging
# Django # Django
from django.db.models import Count from django.db.models import Count
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# AWX # AWX
from awx.main.models import ( from awx.main.models import (

View File

@@ -8,11 +8,11 @@ import operator
from collections import OrderedDict from collections import OrderedDict
from django.conf import settings from django.conf import settings
from django.utils.encoding import smart_text from django.utils.encoding import smart_str
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
@@ -123,6 +123,7 @@ class ApiVersionRootView(APIView):
data['workflow_approvals'] = reverse('api:workflow_approval_list', request=request) data['workflow_approvals'] = reverse('api:workflow_approval_list', request=request)
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request) data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request)
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request) data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request)
data['mesh_visualizer'] = reverse('api:mesh_visualizer_view', request=request)
return Response(data) return Response(data)
@@ -149,13 +150,13 @@ class ApiV2PingView(APIView):
response = {'ha': is_ha_environment(), 'version': get_awx_version(), 'active_node': settings.CLUSTER_HOST_ID, 'install_uuid': settings.INSTALL_UUID} response = {'ha': is_ha_environment(), 'version': get_awx_version(), 'active_node': settings.CLUSTER_HOST_ID, 'install_uuid': settings.INSTALL_UUID}
response['instances'] = [] response['instances'] = []
for instance in Instance.objects.all(): for instance in Instance.objects.exclude(node_type='hop'):
response['instances'].append( response['instances'].append(
dict( dict(
node=instance.hostname, node=instance.hostname,
node_type=instance.node_type, node_type=instance.node_type,
uuid=instance.uuid, uuid=instance.uuid,
heartbeat=instance.modified, heartbeat=instance.last_seen,
capacity=instance.capacity, capacity=instance.capacity,
version=instance.version, version=instance.version,
) )
@@ -204,7 +205,7 @@ class ApiV2SubscriptionView(APIView):
elif isinstance(exc, (ValueError, OSError)) and exc.args: elif isinstance(exc, (ValueError, OSError)) and exc.args:
msg = exc.args[0] msg = exc.args[0]
else: else:
logger.exception(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) logger.exception(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
return Response(validated) return Response(validated)
@@ -245,7 +246,7 @@ class ApiV2AttachView(APIView):
elif isinstance(exc, (ValueError, OSError)) and exc.args: elif isinstance(exc, (ValueError, OSError)) and exc.args:
msg = exc.args[0] msg = exc.args[0]
else: else:
logger.exception(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) logger.exception(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
for sub in validated: for sub in validated:
if sub['pool_id'] == pool_id: if sub['pool_id'] == pool_id:
@@ -321,7 +322,7 @@ class ApiV2ConfigView(APIView):
try: try:
data_actual = json.dumps(request.data) data_actual = json.dumps(request.data)
except Exception: except Exception:
logger.info(smart_text(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username)) logger.info(smart_str(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username))
return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST)
license_data = json.loads(data_actual) license_data = json.loads(data_actual)
@@ -345,7 +346,7 @@ class ApiV2ConfigView(APIView):
try: try:
license_data_validated = get_licenser().license_from_manifest(license_data) license_data_validated = get_licenser().license_from_manifest(license_data)
except Exception: except Exception:
logger.warning(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) logger.warning(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
return Response({"error": _("Invalid License")}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": _("Invalid License")}, status=status.HTTP_400_BAD_REQUEST)
else: else:
license_data_validated = get_licenser().validate() license_data_validated = get_licenser().validate()
@@ -356,7 +357,7 @@ class ApiV2ConfigView(APIView):
settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host()) settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host())
return Response(license_data_validated) return Response(license_data_validated)
logger.warning(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username)) logger.warning(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
return Response({"error": _("Invalid subscription")}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": _("Invalid subscription")}, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request): def delete(self, request):

View File

@@ -4,7 +4,7 @@ import logging
import urllib.parse import urllib.parse
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from rest_framework import status from rest_framework import status
@@ -16,7 +16,7 @@ from awx.api import serializers
from awx.api.generics import APIView, GenericAPIView from awx.api.generics import APIView, GenericAPIView
from awx.api.permissions import WebhookKeyPermission from awx.api.permissions import WebhookKeyPermission
from awx.main.models import Job, JobTemplate, WorkflowJob, WorkflowJobTemplate from awx.main.models import Job, JobTemplate, WorkflowJob, WorkflowJobTemplate
from awx.main.constants import JOB_VARIABLE_PREFIXES
logger = logging.getLogger('awx.api.views.webhooks') logger = logging.getLogger('awx.api.views.webhooks')
@@ -136,15 +136,16 @@ class WebhookReceiverBase(APIView):
'webhook_credential': obj.webhook_credential, 'webhook_credential': obj.webhook_credential,
'webhook_guid': event_guid, 'webhook_guid': event_guid,
}, },
'extra_vars': { 'extra_vars': {},
'tower_webhook_event_type': event_type,
'tower_webhook_event_guid': event_guid,
'tower_webhook_event_ref': event_ref,
'tower_webhook_status_api': status_api,
'tower_webhook_payload': request.data,
},
} }
for name in JOB_VARIABLE_PREFIXES:
kwargs['extra_vars']['{}_webhook_event_type'.format(name)] = event_type
kwargs['extra_vars']['{}_webhook_event_guid'.format(name)] = event_guid
kwargs['extra_vars']['{}_webhook_event_ref'.format(name)] = event_ref
kwargs['extra_vars']['{}_webhook_status_api'.format(name)] = status_api
kwargs['extra_vars']['{}_webhook_payload'.format(name)] = request.data
new_job = obj.create_unified_job(**kwargs) new_job = obj.create_unified_job(**kwargs)
new_job.signal_start() new_job.signal_start()

View File

@@ -7,8 +7,6 @@ from django.utils.module_loading import autodiscover_modules
# AWX # AWX
from .registry import settings_registry from .registry import settings_registry
default_app_config = 'awx.conf.apps.ConfConfig'
def register(setting, **kwargs): def register(setting, **kwargs):
settings_registry.register(setting, **kwargs) settings_registry.register(setting, **kwargs)

View File

@@ -1,8 +1,10 @@
import sys
# Django # Django
from django.apps import AppConfig from django.apps import AppConfig
# from django.core import checks # from django.core import checks
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
class ConfConfig(AppConfig): class ConfConfig(AppConfig):
@@ -12,6 +14,9 @@ class ConfConfig(AppConfig):
def ready(self): def ready(self):
self.module.autodiscover() self.module.autodiscover()
from .settings import SettingsWrapper
SettingsWrapper.initialize() if not set(sys.argv) & {'migrate', 'check_migrations'}:
from .settings import SettingsWrapper
SettingsWrapper.initialize()

View File

@@ -1,6 +1,6 @@
# Django # Django
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# AWX # AWX
from awx.conf import fields, register from awx.conf import fields, register

View File

@@ -7,12 +7,15 @@ from collections import OrderedDict
# Django # Django
from django.core.validators import URLValidator, _lazy_re_compile from django.core.validators import URLValidator, _lazy_re_compile
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, DateTimeField, EmailField, IntegerField, ListField, NullBooleanField # noqa from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, DateTimeField, EmailField, IntegerField, ListField # noqa
from rest_framework.serializers import PrimaryKeyRelatedField # noqa from rest_framework.serializers import PrimaryKeyRelatedField # noqa
# AWX
from awx.main.constants import CONTAINER_VOLUMES_MOUNT_TYPES, MAX_ISOLATED_PATH_COLON_DELIMITER
logger = logging.getLogger('awx.conf.fields') logger = logging.getLogger('awx.conf.fields')
# Use DRF fields to convert/validate settings: # Use DRF fields to convert/validate settings:
@@ -62,11 +65,11 @@ class StringListBooleanField(ListField):
try: try:
if isinstance(value, (list, tuple)): if isinstance(value, (list, tuple)):
return super(StringListBooleanField, self).to_representation(value) return super(StringListBooleanField, self).to_representation(value)
elif value in NullBooleanField.TRUE_VALUES: elif value in BooleanField.TRUE_VALUES:
return True return True
elif value in NullBooleanField.FALSE_VALUES: elif value in BooleanField.FALSE_VALUES:
return False return False
elif value in NullBooleanField.NULL_VALUES: elif value in BooleanField.NULL_VALUES:
return None return None
elif isinstance(value, str): elif isinstance(value, str):
return self.child.to_representation(value) return self.child.to_representation(value)
@@ -79,11 +82,11 @@ class StringListBooleanField(ListField):
try: try:
if isinstance(data, (list, tuple)): if isinstance(data, (list, tuple)):
return super(StringListBooleanField, self).to_internal_value(data) return super(StringListBooleanField, self).to_internal_value(data)
elif data in NullBooleanField.TRUE_VALUES: elif data in BooleanField.TRUE_VALUES:
return True return True
elif data in NullBooleanField.FALSE_VALUES: elif data in BooleanField.FALSE_VALUES:
return False return False
elif data in NullBooleanField.NULL_VALUES: elif data in BooleanField.NULL_VALUES:
return None return None
elif isinstance(data, str): elif isinstance(data, str):
return self.child.run_validation(data) return self.child.run_validation(data)
@@ -109,6 +112,49 @@ class StringListPathField(StringListField):
self.fail('type_error', input_type=type(paths)) self.fail('type_error', input_type=type(paths))
class StringListIsolatedPathField(StringListField):
# Valid formats
# '/etc/pki/ca-trust'
# '/etc/pki/ca-trust:/etc/pki/ca-trust'
# '/etc/pki/ca-trust:/etc/pki/ca-trust:O'
default_error_messages = {
'type_error': _('Expected list of strings but got {input_type} instead.'),
'path_error': _('{path} is not a valid path choice. You must provide an absolute path.'),
'mount_error': _('{scontext} is not a valid mount option. Allowed types are {mount_types}'),
'syntax_error': _('Invalid syntax. A string HOST-DIR[:CONTAINER-DIR[:OPTIONS]] is expected but got {path}.'),
}
def to_internal_value(self, paths):
if isinstance(paths, (list, tuple)):
for p in paths:
if not isinstance(p, str):
self.fail('type_error', input_type=type(p))
if not p.startswith('/'):
self.fail('path_error', path=p)
if p.count(':'):
if p.count(':') > MAX_ISOLATED_PATH_COLON_DELIMITER:
self.fail('syntax_error', path=p)
try:
src, dest, scontext = p.split(':')
except ValueError:
scontext = 'z'
src, dest = p.split(':')
finally:
for sp in [src, dest]:
if not len(sp):
self.fail('syntax_error', path=sp)
if not sp.startswith('/'):
self.fail('path_error', path=sp)
if scontext not in CONTAINER_VOLUMES_MOUNT_TYPES:
self.fail('mount_error', scontext=scontext, mount_types=CONTAINER_VOLUMES_MOUNT_TYPES)
return super(StringListIsolatedPathField, self).to_internal_value(sorted(paths))
else:
self.fail('type_error', input_type=type(paths))
class URLField(CharField): class URLField(CharField):
# these lines set up a custom regex that allow numbers in the # these lines set up a custom regex that allow numbers in the
# top-level domain # top-level domain

View File

@@ -2,9 +2,10 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
import jsonfield.fields
from django.conf import settings from django.conf import settings
import awx.main.fields
class Migration(migrations.Migration): class Migration(migrations.Migration):
@@ -18,7 +19,7 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(default=None, editable=False)), ('created', models.DateTimeField(default=None, editable=False)),
('modified', models.DateTimeField(default=None, editable=False)), ('modified', models.DateTimeField(default=None, editable=False)),
('key', models.CharField(max_length=255)), ('key', models.CharField(max_length=255)),
('value', jsonfield.fields.JSONField(null=True)), ('value', awx.main.fields.JSONBlob(null=True)),
( (
'user', 'user',
models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True), models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True),

View File

@@ -2,6 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations from django.db import migrations
import awx.main.fields import awx.main.fields
@@ -9,4 +10,4 @@ class Migration(migrations.Migration):
dependencies = [('conf', '0002_v310_copy_tower_settings')] dependencies = [('conf', '0002_v310_copy_tower_settings')]
operations = [migrations.AlterField(model_name='setting', name='value', field=awx.main.fields.JSONField(null=True))] operations = [migrations.AlterField(model_name='setting', name='value', field=awx.main.fields.JSONBlob(null=True))]

View File

@@ -5,7 +5,7 @@ from django.utils.timezone import now
def fill_ldap_group_type_params(apps, schema_editor): def fill_ldap_group_type_params(apps, schema_editor):
group_type = settings.AUTH_LDAP_GROUP_TYPE group_type = getattr(settings, 'AUTH_LDAP_GROUP_TYPE', None)
Setting = apps.get_model('conf', 'Setting') Setting = apps.get_model('conf', 'Setting')
group_type_params = {'name_attr': 'cn', 'member_attr': 'member'} group_type_params = {'name_attr': 'cn', 'member_attr': 'member'}
@@ -17,7 +17,7 @@ def fill_ldap_group_type_params(apps, schema_editor):
else: else:
entry = Setting(key='AUTH_LDAP_GROUP_TYPE_PARAMS', value=group_type_params, created=now(), modified=now()) entry = Setting(key='AUTH_LDAP_GROUP_TYPE_PARAMS', value=group_type_params, created=now(), modified=now())
init_attrs = set(inspect.getargspec(group_type.__init__).args[1:]) init_attrs = set(inspect.getfullargspec(group_type.__init__).args[1:])
for k in list(group_type_params.keys()): for k in list(group_type_params.keys()):
if k not in init_attrs: if k not in init_attrs:
del group_type_params[k] del group_type_params[k]

View File

@@ -8,8 +8,8 @@ import json
from django.db import models from django.db import models
# AWX # AWX
from awx.main.fields import JSONBlob
from awx.main.models.base import CreatedModifiedModel, prevent_search from awx.main.models.base import CreatedModifiedModel, prevent_search
from awx.main.fields import JSONField
from awx.main.utils import encrypt_field from awx.main.utils import encrypt_field
from awx.conf import settings_registry from awx.conf import settings_registry
@@ -19,7 +19,7 @@ __all__ = ['Setting']
class Setting(CreatedModifiedModel): class Setting(CreatedModifiedModel):
key = models.CharField(max_length=255) key = models.CharField(max_length=255)
value = JSONField(null=True) value = JSONBlob(null=True)
user = prevent_search(models.ForeignKey('auth.User', related_name='settings', default=None, null=True, editable=False, on_delete=models.CASCADE)) user = prevent_search(models.ForeignKey('auth.User', related_name='settings', default=None, null=True, editable=False, on_delete=models.CASCADE))
def __str__(self): def __str__(self):

View File

@@ -8,7 +8,7 @@ import logging
# Django # Django
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.text import slugify from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from awx.conf.license import get_license from awx.conf.license import get_license

View File

@@ -6,7 +6,7 @@ from uuid import uuid4
from django.conf import LazySettings from django.conf import LazySettings
from django.core.cache.backends.locmem import LocMemCache from django.core.cache.backends.locmem import LocMemCache
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework.fields import empty from rest_framework.fields import empty
import pytest import pytest

View File

@@ -11,7 +11,7 @@ import time
from django.conf import LazySettings from django.conf import LazySettings
from django.core.cache.backends.locmem import LocMemCache from django.core.cache.backends.locmem import LocMemCache
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
import pytest import pytest
from awx.conf import models, fields from awx.conf import models, fields

View File

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

View File

@@ -13,7 +13,7 @@ from socket import SHUT_RDWR
from django.db import connection from django.db import connection
from django.conf import settings from django.conf import settings
from django.http import Http404 from django.http import Http404
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
# Django REST Framework # Django REST Framework
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
@@ -26,7 +26,7 @@ from awx.api.generics import APIView, GenericAPIView, ListAPIView, RetrieveUpdat
from awx.api.permissions import IsSystemAdminOrAuditor from awx.api.permissions import IsSystemAdminOrAuditor
from awx.api.versioning import reverse from awx.api.versioning import reverse
from awx.main.utils import camelcase_to_underscore from awx.main.utils import camelcase_to_underscore
from awx.main.tasks import handle_setting_changes from awx.main.tasks.system import handle_setting_changes
from awx.conf.models import Setting from awx.conf.models import Setting
from awx.conf.serializers import SettingCategorySerializer, SettingSingletonSerializer from awx.conf.serializers import SettingCategorySerializer, SettingSingletonSerializer
from awx.conf import settings_registry from awx.conf import settings_registry

View File

@@ -4856,7 +4856,7 @@ msgid "Exception connecting to PagerDuty: {}"
msgstr "" msgstr ""
#: awx/main/notifications/pagerduty_backend.py:87 #: awx/main/notifications/pagerduty_backend.py:87
#: awx/main/notifications/slack_backend.py:48 #: awx/main/notifications/slack_backend.py:49
#: awx/main/notifications/twilio_backend.py:47 #: awx/main/notifications/twilio_backend.py:47
msgid "Exception sending messages: {}" msgid "Exception sending messages: {}"
msgstr "" msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,3 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
msgid "" msgid ""
@@ -40,7 +37,7 @@ msgstr "secondes"
#: awx/api/conf.py:29 #: awx/api/conf.py:29
msgid "Maximum number of simultaneous logged in sessions" msgid "Maximum number of simultaneous logged in sessions"
msgstr "Le nombre maximum de sessions actives en simultané" msgstr "Nombre maximum de sessions actives en simultané"
#: awx/api/conf.py:30 #: awx/api/conf.py:30
msgid "" msgid ""
@@ -2255,7 +2252,6 @@ msgid ""
"Maximum number of messages to update the UI live job output with per second. " "Maximum number of messages to update the UI live job output with per second. "
"Value of 0 means no limit." "Value of 0 means no limit."
msgstr "Nombre maximal de messages pour mettre à jour la sortie du Job dans l'interface live utilisateur, par seconde. La valeur de 0 signifie qu'il n'y a pas de limite." msgstr "Nombre maximal de messages pour mettre à jour la sortie du Job dans l'interface live utilisateur, par seconde. La valeur de 0 signifie qu'il n'y a pas de limite."
#: awx/main/conf.py:380 #: awx/main/conf.py:380
msgid "Maximum Scheduled Jobs" msgid "Maximum Scheduled Jobs"
msgstr "Nombre max. de tâches planifiées" msgstr "Nombre max. de tâches planifiées"
@@ -2812,7 +2808,7 @@ msgstr "URL du coffre HashiCorp"
#: awx/main/models/credential/__init__.py:920 #: awx/main/models/credential/__init__.py:920
#: awx/main/models/credential/__init__.py:939 #: awx/main/models/credential/__init__.py:939
msgid "Token" msgid "Token"
msgstr "Token" msgstr "Jeton"
#: awx/main/credential_plugins/hashivault.py:25 #: awx/main/credential_plugins/hashivault.py:25
msgid "The access token used to authenticate to the Vault server" msgid "The access token used to authenticate to the Vault server"
@@ -3724,7 +3720,7 @@ msgstr "interne : à la non-importation pour l'hôte"
#: awx/main/models/events.py:193 #: awx/main/models/events.py:193
msgid "Play Started" msgid "Play Started"
msgstr "Scène démarrée" msgstr "Play Démarrage"
#: awx/main/models/events.py:194 #: awx/main/models/events.py:194
msgid "Playbook Complete" msgid "Playbook Complete"
@@ -3981,7 +3977,7 @@ msgid ""
"The host would be marked enabled. If power_state where any value other than " "The host would be marked enabled. If power_state where any value other than "
"powered_on then the host would be disabled when imported. If the key is not " "powered_on then the host would be disabled when imported. If the key is not "
"found then the host will be enabled" "found then the host will be enabled"
msgstr "Utilisé uniquement lorsque enabled_var est défini. Valeur lorsque l'hôte est considéré comme activé. Par exemple, si enabled_var=\"status.power_state \" et enabled_value=\"powered_on\" avec les variables de l'hôte:{ \"status\" : { \"power_state\" : \"powered_on\", \"created\" : \"2020-08-04T18:13:04+00:00\", \"healthy\" : true }, \"name\" : \"foobar\", \"ip_address\" : \"192.168.2.1\"}, l'hôte serait marqué comme étant activé. Si power_state contient une valeur autre que power_on, alors l'hôte sera désactivé lors de l'importation. Si la clé n'est pas trouvée, alors l'hôte sera activé" msgstr "Utilisé uniquement lorsque enabled_var est défini. Valeur lorsque l'hôte est considéré comme activé. Par exemple, si enabled_var=\"status.power_state \" et enabled_value=\"powered_on\" avec les variables de l'hôte:{ \"status\": { \"power_state\": \"powered_on\", \"created\": \"2020-08-04T18:13:04+00:00\", \"healthy\": true },\"name\" : \"foobar\", \"ip_address\" : \"192.168.2.1\"}, l'hôte serait marqué comme étant activé. Si power_state contient une valeur autre que power_on, alors l'hôte sera désactivé lors de l'importation. Si la clé n'est pas trouvée, alors l'hôte sera activé"
#: awx/main/models/inventory.py:878 #: awx/main/models/inventory.py:878
msgid "Regex where only matching hosts will be imported." msgid "Regex where only matching hosts will be imported."
@@ -4301,7 +4297,7 @@ msgstr "Utilisé pour une vérification plus rigoureuse de l'accès à une appli
#: awx/main/models/oauth.py:74 #: awx/main/models/oauth.py:74
msgid "" msgid ""
"Set to Public or Confidential depending on how secure the client device is." "Set to Public or Confidential depending on how secure the client device is."
msgstr "Défini sur sur Public ou Confidentiel selon le degré de sécurité du périphérique client." msgstr "Définir sur sur Public ou Confidentiel selon le degré de sécurité du périphérique client."
#: awx/main/models/oauth.py:76 #: awx/main/models/oauth.py:76
msgid "" msgid ""
@@ -4555,7 +4551,7 @@ msgstr "Utilisation"
#: awx/main/models/rbac.py:52 #: awx/main/models/rbac.py:52
msgid "Approve" msgid "Approve"
msgstr "Approbation" msgstr "Approuver"
#: awx/main/models/rbac.py:56 #: awx/main/models/rbac.py:56
msgid "Can manage all aspects of the system" msgid "Can manage all aspects of the system"
@@ -5147,7 +5143,7 @@ msgstr "Au moins %(min_certs)d certificats sont requis, seulement %(cert_count)d
#: awx/main/validators.py:152 #: awx/main/validators.py:152
#, python-format #, python-format
msgid "Only one certificate is allowed, %(cert_count)d provided." msgid "Only one certificate is allowed, %(cert_count)d provided."
msgstr "Un seul certificat est autorisé, %(cert_count)d ont été fournis." msgstr "Un seul certificat est autorisé, %(cert_count) ont été fournis."
#: awx/main/validators.py:154 #: awx/main/validators.py:154
#, python-format #, python-format
@@ -5633,7 +5629,7 @@ msgstr "Nom de l'organisation GitHub"
msgid "" msgid ""
"The name of your GitHub organization, as used in your organization's URL: " "The name of your GitHub organization, as used in your organization's URL: "
"https://github.com/<yourorg>/." "https://github.com/<yourorg>/."
msgstr "Nom de votre organisation GitHub, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<votreorg>/." msgstr "Nom de votre organisation GitHub, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<yourorg>/."
#: awx/sso/conf.py:762 #: awx/sso/conf.py:762
msgid "GitHub Organization OAuth2 Organization Map" msgid "GitHub Organization OAuth2 Organization Map"
@@ -5653,7 +5649,7 @@ msgid ""
"<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and " "<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and "
"secret (Client Secret). Provide this URL as the callback URL for your " "secret (Client Secret). Provide this URL as the callback URL for your "
"application." "application."
msgstr "Créez une application appartenant à une organisation sur https://github.com/organizations/<votreorg>/settings/applications et obtenez une clé OAuth2 (ID client) et un secret (secret client). Entrez cette URL comme URL de rappel de votre application." msgstr "Créez une application appartenant à une organisation sur https://github.com/organizations/<yourorg>/settings/applications et obtenez une clé OAuth2 (ID client) et un secret (secret client). Entrez cette URL comme URL de rappel de votre application."
#: awx/sso/conf.py:797 awx/sso/conf.py:809 awx/sso/conf.py:820 #: awx/sso/conf.py:797 awx/sso/conf.py:809 awx/sso/conf.py:820
#: awx/sso/conf.py:832 awx/sso/conf.py:843 awx/sso/conf.py:855 #: awx/sso/conf.py:832 awx/sso/conf.py:843 awx/sso/conf.py:855
@@ -5789,7 +5785,7 @@ msgstr "Nom de l'organisation GitHub Enterprise"
msgid "" msgid ""
"The name of your GitHub Enterprise organization, as used in your " "The name of your GitHub Enterprise organization, as used in your "
"organization's URL: https://github.com/<yourorg>/." "organization's URL: https://github.com/<yourorg>/."
msgstr "Nom de votre organisation GitHub Enterprise, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<votreorg>/." msgstr "Nom de votre organisation GitHub Enterprise, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<yourorg>/."
#: awx/sso/conf.py:1030 #: awx/sso/conf.py:1030
msgid "GitHub Enterprise Organization OAuth2 Organization Map" msgid "GitHub Enterprise Organization OAuth2 Organization Map"

View File

@@ -1,6 +1,3 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
msgid "" msgid ""
@@ -596,7 +593,7 @@ msgstr "指定された変数 {} には置き換えるデータベースの値
#: awx/api/serializers.py:3739 #: awx/api/serializers.py:3739
msgid "\"$encrypted$ is a reserved keyword, may not be used for {}.\"" msgid "\"$encrypted$ is a reserved keyword, may not be used for {}.\""
msgstr "\"$encrypted$ は予約されたキーワードで{} には使用できません。\"" msgstr "\"$encrypted は予約されたキーワードで {} には使用できません。\""
#: awx/api/serializers.py:4212 #: awx/api/serializers.py:4212
msgid "A project is required to run a job." msgid "A project is required to run a job."
@@ -824,7 +821,7 @@ msgstr "ポリシーインスタンスの割合"
msgid "" msgid ""
"Minimum percentage of all instances that will be automatically assigned to " "Minimum percentage of all instances that will be automatically assigned to "
"this group when new instances come online." "this group when new instances come online."
msgstr "新規インスタンスがオンラインになると、このグループに自動的に最小限割り当てられるインスタンスの割合を選択します。" msgstr "新規インスタンスがオンラインになると、このグループに自動的に最小限割り当てられるインスタンスの割合"
#: awx/api/serializers.py:4853 #: awx/api/serializers.py:4853
msgid "Policy Instance Minimum" msgid "Policy Instance Minimum"
@@ -1253,7 +1250,7 @@ msgstr "デフォルトで指定されている選択項目は、一覧から回
msgid "" msgid ""
"$encrypted$ is a reserved keyword for password question defaults, survey " "$encrypted$ is a reserved keyword for password question defaults, survey "
"question {idx} is type {survey_item[type]}." "question {idx} is type {survey_item[type]}."
msgstr "$encrypted$ は、デフォルト設定されているパスワードの質問予約されたキーワードで、Survey の質問 {idx} は {survey_item[type]} タイプです。" msgstr "$encrypted$ はパスワードの質問のデフォルトの予約されたキーワードで、Survey の質問 {idx} はタイプ {survey_item[type]} です。"
#: awx/api/views/__init__.py:2567 #: awx/api/views/__init__.py:2567
#, python-brace-format #, python-brace-format
@@ -3638,7 +3635,7 @@ msgstr "ホスト OK"
#: awx/main/models/events.py:169 #: awx/main/models/events.py:169
msgid "Host Failure" msgid "Host Failure"
msgstr "ホストの失敗" msgstr "ホストの障害"
#: awx/main/models/events.py:170 awx/main/models/events.py:767 #: awx/main/models/events.py:170 awx/main/models/events.py:767
msgid "Host Skipped" msgid "Host Skipped"
@@ -4694,7 +4691,7 @@ msgstr "取り消されました"
#: awx/main/models/unified_jobs.py:84 #: awx/main/models/unified_jobs.py:84
msgid "Never Updated" msgid "Never Updated"
msgstr "更新されていません" msgstr "更新"
#: awx/main/models/unified_jobs.py:88 #: awx/main/models/unified_jobs.py:88
msgid "OK" msgid "OK"
@@ -6261,4 +6258,3 @@ msgstr "%s が現在アップグレード中です。"
#: awx/ui/urls.py:24 #: awx/ui/urls.py:24
msgid "This page will refresh when complete." msgid "This page will refresh when complete."
msgstr "このページは完了すると更新されます。" msgstr "このページは完了すると更新されます。"

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