mirror of
https://github.com/ansible/awx.git
synced 2026-02-06 12:04:44 -03:30
Compare commits
442 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b548ad21a9 | ||
|
|
3d0391173b | ||
|
|
ce560bcd5f | ||
|
|
8c3e289170 | ||
|
|
9364c8e562 | ||
|
|
5831949ebf | ||
|
|
7fe98a670f | ||
|
|
6f68f3cba6 | ||
|
|
4dc956c76f | ||
|
|
11a56117eb | ||
|
|
10eed6286a | ||
|
|
d36befd9ce | ||
|
|
0c4ddc7f6f | ||
|
|
3ef9679de3 | ||
|
|
d36441489a | ||
|
|
d26c12dd7c | ||
|
|
7fa7ed3658 | ||
|
|
2c68e7a3d2 | ||
|
|
0c9b1c3c79 | ||
|
|
e10b0e513e | ||
|
|
68c66edada | ||
|
|
6eb17e7af7 | ||
|
|
9a24da3098 | ||
|
|
8ed0543b8b | ||
|
|
73a84444d1 | ||
|
|
451767c179 | ||
|
|
8366386126 | ||
|
|
997686a2ea | ||
|
|
2ba68ef5d0 | ||
|
|
2041665880 | ||
|
|
1e6ca01686 | ||
|
|
e15a76e7aa | ||
|
|
64db44acef | ||
|
|
9972389a8d | ||
|
|
e0b1274eee | ||
|
|
df649e2c56 | ||
|
|
a778017efb | ||
|
|
6a9305818e | ||
|
|
2669904c72 | ||
|
|
35529b5eeb | ||
|
|
d55ed8713c | ||
|
|
7973f28bed | ||
|
|
8189964cce | ||
|
|
ee4c901dc7 | ||
|
|
78220cad82 | ||
|
|
40279bc6c0 | ||
|
|
f6fb46d99e | ||
|
|
954b32941e | ||
|
|
48b016802c | ||
|
|
35aa5dd79f | ||
|
|
237402068c | ||
|
|
31dda6e9d6 | ||
|
|
1c9b4af61d | ||
|
|
eba4a3f1c2 | ||
|
|
0ae9fe3624 | ||
|
|
1b662fcca5 | ||
|
|
cfdba959dd | ||
|
|
78660ad0a2 | ||
|
|
70697869d7 | ||
|
|
10e55108ef | ||
|
|
d4223b8877 | ||
|
|
9537d148d7 | ||
|
|
a133a14b70 | ||
|
|
4ca9e9577b | ||
|
|
44986fad36 | ||
|
|
eb2fca86b6 | ||
|
|
458a1fc035 | ||
|
|
6e87b29e92 | ||
|
|
be1d0c525c | ||
|
|
0787cb4fc2 | ||
|
|
19063a2d90 | ||
|
|
e8e2f820d2 | ||
|
|
aaad634483 | ||
|
|
dfa4127bae | ||
|
|
f3725c714a | ||
|
|
cef3ed01ac | ||
|
|
fc1a3f46f9 | ||
|
|
bfa5feb51b | ||
|
|
4c0813bd69 | ||
|
|
9b0b0f2a5f | ||
|
|
e87c121f8f | ||
|
|
65dfc424bc | ||
|
|
dfea9cc526 | ||
|
|
0d97a0364a | ||
|
|
1da57a4a12 | ||
|
|
b73078e9db | ||
|
|
b17f22cd38 | ||
|
|
7b225057ce | ||
|
|
8242078c06 | ||
|
|
a86740c3c9 | ||
|
|
cbde56549d | ||
|
|
385a94866c | ||
|
|
21972c91dd | ||
|
|
36d3f9afdb | ||
|
|
df2d303ab0 | ||
|
|
05eba350b7 | ||
|
|
1e12e12578 | ||
|
|
bbdab82433 | ||
|
|
f7be6b6423 | ||
|
|
ba358eaa4f | ||
|
|
162e09972f | ||
|
|
2cfccdbe16 | ||
|
|
434fa7b7be | ||
|
|
2f8bdf1eab | ||
|
|
e1705738a1 | ||
|
|
4cfb8fe482 | ||
|
|
d52d2af4b4 | ||
|
|
97fd3832d4 | ||
|
|
3cedd0e0bd | ||
|
|
507b1898ce | ||
|
|
e3fe9010b7 | ||
|
|
2c350b8b90 | ||
|
|
d74e258079 | ||
|
|
b03cabd314 | ||
|
|
6a63af83c0 | ||
|
|
452744b67e | ||
|
|
703a68d4fe | ||
|
|
557893e4b0 | ||
|
|
d7051fb6ce | ||
|
|
867c50da19 | ||
|
|
e8d76ec272 | ||
|
|
c102c61532 | ||
|
|
adb2b0da89 | ||
|
|
3610008699 | ||
|
|
3b44838dde | ||
|
|
0205d7deab | ||
|
|
dd47829bdb | ||
|
|
e7e72d13a9 | ||
|
|
4bbdf1ec8a | ||
|
|
4596df449e | ||
|
|
ecbb636ba1 | ||
|
|
e3aed9dad4 | ||
|
|
213983a322 | ||
|
|
2977084787 | ||
|
|
b6362a63cc | ||
|
|
7517ba820b | ||
|
|
29d60844a8 | ||
|
|
41b0607d7e | ||
|
|
13f7166a30 | ||
|
|
0cc9b84ead | ||
|
|
68ee4311bf | ||
|
|
6e6c3f676e | ||
|
|
c67f50831b | ||
|
|
50ef234bd6 | ||
|
|
2bef5ce09b | ||
|
|
a49c4796f4 | ||
|
|
9eab9586e5 | ||
|
|
cd35787a86 | ||
|
|
cbe84ff4f3 | ||
|
|
410f38eccf | ||
|
|
b885fc2d86 | ||
|
|
4c93f5794a | ||
|
|
456bb75dcb | ||
|
|
02fd8b0d20 | ||
|
|
fbe6c80f86 | ||
|
|
3d5f302d10 | ||
|
|
856a2c1734 | ||
|
|
4277b73438 | ||
|
|
2888f9f8d0 | ||
|
|
68221cdcbe | ||
|
|
f50501cc2a | ||
|
|
c84fac65e0 | ||
|
|
d64c457b3d | ||
|
|
1bd5a880dc | ||
|
|
47d5a89f40 | ||
|
|
6060e7e29f | ||
|
|
677187a43e | ||
|
|
972cb82d16 | ||
|
|
3102df0bf6 | ||
|
|
cb63d92bbf | ||
|
|
c43424ed09 | ||
|
|
a0ccc8c925 | ||
|
|
47160f0118 | ||
|
|
44f0609314 | ||
|
|
689a216726 | ||
|
|
4b45148614 | ||
|
|
c84e603ac5 | ||
|
|
c7049e1a0e | ||
|
|
0b4c3e3046 | ||
|
|
8a5fd11506 | ||
|
|
b565038fdf | ||
|
|
526b1e692a | ||
|
|
c93155132a | ||
|
|
ae7960e9d7 | ||
|
|
3a1268de1e | ||
|
|
10042df309 | ||
|
|
2530ada9d7 | ||
|
|
11890f0eee | ||
|
|
5cb3f31df0 | ||
|
|
ac0624236e | ||
|
|
13eb174c9f | ||
|
|
a3e29317c5 | ||
|
|
75d7cb5bca | ||
|
|
9059dce8af | ||
|
|
1676c02611 | ||
|
|
86a888f0d0 | ||
|
|
816652a8e2 | ||
|
|
c1817ab19e | ||
|
|
b2dcc0d7e9 | ||
|
|
ba5361b25e | ||
|
|
ae826ed19d | ||
|
|
e24fc43a45 | ||
|
|
b719e5771c | ||
|
|
778862fe51 | ||
|
|
30d185a67f | ||
|
|
89c2a4c6ed | ||
|
|
868e811b3f | ||
|
|
f6496c28fe | ||
|
|
81cda0ba74 | ||
|
|
2e9974133a | ||
|
|
49051c4aaf | ||
|
|
e2a89ad8a2 | ||
|
|
f4b0bd68bd | ||
|
|
5a304db840 | ||
|
|
e3044298bf | ||
|
|
bbb9770a97 | ||
|
|
4328b4cb67 | ||
|
|
a324753180 | ||
|
|
1462af61b0 | ||
|
|
8478a0f70b | ||
|
|
8288655b30 | ||
|
|
ac8204427e | ||
|
|
f6b8ce18d0 | ||
|
|
dc42946ff3 | ||
|
|
44cc934c2b | ||
|
|
933956eccb | ||
|
|
27dc8caabd | ||
|
|
4b98df237e | ||
|
|
0fa3ca8dc0 | ||
|
|
0712affa9b | ||
|
|
b646aa03f8 | ||
|
|
4beea35d9e | ||
|
|
e8948a9d6e | ||
|
|
28f25d5aba | ||
|
|
7cbb783b2c | ||
|
|
1793f94f27 | ||
|
|
0b7c9cd8ad | ||
|
|
51b5b78084 | ||
|
|
bea924ddc6 | ||
|
|
b5fcc6e541 | ||
|
|
ffb46fec52 | ||
|
|
4190cf126c | ||
|
|
58721098d5 | ||
|
|
cfd6df7a3b | ||
|
|
9f6fa4cf97 | ||
|
|
7822da03fb | ||
|
|
58cb3d5bdc | ||
|
|
a3c97a51be | ||
|
|
202dc00f4c | ||
|
|
309e58b6d7 | ||
|
|
34b20e26fa | ||
|
|
1de2487e8f | ||
|
|
8d95b72527 | ||
|
|
a920c9cc20 | ||
|
|
427f6d1687 | ||
|
|
dc64168ed4 | ||
|
|
4b913a0ae8 | ||
|
|
dac26e5e91 | ||
|
|
6c56f2b35b | ||
|
|
3b1a626fa9 | ||
|
|
35907fdf51 | ||
|
|
3513956cd6 | ||
|
|
3ed65ce39e | ||
|
|
73e02e745a | ||
|
|
91df8ab0f7 | ||
|
|
ef0f6ca248 | ||
|
|
4ecce81c51 | ||
|
|
823e4cb11a | ||
|
|
28fa90e9e5 | ||
|
|
3d22c8ae91 | ||
|
|
e2135b8d68 | ||
|
|
fe5736dc7f | ||
|
|
b36af5dfb3 | ||
|
|
4446434e5b | ||
|
|
39905b33cd | ||
|
|
dbdc529d4a | ||
|
|
0cbc802cf4 | ||
|
|
b04747676c | ||
|
|
5297a87ad4 | ||
|
|
be6657239d | ||
|
|
0caf263508 | ||
|
|
c77667788a | ||
|
|
bd907425a9 | ||
|
|
229ed53c0e | ||
|
|
f17ceca7a0 | ||
|
|
deac08ba8a | ||
|
|
e0082f4c76 | ||
|
|
bed0443b18 | ||
|
|
24152555c5 | ||
|
|
56f51eebce | ||
|
|
6c1adade25 | ||
|
|
ec5e677635 | ||
|
|
327cae056e | ||
|
|
7a11470817 | ||
|
|
efb01f3c36 | ||
|
|
85ec83c3fd | ||
|
|
1679102204 | ||
|
|
7601531d82 | ||
|
|
56ab1c2f0a | ||
|
|
f309054637 | ||
|
|
8efed4ef62 | ||
|
|
e4c85a5790 | ||
|
|
8af2214979 | ||
|
|
01ce3440eb | ||
|
|
b6573ec2e2 | ||
|
|
d54838cd94 | ||
|
|
e3f3ab224a | ||
|
|
c06ced93f7 | ||
|
|
ea59e895af | ||
|
|
fb7a8dfd16 | ||
|
|
18b1440d7c | ||
|
|
593eebf062 | ||
|
|
fcdff8bdfb | ||
|
|
b9cdd6f2c8 | ||
|
|
270497eda1 | ||
|
|
dbcdb825b0 | ||
|
|
6c28f4b204 | ||
|
|
7b2b979c1b | ||
|
|
e87c9d8811 | ||
|
|
7d04737a65 | ||
|
|
99056e3697 | ||
|
|
c110101cb1 | ||
|
|
aa6129fda0 | ||
|
|
1d181757e8 | ||
|
|
4fa8b6ded8 | ||
|
|
79afdfd1a6 | ||
|
|
7702abb368 | ||
|
|
3d6a49ce7c | ||
|
|
f823049f55 | ||
|
|
b608b73110 | ||
|
|
12c36d279e | ||
|
|
59bd73bff8 | ||
|
|
afbd9f04d7 | ||
|
|
26fb5a0bd7 | ||
|
|
acebff7be1 | ||
|
|
45bd143c07 | ||
|
|
aa46a7fe06 | ||
|
|
07d0eedb0a | ||
|
|
9aae2a11f2 | ||
|
|
51021f380b | ||
|
|
7818a479ee | ||
|
|
799bac4066 | ||
|
|
41b3ad1b83 | ||
|
|
c912dd4e76 | ||
|
|
3ec9bacb30 | ||
|
|
13db49aab7 | ||
|
|
ac6a82eee4 | ||
|
|
546fc24a0a | ||
|
|
f99820a391 | ||
|
|
873875af84 | ||
|
|
fcb1c4823e | ||
|
|
a1203e6fec | ||
|
|
2321f06c8a | ||
|
|
ce8b9750c9 | ||
|
|
574e3ed6ef | ||
|
|
584514766d | ||
|
|
eb8a1fec49 | ||
|
|
38ccea0f1f | ||
|
|
5d000c37d6 | ||
|
|
1803c5bdb4 | ||
|
|
23e700a1ef | ||
|
|
7114b9fa11 | ||
|
|
2e4d866f69 | ||
|
|
f1cc808429 | ||
|
|
30a39e1d1b | ||
|
|
22ad7244fa | ||
|
|
5be901c044 | ||
|
|
2c073ae488 | ||
|
|
d4a4ba7fdb | ||
|
|
3b8a0fcd95 | ||
|
|
d02cef9d92 | ||
|
|
bc783b8f94 | ||
|
|
4de27117e8 | ||
|
|
49bcf2e211 | ||
|
|
f52ef6e967 | ||
|
|
99bbc347ec | ||
|
|
53185a4ea5 | ||
|
|
23f6fae27a | ||
|
|
4b7e3620ca | ||
|
|
e4f0153a7d | ||
|
|
80947e2b32 | ||
|
|
8bf9dd038e | ||
|
|
4080007ced | ||
|
|
7a6fd2623e | ||
|
|
079eed2b9e | ||
|
|
bd5c304a50 | ||
|
|
cd86310562 | ||
|
|
676b8f6d8f | ||
|
|
028f09002f | ||
|
|
0500512c3c | ||
|
|
1e625ed58b | ||
|
|
e620bef2a5 | ||
|
|
05142a779d | ||
|
|
65d17fb316 | ||
|
|
faa12880a9 | ||
|
|
9b6fa55433 | ||
|
|
b852baaa39 | ||
|
|
a3a216f91f | ||
|
|
efff85bc1f | ||
|
|
df61d1a59c | ||
|
|
4040e09cb8 | ||
|
|
bbf6484e89 | ||
|
|
b870659fd9 | ||
|
|
fd135caed5 | ||
|
|
7fbab6760e | ||
|
|
7ebf6b77e5 | ||
|
|
fee47fe347 | ||
|
|
039c038cd7 | ||
|
|
dd99a25db0 | ||
|
|
85791f730c | ||
|
|
e0ce4c49f3 | ||
|
|
ef5cd66494 | ||
|
|
0d1898e72d | ||
|
|
8993dc706a | ||
|
|
af18453691 | ||
|
|
c102bf05af | ||
|
|
b1570302bc | ||
|
|
69a42b1a89 | ||
|
|
272e012626 | ||
|
|
d785f30c5f | ||
|
|
9854f8a6ab | ||
|
|
4235bf67f8 | ||
|
|
a6bc0d4222 | ||
|
|
b859c3360d | ||
|
|
391907c41e | ||
|
|
04a550cc67 | ||
|
|
cf459dc4e8 | ||
|
|
afebcc574d | ||
|
|
f3474f0811 | ||
|
|
7378952a8b | ||
|
|
3cfab418d1 | ||
|
|
8090cd3032 | ||
|
|
cd54d560b3 | ||
|
|
9fc92ccc52 | ||
|
|
b8674a3f8c | ||
|
|
07ccce9845 | ||
|
|
0c8c69f04a | ||
|
|
5856f805fc | ||
|
|
73a5802c11 | ||
|
|
826a069be0 | ||
|
|
1246b14e7e | ||
|
|
50d52c31e2 |
20
.github/dependabot.yml
vendored
Normal file
20
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/awx/ui"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 5
|
||||
allow:
|
||||
- dependency-type: "production"
|
||||
reviewers:
|
||||
- "AlexSCorey"
|
||||
- "keithjgrant"
|
||||
- "kialam"
|
||||
- "mabashian"
|
||||
- "marshmalien"
|
||||
- "nixocio"
|
||||
labels:
|
||||
- "component:ui"
|
||||
- "dependencies"
|
||||
target-branch: "devel"
|
||||
10
.github/pr_labeler.yml
vendored
10
.github/pr_labeler.yml
vendored
@@ -1,14 +1,14 @@
|
||||
"component:api":
|
||||
- any: ['awx/**/*', '!awx/ui/*']
|
||||
- any: ["awx/**/*", "!awx/ui/**"]
|
||||
|
||||
"component:ui":
|
||||
- any: ['awx/ui/**/*']
|
||||
- any: ["awx/ui/**/*"]
|
||||
|
||||
"component:docs":
|
||||
- any: ['docs/**/*']
|
||||
- any: ["docs/**/*"]
|
||||
|
||||
"component:cli":
|
||||
- any: ['awxkit/**/*']
|
||||
- any: ["awxkit/**/*"]
|
||||
|
||||
"component:collection":
|
||||
- any: ['awx_collection/**/*']
|
||||
- any: ["awx_collection/**/*"]
|
||||
|
||||
49
.github/triage_replies.md
vendored
Normal file
49
.github/triage_replies.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
## General
|
||||
- For the roundup of all the different mailing lists available from AWX, Ansible, and beyond visit: https://docs.ansible.com/ansible/latest/community/communication.html
|
||||
- Hello, we think your question is answered in our FAQ. Does this: https://www.ansible.com/products/awx-project/faq cover your question?
|
||||
- You can find the latest documentation here: https://docs.ansible.com/automation-controller/latest/html/userguide/index.html
|
||||
|
||||
## Visit our mailing list
|
||||
- Hello, your question seems like a good one to ask on our mailing list at https://groups.google.com/g/awx-project. You can also join #ansible-awx on https://libera.chat/ and ask your question there.
|
||||
|
||||
## Create an issue
|
||||
- Hello, thanks for reaching out on list. We think this merits an issue on our Github, https://github.com/ansible/awx/issues. If you could open an issue up on Github it will get tagged and integrated into our planning and workflow. All future work will be tracked there.
|
||||
|
||||
## Create a Pull Request
|
||||
- Hello, we think your idea is good, please consider contributing a PR for this, following our contributing guidelines: https://github.com/ansible/awx/blob/devel/CONTRIBUTING.md
|
||||
|
||||
## Give us more info
|
||||
- Hello, we'd love to help but we need a little more information about the problem you're having. Screenshots, log outputs, or any reproducers would be very helpful.
|
||||
|
||||
## Receptor
|
||||
- You can find the receptor docs here: https://receptor.readthedocs.io/en/latest/
|
||||
- Hello, your issue seems related to receptor, could you please open an issue in the receptor repository? https://github.com/ansible/receptor. Thanks!
|
||||
|
||||
## Ansible Engine not AWX
|
||||
- Hello, your question seems to be about Ansible development, not about AWX. Try asking on the Ansible-devel specific mailing list: https://groups.google.com/g/ansible-devel
|
||||
- Hello, your question seems to be about using Ansible, not about AWX. https://groups.google.com/g/ansible-project is the best place to visit for user questions about Ansible. Thanks!
|
||||
|
||||
## Ansible Galaxy not AWX
|
||||
- Hey there, that sounds like an FAQ question, did this: https://www.ansible.com/products/awx-project/faq cover your question?
|
||||
|
||||
## Contributing Guidelines
|
||||
- AWX: https://github.com/ansible/awx/blob/devel/CONTRIBUTING.md
|
||||
- AWX-Operator: https://github.com/ansible/awx-operator/blob/devel/CONTRIBUTING.md
|
||||
|
||||
## Code of Conduct
|
||||
- Hello. Please keep in mind that Ansible adheres to a Code of Conduct in its community spaces. The spirit of the code of conduct is to be kind, and this is your friendly reminder to be so. Please see the full code of conduct here if you have questions: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html
|
||||
|
||||
## AWX Release
|
||||
- Hi all,\
|
||||
\
|
||||
We're happy to announce that the next release of AWX, version 21.0.0 is now available!\
|
||||
In addition AWX Operator version 0.21.0 has also been release!\
|
||||
\
|
||||
Please see the releases pages for more details:\
|
||||
AWX: https://github.com/ansible/awx/releases/tag/21.0.0\
|
||||
Operator: https://github.com/ansible/awx-operator/releases/tag/0.20.1\
|
||||
\
|
||||
The AWX team.
|
||||
|
||||
## Try latest version
|
||||
- Hello, this issue pertains to an older version of AWX. Try upgrading to the lastest version and see if that resolves your issue.
|
||||
@@ -1,11 +1,13 @@
|
||||
---
|
||||
name: Push Development Image
|
||||
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
|
||||
@@ -27,12 +29,15 @@ jobs:
|
||||
|
||||
- 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_devel:${GITHUB_REF##*/} || :
|
||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_kube_devel:${GITHUB_REF##*/} || :
|
||||
|
||||
- name: Build image
|
||||
- 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##*/}
|
||||
1
.github/workflows/label_issue.yml
vendored
1
.github/workflows/label_issue.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- edited
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
|
||||
3
.github/workflows/stage.yml
vendored
3
.github/workflows/stage.yml
vendored
@@ -83,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
|
||||
|
||||
|
||||
2
.github/workflows/upload_schema.yml
vendored
2
.github/workflows/upload_schema.yml
vendored
@@ -4,7 +4,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- devel
|
||||
- release_4.1
|
||||
- release_**
|
||||
jobs:
|
||||
push:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,6 +7,9 @@ reference-schema.json
|
||||
.tags
|
||||
.tags1
|
||||
|
||||
# User level pre-commit hooks
|
||||
pre-commit-user
|
||||
|
||||
# Tower
|
||||
awx-dev
|
||||
awx/settings/local_*.py*
|
||||
@@ -35,7 +38,7 @@ awx/ui/build
|
||||
awx/ui/.env.local
|
||||
awx/ui/instrumented
|
||||
rsyslog.pid
|
||||
tools/prometheus/data
|
||||
tools/prometheus
|
||||
tools/docker-compose/ansible/awx_dump.sql
|
||||
tools/docker-compose/Dockerfile
|
||||
tools/docker-compose/_build
|
||||
|
||||
@@ -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).
|
||||
|
||||
33
Makefile
33
Makefile
@@ -13,10 +13,14 @@ COMPOSE_TAG ?= $(GIT_BRANCH)
|
||||
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
|
||||
# If set to true docker-compose will also start a splunk instance
|
||||
SPLUNK ?= 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
|
||||
@@ -26,7 +30,7 @@ RECEPTOR_IMAGE ?= quay.io/ansible/receptor:devel
|
||||
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
|
||||
|
||||
@@ -175,7 +179,7 @@ collectstatic:
|
||||
fi; \
|
||||
mkdir -p awx/public/static && $(PYTHON) manage.py collectstatic --clear --noinput > /dev/null 2>&1
|
||||
|
||||
UWSGI_DEV_RELOAD_COMMAND ?= supervisorctl restart tower-processes:awx-dispatcher tower-processes:awx-receiver
|
||||
DEV_RELOAD_COMMAND ?= supervisorctl restart tower-processes:*
|
||||
|
||||
uwsgi: collectstatic
|
||||
@if [ "$(VENV_BASE)" ]; then \
|
||||
@@ -190,12 +194,13 @@ uwsgi: collectstatic
|
||||
--processes=5 \
|
||||
--harakiri=120 --master \
|
||||
--no-orphans \
|
||||
--py-autoreload 1 \
|
||||
--max-requests=1000 \
|
||||
--stats /tmp/stats.socket \
|
||||
--lazy-apps \
|
||||
--logformat "%(addr) %(method) %(uri) - %(proto) %(status)" \
|
||||
--hook-accepting1="exec: $(UWSGI_DEV_RELOAD_COMMAND)"
|
||||
--logformat "%(addr) %(method) %(uri) - %(proto) %(status)"
|
||||
|
||||
awx-autoreload:
|
||||
@/awx_devel/tools/docker-compose/awx-autoreload /awx_devel "$(DEV_RELOAD_COMMAND)"
|
||||
|
||||
daphne:
|
||||
@if [ "$(VENV_BASE)" ]; then \
|
||||
@@ -413,7 +418,7 @@ 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:
|
||||
$(PYTHON) setup.py dev_build
|
||||
@@ -462,7 +467,9 @@ docker-compose-sources: .git/hooks/pre-commit
|
||||
-e control_plane_node_count=$(CONTROL_PLANE_NODE_COUNT) \
|
||||
-e execution_node_count=$(EXECUTION_NODE_COUNT) \
|
||||
-e minikube_container_group=$(MINIKUBE_CONTAINER_GROUP) \
|
||||
-e enable_keycloak=$(KEYCLOAK)
|
||||
-e enable_keycloak=$(KEYCLOAK) \
|
||||
-e enable_ldap=$(LDAP) \
|
||||
-e enable_splunk=$(SPLUNK)
|
||||
|
||||
|
||||
docker-compose: awx/projects docker-compose-sources
|
||||
@@ -522,7 +529,12 @@ docker-compose-cluster-elk: awx/projects docker-compose-sources
|
||||
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link-cluster.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
|
||||
|
||||
prometheus:
|
||||
docker run -u0 --net=tools_default --link=`docker ps | egrep -o "tools_awx(_run)?_([^ ]+)?"`:awxweb --volume `pwd`/tools/prometheus:/prometheus --name prometheus -d -p 0.0.0.0:9090:9090 prom/prometheus --web.enable-lifecycle --config.file=/prometheus/prometheus.yml
|
||||
docker volume create prometheus
|
||||
docker run -d --rm --net=_sources_default --link=awx_1:awx1 --volume prometheus-storage:/prometheus --volume `pwd`/tools/prometheus:/etc/prometheus --name prometheus -p 9090:9090 prom/prometheus
|
||||
|
||||
grafana:
|
||||
docker volume create grafana
|
||||
docker run -d --rm --net=_sources_default --volume grafana-storage:/var/lib/grafana --volume `pwd`/tools/grafana:/etc/grafana/provisioning --name grafana -p 3001:3000 grafana/grafana-enterprise
|
||||
|
||||
docker-compose-container-group:
|
||||
MINIKUBE_CONTAINER_GROUP=true make docker-compose
|
||||
@@ -555,8 +567,9 @@ Dockerfile.kube-dev: tools/ansible/roles/dockerfile/templates/Dockerfile.j2
|
||||
-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) .
|
||||
|
||||
|
||||
|
||||
3
SECURITY.md
Normal file
3
SECURITY.md
Normal 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
|
||||
@@ -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
|
||||
@@ -79,9 +78,10 @@ def oauth2_getattribute(self, attr):
|
||||
# Custom method to override
|
||||
# oauth2_provider.settings.OAuth2ProviderSettings.__getattribute__
|
||||
from django.conf import settings
|
||||
from oauth2_provider.settings import DEFAULTS
|
||||
|
||||
val = None
|
||||
if 'migrate' not in sys.argv:
|
||||
if (isinstance(attr, str)) and (attr in DEFAULTS) and (not attr.startswith('_')):
|
||||
# certain Django OAuth Toolkit migrations actually reference
|
||||
# setting lookups for references to model classes (e.g.,
|
||||
# oauth2_settings.REFRESH_TOKEN_MODEL)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
@@ -395,11 +398,11 @@ class OrderByBackend(BaseFilterBackend):
|
||||
order_by = value.split(',')
|
||||
else:
|
||||
order_by = (value,)
|
||||
if order_by is None:
|
||||
order_by = self.get_default_ordering(view)
|
||||
default_order_by = self.get_default_ordering(view)
|
||||
# glue the order by and default order by together so that the default is the backup option
|
||||
order_by = list(order_by or []) + list(default_order_by or [])
|
||||
if order_by:
|
||||
order_by = self._validate_ordering_fields(queryset.model, order_by)
|
||||
|
||||
# Special handling of the type field for ordering. In this
|
||||
# case, we're not sorting exactly on the type field, but
|
||||
# given the limited number of views with multiple types,
|
||||
|
||||
@@ -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
|
||||
@@ -93,10 +93,10 @@ 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'))
|
||||
@@ -104,7 +104,7 @@ class LoggedLoginView(auth_views.LoginView):
|
||||
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
|
||||
|
||||
@@ -392,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()
|
||||
@@ -524,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
|
||||
@@ -638,6 +638,11 @@ class SubListCreateAttachDetachAPIView(SubListCreateAPIView):
|
||||
# attaching/detaching them from the parent.
|
||||
|
||||
def is_valid_relation(self, parent, sub, created=False):
|
||||
"Override in subclasses to do efficient validation of attaching"
|
||||
return None
|
||||
|
||||
def is_valid_removal(self, parent, sub):
|
||||
"Same as is_valid_relation but called on disassociation"
|
||||
return None
|
||||
|
||||
def get_description_context(self):
|
||||
@@ -722,6 +727,11 @@ class SubListCreateAttachDetachAPIView(SubListCreateAPIView):
|
||||
if not request.user.can_access(self.parent_model, 'unattach', parent, sub, self.relationship, request.data):
|
||||
raise PermissionDenied()
|
||||
|
||||
# Verify that removing the relationship is valid.
|
||||
unattach_errors = self.is_valid_removal(parent, sub)
|
||||
if unattach_errors is not None:
|
||||
return Response(unattach_errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
if parent_key:
|
||||
sub.delete()
|
||||
else:
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -250,13 +248,6 @@ class IsSystemAdminOrAuditor(permissions.BasePermission):
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
@@ -97,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,
|
||||
@@ -113,6 +113,7 @@ from awx.main.utils import (
|
||||
)
|
||||
from awx.main.utils.filters import SmartFilter
|
||||
from awx.main.utils.named_url_graph import reset_counters
|
||||
from awx.main.scheduler.task_manager_models import TaskManagerInstanceGroups, TaskManagerInstances
|
||||
from awx.main.redact import UriCleaner, REPLACE_STR
|
||||
|
||||
from awx.main.validators import vars_validate_or_raise
|
||||
@@ -357,7 +358,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
|
||||
|
||||
@@ -645,7 +646,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
|
||||
|
||||
@@ -1263,6 +1264,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):
|
||||
@@ -1600,7 +1607,6 @@ class ProjectUpdateSerializer(UnifiedJobSerializer, ProjectOptionsSerializer):
|
||||
|
||||
class ProjectUpdateDetailSerializer(ProjectUpdateSerializer):
|
||||
|
||||
host_status_counts = serializers.SerializerMethodField(help_text=_('A count of hosts uniquely assigned to each status.'))
|
||||
playbook_counts = serializers.SerializerMethodField(help_text=_('A count of all plays and tasks for the job run.'))
|
||||
|
||||
class Meta:
|
||||
@@ -1615,14 +1621,6 @@ class ProjectUpdateDetailSerializer(ProjectUpdateSerializer):
|
||||
|
||||
return data
|
||||
|
||||
def get_host_status_counts(self, obj):
|
||||
try:
|
||||
counts = obj.project_update_events.only('event_data').get(event='playbook_on_stats').get_host_status_counts()
|
||||
except ProjectUpdateEvent.DoesNotExist:
|
||||
counts = {}
|
||||
|
||||
return counts
|
||||
|
||||
|
||||
class ProjectUpdateListSerializer(ProjectUpdateSerializer, UnifiedJobListSerializer):
|
||||
class Meta:
|
||||
@@ -1718,7 +1716,7 @@ class InventorySerializer(LabelsListMixin, 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
|
||||
@@ -1847,11 +1845,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
|
||||
@@ -1865,13 +1863,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)
|
||||
@@ -1944,7 +1942,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.'))
|
||||
@@ -2666,6 +2664,13 @@ class CredentialSerializer(BaseSerializer):
|
||||
|
||||
return credential_type
|
||||
|
||||
def validate_inputs(self, inputs):
|
||||
if self.instance and self.instance.credential_type.kind == "vault":
|
||||
if 'vault_id' in inputs and inputs['vault_id'] != self.instance.inputs['vault_id']:
|
||||
raise ValidationError(_('Vault IDs cannot be changed once they have been created.'))
|
||||
|
||||
return inputs
|
||||
|
||||
|
||||
class CredentialSerializerCreate(CredentialSerializer):
|
||||
|
||||
@@ -2838,8 +2843,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.')})
|
||||
@@ -3100,7 +3105,6 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
||||
|
||||
class JobDetailSerializer(JobSerializer):
|
||||
|
||||
host_status_counts = serializers.SerializerMethodField(help_text=_('A count of hosts uniquely assigned to each status.'))
|
||||
playbook_counts = serializers.SerializerMethodField(help_text=_('A count of all plays and tasks for the job run.'))
|
||||
custom_virtualenv = serializers.ReadOnlyField()
|
||||
|
||||
@@ -3116,14 +3120,6 @@ class JobDetailSerializer(JobSerializer):
|
||||
|
||||
return data
|
||||
|
||||
def get_host_status_counts(self, obj):
|
||||
try:
|
||||
counts = obj.get_event_queryset().only('event_data').get(event='playbook_on_stats').get_host_status_counts()
|
||||
except JobEvent.DoesNotExist:
|
||||
counts = {}
|
||||
|
||||
return counts
|
||||
|
||||
|
||||
class JobCancelSerializer(BaseSerializer):
|
||||
|
||||
@@ -3312,21 +3308,10 @@ class AdHocCommandSerializer(UnifiedJobSerializer):
|
||||
|
||||
|
||||
class AdHocCommandDetailSerializer(AdHocCommandSerializer):
|
||||
|
||||
host_status_counts = serializers.SerializerMethodField(help_text=_('A count of hosts uniquely assigned to each status.'))
|
||||
|
||||
class Meta:
|
||||
model = AdHocCommand
|
||||
fields = ('*', 'host_status_counts')
|
||||
|
||||
def get_host_status_counts(self, obj):
|
||||
try:
|
||||
counts = obj.ad_hoc_command_events.only('event_data').get(event='playbook_on_stats').get_host_status_counts()
|
||||
except AdHocCommandEvent.DoesNotExist:
|
||||
counts = {}
|
||||
|
||||
return counts
|
||||
|
||||
|
||||
class AdHocCommandCancelSerializer(AdHocCommandSerializer):
|
||||
|
||||
@@ -3628,7 +3613,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 = ()
|
||||
|
||||
@@ -4638,61 +4623,60 @@ class SchedulePreviewSerializer(BaseSerializer):
|
||||
|
||||
# We reject rrules if:
|
||||
# - DTSTART is not include
|
||||
# - INTERVAL is not included
|
||||
# - SECONDLY is used
|
||||
# - TZID is used
|
||||
# - BYDAY prefixed with a number (MO is good but not 20MO)
|
||||
# - BYYEARDAY
|
||||
# - BYWEEKNO
|
||||
# - Multiple DTSTART or RRULE elements
|
||||
# - Can't contain both COUNT and UNTIL
|
||||
# - COUNT > 999
|
||||
# - Multiple DTSTART
|
||||
# - At least one of RRULE is not included
|
||||
# - EXDATE or RDATE is included
|
||||
# For any rule in the ruleset:
|
||||
# - INTERVAL is not included
|
||||
# - SECONDLY is used
|
||||
# - BYDAY prefixed with a number (MO is good but not 20MO)
|
||||
# - Can't contain both COUNT and UNTIL
|
||||
# - COUNT > 999
|
||||
def validate_rrule(self, value):
|
||||
rrule_value = value
|
||||
multi_by_month_day = r".*?BYMONTHDAY[\:\=][0-9]+,-*[0-9]+"
|
||||
multi_by_month = r".*?BYMONTH[\:\=][0-9]+,[0-9]+"
|
||||
by_day_with_numeric_prefix = r".*?BYDAY[\:\=][0-9]+[a-zA-Z]{2}"
|
||||
match_count = re.match(r".*?(COUNT\=[0-9]+)", rrule_value)
|
||||
match_multiple_dtstart = re.findall(r".*?(DTSTART(;[^:]+)?\:[0-9]+T[0-9]+Z?)", rrule_value)
|
||||
match_native_dtstart = re.findall(r".*?(DTSTART:[0-9]+T[0-9]+) ", rrule_value)
|
||||
match_multiple_rrule = re.findall(r".*?(RRULE\:)", rrule_value)
|
||||
match_multiple_rrule = re.findall(r".*?(RULE\:[^\s]*)", rrule_value)
|
||||
errors = []
|
||||
if not len(match_multiple_dtstart):
|
||||
raise serializers.ValidationError(_('Valid DTSTART required in rrule. Value should start with: DTSTART:YYYYMMDDTHHMMSSZ'))
|
||||
errors.append(_('Valid DTSTART required in rrule. Value should start with: DTSTART:YYYYMMDDTHHMMSSZ'))
|
||||
if len(match_native_dtstart):
|
||||
raise serializers.ValidationError(_('DTSTART cannot be a naive datetime. Specify ;TZINFO= or YYYYMMDDTHHMMSSZZ.'))
|
||||
errors.append(_('DTSTART cannot be a naive datetime. Specify ;TZINFO= or YYYYMMDDTHHMMSSZZ.'))
|
||||
if len(match_multiple_dtstart) > 1:
|
||||
raise serializers.ValidationError(_('Multiple DTSTART is not supported.'))
|
||||
if not len(match_multiple_rrule):
|
||||
raise serializers.ValidationError(_('RRULE required in rrule.'))
|
||||
if len(match_multiple_rrule) > 1:
|
||||
raise serializers.ValidationError(_('Multiple RRULE is not supported.'))
|
||||
if 'interval' not in rrule_value.lower():
|
||||
raise serializers.ValidationError(_('INTERVAL required in rrule.'))
|
||||
if 'secondly' in rrule_value.lower():
|
||||
raise serializers.ValidationError(_('SECONDLY is not supported.'))
|
||||
if re.match(multi_by_month_day, rrule_value):
|
||||
raise serializers.ValidationError(_('Multiple BYMONTHDAYs not supported.'))
|
||||
if re.match(multi_by_month, rrule_value):
|
||||
raise serializers.ValidationError(_('Multiple BYMONTHs not supported.'))
|
||||
if re.match(by_day_with_numeric_prefix, rrule_value):
|
||||
raise serializers.ValidationError(_("BYDAY with numeric prefix not supported."))
|
||||
if 'byyearday' in rrule_value.lower():
|
||||
raise serializers.ValidationError(_("BYYEARDAY not supported."))
|
||||
if 'byweekno' in rrule_value.lower():
|
||||
raise serializers.ValidationError(_("BYWEEKNO not supported."))
|
||||
if 'COUNT' in rrule_value and 'UNTIL' in rrule_value:
|
||||
raise serializers.ValidationError(_("RRULE may not contain both COUNT and UNTIL"))
|
||||
if match_count:
|
||||
count_val = match_count.groups()[0].strip().split("=")
|
||||
if int(count_val[1]) > 999:
|
||||
raise serializers.ValidationError(_("COUNT > 999 is unsupported."))
|
||||
errors.append(_('Multiple DTSTART is not supported.'))
|
||||
if "rrule:" not in rrule_value.lower():
|
||||
errors.append(_('One or more rule required in rrule.'))
|
||||
if "exdate:" in rrule_value.lower():
|
||||
raise serializers.ValidationError(_('EXDATE not allowed in rrule.'))
|
||||
if "rdate:" in rrule_value.lower():
|
||||
raise serializers.ValidationError(_('RDATE not allowed in rrule.'))
|
||||
for a_rule in match_multiple_rrule:
|
||||
if 'interval' not in a_rule.lower():
|
||||
errors.append("{0}: {1}".format(_('INTERVAL required in rrule'), a_rule))
|
||||
elif 'secondly' in a_rule.lower():
|
||||
errors.append("{0}: {1}".format(_('SECONDLY is not supported'), a_rule))
|
||||
if re.match(by_day_with_numeric_prefix, a_rule):
|
||||
errors.append("{0}: {1}".format(_("BYDAY with numeric prefix not supported"), a_rule))
|
||||
if 'COUNT' in a_rule and 'UNTIL' in a_rule:
|
||||
errors.append("{0}: {1}".format(_("RRULE may not contain both COUNT and UNTIL"), a_rule))
|
||||
match_count = re.match(r".*?(COUNT\=[0-9]+)", a_rule)
|
||||
if match_count:
|
||||
count_val = match_count.groups()[0].strip().split("=")
|
||||
if int(count_val[1]) > 999:
|
||||
errors.append("{0}: {1}".format(_("COUNT > 999 is unsupported"), a_rule))
|
||||
|
||||
try:
|
||||
Schedule.rrulestr(rrule_value)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
logger.error(traceback.format_exc())
|
||||
raise serializers.ValidationError(_("rrule parsing failed validation: {}").format(e))
|
||||
errors.append(_("rrule parsing failed validation: {}").format(e))
|
||||
|
||||
if errors:
|
||||
raise serializers.ValidationError(errors)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
@@ -4850,6 +4834,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:
|
||||
@@ -4862,7 +4851,6 @@ class InstanceGroupSerializer(BaseSerializer):
|
||||
|
||||
show_capabilities = ['edit', 'delete']
|
||||
|
||||
committed_capacity = serializers.SerializerMethodField()
|
||||
consumed_capacity = serializers.SerializerMethodField()
|
||||
percent_capacity_remaining = serializers.SerializerMethodField()
|
||||
jobs_running = serializers.IntegerField(
|
||||
@@ -4911,7 +4899,6 @@ class InstanceGroupSerializer(BaseSerializer):
|
||||
"created",
|
||||
"modified",
|
||||
"capacity",
|
||||
"committed_capacity",
|
||||
"consumed_capacity",
|
||||
"percent_capacity_remaining",
|
||||
"jobs_running",
|
||||
@@ -4936,6 +4923,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))
|
||||
@@ -4946,6 +4936,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
|
||||
@@ -4964,6 +4959,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'))
|
||||
@@ -4977,30 +4979,29 @@ class InstanceGroupSerializer(BaseSerializer):
|
||||
|
||||
return attrs
|
||||
|
||||
def get_capacity_dict(self):
|
||||
def get_ig_mgr(self):
|
||||
# Store capacity values (globally computed) in the context
|
||||
if 'capacity_map' not in self.context:
|
||||
ig_qs = None
|
||||
if 'task_manager_igs' not in self.context:
|
||||
instance_groups_queryset = None
|
||||
jobs_qs = UnifiedJob.objects.filter(status__in=('running', 'waiting'))
|
||||
if self.parent: # Is ListView:
|
||||
ig_qs = self.parent.instance
|
||||
self.context['capacity_map'] = InstanceGroup.objects.capacity_values(qs=ig_qs, tasks=jobs_qs, breakdown=True)
|
||||
return self.context['capacity_map']
|
||||
instance_groups_queryset = self.parent.instance
|
||||
|
||||
instances = TaskManagerInstances(jobs_qs)
|
||||
instance_groups = TaskManagerInstanceGroups(instances_by_hostname=instances, instance_groups_queryset=instance_groups_queryset)
|
||||
|
||||
self.context['task_manager_igs'] = instance_groups
|
||||
return self.context['task_manager_igs']
|
||||
|
||||
def get_consumed_capacity(self, obj):
|
||||
return self.get_capacity_dict()[obj.name]['running_capacity']
|
||||
|
||||
def get_committed_capacity(self, obj):
|
||||
return self.get_capacity_dict()[obj.name]['committed_capacity']
|
||||
ig_mgr = self.get_ig_mgr()
|
||||
return ig_mgr.get_consumed_capacity(obj.name)
|
||||
|
||||
def get_percent_capacity_remaining(self, obj):
|
||||
if not obj.capacity:
|
||||
return 0.0
|
||||
consumed = self.get_consumed_capacity(obj)
|
||||
if consumed >= obj.capacity:
|
||||
return 0.0
|
||||
else:
|
||||
return float("{0:.2f}".format(((float(obj.capacity) - float(consumed)) / (float(obj.capacity))) * 100))
|
||||
ig_mgr = self.get_ig_mgr()
|
||||
return float("{0:.2f}".format((float(ig_mgr.get_remaining_capacity(obj.name)) / (float(obj.capacity))) * 100))
|
||||
|
||||
def get_instances(self, obj):
|
||||
return obj.instances.count()
|
||||
@@ -5078,7 +5079,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):
|
||||
|
||||
102
awx/api/templates/api/job_job_events_children_summary.md
Normal file
102
awx/api/templates/api/job_job_events_children_summary.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# View a summary of children events
|
||||
|
||||
Special view to facilitate processing job output in the UI.
|
||||
In order to collapse events and their children, the UI needs to know how
|
||||
many children exist for a given event.
|
||||
The UI also needs to know the order of the event (0 based index), which
|
||||
usually matches the counter, but not always.
|
||||
This view returns a JSON object where the key is the event counter, and the value
|
||||
includes the number of children (and grandchildren) events.
|
||||
Only events with children are included in the output.
|
||||
|
||||
## Example
|
||||
|
||||
e.g. Demo Job Template job
|
||||
tuple(event counter, uuid, parent_uuid)
|
||||
|
||||
```
|
||||
(1, '4598d19e-93b4-4e33-a0ae-b387a7348964', '')
|
||||
(2, 'aae0d189-e3cb-102a-9f00-000000000006', '4598d19e-93b4-4e33-a0ae-b387a7348964')
|
||||
(3, 'aae0d189-e3cb-102a-9f00-00000000000c', 'aae0d189-e3cb-102a-9f00-000000000006')
|
||||
(4, 'f4194f14-e406-4124-8519-0fdb08b18f4b', 'aae0d189-e3cb-102a-9f00-00000000000c')
|
||||
(5, '39f7ad99-dbf3-41e0-93f8-9999db4004f2', 'aae0d189-e3cb-102a-9f00-00000000000c')
|
||||
(6, 'aae0d189-e3cb-102a-9f00-000000000008', 'aae0d189-e3cb-102a-9f00-000000000006')
|
||||
(7, '39a49992-5ca4-4b6c-b178-e56d0b0333da', 'aae0d189-e3cb-102a-9f00-000000000008')
|
||||
(8, '504f3b28-3ea8-4f6f-bd82-60cf8e807cc0', 'aae0d189-e3cb-102a-9f00-000000000008')
|
||||
(9, 'a242be54-ebe6-4021-afab-f2878bff2e9f', '4598d19e-93b4-4e33-a0ae-b387a7348964')
|
||||
```
|
||||
|
||||
output
|
||||
|
||||
```
|
||||
{
|
||||
"1": {
|
||||
"rowNumber": 0,
|
||||
"numChildren": 8
|
||||
},
|
||||
"2": {
|
||||
"rowNumber": 1,
|
||||
"numChildren": 6
|
||||
},
|
||||
"3": {
|
||||
"rowNumber": 2,
|
||||
"numChildren": 2
|
||||
},
|
||||
"6": {
|
||||
"rowNumber": 5,
|
||||
"numChildren": 2
|
||||
}
|
||||
}
|
||||
"meta_event_nested_parent_uuid": {}
|
||||
}
|
||||
```
|
||||
|
||||
counter 1 is event 0, and has 8 children
|
||||
counter 2 is event 1, and has 6 children
|
||||
etc.
|
||||
|
||||
The UI also needs to be able to collapse over "meta" events -- events that
|
||||
show up due to verbosity or warnings from the system while the play is running.
|
||||
These events have a 0 level event, with no parent uuid.
|
||||
|
||||
```
|
||||
playbook_on_start
|
||||
verbose
|
||||
playbook_on_play_start
|
||||
playbook_on_task_start
|
||||
runner_on_start <- level 3
|
||||
verbose <- jump to level 0
|
||||
verbose
|
||||
runner_on_ok <- jump back to level 3
|
||||
playbook_on_task_start
|
||||
runner_on_start
|
||||
runner_on_ok
|
||||
verbose
|
||||
verbose
|
||||
playbook_on_stats
|
||||
```
|
||||
|
||||
These verbose statements that fall in the middle of a series of children events
|
||||
are problematic for the UI.
|
||||
To help, this view will attempt to place the events into the hierarchy, without
|
||||
the event level jumps.
|
||||
|
||||
```
|
||||
playbook_on_start
|
||||
verbose
|
||||
playbook_on_play_start
|
||||
playbook_on_task_start
|
||||
runner_on_start <- A
|
||||
verbose <- this maps to the uuid of A
|
||||
verbose
|
||||
runner_on_ok
|
||||
playbook_on_task_start <- B
|
||||
runner_on_start
|
||||
runner_on_ok
|
||||
verbose <- this maps to the uuid of B
|
||||
verbose
|
||||
playbook_on_stats
|
||||
```
|
||||
|
||||
The output will include a JSON object where the key is the event counter,
|
||||
and the value is the assigned nested uuid.
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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,
|
||||
@@ -26,24 +26,24 @@ from awx.api.views import (
|
||||
|
||||
|
||||
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]+)/labels/$', InventoryLabelList.as_view(), name='inventory_label_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']
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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,
|
||||
@@ -10,6 +10,7 @@ from awx.api.views import (
|
||||
JobRelaunch,
|
||||
JobCreateSchedule,
|
||||
JobJobHostSummariesList,
|
||||
JobJobEventsChildrenSummary,
|
||||
JobJobEventsList,
|
||||
JobActivityStreamList,
|
||||
JobStdout,
|
||||
@@ -20,18 +21,19 @@ 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]+)/job_events/children_summary/$', JobJobEventsChildrenSummary.as_view(), name='job_job_events_children_summary'),
|
||||
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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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 (
|
||||
@@ -74,78 +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'^mesh_visualizer/', MeshVisualizer.as_view(), name='mesh_visualizer_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')]
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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'),
|
||||
]
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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
|
||||
@@ -105,7 +105,6 @@ from awx.api.permissions import (
|
||||
ProjectUpdatePermission,
|
||||
InventoryInventorySourcesUpdatePermission,
|
||||
UserPermission,
|
||||
InstanceGroupTowerPermission,
|
||||
VariableDataPermission,
|
||||
WorkflowApprovalPermission,
|
||||
IsSystemAdminOrAuditor,
|
||||
@@ -173,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')
|
||||
@@ -365,6 +365,7 @@ class InstanceList(ListAPIView):
|
||||
model = models.Instance
|
||||
serializer_class = serializers.InstanceSerializer
|
||||
search_fields = ('hostname',)
|
||||
ordering = ('id',)
|
||||
|
||||
|
||||
class InstanceDetail(RetrieveUpdateAPIView):
|
||||
@@ -409,7 +410,15 @@ class InstanceInstanceGroupsList(InstanceGroupMembershipMixin, SubListCreateAtta
|
||||
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 {'msg': _(f"Cannot change instance group membership of hop node : {parent.hostname}.")}
|
||||
return None
|
||||
|
||||
def is_valid_removal(self, parent, sub):
|
||||
res = self.is_valid_relation(parent, sub)
|
||||
if res:
|
||||
return res
|
||||
if sub.name == settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME and parent.node_type == 'hybrid':
|
||||
return {'msg': _(f"Cannot disassociate hybrid instance {parent.hostname} from {sub.name}.")}
|
||||
return None
|
||||
|
||||
|
||||
@@ -480,7 +489,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:
|
||||
@@ -512,7 +520,15 @@ class InstanceGroupInstanceList(InstanceGroupMembershipMixin, SubListAttachDetac
|
||||
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 {'msg': _(f"Cannot change instance group membership of hop node : {sub.hostname}.")}
|
||||
return None
|
||||
|
||||
def is_valid_removal(self, parent, sub):
|
||||
res = self.is_valid_relation(parent, sub)
|
||||
if res:
|
||||
return res
|
||||
if sub.node_type == 'hybrid' and parent.name == settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME:
|
||||
return {'msg': _(f"Cannot disassociate hybrid node {sub.hostname} from {parent.name}.")}
|
||||
return None
|
||||
|
||||
|
||||
@@ -521,6 +537,7 @@ class ScheduleList(ListCreateAPIView):
|
||||
name = _("Schedules")
|
||||
model = models.Schedule
|
||||
serializer_class = serializers.ScheduleSerializer
|
||||
ordering = ('id',)
|
||||
|
||||
|
||||
class ScheduleDetail(RetrieveUpdateDestroyAPIView):
|
||||
@@ -1557,8 +1574,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)
|
||||
@@ -3826,6 +3844,84 @@ class JobJobEventsList(BaseJobEventsList):
|
||||
return job.get_event_queryset().select_related('host').order_by('start_line')
|
||||
|
||||
|
||||
class JobJobEventsChildrenSummary(APIView):
|
||||
|
||||
renderer_classes = [JSONRenderer]
|
||||
meta_events = ('debug', 'verbose', 'warning', 'error', 'system_warning', 'deprecated')
|
||||
|
||||
def get(self, request, **kwargs):
|
||||
resp = dict(children_summary={}, meta_event_nested_uuid={}, event_processing_finished=False)
|
||||
job = get_object_or_404(models.Job, pk=kwargs['pk'])
|
||||
if not job.event_processing_finished:
|
||||
return Response(resp)
|
||||
else:
|
||||
resp["event_processing_finished"] = True
|
||||
|
||||
events = list(job.get_event_queryset().values('counter', 'uuid', 'parent_uuid', 'event').order_by('counter'))
|
||||
if len(events) == 0:
|
||||
return Response(resp)
|
||||
|
||||
# key is counter, value is number of total children (including children of children, etc.)
|
||||
map_counter_children_tally = {i['counter']: {"rowNumber": 0, "numChildren": 0} for i in events}
|
||||
# key is uuid, value is counter
|
||||
map_uuid_counter = {i['uuid']: i['counter'] for i in events}
|
||||
# key is uuid, value is parent uuid. Used as a quick lookup
|
||||
map_uuid_puuid = {i['uuid']: i['parent_uuid'] for i in events}
|
||||
# key is counter of meta events (i.e. verbose), value is uuid of the assigned parent
|
||||
map_meta_counter_nested_uuid = {}
|
||||
|
||||
prev_non_meta_event = events[0]
|
||||
for i, e in enumerate(events):
|
||||
if not e['event'] in JobJobEventsChildrenSummary.meta_events:
|
||||
prev_non_meta_event = e
|
||||
if not e['uuid']:
|
||||
continue
|
||||
puuid = e['parent_uuid']
|
||||
|
||||
# if event is verbose (or debug, etc), we need to "assign" it a
|
||||
# parent. This code looks at the event level of the previous
|
||||
# non-verbose event, and the level of the next (by looking ahead)
|
||||
# non-verbose event. The verbose event is assigned the same parent
|
||||
# uuid of the higher level event.
|
||||
# e.g.
|
||||
# E1
|
||||
# E2
|
||||
# verbose
|
||||
# verbose <- we are on this event currently
|
||||
# E4
|
||||
# We'll compare E2 and E4, and the verbose event
|
||||
# will be assigned the parent uuid of E4 (higher event level)
|
||||
if e['event'] in JobJobEventsChildrenSummary.meta_events:
|
||||
event_level_before = models.JobEvent.LEVEL_FOR_EVENT[prev_non_meta_event['event']]
|
||||
# find next non meta event
|
||||
z = i
|
||||
next_non_meta_event = events[-1]
|
||||
while z < len(events):
|
||||
if events[z]['event'] not in JobJobEventsChildrenSummary.meta_events:
|
||||
next_non_meta_event = events[z]
|
||||
break
|
||||
z += 1
|
||||
event_level_after = models.JobEvent.LEVEL_FOR_EVENT[next_non_meta_event['event']]
|
||||
if event_level_after and event_level_after > event_level_before:
|
||||
puuid = next_non_meta_event['parent_uuid']
|
||||
else:
|
||||
puuid = prev_non_meta_event['parent_uuid']
|
||||
if puuid:
|
||||
map_meta_counter_nested_uuid[e['counter']] = puuid
|
||||
map_counter_children_tally[e['counter']]['rowNumber'] = i
|
||||
if not puuid:
|
||||
continue
|
||||
# now traverse up the parent, grandparent, etc. events and tally those
|
||||
while puuid:
|
||||
map_counter_children_tally[map_uuid_counter[puuid]]['numChildren'] += 1
|
||||
puuid = map_uuid_puuid.get(puuid, None)
|
||||
|
||||
# create new dictionary, dropping events with 0 children
|
||||
resp["children_summary"] = {k: v for k, v in map_counter_children_tally.items() if v['numChildren'] != 0}
|
||||
resp["meta_event_nested_uuid"] = map_meta_counter_nested_uuid
|
||||
return Response(resp)
|
||||
|
||||
|
||||
class AdHocCommandList(ListCreateAPIView):
|
||||
|
||||
model = models.AdHocCommand
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from awx.api.generics import APIView, Response
|
||||
from awx.api.permissions import IsSystemAdminOrAuditor
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -68,49 +68,27 @@ class InstanceGroupMembershipMixin(object):
|
||||
membership.
|
||||
"""
|
||||
|
||||
def attach_validate(self, request):
|
||||
parent = self.get_parent_object()
|
||||
sub_id, res = super().attach_validate(request)
|
||||
if res: # handle an error
|
||||
return sub_id, res
|
||||
sub = get_object_or_400(self.model, pk=sub_id)
|
||||
attach_errors = self.is_valid_relation(parent, sub)
|
||||
if attach_errors:
|
||||
return sub_id, Response(attach_errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
return sub_id, res
|
||||
|
||||
def attach(self, request, *args, **kwargs):
|
||||
response = super(InstanceGroupMembershipMixin, self).attach(request, *args, **kwargs)
|
||||
sub_id, res = self.attach_validate(request)
|
||||
if status.is_success(response.status_code):
|
||||
sub_id = request.data.get('id', None)
|
||||
if self.parent_model is Instance:
|
||||
inst_name = self.get_parent_object().hostname
|
||||
else:
|
||||
inst_name = get_object_or_400(self.model, pk=sub_id).hostname
|
||||
with transaction.atomic():
|
||||
ig_qs = InstanceGroup.objects.select_for_update()
|
||||
instance_groups_queryset = InstanceGroup.objects.select_for_update()
|
||||
if self.parent_model is Instance:
|
||||
ig_obj = get_object_or_400(ig_qs, pk=sub_id)
|
||||
ig_obj = get_object_or_400(instance_groups_queryset, pk=sub_id)
|
||||
else:
|
||||
# similar to get_parent_object, but selected for update
|
||||
parent_filter = {self.lookup_field: self.kwargs.get(self.lookup_field, None)}
|
||||
ig_obj = get_object_or_404(ig_qs, **parent_filter)
|
||||
ig_obj = get_object_or_404(instance_groups_queryset, **parent_filter)
|
||||
if inst_name not in ig_obj.policy_instance_list:
|
||||
ig_obj.policy_instance_list.append(inst_name)
|
||||
ig_obj.save(update_fields=['policy_instance_list'])
|
||||
return response
|
||||
|
||||
def unattach_validate(self, request):
|
||||
parent = self.get_parent_object()
|
||||
(sub_id, res) = super(InstanceGroupMembershipMixin, self).unattach_validate(request)
|
||||
if res:
|
||||
return (sub_id, res)
|
||||
sub = get_object_or_400(self.model, pk=sub_id)
|
||||
attach_errors = self.is_valid_relation(parent, sub)
|
||||
if attach_errors:
|
||||
return (sub_id, Response(attach_errors, status=status.HTTP_400_BAD_REQUEST))
|
||||
return (sub_id, res)
|
||||
|
||||
def unattach(self, request, *args, **kwargs):
|
||||
response = super(InstanceGroupMembershipMixin, self).unattach(request, *args, **kwargs)
|
||||
if status.is_success(response.status_code):
|
||||
@@ -120,13 +98,13 @@ class InstanceGroupMembershipMixin(object):
|
||||
else:
|
||||
inst_name = get_object_or_400(self.model, pk=sub_id).hostname
|
||||
with transaction.atomic():
|
||||
ig_qs = InstanceGroup.objects.select_for_update()
|
||||
instance_groups_queryset = InstanceGroup.objects.select_for_update()
|
||||
if self.parent_model is Instance:
|
||||
ig_obj = get_object_or_400(ig_qs, pk=sub_id)
|
||||
ig_obj = get_object_or_400(instance_groups_queryset, pk=sub_id)
|
||||
else:
|
||||
# similar to get_parent_object, but selected for update
|
||||
parent_filter = {self.lookup_field: self.kwargs.get(self.lookup_field, None)}
|
||||
ig_obj = get_object_or_404(ig_qs, **parent_filter)
|
||||
ig_obj = get_object_or_404(instance_groups_queryset, **parent_filter)
|
||||
if inst_name in ig_obj.policy_instance_list:
|
||||
ig_obj.policy_instance_list.pop(ig_obj.policy_instance_list.index(inst_name))
|
||||
ig_obj.save(update_fields=['policy_instance_list'])
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
@@ -205,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)
|
||||
@@ -246,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:
|
||||
@@ -322,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)
|
||||
@@ -346,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()
|
||||
@@ -357,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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,10 +7,10 @@ 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
|
||||
@@ -65,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)
|
||||
@@ -82,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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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))]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Python
|
||||
import contextlib
|
||||
import logging
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import os
|
||||
@@ -31,7 +30,7 @@ from awx.conf.models import Setting
|
||||
|
||||
logger = logging.getLogger('awx.conf.settings')
|
||||
|
||||
SETTING_MEMORY_TTL = 5 if 'callback_receiver' in ' '.join(sys.argv) else 0
|
||||
SETTING_MEMORY_TTL = 5
|
||||
|
||||
# Store a special value to indicate when a setting is not set in the database.
|
||||
SETTING_CACHE_NOTSET = '___notset___'
|
||||
@@ -81,17 +80,16 @@ def _ctit_db_wrapper(trans_safe=False):
|
||||
yield
|
||||
except DBError as exc:
|
||||
if trans_safe:
|
||||
if 'migrate' not in sys.argv and 'check_migrations' not in sys.argv:
|
||||
level = logger.exception
|
||||
if isinstance(exc, ProgrammingError):
|
||||
if 'relation' in str(exc) and 'does not exist' in str(exc):
|
||||
# this generally means we can't fetch Tower configuration
|
||||
# because the database hasn't actually finished migrating yet;
|
||||
# this is usually a sign that a service in a container (such as ws_broadcast)
|
||||
# has come up *before* the database has finished migrating, and
|
||||
# especially that the conf.settings table doesn't exist yet
|
||||
level = logger.debug
|
||||
level('Database settings are not available, using defaults.')
|
||||
level = logger.exception
|
||||
if isinstance(exc, ProgrammingError):
|
||||
if 'relation' in str(exc) and 'does not exist' in str(exc):
|
||||
# this generally means we can't fetch Tower configuration
|
||||
# because the database hasn't actually finished migrating yet;
|
||||
# this is usually a sign that a service in a container (such as ws_broadcast)
|
||||
# has come up *before* the database has finished migrating, and
|
||||
# especially that the conf.settings table doesn't exist yet
|
||||
level = logger.debug
|
||||
level('Database settings are not available, using defaults.')
|
||||
else:
|
||||
logger.exception('Error modifying something related to database settings.')
|
||||
finally:
|
||||
@@ -235,6 +233,8 @@ class SettingsWrapper(UserSettingsHolder):
|
||||
self.__dict__['_awx_conf_init_readonly'] = False
|
||||
self.__dict__['cache'] = EncryptedCacheProxy(cache, registry)
|
||||
self.__dict__['registry'] = registry
|
||||
self.__dict__['_awx_conf_memoizedcache'] = cachetools.TTLCache(maxsize=2048, ttl=SETTING_MEMORY_TTL)
|
||||
self.__dict__['_awx_conf_memoizedcache_lock'] = threading.Lock()
|
||||
|
||||
# record the current pid so we compare it post-fork for
|
||||
# processes like the dispatcher and callback receiver
|
||||
@@ -397,12 +397,20 @@ class SettingsWrapper(UserSettingsHolder):
|
||||
def SETTINGS_MODULE(self):
|
||||
return self._get_default('SETTINGS_MODULE')
|
||||
|
||||
@cachetools.cached(cache=cachetools.TTLCache(maxsize=2048, ttl=SETTING_MEMORY_TTL))
|
||||
@cachetools.cachedmethod(
|
||||
cache=lambda self: self.__dict__['_awx_conf_memoizedcache'],
|
||||
key=lambda *args, **kwargs: SettingsWrapper.hashkey(*args, **kwargs),
|
||||
lock=lambda self: self.__dict__['_awx_conf_memoizedcache_lock'],
|
||||
)
|
||||
def _get_local_with_cache(self, name):
|
||||
"""Get value while accepting the in-memory cache if key is available"""
|
||||
with _ctit_db_wrapper(trans_safe=True):
|
||||
return self._get_local(name)
|
||||
|
||||
def __getattr__(self, name):
|
||||
value = empty
|
||||
if name in self.all_supported_settings:
|
||||
with _ctit_db_wrapper(trans_safe=True):
|
||||
value = self._get_local(name)
|
||||
value = self._get_local_with_cache(name)
|
||||
if value is not empty:
|
||||
return value
|
||||
return self._get_default(name)
|
||||
@@ -476,6 +484,23 @@ class SettingsWrapper(UserSettingsHolder):
|
||||
set_on_default = getattr(self.default_settings, 'is_overridden', lambda s: False)(setting)
|
||||
return set_locally or set_on_default
|
||||
|
||||
@classmethod
|
||||
def hashkey(cls, *args, **kwargs):
|
||||
"""
|
||||
Usage of @cachetools.cached has changed to @cachetools.cachedmethod
|
||||
The previous cachetools decorator called the hash function and passed in (self, key).
|
||||
The new cachtools decorator calls the hash function with just (key).
|
||||
Ideally, we would continue to pass self, however, the cachetools decorator interface
|
||||
does not allow us to.
|
||||
|
||||
This hashkey function is to maintain that the key generated looks like
|
||||
('<SettingsWrapper>', key). The thought is that maybe it is important to namespace
|
||||
our cache to the SettingsWrapper scope in case some other usage of this cache exists.
|
||||
I can not think of how any other system could and would use our private cache, but
|
||||
for safety sake we are ensuring the key schema does not change.
|
||||
"""
|
||||
return cachetools.keys.hashkey(f"<{cls.__name__}>", *args, **kwargs)
|
||||
|
||||
|
||||
def __getattr_without_cache__(self, name):
|
||||
# Django 1.10 added an optimization to settings lookup:
|
||||
|
||||
@@ -28,6 +28,9 @@ def handle_setting_change(key, for_delete=False):
|
||||
cache_keys = {Setting.get_cache_key(k) for k in setting_keys}
|
||||
cache.delete_many(cache_keys)
|
||||
|
||||
# if we have changed a setting, we want to avoid mucking with the in-memory cache entirely
|
||||
settings._awx_conf_memoizedcache.clear()
|
||||
|
||||
# Send setting_changed signal with new value for each setting.
|
||||
for setting_key in setting_keys:
|
||||
setting_changed.send(sender=Setting, setting=setting_key, value=getattr(settings, setting_key, None), enter=not bool(for_delete))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ import codecs
|
||||
from uuid import uuid4
|
||||
import time
|
||||
|
||||
from unittest import mock
|
||||
|
||||
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
|
||||
@@ -299,3 +301,33 @@ def test_readonly_sensitive_cache_data_is_encrypted(settings):
|
||||
cache.set('AWX_ENCRYPTED', 'SECRET!')
|
||||
assert cache.get('AWX_ENCRYPTED') == 'SECRET!'
|
||||
assert native_cache.get('AWX_ENCRYPTED') == 'FRPERG!'
|
||||
|
||||
|
||||
@pytest.mark.defined_in_file(AWX_VAR='DEFAULT')
|
||||
def test_in_memory_cache_only_for_registered_settings(settings):
|
||||
"Test that we only make use of the in-memory TTL cache for registered settings"
|
||||
settings._awx_conf_memoizedcache.clear()
|
||||
settings.MIDDLEWARE
|
||||
assert len(settings._awx_conf_memoizedcache) == 0 # does not cache MIDDLEWARE
|
||||
settings.registry.register('AWX_VAR', field_class=fields.CharField, category=_('System'), category_slug='system')
|
||||
settings._wrapped.__dict__['all_supported_settings'] = ['AWX_VAR'] # because it is cached_property
|
||||
settings._awx_conf_memoizedcache.clear()
|
||||
assert settings.AWX_VAR == 'DEFAULT'
|
||||
assert len(settings._awx_conf_memoizedcache) == 1 # caches registered settings
|
||||
|
||||
|
||||
@pytest.mark.defined_in_file(AWX_VAR='DEFAULT')
|
||||
def test_in_memory_cache_works(settings):
|
||||
settings._awx_conf_memoizedcache.clear()
|
||||
settings.registry.register('AWX_VAR', field_class=fields.CharField, category=_('System'), category_slug='system')
|
||||
settings._wrapped.__dict__['all_supported_settings'] = ['AWX_VAR']
|
||||
|
||||
settings._awx_conf_memoizedcache.clear()
|
||||
|
||||
with mock.patch('awx.conf.settings.SettingsWrapper._get_local', return_value='DEFAULT') as mock_get:
|
||||
assert settings.AWX_VAR == 'DEFAULT'
|
||||
mock_get.assert_called_once_with('AWX_VAR')
|
||||
|
||||
with mock.patch.object(settings, '_get_local') as mock_get:
|
||||
assert settings.AWX_VAR == 'DEFAULT'
|
||||
mock_get.assert_not_called()
|
||||
|
||||
@@ -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'),
|
||||
]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# 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 ""
|
||||
@@ -8,8 +11,7 @@ msgstr ""
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: es \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Language: \n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
@@ -21,9 +23,7 @@ msgstr "Tiempo de inactividad fuerza desconexión"
|
||||
msgid ""
|
||||
"Number of seconds that a user is inactive before they will need to login "
|
||||
"again."
|
||||
msgstr ""
|
||||
"Número de segundos que un usuario es inactivo antes de que ellos vuelvan a "
|
||||
"conectarse de nuevo."
|
||||
msgstr "Número de segundos que un usuario es inactivo antes de que ellos vuelvan a conectarse de nuevo."
|
||||
|
||||
#: awx/api/conf.py:21 awx/api/conf.py:31 awx/api/conf.py:42 awx/api/conf.py:50
|
||||
#: awx/api/conf.py:70 awx/api/conf.py:85 awx/api/conf.py:96 awx/sso/conf.py:105
|
||||
@@ -45,9 +45,7 @@ msgstr "Número máximo de sesiones activas en simultáneo"
|
||||
msgid ""
|
||||
"Maximum number of simultaneous logged in sessions a user may have. To "
|
||||
"disable enter -1."
|
||||
msgstr ""
|
||||
"Número máximo de sesiones activas en simultáneo que un usuario puede tener. "
|
||||
"Para deshabilitar, introduzca -1."
|
||||
msgstr "Número máximo de sesiones activas en simultáneo que un usuario puede tener. Para deshabilitar, introduzca -1."
|
||||
|
||||
#: awx/api/conf.py:37
|
||||
msgid "Disable the built-in authentication system"
|
||||
@@ -58,10 +56,7 @@ msgid ""
|
||||
"Controls whether users are prevented from using the built-in authentication "
|
||||
"system. You probably want to do this if you are using an LDAP or SAML "
|
||||
"integration."
|
||||
msgstr ""
|
||||
"Controla si se impide que los usuarios utilicen el sistema de autenticación "
|
||||
"integrado. Probablemente desee hacer esto si está usando una integración de "
|
||||
"LDAP o SAML."
|
||||
msgstr "Controla si se impide que los usuarios utilicen el sistema de autenticación integrado. Probablemente desee hacer esto si está usando una integración de LDAP o SAML."
|
||||
|
||||
#: awx/api/conf.py:48
|
||||
msgid "Enable HTTP Basic Auth"
|
||||
@@ -83,13 +78,7 @@ msgid ""
|
||||
"authorization codes in the number of seconds, and "
|
||||
"`REFRESH_TOKEN_EXPIRE_SECONDS`, the duration of refresh tokens, after "
|
||||
"expired access tokens, in the number of seconds."
|
||||
msgstr ""
|
||||
"Diccionario para personalizar los tiempos de espera de OAuth2; los elementos "
|
||||
"disponibles son `ACCESS_TOKEN_EXPIRE_SECONDS`, la duración de los tokens de "
|
||||
"acceso en cantidad de segundos; `AUTHORIZATION_CODE_EXPIRE_SECONDS`, la "
|
||||
"duración de los códigos de autorización en cantidad de segundos; y "
|
||||
"`REFRESH_TOKEN_EXPIRE_SECONDS`, la duración de los tokens de actualización, "
|
||||
"después de los tokens de acceso expirados, en cantidad de segundos."
|
||||
msgstr "Diccionario para personalizar los tiempos de espera de OAuth2; los elementos disponibles son `ACCESS_TOKEN_EXPIRE_SECONDS`, la duración de los tokens de acceso en cantidad de segundos; `AUTHORIZATION_CODE_EXPIRE_SECONDS`, la duración de los códigos de autorización en cantidad de segundos; y `REFRESH_TOKEN_EXPIRE_SECONDS`, la duración de los tokens de actualización, después de los tokens de acceso expirados, en cantidad de segundos."
|
||||
|
||||
#: awx/api/conf.py:78
|
||||
msgid "Allow External Users to Create OAuth2 Tokens"
|
||||
@@ -101,11 +90,7 @@ msgid ""
|
||||
"Radius, and others) are not allowed to create OAuth2 tokens. To change this "
|
||||
"behavior, enable this setting. Existing tokens will not be deleted when this "
|
||||
"setting is toggled off."
|
||||
msgstr ""
|
||||
"Por motivos de seguridad, los usuarios de proveedores de autenticación "
|
||||
"externos (LDAP, SAML, SSO, Radius y otros) no tienen permitido crear tokens "
|
||||
"de OAuth2. Habilite este ajuste para cambiar este comportamiento. Los tokens "
|
||||
"existentes no se eliminarán cuando se desactive este ajuste."
|
||||
msgstr "Por motivos de seguridad, los usuarios de proveedores de autenticación externos (LDAP, SAML, SSO, Radius y otros) no tienen permitido crear tokens de OAuth2. Habilite este ajuste para cambiar este comportamiento. Los tokens existentes no se eliminarán cuando se desactive este ajuste."
|
||||
|
||||
#: awx/api/conf.py:94
|
||||
msgid "Login redirect override URL"
|
||||
@@ -115,10 +100,7 @@ msgstr "URL de invalidación de redireccionamiento de inicio de sesión"
|
||||
msgid ""
|
||||
"URL to which unauthorized users will be redirected to log in. If blank, "
|
||||
"users will be sent to the login page."
|
||||
msgstr ""
|
||||
"URL a la que los usuarios no autorizados serán redirigidos para iniciar "
|
||||
"sesión. Si está en blanco, los usuarios serán enviados a la página de inicio "
|
||||
"de sesión."
|
||||
msgstr "URL a la que los usuarios no autorizados serán redirigidos para iniciar sesión. Si está en blanco, los usuarios serán enviados a la página de inicio de sesión."
|
||||
|
||||
#: awx/api/conf.py:114
|
||||
msgid "There are no remote authentication systems configured."
|
||||
@@ -167,17 +149,13 @@ msgstr "ID{field_name} no válido: {field_id}"
|
||||
msgid ""
|
||||
"Cannot apply role_level filter to this list because its model does not use "
|
||||
"roles for access control."
|
||||
msgstr ""
|
||||
"No se puede aplicar el filtro role_level a esta lista debido a que su modelo "
|
||||
"no usa roles para el control de acceso."
|
||||
msgstr "No se puede aplicar el filtro role_level a esta lista debido a que su modelo no usa roles para el control de acceso."
|
||||
|
||||
#: awx/api/generics.py:179
|
||||
msgid ""
|
||||
"You did not use correct Content-Type in your HTTP request. If you are using "
|
||||
"our REST API, the Content-Type must be application/json"
|
||||
msgstr ""
|
||||
"No utilizó el Tipo de contenido correcto en su solicitud HTTP. Si está "
|
||||
"usando nuestra API REST, el Tipo de contenido debe ser aplicación/json."
|
||||
msgstr "No utilizó el Tipo de contenido correcto en su solicitud HTTP. Si está usando nuestra API REST, el Tipo de contenido debe ser aplicación/json."
|
||||
|
||||
#: awx/api/generics.py:220
|
||||
msgid " To establish a login session, visit"
|
||||
@@ -223,9 +201,7 @@ msgstr "Estructura de datos con URLs de recursos relacionados."
|
||||
msgid ""
|
||||
"Data structure with name/description for related resources. The output for "
|
||||
"some objects may be limited for performance reasons."
|
||||
msgstr ""
|
||||
"Estructura de datos con nombre/descripción de los recursos relacionados. La "
|
||||
"salida de algunos objetos puede estar limitada por motivos de rendimiento."
|
||||
msgstr "Estructura de datos con nombre/descripción de los recursos relacionados. La salida de algunos objetos puede estar limitada por motivos de rendimiento."
|
||||
|
||||
#: awx/api/metadata.py:75
|
||||
msgid "Timestamp when this {} was created."
|
||||
@@ -248,17 +224,14 @@ msgstr "Error de análisis JSON; no es un objeto JSON"
|
||||
msgid ""
|
||||
"JSON parse error - %s\n"
|
||||
"Possible cause: trailing comma."
|
||||
msgstr ""
|
||||
"Error de análisis JSON - %s\n"
|
||||
msgstr "Error de análisis JSON - %s\n"
|
||||
"Posible causa: coma final."
|
||||
|
||||
#: awx/api/serializers.py:205
|
||||
msgid ""
|
||||
"The original object is already named {}, a copy from it cannot have the same "
|
||||
"name."
|
||||
msgstr ""
|
||||
"El objeto original ya tiene el nombre {}, por lo que una copia de este no "
|
||||
"puede tener el mismo nombre."
|
||||
msgstr "El objeto original ya tiene el nombre {}, por lo que una copia de este no puede tener el mismo nombre."
|
||||
|
||||
#: awx/api/serializers.py:334
|
||||
#, python-format
|
||||
@@ -301,9 +274,7 @@ msgstr "Plantilla de trabajo"
|
||||
msgid ""
|
||||
"Indicates whether all of the events generated by this unified job have been "
|
||||
"saved to the database."
|
||||
msgstr ""
|
||||
"Indica si todos los eventos generados por esta tarea unificada se guardaron "
|
||||
"en la base de datos."
|
||||
msgstr "Indica si todos los eventos generados por esta tarea unificada se guardaron en la base de datos."
|
||||
|
||||
#: awx/api/serializers.py:939
|
||||
msgid "Write-only field used to change the password."
|
||||
@@ -324,8 +295,7 @@ msgstr "No se puede cambiar %s en el usuario gestionado por LDAP."
|
||||
|
||||
#: awx/api/serializers.py:1153
|
||||
msgid "Must be a simple space-separated string with allowed scopes {}."
|
||||
msgstr ""
|
||||
"Debe ser una cadena simple separada por espacios con alcances permitidos {}."
|
||||
msgstr "Debe ser una cadena simple separada por espacios con alcances permitidos {}."
|
||||
|
||||
#: awx/api/serializers.py:1238
|
||||
msgid "Authorization Grant Type"
|
||||
@@ -378,9 +348,7 @@ msgstr "SCM track_submodules solo puede usarse con proyectos git."
|
||||
msgid ""
|
||||
"Only Container Registry credentials can be associated with an Execution "
|
||||
"Environment"
|
||||
msgstr ""
|
||||
"Solo las credenciales del registro de contenedores pueden asociarse a un "
|
||||
"entorno de ejecución"
|
||||
msgstr "Solo las credenciales del registro de contenedores pueden asociarse a un entorno de ejecución"
|
||||
|
||||
#: awx/api/serializers.py:1440
|
||||
msgid "Cannot change the organization of an execution environment"
|
||||
@@ -390,9 +358,7 @@ msgstr "No se puede modificar la organización de un entorno de ejecución"
|
||||
msgid ""
|
||||
"One or more job templates depend on branch override behavior for this "
|
||||
"project (ids: {})."
|
||||
msgstr ""
|
||||
"Una o más plantillas de trabajo dependen del comportamiento de invalidación "
|
||||
"de ramas para este proyecto (ids: {})."
|
||||
msgstr "Una o más plantillas de trabajo dependen del comportamiento de invalidación de ramas para este proyecto (ids: {})."
|
||||
|
||||
#: awx/api/serializers.py:1530
|
||||
msgid "Update options must be set to false for manual projects."
|
||||
@@ -406,9 +372,7 @@ msgstr "Colección de playbooks disponibles dentro de este proyecto."
|
||||
msgid ""
|
||||
"Array of inventory files and directories available within this project, not "
|
||||
"comprehensive."
|
||||
msgstr ""
|
||||
"Colección de archivos de inventario y directorios disponibles dentro de este "
|
||||
"proyecto, no global."
|
||||
msgstr "Colección de archivos de inventario y directorios disponibles dentro de este proyecto, no global."
|
||||
|
||||
#: awx/api/serializers.py:1599 awx/api/serializers.py:3098
|
||||
#: awx/api/serializers.py:3311
|
||||
@@ -560,7 +524,7 @@ msgstr "Playbook no encontrado para el proyecto."
|
||||
|
||||
#: awx/api/serializers.py:2842
|
||||
msgid "Must select playbook for project."
|
||||
msgstr "Debe seleccionar un playbook para el proyecto"
|
||||
msgstr "Debe seleccionar un playbook para el proyecto."
|
||||
|
||||
#: awx/api/serializers.py:2844 awx/api/serializers.py:2846
|
||||
msgid "Project does not allow overriding branch."
|
||||
@@ -893,8 +857,7 @@ msgid "Containerized instances may not be managed via the API"
|
||||
msgstr "Las instancias contenedorizadas no pueden ser gestionadas a través de la API."
|
||||
|
||||
#: awx/api/serializers.py:4919 awx/api/serializers.py:4922
|
||||
#, fuzzy, python-format
|
||||
#| msgid "tower instance group name may not be changed."
|
||||
#, python-format
|
||||
msgid "%s instance group name may not be changed."
|
||||
msgstr "El nombre del grupo de instancia %s no puede modificarse."
|
||||
|
||||
@@ -1049,8 +1012,6 @@ msgid ""
|
||||
msgstr "No puede asignar credenciales de acceso a un equipo cuando el campo de organización no está establecido o pertenezca a una organización diferente."
|
||||
|
||||
#: awx/api/views/__init__.py:720
|
||||
#, fuzzy
|
||||
#| msgid "The instance that managed the execution environment."
|
||||
msgid "Only the 'pull' field can be edited for managed execution environments."
|
||||
msgstr "Sólo se puede editar el campo \"pull\" para los entornos de ejecución gestionados."
|
||||
|
||||
@@ -2087,8 +2048,6 @@ msgid "Unique identifier for an installation"
|
||||
msgstr "Identificador único para una instalación"
|
||||
|
||||
#: awx/main/conf.py:183
|
||||
#, fuzzy
|
||||
#| msgid "The Instance group the job was run under"
|
||||
msgid "The instance group where control plane tasks run"
|
||||
msgstr "Grupo de instancias donde se ejecutan las tareas del plano de control"
|
||||
|
||||
@@ -2796,8 +2755,6 @@ msgid "The identifier for the secret e.g., /some/identifier"
|
||||
msgstr "El identificador para el secreto; por ejemplo, /some/identifier"
|
||||
|
||||
#: awx/main/credential_plugins/dsv.py:12
|
||||
#, fuzzy
|
||||
#| msgid "Tenant ID"
|
||||
msgid "Tenant"
|
||||
msgstr "Inquilino"
|
||||
|
||||
@@ -2816,8 +2773,6 @@ msgid ""
|
||||
msgstr "El TLD del inquilino, por ejemplo, \"com\" cuando la URL es https://ex.secretservercloud.com"
|
||||
|
||||
#: awx/main/credential_plugins/dsv.py:34
|
||||
#, fuzzy
|
||||
#| msgid "Secret Name"
|
||||
msgid "Secret Path"
|
||||
msgstr "Ruta secreta"
|
||||
|
||||
@@ -2826,8 +2781,6 @@ msgid "The secret path e.g. /test/secret1"
|
||||
msgstr "La ruta secreta, por ejemplo, /test/secret1"
|
||||
|
||||
#: awx/main/credential_plugins/dsv.py:46
|
||||
#, fuzzy
|
||||
#| msgid "Job Template"
|
||||
msgid "URL template"
|
||||
msgstr "Plantilla URL"
|
||||
|
||||
@@ -2960,8 +2913,6 @@ msgid ""
|
||||
msgstr "Principales válidos (ya sea nombres de usuario o nombres de host) para los que se debería firmar el certificado:"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:10
|
||||
#, fuzzy
|
||||
#| msgid "Auth Server URL"
|
||||
msgid "Secret Server URL"
|
||||
msgstr "URL del servidor secreto"
|
||||
|
||||
@@ -2972,8 +2923,6 @@ msgid ""
|
||||
msgstr "La URL base del servidor secreto, por ejemplo, https://myserver/SecretServer o https://mytenant.secretservercloud.com"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:17
|
||||
#, fuzzy
|
||||
#| msgid "Red Hat customer username"
|
||||
msgid "The (Application) user username"
|
||||
msgstr "El nombre de usuario (de la aplicación)"
|
||||
|
||||
@@ -2995,20 +2944,14 @@ msgid "The corresponding password"
|
||||
msgstr "La contraseña correspondiente"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:31
|
||||
#, fuzzy
|
||||
#| msgid "Secret Key"
|
||||
msgid "Secret ID"
|
||||
msgstr "Identificación secreta"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:32
|
||||
#, fuzzy
|
||||
#| msgid "The name of the secret to look up."
|
||||
msgid "The integer ID of the secret"
|
||||
msgstr "El ID entero del secreto"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:37
|
||||
#, fuzzy
|
||||
#| msgid "Secret Key"
|
||||
msgid "Secret Field"
|
||||
msgstr "Campo secreto"
|
||||
|
||||
@@ -3568,22 +3511,14 @@ msgstr "Ruta de archivo absoluta al archivo CA por usar (opcional)"
|
||||
|
||||
#: awx/main/models/credential/__init__.py:1023
|
||||
#: awx/main/models/credential/__init__.py:1029 awx/main/models/inventory.py:813
|
||||
#, fuzzy
|
||||
#| msgid "Gather data for Insights for Ansible Automation Platform"
|
||||
msgid "Red Hat Ansible Automation Platform"
|
||||
msgstr "Plataforma Red Hat Ansible Automation"
|
||||
|
||||
#: awx/main/models/credential/__init__.py:1031
|
||||
#, fuzzy
|
||||
#| msgid "The Ansible Tower base URL to authenticate with."
|
||||
msgid "Red Hat Ansible Automation Platform base URL to authenticate with."
|
||||
msgstr "URL base de Red Hat Ansible Automation Platform para autenticar."
|
||||
|
||||
#: awx/main/models/credential/__init__.py:1038
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "The Ansible Tower user to authenticate as.This should not be set if an "
|
||||
#| "OAuth token is being used."
|
||||
msgid ""
|
||||
"Red Hat Ansible Automation Platform username id to authenticate as.This "
|
||||
"should not be set if an OAuth token is being used."
|
||||
@@ -4488,7 +4423,7 @@ msgstr "El número de segundos desde de que la última actualización del proyec
|
||||
msgid ""
|
||||
"Allow changing the SCM branch or revision in a job template that uses this "
|
||||
"project."
|
||||
msgstr "Permitir el cambio de la rama o revisión del SCM en una plantilla de trabajo que utilice este proyecto."
|
||||
msgstr "Permitir el cambio de la rama o revisión de SCM en una plantilla de trabajo que utilice este proyecto."
|
||||
|
||||
#: awx/main/models/projects.py:294
|
||||
msgid "The last revision fetched by a project update"
|
||||
@@ -4925,7 +4860,7 @@ msgid "Exception connecting to PagerDuty: {}"
|
||||
msgstr "Excepción conectando a PagerDuty: {}"
|
||||
|
||||
#: awx/main/notifications/pagerduty_backend.py:87
|
||||
#: awx/main/notifications/slack_backend.py:48
|
||||
#: awx/main/notifications/slack_backend.py:49
|
||||
#: awx/main/notifications/twilio_backend.py:47
|
||||
msgid "Exception sending messages: {}"
|
||||
msgstr "Excepción enviando mensajes: {}"
|
||||
@@ -5181,7 +5116,7 @@ msgstr "Al menos un certificado es necesario."
|
||||
msgid ""
|
||||
"At least %(min_certs)d certificates are required, only %(cert_count)d "
|
||||
"provided."
|
||||
msgstr "Se requieren al menos %(min_certs)d certificados, sólo %(cert_count)d proporcionados."
|
||||
msgstr "Al menos %(min_certs)d certificados son necesarios, solo se proporcionó %(cert_count)d."
|
||||
|
||||
#: awx/main/validators.py:152
|
||||
#, python-format
|
||||
@@ -5195,8 +5130,7 @@ msgid ""
|
||||
msgstr "No se permiten más de %(max_certs)d certificados, %(cert_count)d proporcionado."
|
||||
|
||||
#: awx/main/validators.py:289
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "The container image to be used for execution."
|
||||
#, python-brace-format
|
||||
msgid "The container image name {value} is not valid"
|
||||
msgstr "El nombre de la imagen del contenedor {value} no es válido"
|
||||
|
||||
@@ -5666,17 +5600,17 @@ msgstr "La clave secreta OAuth2 (Clave secreta del cliente) from your GitHub org
|
||||
|
||||
#: awx/sso/conf.py:751
|
||||
msgid "GitHub Organization Name"
|
||||
msgstr "Nombre de la organización de GitHub"
|
||||
msgstr "Nombre para la organización GitHub"
|
||||
|
||||
#: awx/sso/conf.py:752
|
||||
msgid ""
|
||||
"The name of your GitHub organization, as used in your organization's URL: "
|
||||
"https://github.com/<yourorg>/."
|
||||
msgstr "El nombre de su organización de GitHub, como se utiliza en la URL de su organización: https://github.com/<votreorg>/."
|
||||
msgstr "El nombre de su organización de GitHub, como se utiliza en la URL de su organización: https://github.com/<yourorg>/."
|
||||
|
||||
#: awx/sso/conf.py:762
|
||||
msgid "GitHub Organization OAuth2 Organization Map"
|
||||
msgstr "Mapa de organización de OAuth2 de la organización de GitHub"
|
||||
msgstr "Mapa de organización OAuth2 para organizaciones GitHub"
|
||||
|
||||
#: awx/sso/conf.py:774
|
||||
msgid "GitHub Organization OAuth2 Team Map"
|
||||
@@ -5684,7 +5618,7 @@ msgstr "Mapa de equipos OAuth2 para equipos GitHub"
|
||||
|
||||
#: awx/sso/conf.py:790
|
||||
msgid "GitHub Team OAuth2 Callback URL"
|
||||
msgstr "URL de devolución de OAuth2 del equipo de GitHub"
|
||||
msgstr "URL callback OAuth2 para los equipos GitHub"
|
||||
|
||||
#: awx/sso/conf.py:792 awx/sso/conf.py:1060
|
||||
msgid ""
|
||||
@@ -5692,12 +5626,12 @@ 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 "Cree una aplicación propiedad de la organización en https://github.com/organizations/<votreorg>/settings/applications y obtenga una clave de OAuth2 (ID del cliente) y secreta (clave secreta de cliente). Proporcione esta URL como URL de devolución para su aplicación."
|
||||
msgstr "Cree una aplicación propiedad de la organización en https://github.com/organizations/<yourorg>/settings/applications y obtenga una clave de OAuth2 (ID del cliente) y secreta (clave secreta de cliente). Proporcione esta URL como URL de devolución para su aplicación."
|
||||
|
||||
#: 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
|
||||
msgid "GitHub Team OAuth2"
|
||||
msgstr "OAuth2 de equipo de GitHub"
|
||||
msgstr "OAuth2 para equipos GitHub"
|
||||
|
||||
#: awx/sso/conf.py:807
|
||||
msgid "GitHub Team OAuth2 Key"
|
||||
@@ -5828,7 +5762,7 @@ msgstr "Nombre de la organización de GitHub Enterprise"
|
||||
msgid ""
|
||||
"The name of your GitHub Enterprise organization, as used in your "
|
||||
"organization's URL: https://github.com/<yourorg>/."
|
||||
msgstr "El nombre de su organización de GitHub Enterprise, como se utiliza en la URL de su organización: https://github.com/<votreorg>/."
|
||||
msgstr "El nombre de su organización de GitHub Enterprise, como se utiliza en la URL de su organización: https://github.com/<yourorg>/."
|
||||
|
||||
#: awx/sso/conf.py:1030
|
||||
msgid "GitHub Enterprise Organization OAuth2 Organization Map"
|
||||
@@ -6303,68 +6237,4 @@ msgstr "%s se está actualizando."
|
||||
|
||||
#: awx/ui/urls.py:24
|
||||
msgid "This page will refresh when complete."
|
||||
msgstr "Esta página se actualizará cuando se complete."
|
||||
|
||||
#~ msgid "SSLError while trying to connect to {}"
|
||||
#~ msgstr "SSLError al intentar conectarse a {}"
|
||||
|
||||
#~ msgid "Request to {} timed out."
|
||||
#~ msgstr "El tiempo de solicitud {} caducó."
|
||||
|
||||
#~ msgid "Unknown exception {} while trying to GET {}"
|
||||
#~ msgstr "Excepción desconocida {} al intentar usar GET {}"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Unauthorized access. Please check your Insights Credential username and "
|
||||
#~ "password."
|
||||
#~ msgstr ""
|
||||
#~ "Acceso no autorizado. Verifique su nombre de usuario y contraseña de "
|
||||
#~ "Insights."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Failed to access the Insights API at URL {}. Server responded with {} "
|
||||
#~ "status code and message {}"
|
||||
#~ msgstr ""
|
||||
#~ "No se pudo acceder a la API de Insights en la URL {}. El servidor "
|
||||
#~ "respondió con el código de estado {} y el mensaje {}"
|
||||
|
||||
#~ msgid "Expected JSON response from Insights at URL {} but instead got {}"
|
||||
#~ msgstr ""
|
||||
#~ "Respuesta JSON esperada de Insights en la URL {}; en cambio, se recibió {}"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Could not translate Insights system ID {} into an Insights platform ID."
|
||||
#~ msgstr ""
|
||||
#~ "No se pudo traducir el ID del sistema Insights {} en un ID de plataforma "
|
||||
#~ "de Insights."
|
||||
|
||||
#~ msgid "This host is not recognized as an Insights host."
|
||||
#~ msgstr "Este host no se reconoce como un host de Insights."
|
||||
|
||||
#~ msgid "The Insights Credential for \"{}\" was not found."
|
||||
#~ msgstr "No se encontró la credencial de Insights para \"{}\"."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The path to the secret stored in the secret backend e.g, /some/secret/"
|
||||
#~ msgstr ""
|
||||
#~ "La ruta al secreto almacenado en el backend de secretos; por ejemplo, /"
|
||||
#~ "some/secret/"
|
||||
|
||||
#~ msgid "Ansible Tower"
|
||||
#~ msgstr "Ansible Tower"
|
||||
|
||||
#~ msgid "Ansible Tower Hostname"
|
||||
#~ msgstr "Nombre de host de Ansible Tower"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Credentials to be used by hosts belonging to this inventory when "
|
||||
#~ "accessing Red Hat Insights API."
|
||||
#~ msgstr ""
|
||||
#~ "Credenciales que utilizarán los hosts que pertenecen a este inventario "
|
||||
#~ "cuando accedan a la API de Red Hat Insights."
|
||||
|
||||
#~ msgid "Assignment not allowed for Smart Inventory"
|
||||
#~ msgstr "Tarea no permitida para el inventario inteligente"
|
||||
|
||||
#~ msgid "Red Hat Insights host unique identifier."
|
||||
#~ msgstr "Identificador único de host de Red Hat Insights."
|
||||
msgstr "Esta página se actualizará cuando se complete."
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6239
awx/locale/ko/LC_MESSAGES/django.po
Normal file
6239
awx/locale/ko/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
# 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 ""
|
||||
@@ -8,8 +11,7 @@ msgstr ""
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: nl \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Language: \n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
@@ -21,9 +23,7 @@ msgstr "Niet-actieve tijd voor forceren van afmelding"
|
||||
msgid ""
|
||||
"Number of seconds that a user is inactive before they will need to login "
|
||||
"again."
|
||||
msgstr ""
|
||||
"Maximumaantal seconden dat een gebruiker niet-actief is voordat deze zich "
|
||||
"opnieuw moet aanmelden."
|
||||
msgstr "Maximumaantal seconden dat een gebruiker niet-actief is voordat deze zich opnieuw moet aanmelden."
|
||||
|
||||
#: awx/api/conf.py:21 awx/api/conf.py:31 awx/api/conf.py:42 awx/api/conf.py:50
|
||||
#: awx/api/conf.py:70 awx/api/conf.py:85 awx/api/conf.py:96 awx/sso/conf.py:105
|
||||
@@ -45,9 +45,7 @@ msgstr "Maximumaantal gelijktijdige aangemelde sessies"
|
||||
msgid ""
|
||||
"Maximum number of simultaneous logged in sessions a user may have. To "
|
||||
"disable enter -1."
|
||||
msgstr ""
|
||||
"Maximumaantal gelijktijdige aangemelde sessies dat een gebruiker kan hebben. "
|
||||
"Voer -1 in om dit uit te schakelen."
|
||||
msgstr "Maximumaantal gelijktijdige aangemelde sessies dat een gebruiker kan hebben. Voer -1 in om dit uit te schakelen."
|
||||
|
||||
#: awx/api/conf.py:37
|
||||
msgid "Disable the built-in authentication system"
|
||||
@@ -58,10 +56,7 @@ msgid ""
|
||||
"Controls whether users are prevented from using the built-in authentication "
|
||||
"system. You probably want to do this if you are using an LDAP or SAML "
|
||||
"integration."
|
||||
msgstr ""
|
||||
"Bepaalt of gebruikers het ingebouwde authenticatiesysteem niet mogen "
|
||||
"gebruiken. U wilt dit waarschijnlijk doen als u een LDAP- of SAML-integratie "
|
||||
"gebruikt."
|
||||
msgstr "Bepaalt of gebruikers het ingebouwde authenticatiesysteem niet mogen gebruiken. U wilt dit waarschijnlijk doen als u een LDAP- of SAML-integratie gebruikt."
|
||||
|
||||
#: awx/api/conf.py:48
|
||||
msgid "Enable HTTP Basic Auth"
|
||||
@@ -83,13 +78,7 @@ msgid ""
|
||||
"authorization codes in the number of seconds, and "
|
||||
"`REFRESH_TOKEN_EXPIRE_SECONDS`, the duration of refresh tokens, after "
|
||||
"expired access tokens, in the number of seconds."
|
||||
msgstr ""
|
||||
"Termenlijst voor het aanpassen van OAuth 2-time-outs. Beschikbare items zijn "
|
||||
"`ACCESS_TOKEN_EXPIRE_SECONDS`, de duur van de toegangstokens in het aantal "
|
||||
"seconden, `AUTHORIZATION_CODE_EXPIRE_SECONDS`, de duur van de "
|
||||
"autorisatiecodes in het aantal seconden. en `REFRESH_TOKEN_EXPIRE_SECONDS`, "
|
||||
"de duur van de verversingstokens na verlopen toegangstokens, in het aantal "
|
||||
"seconden."
|
||||
msgstr "Termenlijst voor het aanpassen van OAuth 2-time-outs. Beschikbare items zijn `ACCESS_TOKEN_EXPIRE_SECONDS`, de duur van de toegangstokens in het aantal seconden, `AUTHORIZATION_CODE_EXPIRE_SECONDS`, de duur van de autorisatiecodes in het aantal seconden. en `REFRESH_TOKEN_EXPIRE_SECONDS`, de duur van de verversingstokens na verlopen toegangstokens, in het aantal seconden."
|
||||
|
||||
#: awx/api/conf.py:78
|
||||
msgid "Allow External Users to Create OAuth2 Tokens"
|
||||
@@ -476,7 +465,7 @@ msgstr "'ask_at_runtime' wordt niet ondersteund voor aangepaste referenties."
|
||||
|
||||
#: awx/api/serializers.py:2547
|
||||
msgid "Credential Type"
|
||||
msgstr "Type toegangsgegevens"
|
||||
msgstr "Soort toegangsgegevens"
|
||||
|
||||
#: awx/api/serializers.py:2614
|
||||
msgid "Modifications not allowed for managed credentials"
|
||||
@@ -868,8 +857,7 @@ msgid "Containerized instances may not be managed via the API"
|
||||
msgstr "Geclusterde instanties worden mogelijk niet beheerd via de API"
|
||||
|
||||
#: awx/api/serializers.py:4919 awx/api/serializers.py:4922
|
||||
#, fuzzy, python-format
|
||||
#| msgid "tower instance group name may not be changed."
|
||||
#, python-format
|
||||
msgid "%s instance group name may not be changed."
|
||||
msgstr "Naam van de %s-instantiegroep mag niet worden gewijzigd."
|
||||
|
||||
@@ -1024,8 +1012,6 @@ msgid ""
|
||||
msgstr "U kunt een team geen referentietoegang verlenen wanneer het veld Organisatie niet is ingesteld of behoort tot een andere organisatie"
|
||||
|
||||
#: awx/api/views/__init__.py:720
|
||||
#, fuzzy
|
||||
#| msgid "The instance that managed the execution environment."
|
||||
msgid "Only the 'pull' field can be edited for managed execution environments."
|
||||
msgstr "Alleen het veld \"pull\" kan worden bewerkt voor beheerde uitvoeringsomgevingen."
|
||||
|
||||
@@ -2062,8 +2048,6 @@ msgid "Unique identifier for an installation"
|
||||
msgstr "Unieke identificatiecode voor installatie"
|
||||
|
||||
#: awx/main/conf.py:183
|
||||
#, fuzzy
|
||||
#| msgid "The Instance group the job was run under"
|
||||
msgid "The instance group where control plane tasks run"
|
||||
msgstr "De instantiegroep waar control plane-taken worden uitgevoerd"
|
||||
|
||||
@@ -2637,7 +2621,7 @@ msgstr "Vault-URL (DNS-naam)"
|
||||
#: awx/main/credential_plugins/dsv.py:23
|
||||
#: awx/main/models/credential/__init__.py:895
|
||||
msgid "Client ID"
|
||||
msgstr "Client-id"
|
||||
msgstr "Klant-ID"
|
||||
|
||||
#: awx/main/credential_plugins/azure_kv.py:29
|
||||
#: awx/main/models/credential/__init__.py:902
|
||||
@@ -2771,8 +2755,6 @@ msgid "The identifier for the secret e.g., /some/identifier"
|
||||
msgstr "De identificatiecode voor het geheim, bijv. /some/identifier"
|
||||
|
||||
#: awx/main/credential_plugins/dsv.py:12
|
||||
#, fuzzy
|
||||
#| msgid "Tenant ID"
|
||||
msgid "Tenant"
|
||||
msgstr "Tenant"
|
||||
|
||||
@@ -2791,8 +2773,6 @@ msgid ""
|
||||
msgstr "Het TLD van de tenant, bv. \"com\" wanneer de URL https://ex.secretservercloud.com is"
|
||||
|
||||
#: awx/main/credential_plugins/dsv.py:34
|
||||
#, fuzzy
|
||||
#| msgid "Secret Name"
|
||||
msgid "Secret Path"
|
||||
msgstr "Geheim pad"
|
||||
|
||||
@@ -2801,8 +2781,6 @@ msgid "The secret path e.g. /test/secret1"
|
||||
msgstr "Het geheime pad, bv. /test/secret1"
|
||||
|
||||
#: awx/main/credential_plugins/dsv.py:46
|
||||
#, fuzzy
|
||||
#| msgid "Job Template"
|
||||
msgid "URL template"
|
||||
msgstr "URL-sjabloon"
|
||||
|
||||
@@ -2935,8 +2913,6 @@ msgid ""
|
||||
msgstr "Geldige principes (gebruikersnamen of hostnamen) waarvoor het certificaat moet worden ondertekend."
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:10
|
||||
#, fuzzy
|
||||
#| msgid "Auth Server URL"
|
||||
msgid "Secret Server URL"
|
||||
msgstr "Geheime-server-URL"
|
||||
|
||||
@@ -2947,8 +2923,6 @@ msgid ""
|
||||
msgstr "De basis-URL van de geheime server, bv. https://myserver/SecretServer of https://mytenant.secretservercloud.com"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:17
|
||||
#, fuzzy
|
||||
#| msgid "Red Hat customer username"
|
||||
msgid "The (Application) user username"
|
||||
msgstr "De gebruikersnaam van de (applicatie) gebruiker"
|
||||
|
||||
@@ -2970,20 +2944,14 @@ msgid "The corresponding password"
|
||||
msgstr "Het bijbehorende wachtwoord"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:31
|
||||
#, fuzzy
|
||||
#| msgid "Secret Key"
|
||||
msgid "Secret ID"
|
||||
msgstr "Geheime id"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:32
|
||||
#, fuzzy
|
||||
#| msgid "The name of the secret to look up."
|
||||
msgid "The integer ID of the secret"
|
||||
msgstr "De id van het geheim als geheel getal"
|
||||
|
||||
#: awx/main/credential_plugins/tss.py:37
|
||||
#, fuzzy
|
||||
#| msgid "Secret Key"
|
||||
msgid "Secret Field"
|
||||
msgstr "Geheim veld"
|
||||
|
||||
@@ -3543,22 +3511,14 @@ msgstr "Absoluut bestandspad naar het CA-bestand om te gebruiken (optioneel)"
|
||||
|
||||
#: awx/main/models/credential/__init__.py:1023
|
||||
#: awx/main/models/credential/__init__.py:1029 awx/main/models/inventory.py:813
|
||||
#, fuzzy
|
||||
#| msgid "Gather data for Insights for Ansible Automation Platform"
|
||||
msgid "Red Hat Ansible Automation Platform"
|
||||
msgstr "Automatiseringsplatform voor Red Hat Ansible"
|
||||
|
||||
#: awx/main/models/credential/__init__.py:1031
|
||||
#, fuzzy
|
||||
#| msgid "The Ansible Tower base URL to authenticate with."
|
||||
msgid "Red Hat Ansible Automation Platform base URL to authenticate with."
|
||||
msgstr "De basis-URL van het automatiseringsplatform voor Red Hat Ansible voor authenticatie."
|
||||
|
||||
#: awx/main/models/credential/__init__.py:1038
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "The Ansible Tower user to authenticate as.This should not be set if an "
|
||||
#| "OAuth token is being used."
|
||||
msgid ""
|
||||
"Red Hat Ansible Automation Platform username id to authenticate as.This "
|
||||
"should not be set if an OAuth token is being used."
|
||||
@@ -4463,7 +4423,7 @@ msgstr "Het aantal seconden na uitvoering van de laatste projectupdate waarna ee
|
||||
msgid ""
|
||||
"Allow changing the SCM branch or revision in a job template that uses this "
|
||||
"project."
|
||||
msgstr "Wijzigen van de SCM-vertakking of de revisie toelaten in een taaksjabloon die gebruik maakt van dit project."
|
||||
msgstr "Maak het mogelijk om de SCM-tak of de revisie te wijzigen in een taaksjabloon die gebruik maakt van dit project."
|
||||
|
||||
#: awx/main/models/projects.py:294
|
||||
msgid "The last revision fetched by a project update"
|
||||
@@ -4900,7 +4860,7 @@ msgid "Exception connecting to PagerDuty: {}"
|
||||
msgstr "Uitzondering bij het maken van de verbinding met PagerDuty: {}"
|
||||
|
||||
#: awx/main/notifications/pagerduty_backend.py:87
|
||||
#: awx/main/notifications/slack_backend.py:48
|
||||
#: awx/main/notifications/slack_backend.py:49
|
||||
#: awx/main/notifications/twilio_backend.py:47
|
||||
msgid "Exception sending messages: {}"
|
||||
msgstr "Uitzondering bij het verzenden van berichten: {}"
|
||||
@@ -5170,8 +5130,7 @@ msgid ""
|
||||
msgstr "Niet meer dan %(max_certs)d certificaten zijn toegestaan, %(cert_count)d geleverd."
|
||||
|
||||
#: awx/main/validators.py:289
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "The container image to be used for execution."
|
||||
#, python-brace-format
|
||||
msgid "The container image name {value} is not valid"
|
||||
msgstr "De naam van de containerafbeelding {value} is ongeldig"
|
||||
|
||||
@@ -6278,68 +6237,4 @@ msgstr "Er wordt momenteel een upgrade van%s geïnstalleerd."
|
||||
|
||||
#: awx/ui/urls.py:24
|
||||
msgid "This page will refresh when complete."
|
||||
msgstr "Deze pagina wordt vernieuwd als hij klaar is."
|
||||
|
||||
#~ msgid "SSLError while trying to connect to {}"
|
||||
#~ msgstr "SSLError tijdens poging om verbinding te maken met {}"
|
||||
|
||||
#~ msgid "Request to {} timed out."
|
||||
#~ msgstr "Er is een time-out opgetreden voor de aanvraag naar {}"
|
||||
|
||||
#~ msgid "Unknown exception {} while trying to GET {}"
|
||||
#~ msgstr "Onbekende uitzondering {} tijdens poging tot OPHALEN {}"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Unauthorized access. Please check your Insights Credential username and "
|
||||
#~ "password."
|
||||
#~ msgstr ""
|
||||
#~ "Geen toegang. Controleer uw Insights Credential gebruikersnaam en "
|
||||
#~ "wachtwoord."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Failed to access the Insights API at URL {}. Server responded with {} "
|
||||
#~ "status code and message {}"
|
||||
#~ msgstr ""
|
||||
#~ "Openen van Insights API via URL {} mislukt. Server reageerde met {} "
|
||||
#~ "statuscode en de melding {}"
|
||||
|
||||
#~ msgid "Expected JSON response from Insights at URL {} but instead got {}"
|
||||
#~ msgstr ""
|
||||
#~ "Verwachte JSON-reactie van Insights via URL {}, maar in plaats daarvan {} "
|
||||
#~ "verkregen."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Could not translate Insights system ID {} into an Insights platform ID."
|
||||
#~ msgstr ""
|
||||
#~ "Omzetten van Insights systeem-ID {} naar een Insights platform-ID mislukt."
|
||||
|
||||
#~ msgid "This host is not recognized as an Insights host."
|
||||
#~ msgstr "Deze host wordt niet herkend als een Insights-host."
|
||||
|
||||
#~ msgid "The Insights Credential for \"{}\" was not found."
|
||||
#~ msgstr "De Insights-referentie voor ‘{}‘ is niet gevonden."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The path to the secret stored in the secret backend e.g, /some/secret/"
|
||||
#~ msgstr ""
|
||||
#~ "De pad naar het geheim dat in de geheime back-end is opgeslagen, bijv. /"
|
||||
#~ "some/secret/"
|
||||
|
||||
#~ msgid "Ansible Tower"
|
||||
#~ msgstr "Ansible Tower"
|
||||
|
||||
#~ msgid "Ansible Tower Hostname"
|
||||
#~ msgstr "Hostnaam Ansible Tower"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Credentials to be used by hosts belonging to this inventory when "
|
||||
#~ "accessing Red Hat Insights API."
|
||||
#~ msgstr ""
|
||||
#~ "Referenties die worden gebruikt door hosts die behoren tot deze "
|
||||
#~ "inventaris bij toegang tot de Red Hat Insights API."
|
||||
|
||||
#~ msgid "Assignment not allowed for Smart Inventory"
|
||||
#~ msgstr "Toewijzing niet toegestaan voor Smart-inventaris"
|
||||
|
||||
#~ msgid "Red Hat Insights host unique identifier."
|
||||
#~ msgstr "Unieke id van Red Hat Insights-host."
|
||||
msgstr "Deze pagina wordt vernieuwd als hij klaar is."
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,2 @@
|
||||
# Copyright (c) 2015 Ansible, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
default_app_config = 'awx.main.apps.MainConfig'
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from django.db.models import Count
|
||||
from django.conf import settings
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.utils.timezone import now, timedelta
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from psycopg2.errors import UntranslatableCharacter
|
||||
|
||||
@@ -84,7 +84,7 @@ def _identify_lower(key, since, until, last_gather):
|
||||
return lower, last_entries
|
||||
|
||||
|
||||
@register('config', '1.3', description=_('General platform configuration.'))
|
||||
@register('config', '1.4', description=_('General platform configuration.'))
|
||||
def config(since, **kwargs):
|
||||
license_info = get_license()
|
||||
install_type = 'traditional'
|
||||
@@ -104,6 +104,22 @@ def config(since, **kwargs):
|
||||
'tower_url_base': settings.TOWER_URL_BASE,
|
||||
'tower_version': get_awx_version(),
|
||||
'license_type': license_info.get('license_type', 'UNLICENSED'),
|
||||
'license_date': license_info.get('license_date'),
|
||||
'subscription_name': license_info.get('subscription_name'),
|
||||
'sku': license_info.get('sku'),
|
||||
'support_level': license_info.get('support_level'),
|
||||
'product_name': license_info.get('product_name'),
|
||||
'valid_key': license_info.get('valid_key'),
|
||||
'satellite': license_info.get('satellite'),
|
||||
'pool_id': license_info.get('pool_id'),
|
||||
'current_instances': license_info.get('current_instances'),
|
||||
'automated_instances': license_info.get('automated_instances'),
|
||||
'automated_since': license_info.get('automated_since'),
|
||||
'trial': license_info.get('trial'),
|
||||
'grace_period_remaining': license_info.get('grace_period_remaining'),
|
||||
'compliant': license_info.get('compliant'),
|
||||
'date_warning': license_info.get('date_warning'),
|
||||
'date_expired': license_info.get('date_expired'),
|
||||
'free_instances': license_info.get('free_instances', 0),
|
||||
'total_licensed_instances': license_info.get('instance_count', 0),
|
||||
'license_expiry': license_info.get('time_remaining', 0),
|
||||
@@ -338,6 +354,7 @@ def _events_table(since, full_path, until, tbl, where_column, project_job_create
|
||||
{tbl}.event,
|
||||
task_action,
|
||||
resolved_action,
|
||||
resolved_role,
|
||||
-- '-' operator listed here:
|
||||
-- https://www.postgresql.org/docs/12/functions-json.html
|
||||
-- note that operator is only supported by jsonb objects
|
||||
@@ -357,7 +374,7 @@ def _events_table(since, full_path, until, tbl, where_column, project_job_create
|
||||
x.duration AS duration,
|
||||
x.res->'warnings' AS warnings,
|
||||
x.res->'deprecations' AS deprecations
|
||||
FROM {tbl}, jsonb_to_record({event_data}) AS x("res" json, "duration" text, "task_action" text, "resolved_action" text, "start" text, "end" text)
|
||||
FROM {tbl}, jsonb_to_record({event_data}) AS x("res" json, "duration" text, "task_action" text, "resolved_action" text, "resolved_role" text, "start" text, "end" text)
|
||||
WHERE ({tbl}.{where_column} > '{since.isoformat()}' AND {tbl}.{where_column} <= '{until.isoformat()}')) TO STDOUT WITH CSV HEADER'''
|
||||
return query
|
||||
|
||||
@@ -367,12 +384,12 @@ def _events_table(since, full_path, until, tbl, where_column, project_job_create
|
||||
return _copy_table(table='events', query=query(f"replace({tbl}.event_data::text, '\\u0000', '')::jsonb"), path=full_path)
|
||||
|
||||
|
||||
@register('events_table', '1.4', format='csv', description=_('Automation task records'), expensive=four_hour_slicing)
|
||||
@register('events_table', '1.5', format='csv', description=_('Automation task records'), expensive=four_hour_slicing)
|
||||
def events_table_unpartitioned(since, full_path, until, **kwargs):
|
||||
return _events_table(since, full_path, until, '_unpartitioned_main_jobevent', 'created', **kwargs)
|
||||
|
||||
|
||||
@register('events_table', '1.4', format='csv', description=_('Automation task records'), expensive=four_hour_slicing)
|
||||
@register('events_table', '1.5', format='csv', description=_('Automation task records'), expensive=four_hour_slicing)
|
||||
def events_table_partitioned_modified(since, full_path, until, **kwargs):
|
||||
return _events_table(since, full_path, until, 'main_jobevent', 'modified', project_job_created=True, **kwargs)
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ def gather(dest=None, module=None, subset=None, since=None, until=None, collecti
|
||||
|
||||
if collection_type != 'dry-run':
|
||||
if not settings.INSIGHTS_TRACKING_STATE:
|
||||
logger.log(log_level, "Insights for Ansible Automation Platform not enabled. Use --dry-run to gather locally without sending.")
|
||||
logger.log(log_level, "Automation Analytics not enabled. Use --dry-run to gather locally without sending.")
|
||||
return None
|
||||
|
||||
if not (settings.AUTOMATION_ANALYTICS_URL and settings.REDHAT_USERNAME and settings.REDHAT_PASSWORD):
|
||||
@@ -332,10 +332,10 @@ def ship(path):
|
||||
Ship gathered metrics to the Insights API
|
||||
"""
|
||||
if not path:
|
||||
logger.error('Insights for Ansible Automation Platform TAR not found')
|
||||
logger.error('Automation Analytics TAR not found')
|
||||
return False
|
||||
if not os.path.exists(path):
|
||||
logger.error('Insights for Ansible Automation Platform TAR {} not found'.format(path))
|
||||
logger.error('Automation Analytics TAR {} not found'.format(path))
|
||||
return False
|
||||
if "Error:" in str(path):
|
||||
return False
|
||||
|
||||
@@ -136,7 +136,7 @@ class HistogramM(BaseM):
|
||||
|
||||
|
||||
class Metrics:
|
||||
def __init__(self, auto_pipe_execute=True):
|
||||
def __init__(self, auto_pipe_execute=True, instance_name=None):
|
||||
self.pipe = redis.Redis.from_url(settings.BROKER_URL).pipeline()
|
||||
self.conn = redis.Redis.from_url(settings.BROKER_URL)
|
||||
self.last_pipe_execute = time.time()
|
||||
@@ -150,7 +150,10 @@ class Metrics:
|
||||
# the calling function should call .pipe_execute() explicitly
|
||||
self.auto_pipe_execute = auto_pipe_execute
|
||||
Instance = apps.get_model('main', 'Instance')
|
||||
self.instance_name = Instance.objects.me().hostname
|
||||
if instance_name:
|
||||
self.instance_name = instance_name
|
||||
else:
|
||||
self.instance_name = Instance.objects.me().hostname
|
||||
|
||||
# metric name, help_text
|
||||
METRICSLIST = [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class MainConfig(AppConfig):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user