Compare commits

..

535 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
aad150cf1d Pin rsa package to latest version 2021-11-16 09:02:11 +00:00
Shane McDonald
39370f1eab Security-related updates for some Python dependencies. 2021-11-14 08:45:49 +00:00
863 changed files with 49473 additions and 46256 deletions

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: -->
- API
- UI
- Installer
- Collection
##### SUMMARY
<!-- Briefly describe the problem. -->

View File

@@ -1,26 +1,24 @@
---
name: Bug Report
description: Create a report to help us improve
labels:
- bug
body:
- type: markdown
attributes:
value: |
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
- https://groups.google.com/forum/#!forum/awx-project
- The awx project mailing list, https://groups.google.com/forum/#!forum/awx-project
- type: checkboxes
id: terms
attributes:
label: Please confirm the following
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
- label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
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
- type: textarea
@@ -39,6 +37,15 @@ body:
validations:
required: true
- type: checkboxes
id: components
attributes:
label: Select the relevant components
options:
- label: UI
- label: API
- label: Docs
- type: dropdown
id: awx-install-method
attributes:

View File

@@ -25,6 +25,7 @@ the change does.
<!--- Name of the module/plugin/module/task -->
- API
- UI
- Collection
##### AWX VERSION
<!--- 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

@@ -5,14 +5,51 @@ env:
on:
pull_request:
jobs:
api-test:
common-tests:
name: ${{ matrix.tests.name }}
runs-on: ubuntu-latest
permissions:
packages: write
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:
- 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
@@ -25,18 +62,23 @@ jobs:
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Run API Tests
- name: ${{ matrix.texts.label }}
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:
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} ${{ matrix.tests.command }}
dev-env:
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
@@ -49,130 +91,12 @@ jobs:
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Run API Linters
- name: Run smoke test
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
export DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }}
export COMPOSE_TAG=${{ env.BRANCH }}
ansible-playbook tools/docker-compose/ansible/smoke-test.yml -e repo_dir=$(pwd) -v
- 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: Generate API Reference
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 swagger
awx-collection:
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 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
run: |
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
- name: Run UI 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 }} make ui-lint
ui-test:
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 UI 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 }} make ui-test
awx-operator:
runs-on: ubuntu-latest
steps:
@@ -207,7 +131,7 @@ jobs:
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
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:
- 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
run: sudo apt-get install -y gettext

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

View File

@@ -8,6 +8,53 @@ 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

View File

@@ -43,6 +43,14 @@ jobs:
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:
@@ -75,7 +83,8 @@ jobs:
- name: Build and stage awx-operator
working-directory: awx-operator
run: |
BUILD_ARGS="--build-arg DEFAULT_AWX_VERSION=${{ github.event.inputs.version }}" \
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

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- devel
- release_**
jobs:
push:
runs-on: ubuntu-latest
@@ -13,6 +14,14 @@ jobs:
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
@@ -38,6 +47,6 @@ jobs:
run: |
ansible localhost -c local, -m command -a "{{ ansible_python_interpreter + ' -m pip install boto3'}}"
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"

4
.gitignore vendored
View File

@@ -7,6 +7,9 @@ reference-schema.json
.tags
.tags1
# User level pre-commit hooks
pre-commit-user
# Tower
awx-dev
awx/settings/local_*.py*
@@ -42,6 +45,7 @@ tools/docker-compose/_build
tools/docker-compose/_sources
tools/docker-compose/overrides/
tools/docker-compose-minikube/_sources
tools/docker-compose/keycloak.awx.realm.json
# Tower setup playbook testing
setup/test/roles/postgresql

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)
- [Accessing the AWX web interface](#accessing-the-awx-web-interface)
- [Purging containers and images](#purging-containers-and-images)
- [Pre commit hooks](#pre-commit-hooks)
- [What should I work on?](#what-should-i-work-on)
- [Submitting Pull Requests](#submitting-pull-requests)
- [PR Checks run by Zuul](#pr-checks-run-by-zuul)
@@ -104,6 +105,14 @@ When necessary, remove any AWX containers and images by running the following:
(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?
For feature work, take a look at the current [Enhancements](https://github.com/ansible/awx/issues?q=is%3Aissue+is%3Aopen+label%3Atype%3Aenhancement).

View File

@@ -1,5 +1,4 @@
PYTHON ?= python3.8
PYTHON_VERSION = $(shell $(PYTHON) -c "from distutils.sysconfig import get_python_version; print(get_python_version())")
PYTHON ?= python3.9
OFFICIAL ?= no
NODE ?= node
NPM_BIN ?= npm
@@ -11,20 +10,25 @@ 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
COMPOSE_TAG ?= $(GIT_BRANCH)
COMPOSE_HOST ?= $(shell hostname)
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
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)
RECEPTOR_IMAGE ?= quay.io/ansible/receptor:devel
# Python packages to install only from source (not from binary wheels)
# Comma separated list
SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio
# These should be upgraded in the AWX and Ansible venv before attempting
# to install the actual requirements
VENV_BOOTSTRAP ?= pip==21.2.4 setuptools==58.2.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
@@ -41,7 +45,7 @@ I18N_FLAG_FILE = .i18n_built
receiver test test_unit test_coverage coverage_html \
dev_build release_build sdist \
ui-release ui-devel \
VERSION docker-compose-sources \
VERSION PYTHON_VERSION docker-compose-sources \
.git/hooks/pre-commit
clean-tmp:
@@ -143,24 +147,6 @@ version_file:
fi; \
$(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: clean requirements_dev version_file develop migrate
@@ -281,16 +267,16 @@ api-lint:
awx-link:
[ -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
PYTEST_ARGS ?= -n auto
# Run all API unit tests.
test:
if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS)
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider $(PYTEST_ARGS) $(TEST_DIRS)
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
awx-manage check_migrations --dry-run --check -n 'missing_migration_file'
@@ -321,7 +307,7 @@ symlink_collection:
mkdir -p ~/.ansible/collections/ansible_collections/$(COLLECTION_NAMESPACE) # in case it does not exist
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) \
@@ -329,6 +315,8 @@ build_collection:
-e '{"awx_template_version":false}'
ansible-galaxy collection build awx_collection_build --force --output-path=awx_collection_build
build_collection: awx_collection_build
install_collection: build_collection
rm -rf $(COLLECTION_INSTALL)
ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(COLLECTION_VERSION).tar.gz
@@ -382,7 +370,7 @@ clean-ui:
rm -rf $(UI_BUILD_FLAG_FILE)
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): awx/ui/node_modules
$(PYTHON) tools/scripts/compilemessages.py
@@ -416,8 +404,17 @@ ui-lint:
ui-test:
$(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.
dev_build:
@@ -463,9 +460,12 @@ docker-compose-sources: .git/hooks/pre-commit
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_tag=$(COMPOSE_TAG) \
-e receptor_image=$(RECEPTOR_IMAGE) \
-e control_plane_node_count=$(CONTROL_PLANE_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: awx/projects docker-compose-sources
@@ -484,8 +484,9 @@ docker-compose-runtest: 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
SCHEMA_DIFF_BASE_BRANCH ?= devel
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
diff -u -b reference-schema.json schema.json
@@ -500,7 +501,7 @@ docker-compose-container-group-clean:
# Base development image 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) \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) .
@@ -543,18 +544,23 @@ psql-container:
VERSION:
@echo "awx: $(VERSION)"
PYTHON_VERSION:
@echo "$(PYTHON)" | sed 's:python::'
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
ansible-playbook tools/ansible/dockerfile.yml \
-e dockerfile_name=Dockerfile.kube-dev \
-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
docker build -f Dockerfile.kube-dev \
DOCKER_BUILDKIT=1 docker build -f Dockerfile.kube-dev \
--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) .
@@ -576,3 +582,6 @@ messages:
. $(VENV_BASE)/awx/bin/activate; \
fi; \
$(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

@@ -36,7 +36,6 @@ else:
from django.db.backends.utils import names_digest
from django.db import connection
if HAS_DJANGO is True:
# See upgrade blocker note in requirements/README.md

View File

@@ -6,7 +6,7 @@ import logging
# Django
from django.conf import settings
from django.utils.encoding import smart_text
from django.utils.encoding import smart_str
# Django REST Framework
from rest_framework import authentication
@@ -24,7 +24,7 @@ class LoggedBasicAuthentication(authentication.BasicAuthentication):
ret = super(LoggedBasicAuthentication, self).authenticate(request)
if ret:
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
def authenticate_header(self, request):
@@ -45,7 +45,7 @@ class LoggedOAuth2Authentication(OAuth2Authentication):
user, token = ret
username = user.username if user else '<none>'
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])
return ret

View File

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

View File

@@ -2,7 +2,7 @@
# All Rights Reserved.
# Django
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
# Django REST Framework
from rest_framework.exceptions import ValidationError
@@ -13,7 +13,7 @@ class ActiveJobConflict(ValidationError):
def __init__(self, active_jobs):
# 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.
super(ActiveJobConflict, self).__init__()
self.detail = {"error": _("Resource is being used by running jobs."), "active_jobs": active_jobs}

View File

@@ -2,7 +2,7 @@
# All Rights Reserved.
# Django
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
# Django REST Framework
@@ -28,13 +28,17 @@ class NullFieldMixin(object):
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.
"""
def __init__(self, **kwargs):
kwargs['allow_null'] = True
super().__init__(**kwargs)
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):
@@ -47,7 +51,7 @@ class CharNullField(NullFieldMixin, serializers.CharField):
super(CharNullField, self).__init__(**kwargs)
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):
@@ -60,7 +64,7 @@ class ChoiceNullField(NullFieldMixin, serializers.ChoiceField):
super(ChoiceNullField, self).__init__(**kwargs)
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):

View File

@@ -7,15 +7,15 @@ import json
from functools import reduce
# Django
from django.core.exceptions import FieldError, ValidationError
from django.core.exceptions import FieldError, ValidationError, FieldDoesNotExist
from django.db import models
from django.db.models import Q, CharField, IntegerField, BooleanField
from django.db.models.fields import FieldDoesNotExist
from django.db.models import Q, CharField, IntegerField, BooleanField, TextField, JSONField
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.fields import GenericForeignKey
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
# Django REST Framework
from rest_framework.exceptions import ParseError, PermissionDenied
@@ -185,16 +185,14 @@ class FieldLookupBackend(BaseFilterBackend):
return (field_list[-1], new_lookup)
def to_python_related(self, value):
value = force_text(value)
value = force_str(value)
if value.lower() in ('none', 'null'):
return None
else:
return int(value)
def value_to_python_for_field(self, field, value):
if isinstance(field, models.NullBooleanField):
return to_python_boolean(value, allow_none=True)
elif isinstance(field, models.BooleanField):
if isinstance(field, models.BooleanField):
return to_python_boolean(value)
elif isinstance(field, (ForeignObjectRel, ManyToManyField, GenericForeignKey, ForeignKey)):
try:
@@ -244,6 +242,8 @@ class FieldLookupBackend(BaseFilterBackend):
new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name))
return value, new_lookups, needs_distinct
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)
return value, new_lookup, needs_distinct
@@ -293,7 +293,7 @@ class FieldLookupBackend(BaseFilterBackend):
search_filter_relation = 'AND'
values = reduce(lambda list1, list2: list1 + list2, [i.split(',') for i 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)
search_filters[search_value] = new_keys
# 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)
if distinct:
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:
chain_filters.append((q_not, new_key, value))
elif q_or:

View File

@@ -10,18 +10,18 @@ import urllib.parse
# Django
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.exceptions import FieldDoesNotExist
from django.db import connection
from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields.related import OneToOneRel
from django.http import QueryDict
from django.shortcuts import get_object_or_404
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.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import views as auth_views
from django.utils.translation import gettext_lazy as _
# Django REST Framework
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.versioning import URLPathVersioning
from awx.api.metadata import SublistAttachDetatchMetadata, Metadata
from awx.conf import settings_registry
__all__ = [
'APIView',
@@ -92,17 +93,18 @@ class LoggedLoginView(auth_views.LoginView):
ret = super(LoggedLoginView, self).post(request, *args, **kwargs)
current_user = getattr(request, 'user', None)
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')
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, '')
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
else:
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
return ret
@@ -208,12 +210,27 @@ class APIView(views.APIView):
return response
if response.status_code >= 400:
status_msg = "status %s received by user %s attempting to access %s from %s" % (
response.status_code,
request.user,
request.path,
request.META.get('REMOTE_ADDR', None),
)
msg_data = {
'status_code': response.status_code,
'user_name': request.user,
'url_path': request.path,
'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__'):
response = self.handle_exception(self.__init_request_error__)
if response.status_code == 401:
@@ -221,6 +238,7 @@ class APIView(views.APIView):
logger.info(status_msg)
else:
logger.warning(status_msg)
response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
time_started = getattr(self, 'time_started', None)
response['X-API-Product-Version'] = get_awx_version()
@@ -374,8 +392,8 @@ class GenericAPIView(generics.GenericAPIView, APIView):
if hasattr(self.model._meta, "verbose_name"):
d.update(
{
'model_verbose_name': smart_text(self.model._meta.verbose_name),
'model_verbose_name_plural': smart_text(self.model._meta.verbose_name_plural),
'model_verbose_name': smart_str(self.model._meta.verbose_name),
'model_verbose_name_plural': smart_str(self.model._meta.verbose_name_plural),
}
)
serializer = self.get_serializer()
@@ -506,8 +524,8 @@ class SubListAPIView(ParentMixin, ListAPIView):
d = super(SubListAPIView, self).get_description_context()
d.update(
{
'parent_model_verbose_name': smart_text(self.parent_model._meta.verbose_name),
'parent_model_verbose_name_plural': smart_text(self.parent_model._meta.verbose_name_plural),
'parent_model_verbose_name': smart_str(self.parent_model._meta.verbose_name),
'parent_model_verbose_name_plural': smart_str(self.parent_model._meta.verbose_name_plural),
}
)
return d
@@ -817,7 +835,7 @@ class ResourceAccessList(ParentMixin, ListAPIView):
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))

View File

@@ -6,11 +6,12 @@ from uuid import UUID
# Django
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.related import ForeignKey
from django.http import Http404
from django.utils.encoding import force_text, smart_text
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_str, smart_str
from django.utils.translation import gettext_lazy as _
# Django REST Framework
from rest_framework import exceptions
@@ -22,7 +23,7 @@ from rest_framework.request import clone_request
# AWX
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.utils.execution_environments import get_default_pod_spec
@@ -53,7 +54,7 @@ class Metadata(metadata.SimpleMetadata):
for attr in text_attrs:
value = getattr(field, attr, None)
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)
if placeholder is not serializers.empty:
@@ -77,7 +78,7 @@ class Metadata(metadata.SimpleMetadata):
}
if field.field_name in field_help_text:
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)
if field.field_name == 'type':

View File

@@ -1,11 +1,11 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from django.urls import re_path
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']

View File

@@ -5,7 +5,7 @@ import json
# Django
from django.conf import settings
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
from rest_framework import parsers

View File

@@ -4,8 +4,6 @@
# Python
import logging
from django.conf import settings
# Django REST Framework
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
from rest_framework import permissions
@@ -243,20 +241,13 @@ class IsSystemAdminOrAuditor(permissions.BasePermission):
"""
def has_permission(self, request, view):
if not request.user:
if not (request.user and request.user.is_authenticated):
return False
if request.method == 'GET':
return request.user.is_superuser or request.user.is_system_auditor
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):
def has_object_permission(self, request, view, obj):
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.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text
from django.utils.translation import gettext_lazy as _
from django.utils.encoding import force_str
from django.utils.text import capfirst
from django.utils.timezone import now
from django.utils.functional import cached_property
@@ -57,6 +57,7 @@ from awx.main.models import (
Host,
Instance,
InstanceGroup,
InstanceLink,
Inventory,
InventorySource,
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.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 (
get_type_for_model,
get_model_for_type,
@@ -356,7 +357,7 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
}
choices = []
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))
return choices
@@ -378,19 +379,22 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
def _get_related(self, obj):
return {} if obj is None else self.get_related(obj)
def _generate_named_url(self, url_path, obj, node):
url_units = url_path.split('/')
def _generate_friendly_id(self, obj, node):
reset_counters()
named_url = node.generate_named_url(obj)
url_units[4] = named_url
return '/'.join(url_units)
return node.generate_named_url(obj)
def get_related(self, obj):
res = OrderedDict()
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:
original_url = self.get_url(obj)
res['named_url'] = self._generate_named_url(original_url, obj, settings.NAMED_URL_GRAPH[type(obj)])
original_path = self.get_url(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):
res['created_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.created_by.pk})
if getattr(obj, 'modified_by', None):
@@ -641,7 +645,7 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
v2.extend(e)
else:
v2.append(e)
d[k] = list(map(force_text, v2))
d[k] = list(map(force_str, v2))
raise ValidationError(d)
return attrs
@@ -861,7 +865,7 @@ class UnifiedJobSerializer(BaseSerializer):
if 'elapsed' in ret:
if obj and obj.pk and obj.started and not obj.finished:
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'])
# 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
@@ -1259,6 +1263,12 @@ class OAuth2ApplicationSerializer(BaseSerializer):
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
def get_modified(self, obj):
@@ -1639,7 +1649,25 @@ class BaseSerializerWithVariables(BaseSerializer):
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']
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}),
instance_groups=self.reverse('api:inventory_instance_groups_list', 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:
@@ -1695,7 +1724,7 @@ class InventorySerializer(BaseSerializerWithVariables):
def validate_host_filter(self, host_filter):
if host_filter:
try:
for match in JSONBField.get_lookups().keys():
for match in models.JSONField.get_lookups().keys():
if match == 'exact':
# __exact is allowed
continue
@@ -1824,11 +1853,11 @@ class HostSerializer(BaseSerializerWithVariables):
if port < 1 or port > 65535:
raise 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
def validate_name(self, value):
name = force_text(value or '')
name = force_str(value or '')
# Validate here only, update in main validate method.
host, port = self._get_host_port_from_name(name)
return value
@@ -1842,13 +1871,13 @@ class HostSerializer(BaseSerializerWithVariables):
return vars_validate_or_raise(value)
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 '')
host, port = self._get_host_port_from_name(name)
if port:
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['ansible_ssh_port'] = port
attrs['variables'] = json.dumps(vars_dict)
@@ -1921,7 +1950,7 @@ class GroupSerializer(BaseSerializerWithVariables):
return res
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 '')
if Host.objects.filter(name=name, inventory=inventory).exists():
raise serializers.ValidationError(_('A Host with that name already exists.'))
@@ -2749,24 +2778,6 @@ class OrganizationCredentialSerializerCreate(CredentialSerializerCreate):
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 Meta:
fields = (
@@ -2833,8 +2844,8 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
if not project:
raise serializers.ValidationError({'project': _('This field is required.')})
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)
or (project and not project.scm_type and playbook and force_text(playbook) not in project.playbooks) # manual
(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_str(playbook) not in project.playbooks) # manual
)
if playbook_not_found:
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)
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)
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)
exclude_errors = ()
@@ -4767,6 +4778,28 @@ class ScheduleSerializer(LaunchConfigurationBaseSerializer, SchedulePreviewSeria
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):
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['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:
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
def get_consumed_capacity(self, obj):
@@ -4822,6 +4856,11 @@ class InstanceSerializer(BaseSerializer):
else:
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 Meta:
@@ -4908,6 +4947,9 @@ class InstanceGroupSerializer(BaseSerializer):
return res
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:
if value.count(instance_name) > 1:
raise serializers.ValidationError(_('Duplicate entry {}.').format(instance_name))
@@ -4918,6 +4960,11 @@ class InstanceGroupSerializer(BaseSerializer):
return 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:
raise serializers.ValidationError(_('Containerized instances may not be managed via the API'))
return value
@@ -4936,6 +4983,13 @@ class InstanceGroupSerializer(BaseSerializer):
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):
if value and not value.kubernetes:
raise serializers.ValidationError(_('Only Kubernetes credentials can be associated with an Instance Group'))
@@ -5050,7 +5104,7 @@ class ActivityStreamSerializer(BaseSerializer):
try:
return json.loads(obj.changes)
except Exception:
logger.warn("Error deserializing activity stream json changes")
logger.warning("Error deserializing activity stream json changes")
return {}
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.
# All Rights Reserved.
from django.conf.urls import url
from django.urls import re_path
from awx.api.views import ActivityStreamList, ActivityStreamDetail
urls = [
url(r'^$', ActivityStreamList.as_view(), name='activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/$', ActivityStreamDetail.as_view(), name='activity_stream_detail'),
re_path(r'^$', ActivityStreamList.as_view(), name='activity_stream_list'),
re_path(r'^(?P<pk>[0-9]+)/$', ActivityStreamDetail.as_view(), name='activity_stream_detail'),
]
__all__ = ['urls']

View File

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

View File

@@ -1,13 +1,13 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from django.urls import re_path
from awx.api.views import AdHocCommandEventDetail
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']

View File

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

View File

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

View File

@@ -1,17 +1,17 @@
# Copyright (c) 2017 Ansible, Inc.
# 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
urls = [
url(r'^$', CredentialTypeList.as_view(), name='credential_type_list'),
url(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'),
url(r'^(?P<pk>[0-9]+)/credentials/$', CredentialTypeCredentialList.as_view(), name='credential_type_credential_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
url(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'),
re_path(r'^$', CredentialTypeList.as_view(), name='credential_type_list'),
re_path(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'),
re_path(r'^(?P<pk>[0-9]+)/credentials/$', CredentialTypeCredentialList.as_view(), name='credential_type_credential_list'),
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
re_path(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'),
]
__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 (
ExecutionEnvironmentList,
@@ -10,11 +10,11 @@ from awx.api.views import (
urls = [
url(r'^$', ExecutionEnvironmentList.as_view(), name='execution_environment_list'),
url(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'),
url(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'^$', ExecutionEnvironmentList.as_view(), name='execution_environment_list'),
re_path(r'^(?P<pk>[0-9]+)/$', ExecutionEnvironmentDetail.as_view(), name='execution_environment_detail'),
re_path(r'^(?P<pk>[0-9]+)/unified_job_templates/$', ExecutionEnvironmentJobTemplateList.as_view(), name='execution_environment_job_template_list'),
re_path(r'^(?P<pk>[0-9]+)/copy/$', ExecutionEnvironmentCopy.as_view(), name='execution_environment_copy'),
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', ExecutionEnvironmentActivityStreamList.as_view(), name='execution_environment_activity_stream_list'),
]
__all__ = ['urls']

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,11 +1,11 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from django.urls import re_path
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']

View File

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

View File

@@ -1,11 +1,11 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from django.urls import re_path
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']

View File

@@ -1,11 +1,14 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from django.urls import re_path
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']

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,18 +1,18 @@
# Copyright (c) 2017 Ansible, Inc.
# 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
urls = [
url(r'^$', RoleList.as_view(), name='role_list'),
url(r'^(?P<pk>[0-9]+)/$', RoleDetail.as_view(), name='role_detail'),
url(r'^(?P<pk>[0-9]+)/users/$', RoleUsersList.as_view(), name='role_users_list'),
url(r'^(?P<pk>[0-9]+)/teams/$', RoleTeamsList.as_view(), name='role_teams_list'),
url(r'^(?P<pk>[0-9]+)/parents/$', RoleParentsList.as_view(), name='role_parents_list'),
url(r'^(?P<pk>[0-9]+)/children/$', RoleChildrenList.as_view(), name='role_children_list'),
re_path(r'^$', RoleList.as_view(), name='role_list'),
re_path(r'^(?P<pk>[0-9]+)/$', RoleDetail.as_view(), name='role_detail'),
re_path(r'^(?P<pk>[0-9]+)/users/$', RoleUsersList.as_view(), name='role_users_list'),
re_path(r'^(?P<pk>[0-9]+)/teams/$', RoleTeamsList.as_view(), name='role_teams_list'),
re_path(r'^(?P<pk>[0-9]+)/parents/$', RoleParentsList.as_view(), name='role_parents_list'),
re_path(r'^(?P<pk>[0-9]+)/children/$', RoleChildrenList.as_view(), name='role_children_list'),
]
__all__ = ['urls']

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import include, url
from django.urls import include, re_path
from awx.api.views import (
WorkflowJobTemplateList,
@@ -24,39 +24,39 @@ from awx.api.views import (
urls = [
url(r'^$', WorkflowJobTemplateList.as_view(), name='workflow_job_template_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateDetail.as_view(), name='workflow_job_template_detail'),
url(r'^(?P<pk>[0-9]+)/workflow_jobs/$', WorkflowJobTemplateJobsList.as_view(), name='workflow_job_template_jobs_list'),
url(r'^(?P<pk>[0-9]+)/launch/$', WorkflowJobTemplateLaunch.as_view(), name='workflow_job_template_launch'),
url(r'^(?P<pk>[0-9]+)/copy/$', WorkflowJobTemplateCopy.as_view(), name='workflow_job_template_copy'),
url(r'^(?P<pk>[0-9]+)/schedules/$', WorkflowJobTemplateSchedulesList.as_view(), name='workflow_job_template_schedules_list'),
url(r'^(?P<pk>[0-9]+)/survey_spec/$', WorkflowJobTemplateSurveySpec.as_view(), name='workflow_job_template_survey_spec'),
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobTemplateWorkflowNodesList.as_view(), name='workflow_job_template_workflow_nodes_list'),
url(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'),
url(
re_path(r'^$', WorkflowJobTemplateList.as_view(), name='workflow_job_template_list'),
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateDetail.as_view(), name='workflow_job_template_detail'),
re_path(r'^(?P<pk>[0-9]+)/workflow_jobs/$', WorkflowJobTemplateJobsList.as_view(), name='workflow_job_template_jobs_list'),
re_path(r'^(?P<pk>[0-9]+)/launch/$', WorkflowJobTemplateLaunch.as_view(), name='workflow_job_template_launch'),
re_path(r'^(?P<pk>[0-9]+)/copy/$', WorkflowJobTemplateCopy.as_view(), name='workflow_job_template_copy'),
re_path(r'^(?P<pk>[0-9]+)/schedules/$', WorkflowJobTemplateSchedulesList.as_view(), name='workflow_job_template_schedules_list'),
re_path(r'^(?P<pk>[0-9]+)/survey_spec/$', WorkflowJobTemplateSurveySpec.as_view(), name='workflow_job_template_survey_spec'),
re_path(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobTemplateWorkflowNodesList.as_view(), name='workflow_job_template_workflow_nodes_list'),
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'),
re_path(
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
WorkflowJobTemplateNotificationTemplatesStartedList.as_view(),
name='workflow_job_template_notification_templates_started_list',
),
url(
re_path(
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
WorkflowJobTemplateNotificationTemplatesErrorList.as_view(),
name='workflow_job_template_notification_templates_error_list',
),
url(
re_path(
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(),
name='workflow_job_template_notification_templates_success_list',
),
url(
re_path(
r'^(?P<pk>[0-9]+)/notification_templates_approvals/$',
WorkflowJobTemplateNotificationTemplatesApprovalList.as_view(),
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'),
url(r'^(?P<pk>[0-9]+)/object_roles/$', WorkflowJobTemplateObjectRolesList.as_view(), name='workflow_job_template_object_roles_list'),
url(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobTemplateLabelList.as_view(), name='workflow_job_template_label_list'),
url(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'workflow_job_templates'}),
re_path(r'^(?P<pk>[0-9]+)/access_list/$', WorkflowJobTemplateAccessList.as_view(), name='workflow_job_template_access_list'),
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', WorkflowJobTemplateObjectRolesList.as_view(), name='workflow_job_template_object_roles_list'),
re_path(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobTemplateLabelList.as_view(), name='workflow_job_template_label_list'),
re_path(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'workflow_job_templates'}),
]
__all__ = ['urls']

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
from django.conf.urls import url
from django.urls import re_path
from awx.api.views import (
WorkflowJobTemplateNodeList,
@@ -15,13 +15,13 @@ from awx.api.views import (
urls = [
url(r'^$', WorkflowJobTemplateNodeList.as_view(), name='workflow_job_template_node_list'),
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateNodeDetail.as_view(), name='workflow_job_template_node_detail'),
url(r'^(?P<pk>[0-9]+)/success_nodes/$', WorkflowJobTemplateNodeSuccessNodesList.as_view(), name='workflow_job_template_node_success_nodes_list'),
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobTemplateNodeFailureNodesList.as_view(), name='workflow_job_template_node_failure_nodes_list'),
url(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobTemplateNodeAlwaysNodesList.as_view(), name='workflow_job_template_node_always_nodes_list'),
url(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobTemplateNodeCredentialsList.as_view(), name='workflow_job_template_node_credentials_list'),
url(r'^(?P<pk>[0-9]+)/create_approval_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'),
re_path(r'^$', WorkflowJobTemplateNodeList.as_view(), name='workflow_job_template_node_list'),
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateNodeDetail.as_view(), name='workflow_job_template_node_detail'),
re_path(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]+)/failure_nodes/$', WorkflowJobTemplateNodeFailureNodesList.as_view(), name='workflow_job_template_node_failure_nodes_list'),
re_path(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]+)/credentials/$', WorkflowJobTemplateNodeCredentialsList.as_view(), name='workflow_job_template_node_credentials_list'),
re_path(r'^(?P<pk>[0-9]+)/create_approval_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'),
]
__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.http import HttpResponse
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
@@ -62,7 +62,7 @@ import pytz
from wsgiref.util import FileWrapper
# 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.api.generics import (
APIView,
@@ -105,7 +105,6 @@ from awx.api.permissions import (
ProjectUpdatePermission,
InventoryInventorySourcesUpdatePermission,
UserPermission,
InstanceGroupTowerPermission,
VariableDataPermission,
WorkflowApprovalPermission,
IsSystemAdminOrAuditor,
@@ -113,7 +112,7 @@ from awx.api.permissions import (
from awx.api import renderers
from awx.api import serializers
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.api.views.mixin import (
ControlledByScmMixin,
@@ -157,8 +156,10 @@ from awx.api.views.inventory import ( # noqa
InventoryAccessList,
InventoryObjectRolesList,
InventoryJobTemplateList,
InventoryLabelList,
InventoryCopy,
)
from awx.api.views.mesh_visualizer import MeshVisualizer # noqa
from awx.api.views.root import ( # noqa
ApiRootView,
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.pagination import UnifiedJobEventPagination
from awx.main.utils import set_environ
logger = logging.getLogger('awx.api.views')
@@ -406,6 +408,8 @@ class InstanceInstanceGroupsList(InstanceGroupMembershipMixin, SubListCreateAtta
def is_valid_relation(self, parent, sub, created=False):
if parent.node_type == 'control':
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
@@ -416,6 +420,10 @@ class InstanceHealthCheck(GenericAPIView):
serializer_class = serializers.InstanceHealthCheckSerializer
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):
obj = self.get_object()
data = self.get_serializer(data=request.data).to_representation(obj)
@@ -425,7 +433,7 @@ class InstanceHealthCheck(GenericAPIView):
obj = self.get_object()
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)
obj.refresh_from_db()
@@ -435,7 +443,7 @@ class InstanceHealthCheck(GenericAPIView):
if extra_field in runner_data:
data[extra_field] = runner_data[extra_field]
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:
cluster_node_health_check(obj.hostname)
@@ -472,7 +480,6 @@ class InstanceGroupDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAP
name = _("Instance Group Detail")
model = models.InstanceGroup
serializer_class = serializers.InstanceGroupSerializer
permission_classes = (InstanceGroupTowerPermission,)
def update_raw_data(self, data):
if self.get_object().is_container_group:
@@ -503,6 +510,8 @@ class InstanceGroupInstanceList(InstanceGroupMembershipMixin, SubListAttachDetac
def is_valid_relation(self, parent, sub, created=False):
if sub.node_type == 'control':
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
@@ -1547,8 +1556,9 @@ class CredentialExternalTest(SubDetailAPIView):
backend_kwargs[field_name] = value
backend_kwargs.update(request.data.get('metadata', {}))
try:
obj.credential_type.plugin.backend(**backend_kwargs)
return Response({}, status=status.HTTP_202_ACCEPTED)
with set_environ(**settings.AWX_TASK_ENV):
obj.credential_type.plugin.backend(**backend_kwargs)
return Response({}, status=status.HTTP_202_ACCEPTED)
except requests.exceptions.HTTPError as exc:
message = 'HTTP {}'.format(exc.response.status_code)
return Response({'inputs': message}, status=status.HTTP_400_BAD_REQUEST)
@@ -2458,8 +2468,6 @@ class JobTemplateSurveySpec(GenericAPIView):
obj_permission_type = 'admin'
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):
obj = self.get_object()
return Response(obj.display_survey_spec())
@@ -2530,17 +2538,17 @@ class JobTemplateSurveySpec(GenericAPIView):
# Type-specific validation
# validate question type <-> default type
qtype = survey_item["type"]
if qtype not in JobTemplateSurveySpec.ALLOWED_TYPES:
if qtype not in SURVEY_TYPE_MAPPING:
return Response(
dict(
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,
)
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'
if qtype in ['integer', 'float']:
type_label = qtype

View File

@@ -8,7 +8,7 @@ import logging
from django.conf import settings
from django.db.models import Q
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
from rest_framework.exceptions import PermissionDenied
@@ -16,17 +16,21 @@ from rest_framework.response import Response
from rest_framework import status
# AWX
from awx.main.models import (
ActivityStream,
Inventory,
JobTemplate,
Role,
User,
InstanceGroup,
InventoryUpdateEvent,
InventoryUpdate,
from awx.main.models import ActivityStream, Inventory, JobTemplate, Role, User, InstanceGroup, InventoryUpdateEvent, InventoryUpdate
from awx.main.models.label import Label
from awx.api.generics import (
ListCreateAPIView,
RetrieveUpdateDestroyAPIView,
SubListAPIView,
SubListAttachDetachAPIView,
ResourceAccessList,
CopyAPIView,
DeleteLastUnattachLabelMixin,
SubListCreateAttachDetachAPIView,
)
from awx.api.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView, SubListAPIView, SubListAttachDetachAPIView, ResourceAccessList, CopyAPIView
from awx.api.serializers import (
InventorySerializer,
@@ -35,6 +39,7 @@ from awx.api.serializers import (
InstanceGroupSerializer,
InventoryUpdateEventSerializer,
JobTemplateSerializer,
LabelSerializer,
)
from awx.api.views.mixin import RelatedJobsPreventDeleteMixin, ControlledByScmMixin
@@ -152,6 +157,30 @@ class InventoryJobTemplateList(SubListAPIView):
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):
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
# Django
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
# Django REST Framework
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.shortcuts import get_object_or_404
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.exceptions import PermissionDenied

View File

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

View File

@@ -8,11 +8,11 @@ import operator
from collections import OrderedDict
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.views.decorators.csrf import ensure_csrf_cookie
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.response import Response
@@ -123,6 +123,7 @@ class ApiVersionRootView(APIView):
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_nodes'] = reverse('api:workflow_job_node_list', request=request)
data['mesh_visualizer'] = reverse('api:mesh_visualizer_view', request=request)
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['instances'] = []
for instance in Instance.objects.all():
for instance in Instance.objects.exclude(node_type='hop'):
response['instances'].append(
dict(
node=instance.hostname,
node_type=instance.node_type,
uuid=instance.uuid,
heartbeat=instance.modified,
heartbeat=instance.last_seen,
capacity=instance.capacity,
version=instance.version,
)
@@ -204,7 +205,7 @@ class ApiV2SubscriptionView(APIView):
elif isinstance(exc, (ValueError, OSError)) and exc.args:
msg = exc.args[0]
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(validated)
@@ -245,7 +246,7 @@ class ApiV2AttachView(APIView):
elif isinstance(exc, (ValueError, OSError)) and exc.args:
msg = exc.args[0]
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)
for sub in validated:
if sub['pool_id'] == pool_id:
@@ -321,7 +322,7 @@ class ApiV2ConfigView(APIView):
try:
data_actual = json.dumps(request.data)
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)
license_data = json.loads(data_actual)
@@ -345,7 +346,7 @@ class ApiV2ConfigView(APIView):
try:
license_data_validated = get_licenser().license_from_manifest(license_data)
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)
else:
license_data_validated = get_licenser().validate()
@@ -356,7 +357,7 @@ class ApiV2ConfigView(APIView):
settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host())
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)
def delete(self, request):

View File

@@ -4,7 +4,7 @@ import logging
import urllib.parse
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 rest_framework import status
@@ -16,7 +16,7 @@ from awx.api import serializers
from awx.api.generics import APIView, GenericAPIView
from awx.api.permissions import WebhookKeyPermission
from awx.main.models import Job, JobTemplate, WorkflowJob, WorkflowJobTemplate
from awx.main.constants import JOB_VARIABLE_PREFIXES
logger = logging.getLogger('awx.api.views.webhooks')
@@ -136,15 +136,16 @@ class WebhookReceiverBase(APIView):
'webhook_credential': obj.webhook_credential,
'webhook_guid': event_guid,
},
'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,
},
'extra_vars': {},
}
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.signal_start()

View File

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

View File

@@ -1,8 +1,10 @@
import sys
# Django
from django.apps import AppConfig
# from django.core import checks
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
class ConfConfig(AppConfig):
@@ -12,6 +14,9 @@ class ConfConfig(AppConfig):
def ready(self):
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
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
# AWX
from awx.conf import fields, register

View File

@@ -7,12 +7,15 @@ from collections import OrderedDict
# Django
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
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
# AWX
from awx.main.constants import CONTAINER_VOLUMES_MOUNT_TYPES, MAX_ISOLATED_PATH_COLON_DELIMITER
logger = logging.getLogger('awx.conf.fields')
# Use DRF fields to convert/validate settings:
@@ -62,11 +65,11 @@ class StringListBooleanField(ListField):
try:
if isinstance(value, (list, tuple)):
return super(StringListBooleanField, self).to_representation(value)
elif value in NullBooleanField.TRUE_VALUES:
elif value in BooleanField.TRUE_VALUES:
return True
elif value in NullBooleanField.FALSE_VALUES:
elif value in BooleanField.FALSE_VALUES:
return False
elif value in NullBooleanField.NULL_VALUES:
elif value in BooleanField.NULL_VALUES:
return None
elif isinstance(value, str):
return self.child.to_representation(value)
@@ -79,11 +82,11 @@ class StringListBooleanField(ListField):
try:
if isinstance(data, (list, tuple)):
return super(StringListBooleanField, self).to_internal_value(data)
elif data in NullBooleanField.TRUE_VALUES:
elif data in BooleanField.TRUE_VALUES:
return True
elif data in NullBooleanField.FALSE_VALUES:
elif data in BooleanField.FALSE_VALUES:
return False
elif data in NullBooleanField.NULL_VALUES:
elif data in BooleanField.NULL_VALUES:
return None
elif isinstance(data, str):
return self.child.run_validation(data)
@@ -109,6 +112,49 @@ class StringListPathField(StringListField):
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):
# these lines set up a custom regex that allow numbers in the
# top-level domain

View File

@@ -2,9 +2,10 @@
from __future__ import unicode_literals
from django.db import migrations, models
import jsonfield.fields
from django.conf import settings
import awx.main.fields
class Migration(migrations.Migration):
@@ -18,7 +19,7 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(default=None, editable=False)),
('modified', models.DateTimeField(default=None, editable=False)),
('key', models.CharField(max_length=255)),
('value', jsonfield.fields.JSONField(null=True)),
('value', awx.main.fields.JSONBlob(null=True)),
(
'user',
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 django.db import migrations
import awx.main.fields
@@ -9,4 +10,4 @@ class Migration(migrations.Migration):
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):
group_type = settings.AUTH_LDAP_GROUP_TYPE
group_type = getattr(settings, 'AUTH_LDAP_GROUP_TYPE', None)
Setting = apps.get_model('conf', 'Setting')
group_type_params = {'name_attr': 'cn', 'member_attr': 'member'}
@@ -17,7 +17,7 @@ def fill_ldap_group_type_params(apps, schema_editor):
else:
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()):
if k not in init_attrs:
del group_type_params[k]

View File

@@ -8,8 +8,8 @@ import json
from django.db import models
# AWX
from awx.main.fields import JSONBlob
from awx.main.models.base import CreatedModifiedModel, prevent_search
from awx.main.fields import JSONField
from awx.main.utils import encrypt_field
from awx.conf import settings_registry
@@ -19,7 +19,7 @@ __all__ = ['Setting']
class Setting(CreatedModifiedModel):
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))
def __str__(self):

View File

@@ -8,7 +8,7 @@ import logging
# Django
from django.core.exceptions import ImproperlyConfigured
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

View File

@@ -6,7 +6,7 @@ from uuid import uuid4
from django.conf import LazySettings
from django.core.cache.backends.locmem import LocMemCache
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
import pytest

View File

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

View File

@@ -1,13 +1,13 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved.
from django.urls import re_path
from django.conf.urls import url
from awx.conf.views import SettingCategoryList, SettingSingletonDetail, SettingLoggingTest
urlpatterns = [
url(r'^$', SettingCategoryList.as_view(), name='setting_category_list'),
url(r'^(?P<category_slug>[a-z0-9-]+)/$', SettingSingletonDetail.as_view(), name='setting_singleton_detail'),
url(r'^logging/test/$', SettingLoggingTest.as_view(), name='setting_logging_test'),
re_path(r'^$', SettingCategoryList.as_view(), name='setting_category_list'),
re_path(r'^(?P<category_slug>[a-z0-9-]+)/$', SettingSingletonDetail.as_view(), name='setting_singleton_detail'),
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.conf import settings
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
# Django REST Framework
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.versioning import reverse
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.serializers import SettingCategorySerializer, SettingSingletonSerializer
from awx.conf import settings_registry

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.
#
msgid ""
@@ -2255,7 +2252,6 @@ msgid ""
"Maximum number of messages to update the UI live job output with per second. "
"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."
#: awx/main/conf.py:380
msgid "Maximum Scheduled Jobs"
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:939
msgid "Token"
msgstr "Token"
msgstr "Jeton"
#: awx/main/credential_plugins/hashivault.py:25
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
msgid "Play Started"
msgstr "Scène démarrée"
msgstr "Play Démarrage"
#: awx/main/models/events.py:194
msgid "Playbook Complete"
@@ -3981,7 +3977,7 @@ msgid ""
"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 "
"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
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
msgid ""
"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
msgid ""
@@ -4555,7 +4551,7 @@ msgstr "Utilisation"
#: awx/main/models/rbac.py:52
msgid "Approve"
msgstr "Approbation"
msgstr "Approuver"
#: awx/main/models/rbac.py:56
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
#, python-format
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
#, python-format
@@ -5633,7 +5629,7 @@ msgstr "Nom de l'organisation GitHub"
msgid ""
"The name of your GitHub organization, as used in your organization's URL: "
"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
msgid "GitHub Organization OAuth2 Organization Map"
@@ -5653,7 +5649,7 @@ msgid ""
"<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and "
"secret (Client Secret). Provide this URL as the callback URL for your "
"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:832 awx/sso/conf.py:843 awx/sso/conf.py:855
@@ -5789,7 +5785,7 @@ msgstr "Nom de l'organisation GitHub Enterprise"
msgid ""
"The name of your GitHub Enterprise organization, as used in your "
"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
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.
#
msgid ""
@@ -596,7 +593,7 @@ msgstr "指定された変数 {} には置き換えるデータベースの値
#: awx/api/serializers.py:3739
msgid "\"$encrypted$ is a reserved keyword, may not be used for {}.\""
msgstr "\"$encrypted$ は予約されたキーワードで{} には使用できません。\""
msgstr "\"$encrypted は予約されたキーワードで {} には使用できません。\""
#: awx/api/serializers.py:4212
msgid "A project is required to run a job."
@@ -824,7 +821,7 @@ msgstr "ポリシーインスタンスの割合"
msgid ""
"Minimum percentage of all instances that will be automatically assigned to "
"this group when new instances come online."
msgstr "新規インスタンスがオンラインになると、このグループに自動的に最小限割り当てられるインスタンスの割合を選択します。"
msgstr "新規インスタンスがオンラインになると、このグループに自動的に最小限割り当てられるインスタンスの割合"
#: awx/api/serializers.py:4853
msgid "Policy Instance Minimum"
@@ -1253,7 +1250,7 @@ msgstr "デフォルトで指定されている選択項目は、一覧から回
msgid ""
"$encrypted$ is a reserved keyword for password question defaults, survey "
"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
#, python-brace-format
@@ -3638,7 +3635,7 @@ msgstr "ホスト OK"
#: awx/main/models/events.py:169
msgid "Host Failure"
msgstr "ホストの失敗"
msgstr "ホストの障害"
#: awx/main/models/events.py:170 awx/main/models/events.py:767
msgid "Host Skipped"
@@ -4694,7 +4691,7 @@ msgstr "取り消されました"
#: awx/main/models/unified_jobs.py:84
msgid "Never Updated"
msgstr "更新されていません"
msgstr "更新"
#: awx/main/models/unified_jobs.py:88
msgid "OK"
@@ -6261,4 +6258,3 @@ msgstr "%s が現在アップグレード中です。"
#: awx/ui/urls.py:24
msgid "This page will refresh when complete."
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.
#
msgid ""
@@ -596,7 +593,7 @@ msgstr "提供的变量 {} 没有要替换的数据库值。"
#: awx/api/serializers.py:3739
msgid "\"$encrypted$ is a reserved keyword, may not be used for {}.\""
msgstr "\"$encrypted$ 是一个保留关键字,可能不能用于 {}\""
msgstr "\"$encrypted$ 是一个保留关键字,可能无法用于 {}\""
#: awx/api/serializers.py:4212
msgid "A project is required to run a job."
@@ -1031,7 +1028,7 @@ msgstr "对于受管执行环境,只能编辑 'pull' 字段。"
#: awx/api/views/__init__.py:805
msgid "Project Schedules"
msgstr "项目调度"
msgstr "项目计划"
#: awx/api/views/__init__.py:816
msgid "Project SCM Inventory Sources"
@@ -1253,14 +1250,14 @@ msgstr "默认的选择必须从列出的选择中回答。"
msgid ""
"$encrypted$ is a reserved keyword for password question defaults, survey "
"question {idx} is type {survey_item[type]}."
msgstr "$encrypted$ 是密码问题默认值的保留关键字,问卷调查问题 {idx} 类型 {survey_item[type]}。"
msgstr "$encrypted$ 是密码问题默认值的保留关键字,问卷调查问题 {idx} 类型 {survey_item[type]}。"
#: awx/api/views/__init__.py:2567
#, python-brace-format
msgid ""
"$encrypted$ is a reserved keyword, may not be used for new default in "
"position {idx}."
msgstr "$encrypted$ 是一个保留关键字,可能无法用于位置 {idx} 中的新默认值。"
msgstr "$encrypted$ 是一个保留关键字,无法用于位置 {idx} 中的新默认值。"
#: awx/api/views/__init__.py:2639
#, python-brace-format
@@ -2865,7 +2862,7 @@ msgstr "Secret 的路径"
#: awx/main/credential_plugins/hashivault.py:78
msgid "Path to Auth"
msgstr "Auth 的路径"
msgstr "Auth 的路径"
#: awx/main/credential_plugins/hashivault.py:81
msgid "The path where the Authentication method is mounted e.g, approle"
@@ -3979,7 +3976,7 @@ msgid ""
"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 "
"found then the host will be enabled"
msgstr "仅在设置 enabled_var 时使用。 主机被视为启用时的值。 例如: if enabled_var=\"status.power_state\"and enabled_value=\"powered_on\" with host variables:{ \"status\": { \"power_state\": \"powered_on\", \"created\": \"2020-08-04T18:13:04+00:00\", \"healthy\": true }, \"name\": \"foobar\", \"ip_address\": \"192.168.2.1\"}The host would be marked enabled. 如果 power_state 在除 powered_on 以外的任何值,则会在导入时禁用主机。如果没有找到密钥,则会启用主机"
msgstr "仅在设置 enabled_var 时使用。 主机被视为启用时的值。 例如:是否 enabled_var=\"status.power_state\"and enabled_value=\"powered_on\" with host variables:{ \"status\": { \"power_state\": \"powered_on\", \"created\": \"2020-08-04T18:13:04+00:00\", \"healthy\": true }, \"name\": \"foobar\", \"ip_address\": \"192.168.2.1\"}如果 power_state 在除 powered_on 以外的任何值,则会在导入时禁用主机。如果没有找到密钥,则会启用主机"
#: awx/main/models/inventory.py:878
msgid "Regex where only matching hosts will be imported."
@@ -6133,7 +6130,7 @@ msgstr "您的帐户不活跃"
#: awx/sso/validators.py:24 awx/sso/validators.py:51
#, python-format
msgid "DN must include \"%%(user)s\" placeholder for username: %s"
msgstr "DN 必须包含 \"%%\" 占位符用于用户名:%s"
msgstr "DN 必须包含 \"%%(user)s\" 占位符用于用户名:%s"
#: awx/sso/validators.py:31
#, python-format
@@ -6263,4 +6260,3 @@ msgstr "%s 当前正在升级。"
#: awx/ui/urls.py:24
msgid "This page will refresh when complete."
msgstr "完成后,此页面会刷新。"

View File

@@ -1,4 +1,2 @@
# Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved.
default_app_config = 'awx.main.apps.MainConfig'

View File

@@ -11,7 +11,7 @@ from functools import reduce
from django.conf import settings
from django.db.models import Q, Prefetch
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
# Django REST Framework
@@ -465,7 +465,7 @@ class BaseAccess(object):
if display_method == 'schedule':
user_capabilities['schedule'] = user_capabilities['start']
continue
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob, CredentialInputSource, ExecutionEnvironment)):
elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob, CredentialInputSource, ExecutionEnvironment, InstanceGroup)):
user_capabilities['delete'] = user_capabilities['edit']
continue
elif display_method == 'copy' and isinstance(obj, (Group, Host)):
@@ -575,6 +575,11 @@ class InstanceGroupAccess(BaseAccess):
def can_change(self, obj, data):
return self.user.is_superuser
def can_delete(self, obj):
if obj.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
return False
return self.user.is_superuser
class UserAccess(BaseAccess):
"""
@@ -853,7 +858,12 @@ class InventoryAccess(BaseAccess):
"""
model = Inventory
prefetch_related = ('created_by', 'modified_by', 'organization')
prefetch_related = (
'created_by',
'modified_by',
'organization',
Prefetch('labels', queryset=Label.objects.all().order_by('name')),
)
def filtered_queryset(self, allowed=None, ad_hoc=None):
return self.model.accessible_objects(self.user, 'read_role')

View File

@@ -89,7 +89,7 @@ class BroadcastWebsocketStatsManager:
await asyncio.sleep(settings.BROADCAST_WEBSOCKET_STATS_POLL_RATE_SECONDS)
except Exception as e:
logger.warn(e)
logger.warning(e)
await asyncio.sleep(settings.BROADCAST_WEBSOCKET_STATS_POLL_RATE_SECONDS)
self.start()

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