mirror of
https://github.com/ansible/awx.git
synced 2026-02-05 03:24:50 -03:30
Compare commits
713 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dac26e5e91 | ||
|
|
3b1a626fa9 | ||
|
|
35907fdf51 | ||
|
|
3513956cd6 | ||
|
|
3ed65ce39e | ||
|
|
73e02e745a | ||
|
|
91df8ab0f7 | ||
|
|
ef0f6ca248 | ||
|
|
4ecce81c51 | ||
|
|
823e4cb11a | ||
|
|
28fa90e9e5 | ||
|
|
3d22c8ae91 | ||
|
|
e2135b8d68 | ||
|
|
fe5736dc7f | ||
|
|
b36af5dfb3 | ||
|
|
4446434e5b | ||
|
|
39905b33cd | ||
|
|
dbdc529d4a | ||
|
|
0cbc802cf4 | ||
|
|
b04747676c | ||
|
|
5297a87ad4 | ||
|
|
bd907425a9 | ||
|
|
229ed53c0e | ||
|
|
f17ceca7a0 | ||
|
|
deac08ba8a | ||
|
|
e0082f4c76 | ||
|
|
bed0443b18 | ||
|
|
24152555c5 | ||
|
|
56f51eebce | ||
|
|
6c1adade25 | ||
|
|
ec5e677635 | ||
|
|
327cae056e | ||
|
|
7a11470817 | ||
|
|
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 | ||
|
|
4c9d028a35 | ||
|
|
bd5c304a50 | ||
|
|
123a3a22c9 | ||
|
|
82d91f8dbd | ||
|
|
cd86310562 | ||
|
|
f04d7733bb | ||
|
|
b2fe1c46ee | ||
|
|
676b8f6d8f | ||
|
|
028f09002f | ||
|
|
0500512c3c | ||
|
|
1e625ed58b | ||
|
|
e620bef2a5 | ||
|
|
05142a779d | ||
|
|
65d17fb316 | ||
|
|
faa12880a9 | ||
|
|
9b6fa55433 | ||
|
|
b852baaa39 | ||
|
|
a3a216f91f | ||
|
|
efff85bc1f | ||
|
|
df61d1a59c | ||
|
|
4450b11e61 | ||
|
|
9f021b780c | ||
|
|
7df66eff5e | ||
|
|
6e5cde0b05 | ||
|
|
a65948de69 | ||
|
|
0d0a8fdc9a | ||
|
|
a5b888c193 | ||
|
|
32cc8e1a63 | ||
|
|
69ea456cf6 | ||
|
|
e02e91adaa | ||
|
|
264c508c80 | ||
|
|
c6209df1e0 | ||
|
|
a155f5561f | ||
|
|
0eac63b844 | ||
|
|
d07c2973e0 | ||
|
|
f1efc578cb | ||
|
|
0b486762fa | ||
|
|
17756f0e72 | ||
|
|
128400bfb5 | ||
|
|
de1df8bf28 | ||
|
|
fe01f13edb | ||
|
|
4040e09cb8 | ||
|
|
3b6cd18283 | ||
|
|
4f505486e3 | ||
|
|
f6e18bbf06 | ||
|
|
bbf6484e89 | ||
|
|
a988ad0c4e | ||
|
|
a815e94209 | ||
|
|
650bee1dea | ||
|
|
80c188586c | ||
|
|
b5cf8f9326 | ||
|
|
1aefd39782 | ||
|
|
8c21a2aa9e | ||
|
|
2df3ca547b | ||
|
|
8645147292 | ||
|
|
169da866f3 | ||
|
|
5e8107621e | ||
|
|
eb52095670 | ||
|
|
cb57752903 | ||
|
|
b870659fd9 | ||
|
|
895c05a84a | ||
|
|
4d47f24dd4 | ||
|
|
4bd6c2a804 | ||
|
|
48fa947692 | ||
|
|
88f66d5c51 | ||
|
|
fd135caed5 | ||
|
|
7fbab6760e | ||
|
|
e9a8175fd7 | ||
|
|
0d75a25bf0 | ||
|
|
6af294e9a4 | ||
|
|
38f50f014b | ||
|
|
a394f11d07 | ||
|
|
3ab73ddf84 | ||
|
|
c7a1fb67d0 | ||
|
|
afb8be4f0b | ||
|
|
dc2a392f4c | ||
|
|
61323c7f85 | ||
|
|
7ebf6b77e5 | ||
|
|
fa47e48a15 | ||
|
|
fee47fe347 | ||
|
|
039c038cd7 | ||
|
|
dd99a25db0 | ||
|
|
85791f730c | ||
|
|
eb859b9812 | ||
|
|
7cf0523561 | ||
|
|
aae2e3f835 | ||
|
|
e0ce4c49f3 | ||
|
|
a60a65cd2a | ||
|
|
b7d0ec53e8 | ||
|
|
ef5cd66494 | ||
|
|
0d1898e72d | ||
|
|
f20cd8c203 | ||
|
|
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 | ||
|
|
1ed0b70601 | ||
|
|
c3621f1e89 | ||
|
|
7de86fc4b4 | ||
|
|
963948b5c8 | ||
|
|
d9749e8975 | ||
|
|
f6e4e53728 | ||
|
|
98adb196ea | ||
|
|
6b60edbe5d | ||
|
|
9d6de42f48 | ||
|
|
a94a602ccd | ||
|
|
301818003d | ||
|
|
50d52c31e2 | ||
|
|
799968460d | ||
|
|
170d95aa3c | ||
|
|
fe7a2fe229 | ||
|
|
3f08e26881 | ||
|
|
921b2bfb28 | ||
|
|
9af2c92795 | ||
|
|
dabae456d9 | ||
|
|
c40785b6eb | ||
|
|
e2e80313ac | ||
|
|
14a99a7b9e | ||
|
|
50e8c299c6 | ||
|
|
326d12382f | ||
|
|
1de9dddd21 | ||
|
|
87b1f0d0de | ||
|
|
dd6cf19c39 | ||
|
|
f085afd92f | ||
|
|
604cbc1737 | ||
|
|
60b6faff19 | ||
|
|
e70059ed6b | ||
|
|
b26c1c16b9 | ||
|
|
c2bf9d94be | ||
|
|
ea09adbbf3 | ||
|
|
9d0de57fae | ||
|
|
da733538c4 | ||
|
|
6db7cea148 | ||
|
|
3993aa9524 | ||
|
|
6f9d4d89cd | ||
|
|
443bdc1234 | ||
|
|
9cd43d044e | ||
|
|
f8e680867b | ||
|
|
96a5540083 | ||
|
|
750e1bd80a | ||
|
|
a12f161be5 | ||
|
|
04568ea830 | ||
|
|
3be0b527d6 | ||
|
|
afc0732a32 | ||
|
|
9703fb06fc | ||
|
|
54cbf13219 | ||
|
|
6774a12c67 | ||
|
|
94e53d988b | ||
|
|
22d47ea8c4 | ||
|
|
73bba00cc6 | ||
|
|
6ed429ada2 | ||
|
|
d2c2d459c4 | ||
|
|
c8b906ffb7 | ||
|
|
264f1d6638 | ||
|
|
16c7908adc | ||
|
|
c9d05d7d4a | ||
|
|
ec7e4488dc | ||
|
|
72f440acf5 | ||
|
|
21bf698c81 | ||
|
|
489ee30e54 | ||
|
|
2abab0772f | ||
|
|
0bca0fabaa | ||
|
|
93ac3fea43 | ||
|
|
c72b71a43a | ||
|
|
9e8c40598c | ||
|
|
4ded4afb7d | ||
|
|
801c45da6d | ||
|
|
278b356a18 | ||
|
|
a718e01dbf | ||
|
|
8e6cdde861 | ||
|
|
62b0c2b647 | ||
|
|
1cd30ceb31 | ||
|
|
15c7a3f85b | ||
|
|
d977aff8cf | ||
|
|
e3b44c3950 | ||
|
|
ba035efc91 | ||
|
|
76cfd7784a | ||
|
|
3e6875ce1d | ||
|
|
1ab7aa0fc4 | ||
|
|
5950e0bfcb | ||
|
|
ac540d3d3f | ||
|
|
848ddc5f3e | ||
|
|
30d1d63813 | ||
|
|
9781a9094f | ||
|
|
ab3de5898d | ||
|
|
7ff8a3764b | ||
|
|
32d6d746b3 | ||
|
|
ecf9a0827d | ||
|
|
a9a7fac308 | ||
|
|
54b5884943 | ||
|
|
1fb38137dc | ||
|
|
2d6192db75 | ||
|
|
9ecceb4a1e | ||
|
|
6b25fcaa80 | ||
|
|
c5c83a4240 | ||
|
|
5e0eb5ab97 | ||
|
|
2de5ffc8d9 | ||
|
|
3b2fe39a0a | ||
|
|
285ff080d0 | ||
|
|
627bde9e9e | ||
|
|
ef7d5e6004 | ||
|
|
598c8a1c4d | ||
|
|
b3c20ee0ae | ||
|
|
cd8d382038 | ||
|
|
b678d61318 | ||
|
|
43c8231f7d | ||
|
|
db401e0daa | ||
|
|
675d4c5f2b | ||
|
|
fdbf3ed279 | ||
|
|
5660f9ac59 | ||
|
|
546e63aa4c | ||
|
|
ddbd143793 | ||
|
|
35ba321546 | ||
|
|
2fe7fe30f8 | ||
|
|
8d4d1d594b | ||
|
|
c86fafbd7e | ||
|
|
709c439afc | ||
|
|
4cdc88e4bb | ||
|
|
7c550a76a5 | ||
|
|
cfabbcaaf6 | ||
|
|
7ae6286152 | ||
|
|
fd9c28c960 | ||
|
|
fa9ee96f7f | ||
|
|
334c33ca07 | ||
|
|
85cc67fb4e | ||
|
|
af9eb7c374 | ||
|
|
44968cc01e | ||
|
|
af69b25eaa | ||
|
|
eb33b95083 | ||
|
|
aa9124e072 | ||
|
|
c086fad945 | ||
|
|
0fef88c358 | ||
|
|
56f8f8d3f4 | ||
|
|
5bced09fc5 | ||
|
|
b4e9ff7ce0 | ||
|
|
208cbabb31 | ||
|
|
2fb5cfd55d | ||
|
|
582036ba45 | ||
|
|
e06f9f5438 | ||
|
|
461876da93 | ||
|
|
4f1c662691 | ||
|
|
9abd4e05d0 | ||
|
|
faba64890e | ||
|
|
add54bfd0b | ||
|
|
16d39bb72b | ||
|
|
e63ce9ed08 | ||
|
|
60831cae88 | ||
|
|
97cf46eaa9 | ||
|
|
381e75b913 | ||
|
|
7bd516a16c | ||
|
|
3dd01cde89 | ||
|
|
495394084d | ||
|
|
2609ee5ed0 | ||
|
|
da930ce276 | ||
|
|
987924cbda | ||
|
|
8fac1c18c8 | ||
|
|
eb64fde885 | ||
|
|
b1e9537499 | ||
|
|
9d636cad29 | ||
|
|
696c0b0055 | ||
|
|
6e030fd62f | ||
|
|
bb14a95076 | ||
|
|
9664aed1f2 | ||
|
|
6dda5f477e | ||
|
|
72cd73ca71 | ||
|
|
02e18cf919 | ||
|
|
82671680e3 | ||
|
|
bff49f2a5f | ||
|
|
59d582ce83 | ||
|
|
a4a3ba65d7 | ||
|
|
11f4b64229 | ||
|
|
b76029fac3 | ||
|
|
3d45f31536 | ||
|
|
ade00c70e5 | ||
|
|
82dca5336d | ||
|
|
8c33d0ecbd | ||
|
|
dea5fd1a9d | ||
|
|
6a131f70f0 | ||
|
|
d33a0d5dde | ||
|
|
11cc7e37e1 | ||
|
|
7e6cb7ecc9 | ||
|
|
807c58dc36 | ||
|
|
1517f2d910 | ||
|
|
b0c59ee330 | ||
|
|
1ff52bab56 | ||
|
|
7a9fca7f77 | ||
|
|
dea53a0dba | ||
|
|
db999b82ed | ||
|
|
c92468062d | ||
|
|
4de0f09c85 | ||
|
|
9c9c1b4d3b | ||
|
|
5ffe91f069 | ||
|
|
63867518ee | ||
|
|
53ff99e391 | ||
|
|
c035c12c0a | ||
|
|
6e39a02e99 | ||
|
|
956638e564 | ||
|
|
37907ad348 | ||
|
|
386aa898ec | ||
|
|
f1c5da7026 | ||
|
|
fc2a5224ef | ||
|
|
ce5aefd3d8 | ||
|
|
b2124dffb5 | ||
|
|
25eaace4be | ||
|
|
bb8efbcc82 | ||
|
|
e0bd5ad041 | ||
|
|
69ec49d0e9 | ||
|
|
8126f734e3 | ||
|
|
f2aaa6778c | ||
|
|
4fd5b01a83 | ||
|
|
1747a844fc | ||
|
|
afc210a70d | ||
|
|
f63003f982 | ||
|
|
e89037dd77 | ||
|
|
ab6e650e9c | ||
|
|
2ed246cb61 | ||
|
|
4449555abe | ||
|
|
f340f491dc | ||
|
|
c8f1e714e1 | ||
|
|
ddc428532f | ||
|
|
3414cae677 | ||
|
|
9d6972c6ce | ||
|
|
0566a0f1d6 | ||
|
|
de0561dcc2 | ||
|
|
a9f4f53f92 | ||
|
|
5fdfd4114a | ||
|
|
b195f9da44 | ||
|
|
1205d71f4b | ||
|
|
3f762a6476 | ||
|
|
4aa403c122 | ||
|
|
a13070a8da | ||
|
|
b63b171653 | ||
|
|
7219f8fed8 | ||
|
|
b6a5f834d6 | ||
|
|
99b9d53bbb | ||
|
|
edca19a697 | ||
|
|
c13d721062 | ||
|
|
d2f316c484 | ||
|
|
70e832d4db | ||
|
|
21895bd09b | ||
|
|
411ef5f9e8 | ||
|
|
f6282b9a09 | ||
|
|
e10030b73d | ||
|
|
cdf14158b4 | ||
|
|
f310e672b0 | ||
|
|
675d0d28d2 | ||
|
|
4c2fd056ef | ||
|
|
a259e48377 | ||
|
|
095c586172 | ||
|
|
c9c198b54b | ||
|
|
2a11bb4f3b | ||
|
|
35bac50962 | ||
|
|
366d2c1d97 | ||
|
|
9a930cbd95 | ||
|
|
03277513a9 | ||
|
|
1b0fca8026 | ||
|
|
c9cf5b78c5 | ||
|
|
d6679a1e9b | ||
|
|
b721a4b361 | ||
|
|
88bbd43314 | ||
|
|
fb1c97cdc1 | ||
|
|
f5ae8a0a4c | ||
|
|
1994eaa406 | ||
|
|
510b40a776 | ||
|
|
f37b070965 | ||
|
|
41385261f3 | ||
|
|
19b4849345 | ||
|
|
76283bd299 | ||
|
|
2e4cda74c8 | ||
|
|
5512b71e16 | ||
|
|
97b60c43b7 | ||
|
|
35b62f8526 | ||
|
|
a15a3f005c | ||
|
|
776c4a988a | ||
|
|
c419969253 | ||
|
|
ba324c73ce | ||
|
|
4a5dc78331 | ||
|
|
55dc9dfb54 | ||
|
|
23a8191bb5 | ||
|
|
c665caaf35 | ||
|
|
099efb883d | ||
|
|
44237426df | ||
|
|
eeefd19ad3 | ||
|
|
47ae6e7a5a | ||
|
|
03ed6e9755 | ||
|
|
8d4e7f0a82 | ||
|
|
7fdf491c05 | ||
|
|
ef1563283e | ||
|
|
a206d79851 | ||
|
|
42c9c0a06b | ||
|
|
f0ede01017 | ||
|
|
d67007f777 | ||
|
|
83d81e3788 | ||
|
|
e789e16289 | ||
|
|
61c9683aa6 | ||
|
|
ee9d1356b2 | ||
|
|
f92a49fda9 | ||
|
|
3dc6a055ac | ||
|
|
229f0d97f9 | ||
|
|
7cc530f950 | ||
|
|
2ef840ce12 | ||
|
|
a372d8d1d5 | ||
|
|
aad150cf1d | ||
|
|
be13a11dd5 | ||
|
|
59c6f35b0b | ||
|
|
37e45c5e7c | ||
|
|
39370f1eab | ||
|
|
aec7ac6ebd | ||
|
|
f6e63d0917 | ||
|
|
0ae67edaba | ||
|
|
481f6435ee | ||
|
|
d0c5c3d3cf | ||
|
|
9f8250bd47 | ||
|
|
3a3fffb2dd | ||
|
|
4cfa4eaf8e | ||
|
|
abb1125a2c | ||
|
|
a2acbe9fe6 | ||
|
|
cab8c690d2 | ||
|
|
0d1f8a06ce | ||
|
|
d42fe921db | ||
|
|
db7fb81855 | ||
|
|
d3c695b853 | ||
|
|
010c3ab0b8 | ||
|
|
58cdbca5cf | ||
|
|
8275082896 | ||
|
|
d79da1ef9f | ||
|
|
a9636426b8 | ||
|
|
329caad681 | ||
|
|
ecb84e090c | ||
|
|
8e9fc14b0e | ||
|
|
0f77ca605d | ||
|
|
231fcc8178 | ||
|
|
2839091b22 | ||
|
|
47e67481b3 | ||
|
|
55059b015f | ||
|
|
eb6c58682d | ||
|
|
26055de772 | ||
|
|
ebb4581595 | ||
|
|
d1fecc11c9 | ||
|
|
056247a34a | ||
|
|
7010015e8a | ||
|
|
62d50d27be | ||
|
|
1e5231d68b | ||
|
|
e04efad3c0 | ||
|
|
e54db3ce50 | ||
|
|
77076dbd67 | ||
|
|
6f20a798ab | ||
|
|
0d3a22bbc3 | ||
|
|
f34c96ecf5 | ||
|
|
206c85778e | ||
|
|
d6b4b9f973 | ||
|
|
3065e29deb | ||
|
|
481047bed8 | ||
|
|
f72292cce2 | ||
|
|
7b35902d33 | ||
|
|
1660900914 | ||
|
|
a7be25ce8b | ||
|
|
54b5ba08b8 | ||
|
|
0fb8d48074 | ||
|
|
b5fac4157d | ||
|
|
9e61949f9f | ||
|
|
6c5640798f | ||
|
|
03222197a3 | ||
|
|
12f417d0a3 | ||
|
|
c77aaece1d | ||
|
|
25140c9072 | ||
|
|
3a636c29ab | ||
|
|
a11d5ccd37 | ||
|
|
f6e7937f74 | ||
|
|
e447b667e5 | ||
|
|
24c635e9bc | ||
|
|
2ad4dcd741 | ||
|
|
f5cd9e0799 | ||
|
|
e7064868b4 | ||
|
|
65cbbf15c9 | ||
|
|
a325509e1e | ||
|
|
69ae731898 | ||
|
|
3452dee1b0 | ||
|
|
64b337e3c6 | ||
|
|
5df9655fe3 | ||
|
|
f3669f3be6 | ||
|
|
61eb99c46d | ||
|
|
f74a14e34f | ||
|
|
517f1d7991 | ||
|
|
25e69885d0 | ||
|
|
60a357eda1 | ||
|
|
d74679a5f9 | ||
|
|
73a865073d | ||
|
|
4ff8c28fe4 | ||
|
|
4ab2539c8a | ||
|
|
459eb3903e | ||
|
|
611a537b55 | ||
|
|
3a74cc5a74 | ||
|
|
f1520e1a70 | ||
|
|
727b4668c2 | ||
|
|
1287e001d8 | ||
|
|
c9b53cf975 | ||
|
|
64811d0b6b | ||
|
|
74af187568 | ||
|
|
a28c023cf1 | ||
|
|
cdf7fd64b2 | ||
|
|
84ffa4a5b7 | ||
|
|
326a43de11 | ||
|
|
07f193d8d6 | ||
|
|
f79a57c3e2 | ||
|
|
f8319fcd02 | ||
|
|
815ef4c9c9 | ||
|
|
d1800aa6d0 | ||
|
|
dda940344e | ||
|
|
1fffeb430c | ||
|
|
7d0bbd0a4c | ||
|
|
15fd22681d | ||
|
|
6a2826b91c | ||
|
|
112111c7f9 | ||
|
|
ed8498f43f | ||
|
|
77a5bb9069 | ||
|
|
37f86803f7 | ||
|
|
160858b051 | ||
|
|
68f44c01ea | ||
|
|
bef8d7426f | ||
|
|
c758f079cd | ||
|
|
7e404b7c19 | ||
|
|
4b7faea552 | ||
|
|
4ddd391033 | ||
|
|
e52416fd47 | ||
|
|
f67a2d2f46 | ||
|
|
fcdda8d7a7 | ||
|
|
1f0b936e82 | ||
|
|
b70793db5c | ||
|
|
0f044f6c21 | ||
|
|
4c205dfde9 | ||
|
|
d58d460119 | ||
|
|
24a6edef9e | ||
|
|
a5485096ac | ||
|
|
60a5ccf70b | ||
|
|
d93a7c2997 | ||
|
|
af5f8e8a4a | ||
|
|
1596c855ff | ||
|
|
f45dd7a748 | ||
|
|
a036363e85 | ||
|
|
4aceea41fd | ||
|
|
7bbfcbaefd | ||
|
|
18eaa9bb92 | ||
|
|
6826d5444b | ||
|
|
622ec69216 | ||
|
|
d38c109d49 | ||
|
|
a31b2d0259 | ||
|
|
b13c076881 | ||
|
|
c429a55382 | ||
|
|
20c4b21c39 | ||
|
|
d3289dc688 | ||
|
|
685c0b844e | ||
|
|
57c9b14198 | ||
|
|
d0a13cb12a | ||
|
|
71c72f74a1 | ||
|
|
ad24fe7017 | ||
|
|
e5578a8ef3 | ||
|
|
3a40d5e243 | ||
|
|
8e34898b4e | ||
|
|
0b0d049071 | ||
|
|
9e74ac24fa | ||
|
|
cbe612baa5 | ||
|
|
899d36b2c9 | ||
|
|
530977d6b3 | ||
|
|
aa682fa2c9 | ||
|
|
e3893b1887 |
@@ -1,2 +1,3 @@
|
|||||||
awx/ui/node_modules
|
awx/ui/node_modules
|
||||||
Dockerfile
|
Dockerfile
|
||||||
|
.git
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -16,7 +16,7 @@ https://www.ansible.com/security
|
|||||||
<!-- Pick the area of AWX for this issue, you can have multiple, delete the rest: -->
|
<!-- Pick the area of AWX for this issue, you can have multiple, delete the rest: -->
|
||||||
- API
|
- API
|
||||||
- UI
|
- UI
|
||||||
- Installer
|
- Collection
|
||||||
|
|
||||||
##### SUMMARY
|
##### SUMMARY
|
||||||
<!-- Briefly describe the problem. -->
|
<!-- Briefly describe the problem. -->
|
||||||
|
|||||||
17
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
17
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,26 +1,24 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: Create a report to help us improve
|
description: Create a report to help us improve
|
||||||
labels:
|
|
||||||
- bug
|
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Issues are for **concrete, actionable bugs and feature requests** only. For debugging help or technical support, please use:
|
Issues are for **concrete, actionable bugs and feature requests** only. For debugging help or technical support, please use:
|
||||||
- The #ansible-awx channel on irc.libera.chat
|
- The #ansible-awx channel on irc.libera.chat
|
||||||
- https://groups.google.com/forum/#!forum/awx-project
|
- The awx project mailing list, https://groups.google.com/forum/#!forum/awx-project
|
||||||
|
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: terms
|
id: terms
|
||||||
attributes:
|
attributes:
|
||||||
label: Please confirm the following
|
label: Please confirm the following
|
||||||
options:
|
options:
|
||||||
- label: I agree to follow this project's [code of conduct](http://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
|
- label: I agree to follow this project's [code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
|
||||||
required: true
|
required: true
|
||||||
- label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
|
- label: I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
|
||||||
required: true
|
required: true
|
||||||
- label: I understand that AWX is open source software provided for free and that I am not entitled to status updates or other assurances.
|
- label: I understand that AWX is open source software provided for free and that I might not receive a timely response.
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -39,6 +37,15 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: components
|
||||||
|
attributes:
|
||||||
|
label: Select the relevant components
|
||||||
|
options:
|
||||||
|
- label: UI
|
||||||
|
- label: API
|
||||||
|
- label: Docs
|
||||||
|
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: awx-install-method
|
id: awx-install-method
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -25,6 +25,7 @@ the change does.
|
|||||||
<!--- Name of the module/plugin/module/task -->
|
<!--- Name of the module/plugin/module/task -->
|
||||||
- API
|
- API
|
||||||
- UI
|
- UI
|
||||||
|
- Collection
|
||||||
|
|
||||||
##### AWX VERSION
|
##### AWX VERSION
|
||||||
<!--- Paste verbatim output from `make VERSION` between quotes below -->
|
<!--- Paste verbatim output from `make VERSION` between quotes below -->
|
||||||
|
|||||||
12
.github/issue_labeler.yml
vendored
Normal file
12
.github/issue_labeler.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
needs_triage:
|
||||||
|
- '.*'
|
||||||
|
"type:bug":
|
||||||
|
- "Please confirm the following"
|
||||||
|
"type:enhancement":
|
||||||
|
- "Feature Idea"
|
||||||
|
"component:ui":
|
||||||
|
- "\\[X\\] UI"
|
||||||
|
"component:api":
|
||||||
|
- "\\[X\\] API"
|
||||||
|
"component:docs":
|
||||||
|
- "\\[X\\] Docs"
|
||||||
14
.github/pr_labeler.yml
vendored
Normal file
14
.github/pr_labeler.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
"component:api":
|
||||||
|
- any: ['awx/**/*', '!awx/ui/*']
|
||||||
|
|
||||||
|
"component:ui":
|
||||||
|
- any: ['awx/ui/**/*']
|
||||||
|
|
||||||
|
"component:docs":
|
||||||
|
- any: ['docs/**/*']
|
||||||
|
|
||||||
|
"component:cli":
|
||||||
|
- any: ['awxkit/**/*']
|
||||||
|
|
||||||
|
"component:collection":
|
||||||
|
- any: ['awx_collection/**/*']
|
||||||
206
.github/workflows/ci.yml
vendored
206
.github/workflows/ci.yml
vendored
@@ -4,64 +4,51 @@ env:
|
|||||||
BRANCH: ${{ github.base_ref || 'devel' }}
|
BRANCH: ${{ github.base_ref || 'devel' }}
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
|
||||||
branches: [devel]
|
|
||||||
jobs:
|
jobs:
|
||||||
api-test:
|
common-tests:
|
||||||
|
name: ${{ matrix.tests.name }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
tests:
|
||||||
|
- name: api-test
|
||||||
|
command: /start_tests.sh
|
||||||
|
label: Run API Tests
|
||||||
|
- name: api-lint
|
||||||
|
command: /var/lib/awx/venv/awx/bin/tox -e linters
|
||||||
|
label: Run API Linters
|
||||||
|
- name: api-swagger
|
||||||
|
command: /start_tests.sh swagger
|
||||||
|
label: Generate API Reference
|
||||||
|
- name: awx-collection
|
||||||
|
command: /start_tests.sh test_collection_all
|
||||||
|
label: Run Collection Tests
|
||||||
|
- name: api-schema
|
||||||
|
label: Check API Schema
|
||||||
|
command: /start_tests.sh detect-schema-change SCHEMA_DIFF_BASE_BRANCH=${{ github.event.pull_request.base.ref }}
|
||||||
|
- name: ui-lint
|
||||||
|
label: Run UI Linters
|
||||||
|
command: make ui-lint
|
||||||
|
- name: ui-test-screens
|
||||||
|
label: Run UI Screens Tests
|
||||||
|
command: make ui-test-screens
|
||||||
|
- name: ui-test-general
|
||||||
|
label: Run UI General Tests
|
||||||
|
command: make ui-test-general
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Log in to registry
|
- name: Get python version from Makefile
|
||||||
run: |
|
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
- name: Install python ${{ env.py_version }}
|
||||||
run: |
|
uses: actions/setup-python@v2
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
|
with:
|
||||||
|
python-version: ${{ env.py_version }}
|
||||||
- name: Build image
|
|
||||||
run: |
|
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
|
||||||
|
|
||||||
- name: Run API Tests
|
|
||||||
run: |
|
|
||||||
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
|
||||||
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh
|
|
||||||
api-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Log in to registry
|
|
||||||
run: |
|
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
|
||||||
run: |
|
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
|
|
||||||
|
|
||||||
- name: Build image
|
|
||||||
run: |
|
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
|
||||||
|
|
||||||
- name: Run API Linters
|
|
||||||
run: |
|
|
||||||
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
|
||||||
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /var/lib/awx/venv/awx/bin/tox -e linters
|
|
||||||
api-swagger:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Log in to registry
|
- name: Log in to registry
|
||||||
run: |
|
run: |
|
||||||
@@ -73,105 +60,78 @@ jobs:
|
|||||||
|
|
||||||
- name: Build image
|
- name: Build image
|
||||||
run: |
|
run: |
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
||||||
|
|
||||||
- name: Generate API Reference
|
- name: ${{ matrix.texts.label }}
|
||||||
run: |
|
run: |
|
||||||
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
||||||
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh swagger
|
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} ${{ matrix.tests.command }}
|
||||||
awx-collection:
|
dev-env:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get python version from Makefile
|
||||||
|
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install python ${{ env.py_version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.py_version }}
|
||||||
|
|
||||||
- name: Log in to registry
|
- name: Log in to registry
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
- name: Pre-pull image to warm build cache
|
||||||
run: |
|
run: |
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
|
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
|
||||||
|
|
||||||
- name: Build image
|
|
||||||
run: |
|
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
|
||||||
|
|
||||||
- name: Run Collection Tests
|
|
||||||
run: |
|
|
||||||
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
|
||||||
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh test_collection_all
|
|
||||||
api-schema:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Log in to registry
|
|
||||||
run: |
|
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
|
||||||
run: |
|
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
|
|
||||||
|
|
||||||
- name: Build image
|
|
||||||
run: |
|
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
|
||||||
|
|
||||||
- name: Check API Schema
|
|
||||||
run: |
|
|
||||||
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
|
||||||
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} /start_tests.sh detect-schema-change
|
|
||||||
ui-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Log in to registry
|
|
||||||
run: |
|
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
|
||||||
run: |
|
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
|
|
||||||
|
|
||||||
- name: Build image
|
- name: Build image
|
||||||
run: |
|
run: |
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
||||||
|
|
||||||
- name: Run UI Linters
|
- name: Run smoke test
|
||||||
run: |
|
run: |
|
||||||
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
export DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }}
|
||||||
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} make ui-lint
|
export COMPOSE_TAG=${{ env.BRANCH }}
|
||||||
ui-test:
|
ansible-playbook tools/docker-compose/ansible/smoke-test.yml -e repo_dir=$(pwd) -v
|
||||||
|
|
||||||
|
awx-operator:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout awx
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: awx
|
||||||
|
|
||||||
- name: Log in to registry
|
- name: Checkout awx-operator
|
||||||
run: |
|
uses: actions/checkout@v2
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
with:
|
||||||
|
repository: ansible/awx-operator
|
||||||
|
path: awx-operator
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
- name: Install playbook dependencies
|
||||||
run: |
|
run: |
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
|
python3 -m pip install docker
|
||||||
|
|
||||||
- name: Build image
|
- name: Build AWX image
|
||||||
|
working-directory: awx
|
||||||
run: |
|
run: |
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${{ env.BRANCH }} make docker-compose-build
|
ansible-playbook -v tools/ansible/build.yml \
|
||||||
|
-e headless=yes \
|
||||||
|
-e awx_image=awx \
|
||||||
|
-e awx_image_tag=ci \
|
||||||
|
-e ansible_python_interpreter=$(which python3)
|
||||||
|
|
||||||
- name: Run UI Tests
|
- name: Run test deployment with awx-operator
|
||||||
|
working-directory: awx-operator
|
||||||
run: |
|
run: |
|
||||||
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
|
python3 -m pip install -r molecule/requirements.txt
|
||||||
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} make ui-test
|
ansible-galaxy collection install -r molecule/requirements.yml
|
||||||
|
sudo rm -f $(which kustomize)
|
||||||
|
make kustomize
|
||||||
|
KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule -v test -s kind
|
||||||
|
env:
|
||||||
|
AWX_TEST_IMAGE: awx
|
||||||
|
AWX_TEST_VERSION: ci
|
||||||
|
|||||||
30
.github/workflows/devel_image.yml
vendored
30
.github/workflows/devel_image.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
name: Push Development Image
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- devel
|
|
||||||
jobs:
|
|
||||||
push:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Log in to registry
|
|
||||||
run: |
|
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
|
||||||
run: |
|
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
|
|
||||||
|
|
||||||
- name: Build image
|
|
||||||
run: |
|
|
||||||
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make docker-compose-build
|
|
||||||
|
|
||||||
- name: Push image
|
|
||||||
run: |
|
|
||||||
docker push ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
|
|
||||||
43
.github/workflows/devel_images.yml
vendored
Normal file
43
.github/workflows/devel_images.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
name: Build/Push Development Images
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- devel
|
||||||
|
- release_*
|
||||||
|
jobs:
|
||||||
|
push:
|
||||||
|
if: endsWith(github.repository, '/awx') || startsWith(github.ref, 'refs/heads/release_')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get python version from Makefile
|
||||||
|
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install python ${{ env.py_version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.py_version }}
|
||||||
|
|
||||||
|
- name: Log in to registry
|
||||||
|
run: |
|
||||||
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
|
- name: Pre-pull image to warm build cache
|
||||||
|
run: |
|
||||||
|
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} || :
|
||||||
|
docker pull ghcr.io/${{ github.repository_owner }}/awx_kube_devel:${GITHUB_REF##*/} || :
|
||||||
|
|
||||||
|
- name: Build images
|
||||||
|
run: |
|
||||||
|
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make docker-compose-build
|
||||||
|
DEV_DOCKER_TAG_BASE=ghcr.io/${{ github.repository_owner }} COMPOSE_TAG=${GITHUB_REF##*/} make awx-kube-dev-build
|
||||||
|
|
||||||
|
- name: Push image
|
||||||
|
run: |
|
||||||
|
docker push ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
|
||||||
|
docker push ghcr.io/${{ github.repository_owner }}/awx_kube_devel:${GITHUB_REF##*/}
|
||||||
10
.github/workflows/e2e_test.yml
vendored
10
.github/workflows/e2e_test.yml
vendored
@@ -18,6 +18,14 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get python version from Makefile
|
||||||
|
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install python ${{ env.py_version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.py_version }}
|
||||||
|
|
||||||
- name: Install system deps
|
- name: Install system deps
|
||||||
run: sudo apt-get install -y gettext
|
run: sudo apt-get install -y gettext
|
||||||
|
|
||||||
@@ -85,7 +93,7 @@ jobs:
|
|||||||
-e CYPRESS_baseUrl="https://$AWX_IP:8043" \
|
-e CYPRESS_baseUrl="https://$AWX_IP:8043" \
|
||||||
-e CYPRESS_AWX_E2E_USERNAME=admin \
|
-e CYPRESS_AWX_E2E_USERNAME=admin \
|
||||||
-e CYPRESS_AWX_E2E_PASSWORD='password' \
|
-e CYPRESS_AWX_E2E_PASSWORD='password' \
|
||||||
-e COMMAND="npm run cypress-gha" \
|
-e COMMAND="npm run cypress-concurrently-gha" \
|
||||||
-v /dev/shm:/dev/shm \
|
-v /dev/shm:/dev/shm \
|
||||||
-v $PWD:/e2e \
|
-v $PWD:/e2e \
|
||||||
-w /e2e \
|
-w /e2e \
|
||||||
|
|||||||
21
.github/workflows/label_issue.yml
vendored
Normal file
21
.github/workflows/label_issue.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: Label Issue
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
triage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Label Issue
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Label Issue
|
||||||
|
uses: github/issue-labeler@v2.4.1
|
||||||
|
with:
|
||||||
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
not-before: 2021-12-07T07:00:00Z
|
||||||
|
configuration-path: .github/issue_labeler.yml
|
||||||
|
enable-versioned-regex: 0
|
||||||
20
.github/workflows/label_pr.yml
vendored
Normal file
20
.github/workflows/label_pr.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
name: Label PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
triage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Label PR
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Label PR
|
||||||
|
uses: actions/labeler@v3
|
||||||
|
with:
|
||||||
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
configuration-path: .github/pr_labeler.yml
|
||||||
73
.github/workflows/promote.yml
vendored
Normal file
73
.github/workflows/promote.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
name: Promote Release
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
promote:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout awx
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get python version from Makefile
|
||||||
|
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install python ${{ env.py_version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.py_version }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python${{ env.py_version }} -m pip install wheel twine
|
||||||
|
|
||||||
|
- name: Set official collection namespace
|
||||||
|
run: echo collection_namespace=awx >> $GITHUB_ENV
|
||||||
|
if: ${{ github.repository_owner == 'ansible' }}
|
||||||
|
|
||||||
|
- name: Set unofficial collection namespace
|
||||||
|
run: echo collection_namespace=${{ github.repository_owner }} >> $GITHUB_ENV
|
||||||
|
if: ${{ github.repository_owner != 'ansible' }}
|
||||||
|
|
||||||
|
- name: Build collection and publish to galaxy
|
||||||
|
run: |
|
||||||
|
COLLECTION_NAMESPACE=${{ env.collection_namespace }} make build_collection
|
||||||
|
ansible-galaxy collection publish \
|
||||||
|
--token=${{ secrets.GALAXY_TOKEN }} \
|
||||||
|
awx_collection_build/${{ env.collection_namespace }}-awx-${{ github.event.release.tag_name }}.tar.gz
|
||||||
|
|
||||||
|
- name: Set official pypi info
|
||||||
|
run: echo pypi_repo=pypi >> $GITHUB_ENV
|
||||||
|
if: ${{ github.repository_owner == 'ansible' }}
|
||||||
|
|
||||||
|
- name: Set unofficial pypi info
|
||||||
|
run: echo pypi_repo=testpypi >> $GITHUB_ENV
|
||||||
|
if: ${{ github.repository_owner != 'ansible' }}
|
||||||
|
|
||||||
|
- name: Build awxkit and upload to pypi
|
||||||
|
run: |
|
||||||
|
cd awxkit && python3 setup.py bdist_wheel
|
||||||
|
twine upload \
|
||||||
|
-r ${{ env.pypi_repo }} \
|
||||||
|
-u ${{ secrets.PYPI_USERNAME }} \
|
||||||
|
-p ${{ secrets.PYPI_PASSWORD }} \
|
||||||
|
dist/*
|
||||||
|
|
||||||
|
- name: Log in to GHCR
|
||||||
|
run: |
|
||||||
|
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
|
- name: Log in to Quay
|
||||||
|
run: |
|
||||||
|
echo ${{ secrets.QUAY_TOKEN }} | docker login quay.io -u ${{ secrets.QUAY_USER }} --password-stdin
|
||||||
|
|
||||||
|
- name: Re-tag and promote awx image
|
||||||
|
run: |
|
||||||
|
docker pull ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }}
|
||||||
|
docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:${{ github.event.release.tag_name }}
|
||||||
|
docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:latest
|
||||||
|
docker push quay.io/${{ github.repository }}:${{ github.event.release.tag_name }}
|
||||||
|
docker push quay.io/${{ github.repository }}:latest
|
||||||
|
|
||||||
56
.github/workflows/release.yml
vendored
56
.github/workflows/release.yml
vendored
@@ -1,56 +0,0 @@
|
|||||||
name: Release AWX
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: 'Version'
|
|
||||||
required: true
|
|
||||||
default: ''
|
|
||||||
confirm:
|
|
||||||
description: 'Are you sure? Set this to yes.'
|
|
||||||
required: true
|
|
||||||
default: 'no'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: "Verify inputs"
|
|
||||||
run: |
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [[ ${{ github.event.inputs.confirm }} != "yes" ]]; then
|
|
||||||
>&2 echo "Confirm must be 'yes'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${{ github.event.inputs.version }} == "" ]]; then
|
|
||||||
>&2 echo "Set version to continue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
- name: Generate changelog
|
|
||||||
uses: shanemcd/simple-changelog-generator@v1
|
|
||||||
id: changelog
|
|
||||||
with:
|
|
||||||
repo: "${{ github.repository }}"
|
|
||||||
|
|
||||||
- name: Write changelog to file
|
|
||||||
run: |
|
|
||||||
cat << 'EOF' > /tmp/changelog
|
|
||||||
${{ steps.changelog.outputs.changelog }}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- name: Release AWX
|
|
||||||
run: |
|
|
||||||
ansible-playbook -v tools/ansible/release.yml \
|
|
||||||
-e changelog_path=/tmp/changelog \
|
|
||||||
-e version=${{ github.event.inputs.version }} \
|
|
||||||
-e github_token=${{ secrets.GITHUB_TOKEN }} \
|
|
||||||
-e repo=${{ github.repository }}
|
|
||||||
|
|
||||||
|
|
||||||
132
.github/workflows/stage.yml
vendored
Normal file
132
.github/workflows/stage.yml
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
---
|
||||||
|
name: Stage Release
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'AWX version.'
|
||||||
|
required: true
|
||||||
|
default: ''
|
||||||
|
operator_version:
|
||||||
|
description: 'Operator version. Leave blank to skip staging awx-operator.'
|
||||||
|
default: ''
|
||||||
|
confirm:
|
||||||
|
description: 'Are you sure? Set this to yes.'
|
||||||
|
required: true
|
||||||
|
default: 'no'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Verify inputs
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ ${{ github.event.inputs.confirm }} != "yes" ]]; then
|
||||||
|
>&2 echo "Confirm must be 'yes'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${{ github.event.inputs.version }} == "" ]]; then
|
||||||
|
>&2 echo "Set version to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
- name: Checkout awx
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: awx
|
||||||
|
|
||||||
|
- name: Get python version from Makefile
|
||||||
|
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install python ${{ env.py_version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.py_version }}
|
||||||
|
|
||||||
|
- name: Checkout awx-logos
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ansible/awx-logos
|
||||||
|
path: awx-logos
|
||||||
|
|
||||||
|
- name: Checkout awx-operator
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ${{ github.repository_owner }}/awx-operator
|
||||||
|
path: awx-operator
|
||||||
|
|
||||||
|
- name: Install playbook dependencies
|
||||||
|
run: |
|
||||||
|
python3 -m pip install docker
|
||||||
|
|
||||||
|
- name: Build and stage AWX
|
||||||
|
working-directory: awx
|
||||||
|
run: |
|
||||||
|
ansible-playbook -v tools/ansible/build.yml \
|
||||||
|
-e registry=ghcr.io \
|
||||||
|
-e registry_username=${{ github.actor }} \
|
||||||
|
-e registry_password=${{ secrets.GITHUB_TOKEN }} \
|
||||||
|
-e awx_image=${{ github.repository }} \
|
||||||
|
-e awx_version=${{ github.event.inputs.version }} \
|
||||||
|
-e ansible_python_interpreter=$(which python3) \
|
||||||
|
-e push=yes \
|
||||||
|
-e awx_official=yes
|
||||||
|
|
||||||
|
- name: Build and stage awx-operator
|
||||||
|
working-directory: awx-operator
|
||||||
|
run: |
|
||||||
|
BUILD_ARGS="--build-arg DEFAULT_AWX_VERSION=${{ github.event.inputs.version }} \
|
||||||
|
--build-arg OPERATOR_VERSION=${{ github.event.inputs.operator_version }}" \
|
||||||
|
IMAGE_TAG_BASE=ghcr.io/${{ github.repository_owner }}/awx-operator \
|
||||||
|
VERSION=${{ github.event.inputs.operator_version }} make docker-build docker-push
|
||||||
|
|
||||||
|
- name: Run test deployment with awx-operator
|
||||||
|
working-directory: awx-operator
|
||||||
|
run: |
|
||||||
|
python3 -m pip install -r molecule/requirements.txt
|
||||||
|
ansible-galaxy collection install -r molecule/requirements.yml
|
||||||
|
sudo rm -f $(which kustomize)
|
||||||
|
make kustomize
|
||||||
|
KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule test -s kind
|
||||||
|
env:
|
||||||
|
AWX_TEST_IMAGE: ${{ github.repository }}
|
||||||
|
AWX_TEST_VERSION: ${{ github.event.inputs.version }}
|
||||||
|
|
||||||
|
- name: Generate changelog
|
||||||
|
uses: shanemcd/simple-changelog-generator@v1
|
||||||
|
id: changelog
|
||||||
|
with:
|
||||||
|
repo: "${{ github.repository }}"
|
||||||
|
|
||||||
|
- name: Write changelog to file
|
||||||
|
run: |
|
||||||
|
cat << 'EOF' > /tmp/awx-changelog
|
||||||
|
${{ steps.changelog.outputs.changelog }}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Create draft release for AWX
|
||||||
|
working-directory: awx
|
||||||
|
run: |
|
||||||
|
ansible-playbook -v tools/ansible/stage.yml \
|
||||||
|
-e changelog_path=/tmp/awx-changelog \
|
||||||
|
-e repo=${{ github.repository }} \
|
||||||
|
-e awx_image=ghcr.io/${{ github.repository }} \
|
||||||
|
-e version=${{ github.event.inputs.version }} \
|
||||||
|
-e github_token=${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Create draft release for awx-operator
|
||||||
|
if: ${{ github.event.inputs.operator_version != '' }}
|
||||||
|
working-directory: awx
|
||||||
|
run: |
|
||||||
|
ansible-playbook tools/ansible/stage.yml \
|
||||||
|
-e version=${{ github.event.inputs.operator_version }} \
|
||||||
|
-e repo=${{ github.repository_owner }}/awx-operator \
|
||||||
|
-e github_token=${{ secrets.AWX_OPERATOR_RELEASE_TOKEN }}
|
||||||
13
.github/workflows/upload_schema.yml
vendored
13
.github/workflows/upload_schema.yml
vendored
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- devel
|
- devel
|
||||||
|
- release_**
|
||||||
jobs:
|
jobs:
|
||||||
push:
|
push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -13,13 +14,21 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get python version from Makefile
|
||||||
|
run: echo py_version=`make PYTHON_VERSION` >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install python ${{ env.py_version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.py_version }}
|
||||||
|
|
||||||
- name: Log in to registry
|
- name: Log in to registry
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
- name: Pre-pull image to warm build cache
|
- name: Pre-pull image to warm build cache
|
||||||
run: |
|
run: |
|
||||||
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
|
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} || :
|
||||||
|
|
||||||
- name: Build image
|
- name: Build image
|
||||||
run: |
|
run: |
|
||||||
@@ -38,6 +47,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
ansible localhost -c local, -m command -a "{{ ansible_python_interpreter + ' -m pip install boto3'}}"
|
ansible localhost -c local, -m command -a "{{ ansible_python_interpreter + ' -m pip install boto3'}}"
|
||||||
ansible localhost -c local -m aws_s3 \
|
ansible localhost -c local -m aws_s3 \
|
||||||
-a 'src=${{ github.workspace }}/schema.json bucket=awx-public-ci-files object=schema.json mode=put permission=public-read'
|
-a "src=${{ github.workspace }}/schema.json bucket=awx-public-ci-files object=${GITHUB_REF##*/}/schema.json mode=put permission=public-read"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,6 +7,9 @@ reference-schema.json
|
|||||||
.tags
|
.tags
|
||||||
.tags1
|
.tags1
|
||||||
|
|
||||||
|
# User level pre-commit hooks
|
||||||
|
pre-commit-user
|
||||||
|
|
||||||
# Tower
|
# Tower
|
||||||
awx-dev
|
awx-dev
|
||||||
awx/settings/local_*.py*
|
awx/settings/local_*.py*
|
||||||
@@ -42,6 +45,7 @@ tools/docker-compose/_build
|
|||||||
tools/docker-compose/_sources
|
tools/docker-compose/_sources
|
||||||
tools/docker-compose/overrides/
|
tools/docker-compose/overrides/
|
||||||
tools/docker-compose-minikube/_sources
|
tools/docker-compose-minikube/_sources
|
||||||
|
tools/docker-compose/keycloak.awx.realm.json
|
||||||
|
|
||||||
# Tower setup playbook testing
|
# Tower setup playbook testing
|
||||||
setup/test/roles/postgresql
|
setup/test/roles/postgresql
|
||||||
@@ -58,6 +62,7 @@ __pycache__
|
|||||||
/dist
|
/dist
|
||||||
/*.egg-info
|
/*.egg-info
|
||||||
*.py[c,o]
|
*.py[c,o]
|
||||||
|
/.eggs
|
||||||
|
|
||||||
# JavaScript
|
# JavaScript
|
||||||
/Gruntfile.js
|
/Gruntfile.js
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ ignore: |
|
|||||||
# vault files
|
# vault files
|
||||||
awx/main/tests/data/ansible_utils/playbooks/valid/vault.yml
|
awx/main/tests/data/ansible_utils/playbooks/valid/vault.yml
|
||||||
awx/ui/test/e2e/tests/smoke-vars.yml
|
awx/ui/test/e2e/tests/smoke-vars.yml
|
||||||
|
awx/ui/node_modules
|
||||||
|
tools/docker-compose/_sources
|
||||||
|
|
||||||
extends: default
|
extends: default
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
line-length: disable
|
line-length: disable
|
||||||
|
truthy: disable
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ Have questions about this document or anything not covered here? Come chat with
|
|||||||
- [Building API Documentation](#building-api-documentation)
|
- [Building API Documentation](#building-api-documentation)
|
||||||
- [Accessing the AWX web interface](#accessing-the-awx-web-interface)
|
- [Accessing the AWX web interface](#accessing-the-awx-web-interface)
|
||||||
- [Purging containers and images](#purging-containers-and-images)
|
- [Purging containers and images](#purging-containers-and-images)
|
||||||
|
- [Pre commit hooks](#pre-commit-hooks)
|
||||||
- [What should I work on?](#what-should-i-work-on)
|
- [What should I work on?](#what-should-i-work-on)
|
||||||
- [Submitting Pull Requests](#submitting-pull-requests)
|
- [Submitting Pull Requests](#submitting-pull-requests)
|
||||||
- [PR Checks run by Zuul](#pr-checks-run-by-zuul)
|
- [PR Checks run by Zuul](#pr-checks-run-by-zuul)
|
||||||
@@ -104,13 +105,21 @@ When necessary, remove any AWX containers and images by running the following:
|
|||||||
(host)$ make docker-clean
|
(host)$ make docker-clean
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Pre commit hooks
|
||||||
|
|
||||||
|
When you attempt to perform a `git commit` there will be a pre-commit hook that gets run before the commit is allowed to your local repository. For example, python's [black](https://pypi.org/project/black/) will be run to test the formatting of any python files.
|
||||||
|
|
||||||
|
While you can use environment variables to skip the pre-commit hooks GitHub will run similar tests and prevent merging of PRs if the tests do not pass.
|
||||||
|
|
||||||
|
If you would like to add additional commit hooks for your own usage you can create a directory in the root of the repository called `pre-commit-user`. Any executable file in that directory will be executed as part of the pre-commit hooks. If any of the pre-commit checks fail the commit will be halted. For your convenience in user scripts, a variable called `CHANGED_FILES` will be set with any changed files present in the commit.
|
||||||
|
|
||||||
## What should I work on?
|
## What should I work on?
|
||||||
|
|
||||||
For feature work, take a look at the current [Enhancements](https://github.com/ansible/awx/issues?q=is%3Aissue+is%3Aopen+label%3Atype%3Aenhancement).
|
For feature work, take a look at the current [Enhancements](https://github.com/ansible/awx/issues?q=is%3Aissue+is%3Aopen+label%3Atype%3Aenhancement).
|
||||||
|
|
||||||
If it has someone assigned to it then that person is the person responsible for working the enhancement. If you feel like you could contribute then reach out to that person.
|
If it has someone assigned to it then that person is the person responsible for working the enhancement. If you feel like you could contribute then reach out to that person.
|
||||||
|
|
||||||
Fixing bugs, adding translations, and updating the documentation are always appreciated, so reviewing the backlog of issues is always a good place to start. For extra information on debugging tools, see [Debugging](https://github.com/ansible/awx/blob/devel/docs/debugging.md).
|
Fixing bugs, adding translations, and updating the documentation are always appreciated, so reviewing the backlog of issues is always a good place to start. For extra information on debugging tools, see [Debugging](./docs/debugging/).
|
||||||
|
|
||||||
**NOTE**
|
**NOTE**
|
||||||
|
|
||||||
|
|||||||
122
Makefile
122
Makefile
@@ -1,29 +1,34 @@
|
|||||||
PYTHON ?= python3.8
|
PYTHON ?= python3.9
|
||||||
PYTHON_VERSION = $(shell $(PYTHON) -c "from distutils.sysconfig import get_python_version; print(get_python_version())")
|
|
||||||
OFFICIAL ?= no
|
OFFICIAL ?= no
|
||||||
NODE ?= node
|
NODE ?= node
|
||||||
NPM_BIN ?= npm
|
NPM_BIN ?= npm
|
||||||
CHROMIUM_BIN=/tmp/chrome-linux/chrome
|
CHROMIUM_BIN=/tmp/chrome-linux/chrome
|
||||||
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
|
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
MANAGEMENT_COMMAND ?= awx-manage
|
MANAGEMENT_COMMAND ?= awx-manage
|
||||||
VERSION := $(shell cat VERSION)
|
VERSION := $(shell $(PYTHON) setup.py --version)
|
||||||
|
COLLECTION_VERSION := $(shell $(PYTHON) setup.py --version | cut -d . -f 1-3)
|
||||||
|
|
||||||
# NOTE: This defaults the container image version to the branch that's active
|
# NOTE: This defaults the container image version to the branch that's active
|
||||||
COMPOSE_TAG ?= $(GIT_BRANCH)
|
COMPOSE_TAG ?= $(GIT_BRANCH)
|
||||||
COMPOSE_HOST ?= $(shell hostname)
|
|
||||||
MAIN_NODE_TYPE ?= hybrid
|
MAIN_NODE_TYPE ?= hybrid
|
||||||
|
# If set to true docker-compose will also start a keycloak instance
|
||||||
|
KEYCLOAK ?= false
|
||||||
|
# If set to true docker-compose will also start an ldap instance
|
||||||
|
LDAP ?= false
|
||||||
|
|
||||||
VENV_BASE ?= /var/lib/awx/venv
|
VENV_BASE ?= /var/lib/awx/venv
|
||||||
|
|
||||||
DEV_DOCKER_TAG_BASE ?= quay.io/awx
|
DEV_DOCKER_TAG_BASE ?= ghcr.io/ansible
|
||||||
DEVEL_IMAGE_NAME ?= $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
|
DEVEL_IMAGE_NAME ?= $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
|
||||||
|
|
||||||
|
RECEPTOR_IMAGE ?= quay.io/ansible/receptor:devel
|
||||||
|
|
||||||
# Python packages to install only from source (not from binary wheels)
|
# Python packages to install only from source (not from binary wheels)
|
||||||
# Comma separated list
|
# Comma separated list
|
||||||
SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio
|
SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio
|
||||||
# These should be upgraded in the AWX and Ansible venv before attempting
|
# These should be upgraded in the AWX and Ansible venv before attempting
|
||||||
# to install the actual requirements
|
# to install the actual requirements
|
||||||
VENV_BOOTSTRAP ?= pip==19.3.1 setuptools==41.6.0 wheel==0.36.2
|
VENV_BOOTSTRAP ?= pip==21.2.4 setuptools==58.2.0 setuptools_scm[toml]==6.4.2 wheel==0.36.2
|
||||||
|
|
||||||
NAME ?= awx
|
NAME ?= awx
|
||||||
|
|
||||||
@@ -40,7 +45,7 @@ I18N_FLAG_FILE = .i18n_built
|
|||||||
receiver test test_unit test_coverage coverage_html \
|
receiver test test_unit test_coverage coverage_html \
|
||||||
dev_build release_build sdist \
|
dev_build release_build sdist \
|
||||||
ui-release ui-devel \
|
ui-release ui-devel \
|
||||||
VERSION docker-compose-sources \
|
VERSION PYTHON_VERSION docker-compose-sources \
|
||||||
.git/hooks/pre-commit
|
.git/hooks/pre-commit
|
||||||
|
|
||||||
clean-tmp:
|
clean-tmp:
|
||||||
@@ -142,24 +147,6 @@ version_file:
|
|||||||
fi; \
|
fi; \
|
||||||
$(PYTHON) -c "import awx; print(awx.__version__)" > /var/lib/awx/.awx_version; \
|
$(PYTHON) -c "import awx; print(awx.__version__)" > /var/lib/awx/.awx_version; \
|
||||||
|
|
||||||
# Do any one-time init tasks.
|
|
||||||
comma := ,
|
|
||||||
init:
|
|
||||||
if [ "$(VENV_BASE)" ]; then \
|
|
||||||
. $(VENV_BASE)/awx/bin/activate; \
|
|
||||||
fi; \
|
|
||||||
$(MANAGEMENT_COMMAND) provision_instance --hostname=$(COMPOSE_HOST) --node_type=$(MAIN_NODE_TYPE); \
|
|
||||||
$(MANAGEMENT_COMMAND) register_queue --queuename=controlplane --instance_percent=100;\
|
|
||||||
$(MANAGEMENT_COMMAND) register_queue --queuename=default --instance_percent=100;
|
|
||||||
if [ ! -f /etc/receptor/certs/awx.key ]; then \
|
|
||||||
rm -f /etc/receptor/certs/*; \
|
|
||||||
receptor --cert-init commonname="AWX Test CA" bits=2048 outcert=/etc/receptor/certs/ca.crt outkey=/etc/receptor/certs/ca.key; \
|
|
||||||
for node in $(RECEPTOR_MUTUAL_TLS); do \
|
|
||||||
receptor --cert-makereq bits=2048 commonname="$$node test cert" dnsname=$$node nodeid=$$node outreq=/etc/receptor/certs/$$node.csr outkey=/etc/receptor/certs/$$node.key; \
|
|
||||||
receptor --cert-signreq req=/etc/receptor/certs/$$node.csr cacert=/etc/receptor/certs/ca.crt cakey=/etc/receptor/certs/ca.key outcert=/etc/receptor/certs/$$node.crt verify=yes; \
|
|
||||||
done; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Refresh development environment after pulling new code.
|
# Refresh development environment after pulling new code.
|
||||||
refresh: clean requirements_dev version_file develop migrate
|
refresh: clean requirements_dev version_file develop migrate
|
||||||
|
|
||||||
@@ -280,17 +267,16 @@ api-lint:
|
|||||||
|
|
||||||
awx-link:
|
awx-link:
|
||||||
[ -d "/awx_devel/awx.egg-info" ] || $(PYTHON) /awx_devel/setup.py egg_info_dev
|
[ -d "/awx_devel/awx.egg-info" ] || $(PYTHON) /awx_devel/setup.py egg_info_dev
|
||||||
cp -f /tmp/awx.egg-link /var/lib/awx/venv/awx/lib/python$(PYTHON_VERSION)/site-packages/awx.egg-link
|
cp -f /tmp/awx.egg-link /var/lib/awx/venv/awx/lib/$(PYTHON)/site-packages/awx.egg-link
|
||||||
|
|
||||||
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
|
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
|
||||||
|
PYTEST_ARGS ?= -n auto
|
||||||
# Run all API unit tests.
|
# Run all API unit tests.
|
||||||
test:
|
test:
|
||||||
if [ "$(VENV_BASE)" ]; then \
|
if [ "$(VENV_BASE)" ]; then \
|
||||||
. $(VENV_BASE)/awx/bin/activate; \
|
. $(VENV_BASE)/awx/bin/activate; \
|
||||||
fi; \
|
fi; \
|
||||||
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS)
|
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider $(PYTEST_ARGS) $(TEST_DIRS)
|
||||||
cmp VERSION awxkit/VERSION || "VERSION and awxkit/VERSION *must* match"
|
|
||||||
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
|
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
|
||||||
awx-manage check_migrations --dry-run --check -n 'missing_migration_file'
|
awx-manage check_migrations --dry-run --check -n 'missing_migration_file'
|
||||||
|
|
||||||
@@ -321,13 +307,19 @@ symlink_collection:
|
|||||||
mkdir -p ~/.ansible/collections/ansible_collections/$(COLLECTION_NAMESPACE) # in case it does not exist
|
mkdir -p ~/.ansible/collections/ansible_collections/$(COLLECTION_NAMESPACE) # in case it does not exist
|
||||||
ln -s $(shell pwd)/awx_collection $(COLLECTION_INSTALL)
|
ln -s $(shell pwd)/awx_collection $(COLLECTION_INSTALL)
|
||||||
|
|
||||||
build_collection:
|
awx_collection_build: $(shell find awx_collection -type f)
|
||||||
ansible-playbook -i localhost, awx_collection/tools/template_galaxy.yml -e collection_package=$(COLLECTION_PACKAGE) -e collection_namespace=$(COLLECTION_NAMESPACE) -e collection_version=$(VERSION) -e '{"awx_template_version":false}'
|
ansible-playbook -i localhost, awx_collection/tools/template_galaxy.yml \
|
||||||
|
-e collection_package=$(COLLECTION_PACKAGE) \
|
||||||
|
-e collection_namespace=$(COLLECTION_NAMESPACE) \
|
||||||
|
-e collection_version=$(COLLECTION_VERSION) \
|
||||||
|
-e '{"awx_template_version":false}'
|
||||||
ansible-galaxy collection build awx_collection_build --force --output-path=awx_collection_build
|
ansible-galaxy collection build awx_collection_build --force --output-path=awx_collection_build
|
||||||
|
|
||||||
|
build_collection: awx_collection_build
|
||||||
|
|
||||||
install_collection: build_collection
|
install_collection: build_collection
|
||||||
rm -rf $(COLLECTION_INSTALL)
|
rm -rf $(COLLECTION_INSTALL)
|
||||||
ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(VERSION).tar.gz
|
ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(COLLECTION_VERSION).tar.gz
|
||||||
|
|
||||||
test_collection_sanity: install_collection
|
test_collection_sanity: install_collection
|
||||||
cd $(COLLECTION_INSTALL) && ansible-test sanity
|
cd $(COLLECTION_INSTALL) && ansible-test sanity
|
||||||
@@ -378,9 +370,9 @@ clean-ui:
|
|||||||
rm -rf $(UI_BUILD_FLAG_FILE)
|
rm -rf $(UI_BUILD_FLAG_FILE)
|
||||||
|
|
||||||
awx/ui/node_modules:
|
awx/ui/node_modules:
|
||||||
NODE_OPTIONS=--max-old-space-size=4096 $(NPM_BIN) --prefix awx/ui --loglevel warn ci
|
NODE_OPTIONS=--max-old-space-size=6144 $(NPM_BIN) --prefix awx/ui --loglevel warn ci
|
||||||
|
|
||||||
$(UI_BUILD_FLAG_FILE):
|
$(UI_BUILD_FLAG_FILE): awx/ui/node_modules
|
||||||
$(PYTHON) tools/scripts/compilemessages.py
|
$(PYTHON) tools/scripts/compilemessages.py
|
||||||
$(NPM_BIN) --prefix awx/ui --loglevel warn run compile-strings
|
$(NPM_BIN) --prefix awx/ui --loglevel warn run compile-strings
|
||||||
$(NPM_BIN) --prefix awx/ui --loglevel warn run build
|
$(NPM_BIN) --prefix awx/ui --loglevel warn run build
|
||||||
@@ -392,7 +384,9 @@ $(UI_BUILD_FLAG_FILE):
|
|||||||
cp -r awx/ui/build/static/media/* awx/public/static/media
|
cp -r awx/ui/build/static/media/* awx/public/static/media
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
ui-release: awx/ui/node_modules $(UI_BUILD_FLAG_FILE)
|
|
||||||
|
|
||||||
|
ui-release: $(UI_BUILD_FLAG_FILE)
|
||||||
|
|
||||||
ui-devel: awx/ui/node_modules
|
ui-devel: awx/ui/node_modules
|
||||||
@$(MAKE) -B $(UI_BUILD_FLAG_FILE)
|
@$(MAKE) -B $(UI_BUILD_FLAG_FILE)
|
||||||
@@ -410,8 +404,17 @@ ui-lint:
|
|||||||
|
|
||||||
ui-test:
|
ui-test:
|
||||||
$(NPM_BIN) --prefix awx/ui install
|
$(NPM_BIN) --prefix awx/ui install
|
||||||
$(NPM_BIN) run --prefix awx/ui test -- --coverage --maxWorkers=4 --watchAll=false
|
$(NPM_BIN) run --prefix awx/ui test
|
||||||
|
|
||||||
|
ui-test-screens:
|
||||||
|
$(NPM_BIN) --prefix awx/ui install
|
||||||
|
$(NPM_BIN) run --prefix awx/ui pretest
|
||||||
|
$(NPM_BIN) run --prefix awx/ui test-screens --runInBand
|
||||||
|
|
||||||
|
ui-test-general:
|
||||||
|
$(NPM_BIN) --prefix awx/ui install
|
||||||
|
$(NPM_BIN) run --prefix awx/ui pretest
|
||||||
|
$(NPM_BIN) run --prefix awx/ui/ test-general --runInBand
|
||||||
|
|
||||||
# Build a pip-installable package into dist/ with a timestamped version number.
|
# Build a pip-installable package into dist/ with a timestamped version number.
|
||||||
dev_build:
|
dev_build:
|
||||||
@@ -421,10 +424,17 @@ dev_build:
|
|||||||
release_build:
|
release_build:
|
||||||
$(PYTHON) setup.py release_build
|
$(PYTHON) setup.py release_build
|
||||||
|
|
||||||
dist/$(SDIST_TAR_FILE): ui-release VERSION
|
HEADLESS ?= no
|
||||||
|
ifeq ($(HEADLESS), yes)
|
||||||
|
dist/$(SDIST_TAR_FILE):
|
||||||
|
else
|
||||||
|
dist/$(SDIST_TAR_FILE): $(UI_BUILD_FLAG_FILE)
|
||||||
|
endif
|
||||||
$(PYTHON) setup.py $(SDIST_COMMAND)
|
$(PYTHON) setup.py $(SDIST_COMMAND)
|
||||||
|
ln -sf $(SDIST_TAR_FILE) dist/awx.tar.gz
|
||||||
|
|
||||||
sdist: dist/$(SDIST_TAR_FILE)
|
sdist: dist/$(SDIST_TAR_FILE)
|
||||||
|
echo $(HEADLESS)
|
||||||
@echo "#############################################"
|
@echo "#############################################"
|
||||||
@echo "Artifacts:"
|
@echo "Artifacts:"
|
||||||
@echo dist/$(SDIST_TAR_FILE)
|
@echo dist/$(SDIST_TAR_FILE)
|
||||||
@@ -450,19 +460,22 @@ docker-compose-sources: .git/hooks/pre-commit
|
|||||||
ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/sources.yml \
|
ansible-playbook -i tools/docker-compose/inventory tools/docker-compose/ansible/sources.yml \
|
||||||
-e awx_image=$(DEV_DOCKER_TAG_BASE)/awx_devel \
|
-e awx_image=$(DEV_DOCKER_TAG_BASE)/awx_devel \
|
||||||
-e awx_image_tag=$(COMPOSE_TAG) \
|
-e awx_image_tag=$(COMPOSE_TAG) \
|
||||||
|
-e receptor_image=$(RECEPTOR_IMAGE) \
|
||||||
-e control_plane_node_count=$(CONTROL_PLANE_NODE_COUNT) \
|
-e control_plane_node_count=$(CONTROL_PLANE_NODE_COUNT) \
|
||||||
-e execution_node_count=$(EXECUTION_NODE_COUNT) \
|
-e execution_node_count=$(EXECUTION_NODE_COUNT) \
|
||||||
-e minikube_container_group=$(MINIKUBE_CONTAINER_GROUP)
|
-e minikube_container_group=$(MINIKUBE_CONTAINER_GROUP) \
|
||||||
|
-e enable_keycloak=$(KEYCLOAK) \
|
||||||
|
-e enable_ldap=$(LDAP)
|
||||||
|
|
||||||
|
|
||||||
docker-compose: docker-auth awx/projects docker-compose-sources
|
docker-compose: awx/projects docker-compose-sources
|
||||||
docker-compose -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans
|
docker-compose -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans
|
||||||
|
|
||||||
docker-compose-credential-plugins: docker-auth awx/projects docker-compose-sources
|
docker-compose-credential-plugins: awx/projects docker-compose-sources
|
||||||
echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m"
|
echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m"
|
||||||
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/docker-credential-plugins-override.yml up --no-recreate awx_1 --remove-orphans
|
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/docker-credential-plugins-override.yml up --no-recreate awx_1 --remove-orphans
|
||||||
|
|
||||||
docker-compose-test: docker-auth awx/projects docker-compose-sources
|
docker-compose-test: awx/projects docker-compose-sources
|
||||||
docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports awx_1 /bin/bash
|
docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports awx_1 /bin/bash
|
||||||
|
|
||||||
docker-compose-runtest: awx/projects docker-compose-sources
|
docker-compose-runtest: awx/projects docker-compose-sources
|
||||||
@@ -471,8 +484,9 @@ docker-compose-runtest: awx/projects docker-compose-sources
|
|||||||
docker-compose-build-swagger: awx/projects docker-compose-sources
|
docker-compose-build-swagger: awx/projects docker-compose-sources
|
||||||
docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports --no-deps awx_1 /start_tests.sh swagger
|
docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports --no-deps awx_1 /start_tests.sh swagger
|
||||||
|
|
||||||
|
SCHEMA_DIFF_BASE_BRANCH ?= devel
|
||||||
detect-schema-change: genschema
|
detect-schema-change: genschema
|
||||||
curl https://s3.amazonaws.com/awx-public-ci-files/schema.json -o reference-schema.json
|
curl https://s3.amazonaws.com/awx-public-ci-files/$(SCHEMA_DIFF_BASE_BRANCH)/schema.json -o reference-schema.json
|
||||||
# Ignore differences in whitespace with -b
|
# Ignore differences in whitespace with -b
|
||||||
diff -u -b reference-schema.json schema.json
|
diff -u -b reference-schema.json schema.json
|
||||||
|
|
||||||
@@ -487,15 +501,15 @@ docker-compose-container-group-clean:
|
|||||||
|
|
||||||
# Base development image build
|
# Base development image build
|
||||||
docker-compose-build:
|
docker-compose-build:
|
||||||
ansible-playbook tools/ansible/dockerfile.yml -e build_dev=True
|
ansible-playbook tools/ansible/dockerfile.yml -e build_dev=True -e receptor_image=$(RECEPTOR_IMAGE)
|
||||||
DOCKER_BUILDKIT=1 docker build -t $(DEVEL_IMAGE_NAME) \
|
DOCKER_BUILDKIT=1 docker build -t $(DEVEL_IMAGE_NAME) \
|
||||||
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
||||||
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) .
|
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG) .
|
||||||
|
|
||||||
docker-clean:
|
docker-clean:
|
||||||
$(foreach container_id,$(shell docker ps -f name=tools_awx -aq && docker ps -f name=tools_receptor -aq),docker stop $(container_id); docker rm -f $(container_id);)
|
$(foreach container_id,$(shell docker ps -f name=tools_awx -aq && docker ps -f name=tools_receptor -aq),docker stop $(container_id); docker rm -f $(container_id);)
|
||||||
if [ $(shell docker images | grep "awx_devel") ]; then \
|
if [ "$(shell docker images | grep awx_devel)" ]; then \
|
||||||
docker images | grep "awx_devel" | awk '{print $$3}' | xargs docker rmi --force; \
|
docker images | grep awx_devel | awk '{print $$3}' | xargs docker rmi --force; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
|
docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
|
||||||
@@ -504,10 +518,10 @@ docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
|
|||||||
docker-refresh: docker-clean docker-compose
|
docker-refresh: docker-clean docker-compose
|
||||||
|
|
||||||
# Docker Development Environment with Elastic Stack Connected
|
# Docker Development Environment with Elastic Stack Connected
|
||||||
docker-compose-elk: docker-auth awx/projects docker-compose-sources
|
docker-compose-elk: awx/projects docker-compose-sources
|
||||||
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
|
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
|
||||||
|
|
||||||
docker-compose-cluster-elk: docker-auth awx/projects docker-compose-sources
|
docker-compose-cluster-elk: awx/projects docker-compose-sources
|
||||||
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link-cluster.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
|
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link-cluster.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
@@ -530,18 +544,23 @@ psql-container:
|
|||||||
VERSION:
|
VERSION:
|
||||||
@echo "awx: $(VERSION)"
|
@echo "awx: $(VERSION)"
|
||||||
|
|
||||||
|
PYTHON_VERSION:
|
||||||
|
@echo "$(PYTHON)" | sed 's:python::'
|
||||||
|
|
||||||
Dockerfile: tools/ansible/roles/dockerfile/templates/Dockerfile.j2
|
Dockerfile: tools/ansible/roles/dockerfile/templates/Dockerfile.j2
|
||||||
ansible-playbook tools/ansible/dockerfile.yml
|
ansible-playbook tools/ansible/dockerfile.yml -e receptor_image=$(RECEPTOR_IMAGE)
|
||||||
|
|
||||||
Dockerfile.kube-dev: tools/ansible/roles/dockerfile/templates/Dockerfile.j2
|
Dockerfile.kube-dev: tools/ansible/roles/dockerfile/templates/Dockerfile.j2
|
||||||
ansible-playbook tools/ansible/dockerfile.yml \
|
ansible-playbook tools/ansible/dockerfile.yml \
|
||||||
-e dockerfile_name=Dockerfile.kube-dev \
|
-e dockerfile_name=Dockerfile.kube-dev \
|
||||||
-e kube_dev=True \
|
-e kube_dev=True \
|
||||||
-e template_dest=_build_kube_dev
|
-e template_dest=_build_kube_dev \
|
||||||
|
-e receptor_image=$(RECEPTOR_IMAGE)
|
||||||
|
|
||||||
awx-kube-dev-build: Dockerfile.kube-dev
|
awx-kube-dev-build: Dockerfile.kube-dev
|
||||||
docker build -f Dockerfile.kube-dev \
|
DOCKER_BUILDKIT=1 docker build -f Dockerfile.kube-dev \
|
||||||
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
||||||
|
--cache-from=$(DEV_DOCKER_TAG_BASE)/awx_kube_devel:$(COMPOSE_TAG) \
|
||||||
-t $(DEV_DOCKER_TAG_BASE)/awx_kube_devel:$(COMPOSE_TAG) .
|
-t $(DEV_DOCKER_TAG_BASE)/awx_kube_devel:$(COMPOSE_TAG) .
|
||||||
|
|
||||||
|
|
||||||
@@ -563,3 +582,6 @@ messages:
|
|||||||
. $(VENV_BASE)/awx/bin/activate; \
|
. $(VENV_BASE)/awx/bin/activate; \
|
||||||
fi; \
|
fi; \
|
||||||
$(PYTHON) manage.py makemessages -l $(LANG) --keep-pot
|
$(PYTHON) manage.py makemessages -l $(LANG) --keep-pot
|
||||||
|
|
||||||
|
print-%:
|
||||||
|
@echo $($*)
|
||||||
|
|||||||
3
SECURITY.md
Normal file
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.backends.utils import names_digest
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
|
|
||||||
|
|
||||||
if HAS_DJANGO is True:
|
if HAS_DJANGO is True:
|
||||||
|
|
||||||
# See upgrade blocker note in requirements/README.md
|
# See upgrade blocker note in requirements/README.md
|
||||||
@@ -151,7 +150,7 @@ def manage():
|
|||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
# enforce the postgres version is equal to 12. if not, then terminate program with exit code of 1
|
# enforce the postgres version is equal to 12. if not, then terminate program with exit code of 1
|
||||||
if not MODE == 'development':
|
if not os.getenv('SKIP_PG_VERSION_CHECK', False) and not MODE == 'development':
|
||||||
if (connection.pg_version // 10000) < 12:
|
if (connection.pg_version // 10000) < 12:
|
||||||
sys.stderr.write("Postgres version 12 is required\n")
|
sys.stderr.write("Postgres version 12 is required\n")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import logging
|
|||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_str
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework import authentication
|
from rest_framework import authentication
|
||||||
@@ -24,7 +24,7 @@ class LoggedBasicAuthentication(authentication.BasicAuthentication):
|
|||||||
ret = super(LoggedBasicAuthentication, self).authenticate(request)
|
ret = super(LoggedBasicAuthentication, self).authenticate(request)
|
||||||
if ret:
|
if ret:
|
||||||
username = ret[0].username if ret[0] else '<none>'
|
username = ret[0].username if ret[0] else '<none>'
|
||||||
logger.info(smart_text(u"User {} performed a {} to {} through the API".format(username, request.method, request.path)))
|
logger.info(smart_str(u"User {} performed a {} to {} through the API".format(username, request.method, request.path)))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def authenticate_header(self, request):
|
def authenticate_header(self, request):
|
||||||
@@ -45,7 +45,7 @@ class LoggedOAuth2Authentication(OAuth2Authentication):
|
|||||||
user, token = ret
|
user, token = ret
|
||||||
username = user.username if user else '<none>'
|
username = user.username if user else '<none>'
|
||||||
logger.info(
|
logger.info(
|
||||||
smart_text(u"User {} performed a {} to {} through the API using OAuth 2 token {}.".format(username, request.method, request.path, token.pk))
|
smart_str(u"User {} performed a {} to {} through the API using OAuth 2 token {}.".format(username, request.method, request.path, token.pk))
|
||||||
)
|
)
|
||||||
setattr(user, 'oauth_scopes', [x for x in token.scope.split() if x])
|
setattr(user, 'oauth_scopes', [x for x in token.scope.split() if x])
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Django
|
# Django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
@@ -13,7 +13,7 @@ class ActiveJobConflict(ValidationError):
|
|||||||
|
|
||||||
def __init__(self, active_jobs):
|
def __init__(self, active_jobs):
|
||||||
# During APIException.__init__(), Django Rest Framework
|
# During APIException.__init__(), Django Rest Framework
|
||||||
# turn everything in self.detail into string by using force_text.
|
# turn everything in self.detail into string by using force_str.
|
||||||
# Declare detail afterwards circumvent this behavior.
|
# Declare detail afterwards circumvent this behavior.
|
||||||
super(ActiveJobConflict, self).__init__()
|
super(ActiveJobConflict, self).__init__()
|
||||||
self.detail = {"error": _("Resource is being used by running jobs."), "active_jobs": active_jobs}
|
self.detail = {"error": _("Resource is being used by running jobs."), "active_jobs": active_jobs}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
@@ -28,13 +28,17 @@ class NullFieldMixin(object):
|
|||||||
return (is_empty_value, data)
|
return (is_empty_value, data)
|
||||||
|
|
||||||
|
|
||||||
class BooleanNullField(NullFieldMixin, serializers.NullBooleanField):
|
class BooleanNullField(NullFieldMixin, serializers.BooleanField):
|
||||||
"""
|
"""
|
||||||
Custom boolean field that allows null and empty string as False values.
|
Custom boolean field that allows null and empty string as False values.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
kwargs['allow_null'] = True
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
return bool(super(BooleanNullField, self).to_internal_value(data))
|
return bool(super().to_internal_value(data))
|
||||||
|
|
||||||
|
|
||||||
class CharNullField(NullFieldMixin, serializers.CharField):
|
class CharNullField(NullFieldMixin, serializers.CharField):
|
||||||
@@ -47,7 +51,7 @@ class CharNullField(NullFieldMixin, serializers.CharField):
|
|||||||
super(CharNullField, self).__init__(**kwargs)
|
super(CharNullField, self).__init__(**kwargs)
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
return super(CharNullField, self).to_internal_value(data or u'')
|
return super(CharNullField, self).to_internal_value(data or '')
|
||||||
|
|
||||||
|
|
||||||
class ChoiceNullField(NullFieldMixin, serializers.ChoiceField):
|
class ChoiceNullField(NullFieldMixin, serializers.ChoiceField):
|
||||||
@@ -60,7 +64,7 @@ class ChoiceNullField(NullFieldMixin, serializers.ChoiceField):
|
|||||||
super(ChoiceNullField, self).__init__(**kwargs)
|
super(ChoiceNullField, self).__init__(**kwargs)
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
return super(ChoiceNullField, self).to_internal_value(data or u'')
|
return super(ChoiceNullField, self).to_internal_value(data or '')
|
||||||
|
|
||||||
|
|
||||||
class VerbatimField(serializers.Field):
|
class VerbatimField(serializers.Field):
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ import json
|
|||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.core.exceptions import FieldError, ValidationError
|
from django.core.exceptions import FieldError, ValidationError, FieldDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q, CharField, IntegerField, BooleanField
|
from django.db.models import Q, CharField, IntegerField, BooleanField, TextField, JSONField
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
|
||||||
from django.db.models.fields.related import ForeignObjectRel, ManyToManyField, ForeignKey
|
from django.db.models.fields.related import ForeignObjectRel, ManyToManyField, ForeignKey
|
||||||
|
from django.db.models.functions import Cast
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_str
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.exceptions import ParseError, PermissionDenied
|
from rest_framework.exceptions import ParseError, PermissionDenied
|
||||||
@@ -185,16 +185,14 @@ class FieldLookupBackend(BaseFilterBackend):
|
|||||||
return (field_list[-1], new_lookup)
|
return (field_list[-1], new_lookup)
|
||||||
|
|
||||||
def to_python_related(self, value):
|
def to_python_related(self, value):
|
||||||
value = force_text(value)
|
value = force_str(value)
|
||||||
if value.lower() in ('none', 'null'):
|
if value.lower() in ('none', 'null'):
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return int(value)
|
return int(value)
|
||||||
|
|
||||||
def value_to_python_for_field(self, field, value):
|
def value_to_python_for_field(self, field, value):
|
||||||
if isinstance(field, models.NullBooleanField):
|
if isinstance(field, models.BooleanField):
|
||||||
return to_python_boolean(value, allow_none=True)
|
|
||||||
elif isinstance(field, models.BooleanField):
|
|
||||||
return to_python_boolean(value)
|
return to_python_boolean(value)
|
||||||
elif isinstance(field, (ForeignObjectRel, ManyToManyField, GenericForeignKey, ForeignKey)):
|
elif isinstance(field, (ForeignObjectRel, ManyToManyField, GenericForeignKey, ForeignKey)):
|
||||||
try:
|
try:
|
||||||
@@ -244,6 +242,8 @@ class FieldLookupBackend(BaseFilterBackend):
|
|||||||
new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name))
|
new_lookups.append('{}__{}__icontains'.format(new_lookup[:-8], rm_field.name))
|
||||||
return value, new_lookups, needs_distinct
|
return value, new_lookups, needs_distinct
|
||||||
else:
|
else:
|
||||||
|
if isinstance(field, JSONField):
|
||||||
|
new_lookup = new_lookup.replace(field.name, f'{field.name}_as_txt')
|
||||||
value = self.value_to_python_for_field(field, value)
|
value = self.value_to_python_for_field(field, value)
|
||||||
return value, new_lookup, needs_distinct
|
return value, new_lookup, needs_distinct
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ class FieldLookupBackend(BaseFilterBackend):
|
|||||||
search_filter_relation = 'AND'
|
search_filter_relation = 'AND'
|
||||||
values = reduce(lambda list1, list2: list1 + list2, [i.split(',') for i in values])
|
values = reduce(lambda list1, list2: list1 + list2, [i.split(',') for i in values])
|
||||||
for value in values:
|
for value in values:
|
||||||
search_value, new_keys, _ = self.value_to_python(queryset.model, key, force_text(value))
|
search_value, new_keys, _ = self.value_to_python(queryset.model, key, force_str(value))
|
||||||
assert isinstance(new_keys, list)
|
assert isinstance(new_keys, list)
|
||||||
search_filters[search_value] = new_keys
|
search_filters[search_value] = new_keys
|
||||||
# by definition, search *only* joins across relations,
|
# by definition, search *only* joins across relations,
|
||||||
@@ -325,6 +325,9 @@ class FieldLookupBackend(BaseFilterBackend):
|
|||||||
value, new_key, distinct = self.value_to_python(queryset.model, key, value)
|
value, new_key, distinct = self.value_to_python(queryset.model, key, value)
|
||||||
if distinct:
|
if distinct:
|
||||||
needs_distinct = True
|
needs_distinct = True
|
||||||
|
if '_as_txt' in new_key:
|
||||||
|
fname = next(item for item in new_key.split('__') if item.endswith('_as_txt'))
|
||||||
|
queryset = queryset.annotate(**{fname: Cast(fname[:-7], output_field=TextField())})
|
||||||
if q_chain:
|
if q_chain:
|
||||||
chain_filters.append((q_not, new_key, value))
|
chain_filters.append((q_not, new_key, value))
|
||||||
elif q_or:
|
elif q_or:
|
||||||
|
|||||||
@@ -10,18 +10,18 @@ import urllib.parse
|
|||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.auth import views as auth_views
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
|
||||||
from django.db.models.fields.related import OneToOneRel
|
from django.db.models.fields.related import OneToOneRel
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_str
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from django.contrib.auth import views as auth_views
|
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.exceptions import PermissionDenied, AuthenticationFailed, ParseError, NotAcceptable, UnsupportedMediaType
|
from rest_framework.exceptions import PermissionDenied, AuthenticationFailed, ParseError, NotAcceptable, UnsupportedMediaType
|
||||||
@@ -44,6 +44,7 @@ from awx.main.views import ApiErrorView
|
|||||||
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
|
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
|
||||||
from awx.api.versioning import URLPathVersioning
|
from awx.api.versioning import URLPathVersioning
|
||||||
from awx.api.metadata import SublistAttachDetatchMetadata, Metadata
|
from awx.api.metadata import SublistAttachDetatchMetadata, Metadata
|
||||||
|
from awx.conf import settings_registry
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'APIView',
|
'APIView',
|
||||||
@@ -92,17 +93,18 @@ class LoggedLoginView(auth_views.LoginView):
|
|||||||
ret = super(LoggedLoginView, self).post(request, *args, **kwargs)
|
ret = super(LoggedLoginView, self).post(request, *args, **kwargs)
|
||||||
current_user = getattr(request, 'user', None)
|
current_user = getattr(request, 'user', None)
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
logger.info(smart_text(u"User {} logged in from {}".format(self.request.user.username, request.META.get('REMOTE_ADDR', None))))
|
logger.info(smart_str(u"User {} logged in from {}".format(self.request.user.username, request.META.get('REMOTE_ADDR', None))))
|
||||||
ret.set_cookie('userLoggedIn', 'true')
|
ret.set_cookie('userLoggedIn', 'true')
|
||||||
current_user = UserSerializer(self.request.user)
|
current_user = UserSerializer(self.request.user)
|
||||||
current_user = smart_text(JSONRenderer().render(current_user.data))
|
current_user = smart_str(JSONRenderer().render(current_user.data))
|
||||||
current_user = urllib.parse.quote('%s' % current_user, '')
|
current_user = urllib.parse.quote('%s' % current_user, '')
|
||||||
ret.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None)
|
ret.set_cookie('current_user', current_user, secure=settings.SESSION_COOKIE_SECURE or None)
|
||||||
|
ret.setdefault('X-API-Session-Cookie-Name', getattr(settings, 'SESSION_COOKIE_NAME', 'awx_sessionid'))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
else:
|
else:
|
||||||
if 'username' in self.request.POST:
|
if 'username' in self.request.POST:
|
||||||
logger.warn(smart_text(u"Login failed for user {} from {}".format(self.request.POST.get('username'), request.META.get('REMOTE_ADDR', None))))
|
logger.warning(smart_str(u"Login failed for user {} from {}".format(self.request.POST.get('username'), request.META.get('REMOTE_ADDR', None))))
|
||||||
ret.status_code = 401
|
ret.status_code = 401
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@@ -208,12 +210,27 @@ class APIView(views.APIView):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
if response.status_code >= 400:
|
if response.status_code >= 400:
|
||||||
status_msg = "status %s received by user %s attempting to access %s from %s" % (
|
msg_data = {
|
||||||
response.status_code,
|
'status_code': response.status_code,
|
||||||
request.user,
|
'user_name': request.user,
|
||||||
request.path,
|
'url_path': request.path,
|
||||||
request.META.get('REMOTE_ADDR', None),
|
'remote_addr': request.META.get('REMOTE_ADDR', None),
|
||||||
)
|
}
|
||||||
|
|
||||||
|
if type(response.data) is dict:
|
||||||
|
msg_data['error'] = response.data.get('error', response.status_text)
|
||||||
|
elif type(response.data) is list:
|
||||||
|
msg_data['error'] = ", ".join(list(map(lambda x: x.get('error', response.status_text), response.data)))
|
||||||
|
else:
|
||||||
|
msg_data['error'] = response.status_text
|
||||||
|
|
||||||
|
try:
|
||||||
|
status_msg = getattr(settings, 'API_400_ERROR_LOG_FORMAT').format(**msg_data)
|
||||||
|
except Exception as e:
|
||||||
|
if getattr(settings, 'API_400_ERROR_LOG_FORMAT', None):
|
||||||
|
logger.error("Unable to format API_400_ERROR_LOG_FORMAT setting, defaulting log message: {}".format(e))
|
||||||
|
status_msg = settings_registry.get_setting_field('API_400_ERROR_LOG_FORMAT').get_default().format(**msg_data)
|
||||||
|
|
||||||
if hasattr(self, '__init_request_error__'):
|
if hasattr(self, '__init_request_error__'):
|
||||||
response = self.handle_exception(self.__init_request_error__)
|
response = self.handle_exception(self.__init_request_error__)
|
||||||
if response.status_code == 401:
|
if response.status_code == 401:
|
||||||
@@ -221,6 +238,7 @@ class APIView(views.APIView):
|
|||||||
logger.info(status_msg)
|
logger.info(status_msg)
|
||||||
else:
|
else:
|
||||||
logger.warning(status_msg)
|
logger.warning(status_msg)
|
||||||
|
|
||||||
response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
|
response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
|
||||||
time_started = getattr(self, 'time_started', None)
|
time_started = getattr(self, 'time_started', None)
|
||||||
response['X-API-Product-Version'] = get_awx_version()
|
response['X-API-Product-Version'] = get_awx_version()
|
||||||
@@ -374,8 +392,8 @@ class GenericAPIView(generics.GenericAPIView, APIView):
|
|||||||
if hasattr(self.model._meta, "verbose_name"):
|
if hasattr(self.model._meta, "verbose_name"):
|
||||||
d.update(
|
d.update(
|
||||||
{
|
{
|
||||||
'model_verbose_name': smart_text(self.model._meta.verbose_name),
|
'model_verbose_name': smart_str(self.model._meta.verbose_name),
|
||||||
'model_verbose_name_plural': smart_text(self.model._meta.verbose_name_plural),
|
'model_verbose_name_plural': smart_str(self.model._meta.verbose_name_plural),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
serializer = self.get_serializer()
|
serializer = self.get_serializer()
|
||||||
@@ -506,8 +524,8 @@ class SubListAPIView(ParentMixin, ListAPIView):
|
|||||||
d = super(SubListAPIView, self).get_description_context()
|
d = super(SubListAPIView, self).get_description_context()
|
||||||
d.update(
|
d.update(
|
||||||
{
|
{
|
||||||
'parent_model_verbose_name': smart_text(self.parent_model._meta.verbose_name),
|
'parent_model_verbose_name': smart_str(self.parent_model._meta.verbose_name),
|
||||||
'parent_model_verbose_name_plural': smart_text(self.parent_model._meta.verbose_name_plural),
|
'parent_model_verbose_name_plural': smart_str(self.parent_model._meta.verbose_name_plural),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return d
|
return d
|
||||||
@@ -817,7 +835,7 @@ class ResourceAccessList(ParentMixin, ListAPIView):
|
|||||||
|
|
||||||
|
|
||||||
def trigger_delayed_deep_copy(*args, **kwargs):
|
def trigger_delayed_deep_copy(*args, **kwargs):
|
||||||
from awx.main.tasks import deep_copy_model_obj
|
from awx.main.tasks.system import deep_copy_model_obj
|
||||||
|
|
||||||
connection.on_commit(lambda: deep_copy_model_obj.delay(*args, **kwargs))
|
connection.on_commit(lambda: deep_copy_model_obj.delay(*args, **kwargs))
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ from uuid import UUID
|
|||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
from django.db.models import JSONField
|
||||||
from django.db.models.fields import PositiveIntegerField, BooleanField
|
from django.db.models.fields import PositiveIntegerField, BooleanField
|
||||||
from django.db.models.fields.related import ForeignKey
|
from django.db.models.fields.related import ForeignKey
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.utils.encoding import force_text, smart_text
|
from django.utils.encoding import force_str, smart_str
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
@@ -22,7 +23,7 @@ from rest_framework.request import clone_request
|
|||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.api.fields import ChoiceNullField
|
from awx.api.fields import ChoiceNullField
|
||||||
from awx.main.fields import JSONField, ImplicitRoleField
|
from awx.main.fields import ImplicitRoleField
|
||||||
from awx.main.models import NotificationTemplate
|
from awx.main.models import NotificationTemplate
|
||||||
from awx.main.utils.execution_environments import get_default_pod_spec
|
from awx.main.utils.execution_environments import get_default_pod_spec
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ class Metadata(metadata.SimpleMetadata):
|
|||||||
for attr in text_attrs:
|
for attr in text_attrs:
|
||||||
value = getattr(field, attr, None)
|
value = getattr(field, attr, None)
|
||||||
if value is not None and value != '':
|
if value is not None and value != '':
|
||||||
field_info[attr] = force_text(value, strings_only=True)
|
field_info[attr] = force_str(value, strings_only=True)
|
||||||
|
|
||||||
placeholder = getattr(field, 'placeholder', serializers.empty)
|
placeholder = getattr(field, 'placeholder', serializers.empty)
|
||||||
if placeholder is not serializers.empty:
|
if placeholder is not serializers.empty:
|
||||||
@@ -77,7 +78,7 @@ class Metadata(metadata.SimpleMetadata):
|
|||||||
}
|
}
|
||||||
if field.field_name in field_help_text:
|
if field.field_name in field_help_text:
|
||||||
opts = serializer.Meta.model._meta.concrete_model._meta
|
opts = serializer.Meta.model._meta.concrete_model._meta
|
||||||
verbose_name = smart_text(opts.verbose_name)
|
verbose_name = smart_str(opts.verbose_name)
|
||||||
field_info['help_text'] = field_help_text[field.field_name].format(verbose_name)
|
field_info['help_text'] = field_help_text[field.field_name].format(verbose_name)
|
||||||
|
|
||||||
if field.field_name == 'type':
|
if field.field_name == 'type':
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import MetricsView
|
from awx.api.views import MetricsView
|
||||||
|
|
||||||
|
|
||||||
urls = [url(r'^$', MetricsView.as_view(), name='metrics_view')]
|
urls = [re_path(r'^$', MetricsView.as_view(), name='metrics_view')]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import json
|
|||||||
# Django
|
# Django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework import parsers
|
from rest_framework import parsers
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
# Python
|
# Python
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
|
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
@@ -243,20 +241,13 @@ class IsSystemAdminOrAuditor(permissions.BasePermission):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
if not request.user:
|
if not (request.user and request.user.is_authenticated):
|
||||||
return False
|
return False
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return request.user.is_superuser or request.user.is_system_auditor
|
return request.user.is_superuser or request.user.is_system_auditor
|
||||||
return request.user.is_superuser
|
return request.user.is_superuser
|
||||||
|
|
||||||
|
|
||||||
class InstanceGroupTowerPermission(ModelAccessPermission):
|
|
||||||
def has_object_permission(self, request, view, obj):
|
|
||||||
if request.method == 'DELETE' and obj.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
|
|
||||||
return False
|
|
||||||
return super(InstanceGroupTowerPermission, self).has_object_permission(request, view, obj)
|
|
||||||
|
|
||||||
|
|
||||||
class WebhookKeyPermission(permissions.BasePermission):
|
class WebhookKeyPermission(permissions.BasePermission):
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
return request.user.can_access(view.model, 'admin', obj, request.data)
|
return request.user.can_access(view.model, 'admin', obj, request.data)
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ from django.contrib.auth.password_validation import validate_password as django_
|
|||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError as DjangoValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_str
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
@@ -57,6 +57,7 @@ from awx.main.models import (
|
|||||||
Host,
|
Host,
|
||||||
Instance,
|
Instance,
|
||||||
InstanceGroup,
|
InstanceGroup,
|
||||||
|
InstanceLink,
|
||||||
Inventory,
|
Inventory,
|
||||||
InventorySource,
|
InventorySource,
|
||||||
InventoryUpdate,
|
InventoryUpdate,
|
||||||
@@ -96,7 +97,7 @@ from awx.main.models import (
|
|||||||
)
|
)
|
||||||
from awx.main.models.base import VERBOSITY_CHOICES, NEW_JOB_TYPE_CHOICES
|
from awx.main.models.base import VERBOSITY_CHOICES, NEW_JOB_TYPE_CHOICES
|
||||||
from awx.main.models.rbac import get_roles_on_resource, role_summary_fields_generator
|
from awx.main.models.rbac import get_roles_on_resource, role_summary_fields_generator
|
||||||
from awx.main.fields import ImplicitRoleField, JSONBField
|
from awx.main.fields import ImplicitRoleField
|
||||||
from awx.main.utils import (
|
from awx.main.utils import (
|
||||||
get_type_for_model,
|
get_type_for_model,
|
||||||
get_model_for_type,
|
get_model_for_type,
|
||||||
@@ -356,7 +357,7 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
|
|||||||
}
|
}
|
||||||
choices = []
|
choices = []
|
||||||
for t in self.get_types():
|
for t in self.get_types():
|
||||||
name = _(type_name_map.get(t, force_text(get_model_for_type(t)._meta.verbose_name).title()))
|
name = _(type_name_map.get(t, force_str(get_model_for_type(t)._meta.verbose_name).title()))
|
||||||
choices.append((t, name))
|
choices.append((t, name))
|
||||||
return choices
|
return choices
|
||||||
|
|
||||||
@@ -378,19 +379,22 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
|
|||||||
def _get_related(self, obj):
|
def _get_related(self, obj):
|
||||||
return {} if obj is None else self.get_related(obj)
|
return {} if obj is None else self.get_related(obj)
|
||||||
|
|
||||||
def _generate_named_url(self, url_path, obj, node):
|
def _generate_friendly_id(self, obj, node):
|
||||||
url_units = url_path.split('/')
|
|
||||||
reset_counters()
|
reset_counters()
|
||||||
named_url = node.generate_named_url(obj)
|
return node.generate_named_url(obj)
|
||||||
url_units[4] = named_url
|
|
||||||
return '/'.join(url_units)
|
|
||||||
|
|
||||||
def get_related(self, obj):
|
def get_related(self, obj):
|
||||||
res = OrderedDict()
|
res = OrderedDict()
|
||||||
view = self.context.get('view', None)
|
view = self.context.get('view', None)
|
||||||
if view and (hasattr(view, 'retrieve') or view.request.method == 'POST') and type(obj) in settings.NAMED_URL_GRAPH:
|
if view and (hasattr(view, 'retrieve') or view.request.method == 'POST') and type(obj) in settings.NAMED_URL_GRAPH:
|
||||||
original_url = self.get_url(obj)
|
original_path = self.get_url(obj)
|
||||||
res['named_url'] = self._generate_named_url(original_url, obj, settings.NAMED_URL_GRAPH[type(obj)])
|
path_components = original_path.lstrip('/').rstrip('/').split('/')
|
||||||
|
|
||||||
|
friendly_id = self._generate_friendly_id(obj, settings.NAMED_URL_GRAPH[type(obj)])
|
||||||
|
path_components[-1] = friendly_id
|
||||||
|
|
||||||
|
new_path = '/' + '/'.join(path_components) + '/'
|
||||||
|
res['named_url'] = new_path
|
||||||
if getattr(obj, 'created_by', None):
|
if getattr(obj, 'created_by', None):
|
||||||
res['created_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.created_by.pk})
|
res['created_by'] = self.reverse('api:user_detail', kwargs={'pk': obj.created_by.pk})
|
||||||
if getattr(obj, 'modified_by', None):
|
if getattr(obj, 'modified_by', None):
|
||||||
@@ -641,7 +645,7 @@ class BaseSerializer(serializers.ModelSerializer, metaclass=BaseSerializerMetacl
|
|||||||
v2.extend(e)
|
v2.extend(e)
|
||||||
else:
|
else:
|
||||||
v2.append(e)
|
v2.append(e)
|
||||||
d[k] = list(map(force_text, v2))
|
d[k] = list(map(force_str, v2))
|
||||||
raise ValidationError(d)
|
raise ValidationError(d)
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
@@ -861,7 +865,7 @@ class UnifiedJobSerializer(BaseSerializer):
|
|||||||
if 'elapsed' in ret:
|
if 'elapsed' in ret:
|
||||||
if obj and obj.pk and obj.started and not obj.finished:
|
if obj and obj.pk and obj.started and not obj.finished:
|
||||||
td = now() - obj.started
|
td = now() - obj.started
|
||||||
ret['elapsed'] = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / (10 ** 6 * 1.0)
|
ret['elapsed'] = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / (10**6 * 1.0)
|
||||||
ret['elapsed'] = float(ret['elapsed'])
|
ret['elapsed'] = float(ret['elapsed'])
|
||||||
# Because this string is saved in the db in the source language,
|
# Because this string is saved in the db in the source language,
|
||||||
# it must be marked for translation after it is pulled from the db, not when set
|
# it must be marked for translation after it is pulled from the db, not when set
|
||||||
@@ -1259,6 +1263,12 @@ class OAuth2ApplicationSerializer(BaseSerializer):
|
|||||||
activity_stream=self.reverse('api:o_auth2_application_activity_stream_list', kwargs={'pk': obj.pk}),
|
activity_stream=self.reverse('api:o_auth2_application_activity_stream_list', kwargs={'pk': obj.pk}),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if obj.organization_id:
|
||||||
|
res.update(
|
||||||
|
dict(
|
||||||
|
organization=self.reverse('api:organization_detail', kwargs={'pk': obj.organization_id}),
|
||||||
|
)
|
||||||
|
)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_modified(self, obj):
|
def get_modified(self, obj):
|
||||||
@@ -1639,7 +1649,25 @@ class BaseSerializerWithVariables(BaseSerializer):
|
|||||||
return vars_validate_or_raise(value)
|
return vars_validate_or_raise(value)
|
||||||
|
|
||||||
|
|
||||||
class InventorySerializer(BaseSerializerWithVariables):
|
class LabelsListMixin(object):
|
||||||
|
def _summary_field_labels(self, obj):
|
||||||
|
label_list = [{'id': x.id, 'name': x.name} for x in obj.labels.all()[:10]]
|
||||||
|
if has_model_field_prefetched(obj, 'labels'):
|
||||||
|
label_ct = len(obj.labels.all())
|
||||||
|
else:
|
||||||
|
if len(label_list) < 10:
|
||||||
|
label_ct = len(label_list)
|
||||||
|
else:
|
||||||
|
label_ct = obj.labels.count()
|
||||||
|
return {'count': label_ct, 'results': label_list}
|
||||||
|
|
||||||
|
def get_summary_fields(self, obj):
|
||||||
|
res = super(LabelsListMixin, self).get_summary_fields(obj)
|
||||||
|
res['labels'] = self._summary_field_labels(obj)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class InventorySerializer(LabelsListMixin, BaseSerializerWithVariables):
|
||||||
show_capabilities = ['edit', 'delete', 'adhoc', 'copy']
|
show_capabilities = ['edit', 'delete', 'adhoc', 'copy']
|
||||||
capabilities_prefetch = ['admin', 'adhoc', {'copy': 'organization.inventory_admin'}]
|
capabilities_prefetch = ['admin', 'adhoc', {'copy': 'organization.inventory_admin'}]
|
||||||
|
|
||||||
@@ -1680,6 +1708,7 @@ class InventorySerializer(BaseSerializerWithVariables):
|
|||||||
object_roles=self.reverse('api:inventory_object_roles_list', kwargs={'pk': obj.pk}),
|
object_roles=self.reverse('api:inventory_object_roles_list', kwargs={'pk': obj.pk}),
|
||||||
instance_groups=self.reverse('api:inventory_instance_groups_list', kwargs={'pk': obj.pk}),
|
instance_groups=self.reverse('api:inventory_instance_groups_list', kwargs={'pk': obj.pk}),
|
||||||
copy=self.reverse('api:inventory_copy', kwargs={'pk': obj.pk}),
|
copy=self.reverse('api:inventory_copy', kwargs={'pk': obj.pk}),
|
||||||
|
labels=self.reverse('api:inventory_label_list', kwargs={'pk': obj.pk}),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
@@ -1695,7 +1724,7 @@ class InventorySerializer(BaseSerializerWithVariables):
|
|||||||
def validate_host_filter(self, host_filter):
|
def validate_host_filter(self, host_filter):
|
||||||
if host_filter:
|
if host_filter:
|
||||||
try:
|
try:
|
||||||
for match in JSONBField.get_lookups().keys():
|
for match in models.JSONField.get_lookups().keys():
|
||||||
if match == 'exact':
|
if match == 'exact':
|
||||||
# __exact is allowed
|
# __exact is allowed
|
||||||
continue
|
continue
|
||||||
@@ -1824,11 +1853,11 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
if port < 1 or port > 65535:
|
if port < 1 or port > 65535:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise serializers.ValidationError(_(u'Invalid port specification: %s') % force_text(port))
|
raise serializers.ValidationError(_(u'Invalid port specification: %s') % force_str(port))
|
||||||
return name, port
|
return name, port
|
||||||
|
|
||||||
def validate_name(self, value):
|
def validate_name(self, value):
|
||||||
name = force_text(value or '')
|
name = force_str(value or '')
|
||||||
# Validate here only, update in main validate method.
|
# Validate here only, update in main validate method.
|
||||||
host, port = self._get_host_port_from_name(name)
|
host, port = self._get_host_port_from_name(name)
|
||||||
return value
|
return value
|
||||||
@@ -1842,13 +1871,13 @@ class HostSerializer(BaseSerializerWithVariables):
|
|||||||
return vars_validate_or_raise(value)
|
return vars_validate_or_raise(value)
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
name = force_text(attrs.get('name', self.instance and self.instance.name or ''))
|
name = force_str(attrs.get('name', self.instance and self.instance.name or ''))
|
||||||
inventory = attrs.get('inventory', self.instance and self.instance.inventory or '')
|
inventory = attrs.get('inventory', self.instance and self.instance.inventory or '')
|
||||||
host, port = self._get_host_port_from_name(name)
|
host, port = self._get_host_port_from_name(name)
|
||||||
|
|
||||||
if port:
|
if port:
|
||||||
attrs['name'] = host
|
attrs['name'] = host
|
||||||
variables = force_text(attrs.get('variables', self.instance and self.instance.variables or ''))
|
variables = force_str(attrs.get('variables', self.instance and self.instance.variables or ''))
|
||||||
vars_dict = parse_yaml_or_json(variables)
|
vars_dict = parse_yaml_or_json(variables)
|
||||||
vars_dict['ansible_ssh_port'] = port
|
vars_dict['ansible_ssh_port'] = port
|
||||||
attrs['variables'] = json.dumps(vars_dict)
|
attrs['variables'] = json.dumps(vars_dict)
|
||||||
@@ -1921,7 +1950,7 @@ class GroupSerializer(BaseSerializerWithVariables):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
name = force_text(attrs.get('name', self.instance and self.instance.name or ''))
|
name = force_str(attrs.get('name', self.instance and self.instance.name or ''))
|
||||||
inventory = attrs.get('inventory', self.instance and self.instance.inventory or '')
|
inventory = attrs.get('inventory', self.instance and self.instance.inventory or '')
|
||||||
if Host.objects.filter(name=name, inventory=inventory).exists():
|
if Host.objects.filter(name=name, inventory=inventory).exists():
|
||||||
raise serializers.ValidationError(_('A Host with that name already exists.'))
|
raise serializers.ValidationError(_('A Host with that name already exists.'))
|
||||||
@@ -2749,24 +2778,6 @@ class OrganizationCredentialSerializerCreate(CredentialSerializerCreate):
|
|||||||
fields = ('*', '-user', '-team')
|
fields = ('*', '-user', '-team')
|
||||||
|
|
||||||
|
|
||||||
class LabelsListMixin(object):
|
|
||||||
def _summary_field_labels(self, obj):
|
|
||||||
label_list = [{'id': x.id, 'name': x.name} for x in obj.labels.all()[:10]]
|
|
||||||
if has_model_field_prefetched(obj, 'labels'):
|
|
||||||
label_ct = len(obj.labels.all())
|
|
||||||
else:
|
|
||||||
if len(label_list) < 10:
|
|
||||||
label_ct = len(label_list)
|
|
||||||
else:
|
|
||||||
label_ct = obj.labels.count()
|
|
||||||
return {'count': label_ct, 'results': label_list}
|
|
||||||
|
|
||||||
def get_summary_fields(self, obj):
|
|
||||||
res = super(LabelsListMixin, self).get_summary_fields(obj)
|
|
||||||
res['labels'] = self._summary_field_labels(obj)
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
|
class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = (
|
fields = (
|
||||||
@@ -2833,8 +2844,8 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
|
|||||||
if not project:
|
if not project:
|
||||||
raise serializers.ValidationError({'project': _('This field is required.')})
|
raise serializers.ValidationError({'project': _('This field is required.')})
|
||||||
playbook_not_found = bool(
|
playbook_not_found = bool(
|
||||||
(project and project.scm_type and (not project.allow_override) and playbook and force_text(playbook) not in project.playbook_files)
|
(project and project.scm_type and (not project.allow_override) and playbook and force_str(playbook) not in project.playbook_files)
|
||||||
or (project and not project.scm_type and playbook and force_text(playbook) not in project.playbooks) # manual
|
or (project and not project.scm_type and playbook and force_str(playbook) not in project.playbooks) # manual
|
||||||
)
|
)
|
||||||
if playbook_not_found:
|
if playbook_not_found:
|
||||||
raise serializers.ValidationError({'playbook': _('Playbook not found for project.')})
|
raise serializers.ValidationError({'playbook': _('Playbook not found for project.')})
|
||||||
@@ -3623,7 +3634,7 @@ class LaunchConfigurationBaseSerializer(BaseSerializer):
|
|||||||
job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
job_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||||
limit = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
limit = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||||
skip_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
skip_tags = serializers.CharField(allow_blank=True, allow_null=True, required=False, default=None)
|
||||||
diff_mode = serializers.NullBooleanField(required=False, default=None)
|
diff_mode = serializers.BooleanField(required=False, allow_null=True, default=None)
|
||||||
verbosity = serializers.ChoiceField(allow_null=True, required=False, default=None, choices=VERBOSITY_CHOICES)
|
verbosity = serializers.ChoiceField(allow_null=True, required=False, default=None, choices=VERBOSITY_CHOICES)
|
||||||
exclude_errors = ()
|
exclude_errors = ()
|
||||||
|
|
||||||
@@ -4767,6 +4778,28 @@ class ScheduleSerializer(LaunchConfigurationBaseSerializer, SchedulePreviewSeria
|
|||||||
return super(ScheduleSerializer, self).validate(attrs)
|
return super(ScheduleSerializer, self).validate(attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceLinkSerializer(BaseSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = InstanceLink
|
||||||
|
fields = ('source', 'target')
|
||||||
|
|
||||||
|
source = serializers.SlugRelatedField(slug_field="hostname", read_only=True)
|
||||||
|
target = serializers.SlugRelatedField(slug_field="hostname", read_only=True)
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceNodeSerializer(BaseSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Instance
|
||||||
|
fields = ('id', 'hostname', 'node_type', 'node_state')
|
||||||
|
|
||||||
|
node_state = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
def get_node_state(self, obj):
|
||||||
|
if not obj.enabled:
|
||||||
|
return "disabled"
|
||||||
|
return "error" if obj.errors else "healthy"
|
||||||
|
|
||||||
|
|
||||||
class InstanceSerializer(BaseSerializer):
|
class InstanceSerializer(BaseSerializer):
|
||||||
|
|
||||||
consumed_capacity = serializers.SerializerMethodField()
|
consumed_capacity = serializers.SerializerMethodField()
|
||||||
@@ -4810,7 +4843,8 @@ class InstanceSerializer(BaseSerializer):
|
|||||||
res['jobs'] = self.reverse('api:instance_unified_jobs_list', kwargs={'pk': obj.pk})
|
res['jobs'] = self.reverse('api:instance_unified_jobs_list', kwargs={'pk': obj.pk})
|
||||||
res['instance_groups'] = self.reverse('api:instance_instance_groups_list', kwargs={'pk': obj.pk})
|
res['instance_groups'] = self.reverse('api:instance_instance_groups_list', kwargs={'pk': obj.pk})
|
||||||
if self.context['request'].user.is_superuser or self.context['request'].user.is_system_auditor:
|
if self.context['request'].user.is_superuser or self.context['request'].user.is_system_auditor:
|
||||||
res['health_check'] = self.reverse('api:instance_health_check', kwargs={'pk': obj.pk})
|
if obj.node_type != 'hop':
|
||||||
|
res['health_check'] = self.reverse('api:instance_health_check', kwargs={'pk': obj.pk})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_consumed_capacity(self, obj):
|
def get_consumed_capacity(self, obj):
|
||||||
@@ -4822,6 +4856,11 @@ class InstanceSerializer(BaseSerializer):
|
|||||||
else:
|
else:
|
||||||
return float("{0:.2f}".format(((float(obj.capacity) - float(obj.consumed_capacity)) / (float(obj.capacity))) * 100))
|
return float("{0:.2f}".format(((float(obj.capacity) - float(obj.consumed_capacity)) / (float(obj.capacity))) * 100))
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
if self.instance.node_type == 'hop':
|
||||||
|
raise serializers.ValidationError(_('Hop node instances may not be changed.'))
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class InstanceHealthCheckSerializer(BaseSerializer):
|
class InstanceHealthCheckSerializer(BaseSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -4908,6 +4947,9 @@ class InstanceGroupSerializer(BaseSerializer):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def validate_policy_instance_list(self, value):
|
def validate_policy_instance_list(self, value):
|
||||||
|
if self.instance and self.instance.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
|
||||||
|
if self.instance.policy_instance_list != value:
|
||||||
|
raise serializers.ValidationError(_('%s instance group policy_instance_list may not be changed.' % self.instance.name))
|
||||||
for instance_name in value:
|
for instance_name in value:
|
||||||
if value.count(instance_name) > 1:
|
if value.count(instance_name) > 1:
|
||||||
raise serializers.ValidationError(_('Duplicate entry {}.').format(instance_name))
|
raise serializers.ValidationError(_('Duplicate entry {}.').format(instance_name))
|
||||||
@@ -4918,6 +4960,11 @@ class InstanceGroupSerializer(BaseSerializer):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
def validate_policy_instance_percentage(self, value):
|
def validate_policy_instance_percentage(self, value):
|
||||||
|
if self.instance and self.instance.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
|
||||||
|
if value != self.instance.policy_instance_percentage:
|
||||||
|
raise serializers.ValidationError(
|
||||||
|
_('%s instance group policy_instance_percentage may not be changed from the initial value set by the installer.' % self.instance.name)
|
||||||
|
)
|
||||||
if value and self.instance and self.instance.is_container_group:
|
if value and self.instance and self.instance.is_container_group:
|
||||||
raise serializers.ValidationError(_('Containerized instances may not be managed via the API'))
|
raise serializers.ValidationError(_('Containerized instances may not be managed via the API'))
|
||||||
return value
|
return value
|
||||||
@@ -4936,6 +4983,13 @@ class InstanceGroupSerializer(BaseSerializer):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def validate_is_container_group(self, value):
|
||||||
|
if self.instance and self.instance.name in [settings.DEFAULT_EXECUTION_QUEUE_NAME, settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME]:
|
||||||
|
if value != self.instance.is_container_group:
|
||||||
|
raise serializers.ValidationError(_('%s instance group is_container_group may not be changed.' % self.instance.name))
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
def validate_credential(self, value):
|
def validate_credential(self, value):
|
||||||
if value and not value.kubernetes:
|
if value and not value.kubernetes:
|
||||||
raise serializers.ValidationError(_('Only Kubernetes credentials can be associated with an Instance Group'))
|
raise serializers.ValidationError(_('Only Kubernetes credentials can be associated with an Instance Group'))
|
||||||
@@ -5003,6 +5057,7 @@ class ActivityStreamSerializer(BaseSerializer):
|
|||||||
('credential_type', ('id', 'name', 'description', 'kind', 'managed')),
|
('credential_type', ('id', 'name', 'description', 'kind', 'managed')),
|
||||||
('ad_hoc_command', ('id', 'name', 'status', 'limit')),
|
('ad_hoc_command', ('id', 'name', 'status', 'limit')),
|
||||||
('workflow_approval', ('id', 'name', 'unified_job_id')),
|
('workflow_approval', ('id', 'name', 'unified_job_id')),
|
||||||
|
('instance', ('id', 'hostname')),
|
||||||
]
|
]
|
||||||
return field_list
|
return field_list
|
||||||
|
|
||||||
@@ -5049,7 +5104,7 @@ class ActivityStreamSerializer(BaseSerializer):
|
|||||||
try:
|
try:
|
||||||
return json.loads(obj.changes)
|
return json.loads(obj.changes)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warn("Error deserializing activity stream json changes")
|
logger.warning("Error deserializing activity stream json changes")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_object_association(self, obj):
|
def get_object_association(self, obj):
|
||||||
|
|||||||
1
awx/api/templates/api/mesh_visualizer.md
Normal file
1
awx/api/templates/api/mesh_visualizer.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Make a GET request to this resource to obtain a list all Receptor Nodes and their links.
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import ActivityStreamList, ActivityStreamDetail
|
from awx.api.views import ActivityStreamList, ActivityStreamDetail
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', ActivityStreamList.as_view(), name='activity_stream_list'),
|
re_path(r'^$', ActivityStreamList.as_view(), name='activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', ActivityStreamDetail.as_view(), name='activity_stream_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', ActivityStreamDetail.as_view(), name='activity_stream_detail'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
AdHocCommandList,
|
AdHocCommandList,
|
||||||
@@ -16,14 +16,14 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', AdHocCommandList.as_view(), name='ad_hoc_command_list'),
|
re_path(r'^$', AdHocCommandList.as_view(), name='ad_hoc_command_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', AdHocCommandDetail.as_view(), name='ad_hoc_command_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', AdHocCommandDetail.as_view(), name='ad_hoc_command_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/cancel/$', AdHocCommandCancel.as_view(), name='ad_hoc_command_cancel'),
|
re_path(r'^(?P<pk>[0-9]+)/cancel/$', AdHocCommandCancel.as_view(), name='ad_hoc_command_cancel'),
|
||||||
url(r'^(?P<pk>[0-9]+)/relaunch/$', AdHocCommandRelaunch.as_view(), name='ad_hoc_command_relaunch'),
|
re_path(r'^(?P<pk>[0-9]+)/relaunch/$', AdHocCommandRelaunch.as_view(), name='ad_hoc_command_relaunch'),
|
||||||
url(r'^(?P<pk>[0-9]+)/events/$', AdHocCommandAdHocCommandEventsList.as_view(), name='ad_hoc_command_ad_hoc_command_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/events/$', AdHocCommandAdHocCommandEventsList.as_view(), name='ad_hoc_command_ad_hoc_command_events_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', AdHocCommandActivityStreamList.as_view(), name='ad_hoc_command_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', AdHocCommandActivityStreamList.as_view(), name='ad_hoc_command_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notifications/$', AdHocCommandNotificationsList.as_view(), name='ad_hoc_command_notifications_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notifications/$', AdHocCommandNotificationsList.as_view(), name='ad_hoc_command_notifications_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/stdout/$', AdHocCommandStdout.as_view(), name='ad_hoc_command_stdout'),
|
re_path(r'^(?P<pk>[0-9]+)/stdout/$', AdHocCommandStdout.as_view(), name='ad_hoc_command_stdout'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import AdHocCommandEventDetail
|
from awx.api.views import AdHocCommandEventDetail
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^(?P<pk>[0-9]+)/$', AdHocCommandEventDetail.as_view(), name='ad_hoc_command_event_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', AdHocCommandEventDetail.as_view(), name='ad_hoc_command_event_detail'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
CredentialList,
|
CredentialList,
|
||||||
@@ -18,16 +18,16 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', CredentialList.as_view(), name='credential_list'),
|
re_path(r'^$', CredentialList.as_view(), name='credential_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialActivityStreamList.as_view(), name='credential_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialActivityStreamList.as_view(), name='credential_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', CredentialDetail.as_view(), name='credential_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', CredentialDetail.as_view(), name='credential_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', CredentialAccessList.as_view(), name='credential_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', CredentialAccessList.as_view(), name='credential_access_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', CredentialObjectRolesList.as_view(), name='credential_object_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', CredentialObjectRolesList.as_view(), name='credential_object_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/owner_users/$', CredentialOwnerUsersList.as_view(), name='credential_owner_users_list'),
|
re_path(r'^(?P<pk>[0-9]+)/owner_users/$', CredentialOwnerUsersList.as_view(), name='credential_owner_users_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/owner_teams/$', CredentialOwnerTeamsList.as_view(), name='credential_owner_teams_list'),
|
re_path(r'^(?P<pk>[0-9]+)/owner_teams/$', CredentialOwnerTeamsList.as_view(), name='credential_owner_teams_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', CredentialCopy.as_view(), name='credential_copy'),
|
re_path(r'^(?P<pk>[0-9]+)/copy/$', CredentialCopy.as_view(), name='credential_copy'),
|
||||||
url(r'^(?P<pk>[0-9]+)/input_sources/$', CredentialInputSourceSubList.as_view(), name='credential_input_source_sublist'),
|
re_path(r'^(?P<pk>[0-9]+)/input_sources/$', CredentialInputSourceSubList.as_view(), name='credential_input_source_sublist'),
|
||||||
url(r'^(?P<pk>[0-9]+)/test/$', CredentialExternalTest.as_view(), name='credential_external_test'),
|
re_path(r'^(?P<pk>[0-9]+)/test/$', CredentialExternalTest.as_view(), name='credential_external_test'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
# Copyright (c) 2019 Ansible, Inc.
|
# Copyright (c) 2019 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import CredentialInputSourceDetail, CredentialInputSourceList
|
from awx.api.views import CredentialInputSourceDetail, CredentialInputSourceList
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', CredentialInputSourceList.as_view(), name='credential_input_source_list'),
|
re_path(r'^$', CredentialInputSourceList.as_view(), name='credential_input_source_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', CredentialInputSourceDetail.as_view(), name='credential_input_source_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', CredentialInputSourceDetail.as_view(), name='credential_input_source_detail'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import CredentialTypeList, CredentialTypeDetail, CredentialTypeCredentialList, CredentialTypeActivityStreamList, CredentialTypeExternalTest
|
from awx.api.views import CredentialTypeList, CredentialTypeDetail, CredentialTypeCredentialList, CredentialTypeActivityStreamList, CredentialTypeExternalTest
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', CredentialTypeList.as_view(), name='credential_type_list'),
|
re_path(r'^$', CredentialTypeList.as_view(), name='credential_type_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', CredentialTypeDetail.as_view(), name='credential_type_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', CredentialTypeCredentialList.as_view(), name='credential_type_credential_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', CredentialTypeCredentialList.as_view(), name='credential_type_credential_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', CredentialTypeActivityStreamList.as_view(), name='credential_type_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'),
|
re_path(r'^(?P<pk>[0-9]+)/test/$', CredentialTypeExternalTest.as_view(), name='credential_type_external_test'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
ExecutionEnvironmentList,
|
ExecutionEnvironmentList,
|
||||||
@@ -10,11 +10,11 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', ExecutionEnvironmentList.as_view(), name='execution_environment_list'),
|
re_path(r'^$', ExecutionEnvironmentList.as_view(), name='execution_environment_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', ExecutionEnvironmentDetail.as_view(), name='execution_environment_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', ExecutionEnvironmentDetail.as_view(), name='execution_environment_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/unified_job_templates/$', ExecutionEnvironmentJobTemplateList.as_view(), name='execution_environment_job_template_list'),
|
re_path(r'^(?P<pk>[0-9]+)/unified_job_templates/$', ExecutionEnvironmentJobTemplateList.as_view(), name='execution_environment_job_template_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', ExecutionEnvironmentCopy.as_view(), name='execution_environment_copy'),
|
re_path(r'^(?P<pk>[0-9]+)/copy/$', ExecutionEnvironmentCopy.as_view(), name='execution_environment_copy'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', ExecutionEnvironmentActivityStreamList.as_view(), name='execution_environment_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', ExecutionEnvironmentActivityStreamList.as_view(), name='execution_environment_activity_stream_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
GroupList,
|
GroupList,
|
||||||
@@ -20,18 +20,18 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', GroupList.as_view(), name='group_list'),
|
re_path(r'^$', GroupList.as_view(), name='group_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', GroupDetail.as_view(), name='group_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', GroupDetail.as_view(), name='group_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/children/$', GroupChildrenList.as_view(), name='group_children_list'),
|
re_path(r'^(?P<pk>[0-9]+)/children/$', GroupChildrenList.as_view(), name='group_children_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/hosts/$', GroupHostsList.as_view(), name='group_hosts_list'),
|
re_path(r'^(?P<pk>[0-9]+)/hosts/$', GroupHostsList.as_view(), name='group_hosts_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/all_hosts/$', GroupAllHostsList.as_view(), name='group_all_hosts_list'),
|
re_path(r'^(?P<pk>[0-9]+)/all_hosts/$', GroupAllHostsList.as_view(), name='group_all_hosts_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/variable_data/$', GroupVariableData.as_view(), name='group_variable_data'),
|
re_path(r'^(?P<pk>[0-9]+)/variable_data/$', GroupVariableData.as_view(), name='group_variable_data'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_events/$', GroupJobEventsList.as_view(), name='group_job_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_events/$', GroupJobEventsList.as_view(), name='group_job_events_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', GroupJobHostSummariesList.as_view(), name='group_job_host_summaries_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_host_summaries/$', GroupJobHostSummariesList.as_view(), name='group_job_host_summaries_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/potential_children/$', GroupPotentialChildrenList.as_view(), name='group_potential_children_list'),
|
re_path(r'^(?P<pk>[0-9]+)/potential_children/$', GroupPotentialChildrenList.as_view(), name='group_potential_children_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', GroupActivityStreamList.as_view(), name='group_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', GroupActivityStreamList.as_view(), name='group_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', GroupInventorySourcesList.as_view(), name='group_inventory_sources_list'),
|
re_path(r'^(?P<pk>[0-9]+)/inventory_sources/$', GroupInventorySourcesList.as_view(), name='group_inventory_sources_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', GroupAdHocCommandsList.as_view(), name='group_ad_hoc_commands_list'),
|
re_path(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', GroupAdHocCommandsList.as_view(), name='group_ad_hoc_commands_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
HostList,
|
HostList,
|
||||||
@@ -20,18 +20,18 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', HostList.as_view(), name='host_list'),
|
re_path(r'^$', HostList.as_view(), name='host_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', HostDetail.as_view(), name='host_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', HostDetail.as_view(), name='host_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/variable_data/$', HostVariableData.as_view(), name='host_variable_data'),
|
re_path(r'^(?P<pk>[0-9]+)/variable_data/$', HostVariableData.as_view(), name='host_variable_data'),
|
||||||
url(r'^(?P<pk>[0-9]+)/groups/$', HostGroupsList.as_view(), name='host_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/groups/$', HostGroupsList.as_view(), name='host_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/all_groups/$', HostAllGroupsList.as_view(), name='host_all_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/all_groups/$', HostAllGroupsList.as_view(), name='host_all_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_events/', HostJobEventsList.as_view(), name='host_job_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_events/', HostJobEventsList.as_view(), name='host_job_events_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', HostJobHostSummariesList.as_view(), name='host_job_host_summaries_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_host_summaries/$', HostJobHostSummariesList.as_view(), name='host_job_host_summaries_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', HostActivityStreamList.as_view(), name='host_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', HostActivityStreamList.as_view(), name='host_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', HostInventorySourcesList.as_view(), name='host_inventory_sources_list'),
|
re_path(r'^(?P<pk>[0-9]+)/inventory_sources/$', HostInventorySourcesList.as_view(), name='host_inventory_sources_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/smart_inventories/$', HostSmartInventoriesList.as_view(), name='host_smart_inventories_list'),
|
re_path(r'^(?P<pk>[0-9]+)/smart_inventories/$', HostSmartInventoriesList.as_view(), name='host_smart_inventories_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', HostAdHocCommandsList.as_view(), name='host_ad_hoc_commands_list'),
|
re_path(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', HostAdHocCommandsList.as_view(), name='host_ad_hoc_commands_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_command_events/$', HostAdHocCommandEventsList.as_view(), name='host_ad_hoc_command_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/ad_hoc_command_events/$', HostAdHocCommandEventsList.as_view(), name='host_ad_hoc_command_events_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import InstanceList, InstanceDetail, InstanceUnifiedJobsList, InstanceInstanceGroupsList, InstanceHealthCheck
|
from awx.api.views import InstanceList, InstanceDetail, InstanceUnifiedJobsList, InstanceInstanceGroupsList, InstanceHealthCheck
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', InstanceList.as_view(), name='instance_list'),
|
re_path(r'^$', InstanceList.as_view(), name='instance_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', InstanceDetail.as_view(), name='instance_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', InstanceDetail.as_view(), name='instance_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/jobs/$', InstanceUnifiedJobsList.as_view(), name='instance_unified_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/jobs/$', InstanceUnifiedJobsList.as_view(), name='instance_unified_jobs_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/instance_groups/$', InstanceInstanceGroupsList.as_view(), name='instance_instance_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/instance_groups/$', InstanceInstanceGroupsList.as_view(), name='instance_instance_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/health_check/$', InstanceHealthCheck.as_view(), name='instance_health_check'),
|
re_path(r'^(?P<pk>[0-9]+)/health_check/$', InstanceHealthCheck.as_view(), name='instance_health_check'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import InstanceGroupList, InstanceGroupDetail, InstanceGroupUnifiedJobsList, InstanceGroupInstanceList
|
from awx.api.views import InstanceGroupList, InstanceGroupDetail, InstanceGroupUnifiedJobsList, InstanceGroupInstanceList
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', InstanceGroupList.as_view(), name='instance_group_list'),
|
re_path(r'^$', InstanceGroupList.as_view(), name='instance_group_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', InstanceGroupDetail.as_view(), name='instance_group_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', InstanceGroupDetail.as_view(), name='instance_group_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/jobs/$', InstanceGroupUnifiedJobsList.as_view(), name='instance_group_unified_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/jobs/$', InstanceGroupUnifiedJobsList.as_view(), name='instance_group_unified_jobs_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/instances/$', InstanceGroupInstanceList.as_view(), name='instance_group_instance_list'),
|
re_path(r'^(?P<pk>[0-9]+)/instances/$', InstanceGroupInstanceList.as_view(), name='instance_group_instance_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
InventoryList,
|
InventoryList,
|
||||||
@@ -20,28 +20,30 @@ from awx.api.views import (
|
|||||||
InventoryAccessList,
|
InventoryAccessList,
|
||||||
InventoryObjectRolesList,
|
InventoryObjectRolesList,
|
||||||
InventoryInstanceGroupsList,
|
InventoryInstanceGroupsList,
|
||||||
|
InventoryLabelList,
|
||||||
InventoryCopy,
|
InventoryCopy,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', InventoryList.as_view(), name='inventory_list'),
|
re_path(r'^$', InventoryList.as_view(), name='inventory_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', InventoryDetail.as_view(), name='inventory_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', InventoryDetail.as_view(), name='inventory_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/hosts/$', InventoryHostsList.as_view(), name='inventory_hosts_list'),
|
re_path(r'^(?P<pk>[0-9]+)/hosts/$', InventoryHostsList.as_view(), name='inventory_hosts_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/groups/$', InventoryGroupsList.as_view(), name='inventory_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/groups/$', InventoryGroupsList.as_view(), name='inventory_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/root_groups/$', InventoryRootGroupsList.as_view(), name='inventory_root_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/root_groups/$', InventoryRootGroupsList.as_view(), name='inventory_root_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/variable_data/$', InventoryVariableData.as_view(), name='inventory_variable_data'),
|
re_path(r'^(?P<pk>[0-9]+)/variable_data/$', InventoryVariableData.as_view(), name='inventory_variable_data'),
|
||||||
url(r'^(?P<pk>[0-9]+)/script/$', InventoryScriptView.as_view(), name='inventory_script_view'),
|
re_path(r'^(?P<pk>[0-9]+)/script/$', InventoryScriptView.as_view(), name='inventory_script_view'),
|
||||||
url(r'^(?P<pk>[0-9]+)/tree/$', InventoryTreeView.as_view(), name='inventory_tree_view'),
|
re_path(r'^(?P<pk>[0-9]+)/tree/$', InventoryTreeView.as_view(), name='inventory_tree_view'),
|
||||||
url(r'^(?P<pk>[0-9]+)/inventory_sources/$', InventoryInventorySourcesList.as_view(), name='inventory_inventory_sources_list'),
|
re_path(r'^(?P<pk>[0-9]+)/inventory_sources/$', InventoryInventorySourcesList.as_view(), name='inventory_inventory_sources_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/update_inventory_sources/$', InventoryInventorySourcesUpdate.as_view(), name='inventory_inventory_sources_update'),
|
re_path(r'^(?P<pk>[0-9]+)/update_inventory_sources/$', InventoryInventorySourcesUpdate.as_view(), name='inventory_inventory_sources_update'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', InventoryActivityStreamList.as_view(), name='inventory_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', InventoryActivityStreamList.as_view(), name='inventory_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_templates/$', InventoryJobTemplateList.as_view(), name='inventory_job_template_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_templates/$', InventoryJobTemplateList.as_view(), name='inventory_job_template_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', InventoryAdHocCommandsList.as_view(), name='inventory_ad_hoc_commands_list'),
|
re_path(r'^(?P<pk>[0-9]+)/ad_hoc_commands/$', InventoryAdHocCommandsList.as_view(), name='inventory_ad_hoc_commands_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', InventoryAccessList.as_view(), name='inventory_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', InventoryAccessList.as_view(), name='inventory_access_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', InventoryObjectRolesList.as_view(), name='inventory_object_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', InventoryObjectRolesList.as_view(), name='inventory_object_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/instance_groups/$', InventoryInstanceGroupsList.as_view(), name='inventory_instance_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/instance_groups/$', InventoryInstanceGroupsList.as_view(), name='inventory_instance_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', InventoryCopy.as_view(), name='inventory_copy'),
|
re_path(r'^(?P<pk>[0-9]+)/labels/$', InventoryLabelList.as_view(), name='inventory_label_list'),
|
||||||
|
re_path(r'^(?P<pk>[0-9]+)/copy/$', InventoryCopy.as_view(), name='inventory_copy'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
InventorySourceList,
|
InventorySourceList,
|
||||||
@@ -20,26 +20,26 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', InventorySourceList.as_view(), name='inventory_source_list'),
|
re_path(r'^$', InventorySourceList.as_view(), name='inventory_source_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', InventorySourceDetail.as_view(), name='inventory_source_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', InventorySourceDetail.as_view(), name='inventory_source_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/update/$', InventorySourceUpdateView.as_view(), name='inventory_source_update_view'),
|
re_path(r'^(?P<pk>[0-9]+)/update/$', InventorySourceUpdateView.as_view(), name='inventory_source_update_view'),
|
||||||
url(r'^(?P<pk>[0-9]+)/inventory_updates/$', InventorySourceUpdatesList.as_view(), name='inventory_source_updates_list'),
|
re_path(r'^(?P<pk>[0-9]+)/inventory_updates/$', InventorySourceUpdatesList.as_view(), name='inventory_source_updates_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', InventorySourceActivityStreamList.as_view(), name='inventory_source_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', InventorySourceActivityStreamList.as_view(), name='inventory_source_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/schedules/$', InventorySourceSchedulesList.as_view(), name='inventory_source_schedules_list'),
|
re_path(r'^(?P<pk>[0-9]+)/schedules/$', InventorySourceSchedulesList.as_view(), name='inventory_source_schedules_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', InventorySourceCredentialsList.as_view(), name='inventory_source_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', InventorySourceCredentialsList.as_view(), name='inventory_source_credentials_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/groups/$', InventorySourceGroupsList.as_view(), name='inventory_source_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/groups/$', InventorySourceGroupsList.as_view(), name='inventory_source_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/hosts/$', InventorySourceHostsList.as_view(), name='inventory_source_hosts_list'),
|
re_path(r'^(?P<pk>[0-9]+)/hosts/$', InventorySourceHostsList.as_view(), name='inventory_source_hosts_list'),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
||||||
InventorySourceNotificationTemplatesStartedList.as_view(),
|
InventorySourceNotificationTemplatesStartedList.as_view(),
|
||||||
name='inventory_source_notification_templates_started_list',
|
name='inventory_source_notification_templates_started_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
||||||
InventorySourceNotificationTemplatesErrorList.as_view(),
|
InventorySourceNotificationTemplatesErrorList.as_view(),
|
||||||
name='inventory_source_notification_templates_error_list',
|
name='inventory_source_notification_templates_error_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
||||||
InventorySourceNotificationTemplatesSuccessList.as_view(),
|
InventorySourceNotificationTemplatesSuccessList.as_view(),
|
||||||
name='inventory_source_notification_templates_success_list',
|
name='inventory_source_notification_templates_success_list',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
InventoryUpdateList,
|
InventoryUpdateList,
|
||||||
@@ -15,13 +15,13 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', InventoryUpdateList.as_view(), name='inventory_update_list'),
|
re_path(r'^$', InventoryUpdateList.as_view(), name='inventory_update_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', InventoryUpdateDetail.as_view(), name='inventory_update_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', InventoryUpdateDetail.as_view(), name='inventory_update_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/cancel/$', InventoryUpdateCancel.as_view(), name='inventory_update_cancel'),
|
re_path(r'^(?P<pk>[0-9]+)/cancel/$', InventoryUpdateCancel.as_view(), name='inventory_update_cancel'),
|
||||||
url(r'^(?P<pk>[0-9]+)/stdout/$', InventoryUpdateStdout.as_view(), name='inventory_update_stdout'),
|
re_path(r'^(?P<pk>[0-9]+)/stdout/$', InventoryUpdateStdout.as_view(), name='inventory_update_stdout'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notifications/$', InventoryUpdateNotificationsList.as_view(), name='inventory_update_notifications_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notifications/$', InventoryUpdateNotificationsList.as_view(), name='inventory_update_notifications_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', InventoryUpdateCredentialsList.as_view(), name='inventory_update_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', InventoryUpdateCredentialsList.as_view(), name='inventory_update_credentials_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/events/$', InventoryUpdateEventsList.as_view(), name='inventory_update_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/events/$', InventoryUpdateEventsList.as_view(), name='inventory_update_events_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
JobList,
|
JobList,
|
||||||
@@ -20,18 +20,18 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', JobList.as_view(), name='job_list'),
|
re_path(r'^$', JobList.as_view(), name='job_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', JobDetail.as_view(), name='job_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', JobDetail.as_view(), name='job_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/cancel/$', JobCancel.as_view(), name='job_cancel'),
|
re_path(r'^(?P<pk>[0-9]+)/cancel/$', JobCancel.as_view(), name='job_cancel'),
|
||||||
url(r'^(?P<pk>[0-9]+)/relaunch/$', JobRelaunch.as_view(), name='job_relaunch'),
|
re_path(r'^(?P<pk>[0-9]+)/relaunch/$', JobRelaunch.as_view(), name='job_relaunch'),
|
||||||
url(r'^(?P<pk>[0-9]+)/create_schedule/$', JobCreateSchedule.as_view(), name='job_create_schedule'),
|
re_path(r'^(?P<pk>[0-9]+)/create_schedule/$', JobCreateSchedule.as_view(), name='job_create_schedule'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_host_summaries/$', JobJobHostSummariesList.as_view(), name='job_job_host_summaries_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_host_summaries/$', JobJobHostSummariesList.as_view(), name='job_job_host_summaries_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_events/$', JobJobEventsList.as_view(), name='job_job_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_events/$', JobJobEventsList.as_view(), name='job_job_events_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', JobActivityStreamList.as_view(), name='job_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', JobActivityStreamList.as_view(), name='job_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/stdout/$', JobStdout.as_view(), name='job_stdout'),
|
re_path(r'^(?P<pk>[0-9]+)/stdout/$', JobStdout.as_view(), name='job_stdout'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notifications/$', JobNotificationsList.as_view(), name='job_notifications_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notifications/$', JobNotificationsList.as_view(), name='job_notifications_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/labels/$', JobLabelList.as_view(), name='job_label_list'),
|
re_path(r'^(?P<pk>[0-9]+)/labels/$', JobLabelList.as_view(), name='job_label_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', JobHostSummaryDetail.as_view(), name='job_host_summary_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', JobHostSummaryDetail.as_view(), name='job_host_summary_detail'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import JobEventDetail, JobEventChildrenList
|
from awx.api.views import JobEventDetail, JobEventChildrenList
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^(?P<pk>[0-9]+)/$', JobEventDetail.as_view(), name='job_event_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', JobEventDetail.as_view(), name='job_event_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/children/$', JobEventChildrenList.as_view(), name='job_event_children_list'),
|
re_path(r'^(?P<pk>[0-9]+)/children/$', JobEventChildrenList.as_view(), name='job_event_children_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import JobHostSummaryDetail
|
from awx.api.views import JobHostSummaryDetail
|
||||||
|
|
||||||
|
|
||||||
urls = [url(r'^(?P<pk>[0-9]+)/$', JobHostSummaryDetail.as_view(), name='job_host_summary_detail')]
|
urls = [re_path(r'^(?P<pk>[0-9]+)/$', JobHostSummaryDetail.as_view(), name='job_host_summary_detail')]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import include, url
|
from django.urls import include, re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
JobTemplateList,
|
JobTemplateList,
|
||||||
@@ -25,36 +25,36 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', JobTemplateList.as_view(), name='job_template_list'),
|
re_path(r'^$', JobTemplateList.as_view(), name='job_template_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', JobTemplateDetail.as_view(), name='job_template_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', JobTemplateDetail.as_view(), name='job_template_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/launch/$', JobTemplateLaunch.as_view(), name='job_template_launch'),
|
re_path(r'^(?P<pk>[0-9]+)/launch/$', JobTemplateLaunch.as_view(), name='job_template_launch'),
|
||||||
url(r'^(?P<pk>[0-9]+)/jobs/$', JobTemplateJobsList.as_view(), name='job_template_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/jobs/$', JobTemplateJobsList.as_view(), name='job_template_jobs_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/slice_workflow_jobs/$', JobTemplateSliceWorkflowJobsList.as_view(), name='job_template_slice_workflow_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/slice_workflow_jobs/$', JobTemplateSliceWorkflowJobsList.as_view(), name='job_template_slice_workflow_jobs_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/callback/$', JobTemplateCallback.as_view(), name='job_template_callback'),
|
re_path(r'^(?P<pk>[0-9]+)/callback/$', JobTemplateCallback.as_view(), name='job_template_callback'),
|
||||||
url(r'^(?P<pk>[0-9]+)/schedules/$', JobTemplateSchedulesList.as_view(), name='job_template_schedules_list'),
|
re_path(r'^(?P<pk>[0-9]+)/schedules/$', JobTemplateSchedulesList.as_view(), name='job_template_schedules_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/survey_spec/$', JobTemplateSurveySpec.as_view(), name='job_template_survey_spec'),
|
re_path(r'^(?P<pk>[0-9]+)/survey_spec/$', JobTemplateSurveySpec.as_view(), name='job_template_survey_spec'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', JobTemplateActivityStreamList.as_view(), name='job_template_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', JobTemplateActivityStreamList.as_view(), name='job_template_activity_stream_list'),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
||||||
JobTemplateNotificationTemplatesStartedList.as_view(),
|
JobTemplateNotificationTemplatesStartedList.as_view(),
|
||||||
name='job_template_notification_templates_started_list',
|
name='job_template_notification_templates_started_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
||||||
JobTemplateNotificationTemplatesErrorList.as_view(),
|
JobTemplateNotificationTemplatesErrorList.as_view(),
|
||||||
name='job_template_notification_templates_error_list',
|
name='job_template_notification_templates_error_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
||||||
JobTemplateNotificationTemplatesSuccessList.as_view(),
|
JobTemplateNotificationTemplatesSuccessList.as_view(),
|
||||||
name='job_template_notification_templates_success_list',
|
name='job_template_notification_templates_success_list',
|
||||||
),
|
),
|
||||||
url(r'^(?P<pk>[0-9]+)/instance_groups/$', JobTemplateInstanceGroupsList.as_view(), name='job_template_instance_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/instance_groups/$', JobTemplateInstanceGroupsList.as_view(), name='job_template_instance_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', JobTemplateAccessList.as_view(), name='job_template_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', JobTemplateAccessList.as_view(), name='job_template_access_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', JobTemplateObjectRolesList.as_view(), name='job_template_object_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', JobTemplateObjectRolesList.as_view(), name='job_template_object_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/labels/$', JobTemplateLabelList.as_view(), name='job_template_label_list'),
|
re_path(r'^(?P<pk>[0-9]+)/labels/$', JobTemplateLabelList.as_view(), name='job_template_label_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', JobTemplateCopy.as_view(), name='job_template_copy'),
|
re_path(r'^(?P<pk>[0-9]+)/copy/$', JobTemplateCopy.as_view(), name='job_template_copy'),
|
||||||
url(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'job_templates'}),
|
re_path(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'job_templates'}),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import LabelList, LabelDetail
|
from awx.api.views import LabelList, LabelDetail
|
||||||
|
|
||||||
|
|
||||||
urls = [url(r'^$', LabelList.as_view(), name='label_list'), url(r'^(?P<pk>[0-9]+)/$', LabelDetail.as_view(), name='label_detail')]
|
urls = [re_path(r'^$', LabelList.as_view(), name='label_list'), re_path(r'^(?P<pk>[0-9]+)/$', LabelDetail.as_view(), name='label_detail')]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import NotificationList, NotificationDetail
|
from awx.api.views import NotificationList, NotificationDetail
|
||||||
|
|
||||||
|
|
||||||
urls = [url(r'^$', NotificationList.as_view(), name='notification_list'), url(r'^(?P<pk>[0-9]+)/$', NotificationDetail.as_view(), name='notification_detail')]
|
urls = [
|
||||||
|
re_path(r'^$', NotificationList.as_view(), name='notification_list'),
|
||||||
|
re_path(r'^(?P<pk>[0-9]+)/$', NotificationDetail.as_view(), name='notification_detail'),
|
||||||
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
NotificationTemplateList,
|
NotificationTemplateList,
|
||||||
@@ -13,11 +13,11 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', NotificationTemplateList.as_view(), name='notification_template_list'),
|
re_path(r'^$', NotificationTemplateList.as_view(), name='notification_template_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', NotificationTemplateDetail.as_view(), name='notification_template_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', NotificationTemplateDetail.as_view(), name='notification_template_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/test/$', NotificationTemplateTest.as_view(), name='notification_template_test'),
|
re_path(r'^(?P<pk>[0-9]+)/test/$', NotificationTemplateTest.as_view(), name='notification_template_test'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notifications/$', NotificationTemplateNotificationList.as_view(), name='notification_template_notification_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notifications/$', NotificationTemplateNotificationList.as_view(), name='notification_template_notification_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', NotificationTemplateCopy.as_view(), name='notification_template_copy'),
|
re_path(r'^(?P<pk>[0-9]+)/copy/$', NotificationTemplateCopy.as_view(), name='notification_template_copy'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
OAuth2ApplicationList,
|
OAuth2ApplicationList,
|
||||||
@@ -15,13 +15,13 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
|
re_path(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
|
||||||
url(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
|
re_path(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
|
||||||
url(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='o_auth2_application_token_list'),
|
re_path(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='o_auth2_application_token_list'),
|
||||||
url(r'^applications/(?P<pk>[0-9]+)/activity_stream/$', OAuth2ApplicationActivityStreamList.as_view(), name='o_auth2_application_activity_stream_list'),
|
re_path(r'^applications/(?P<pk>[0-9]+)/activity_stream/$', OAuth2ApplicationActivityStreamList.as_view(), name='o_auth2_application_activity_stream_list'),
|
||||||
url(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
|
re_path(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
|
||||||
url(r'^tokens/(?P<pk>[0-9]+)/$', OAuth2TokenDetail.as_view(), name='o_auth2_token_detail'),
|
re_path(r'^tokens/(?P<pk>[0-9]+)/$', OAuth2TokenDetail.as_view(), name='o_auth2_token_detail'),
|
||||||
url(r'^tokens/(?P<pk>[0-9]+)/activity_stream/$', OAuth2TokenActivityStreamList.as_view(), name='o_auth2_token_activity_stream_list'),
|
re_path(r'^tokens/(?P<pk>[0-9]+)/activity_stream/$', OAuth2TokenActivityStreamList.as_view(), name='o_auth2_token_activity_stream_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from datetime import timedelta
|
|||||||
|
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from oauthlib import oauth2
|
from oauthlib import oauth2
|
||||||
from oauth2_provider import views
|
from oauth2_provider import views
|
||||||
@@ -35,10 +35,10 @@ class TokenView(views.TokenView):
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', ApiOAuthAuthorizationRootView.as_view(), name='oauth_authorization_root_view'),
|
re_path(r'^$', ApiOAuthAuthorizationRootView.as_view(), name='oauth_authorization_root_view'),
|
||||||
url(r"^authorize/$", views.AuthorizationView.as_view(), name="authorize"),
|
re_path(r"^authorize/$", views.AuthorizationView.as_view(), name="authorize"),
|
||||||
url(r"^token/$", TokenView.as_view(), name="token"),
|
re_path(r"^token/$", TokenView.as_view(), name="token"),
|
||||||
url(r"^revoke_token/$", views.RevokeTokenView.as_view(), name="revoke-token"),
|
re_path(r"^revoke_token/$", views.RevokeTokenView.as_view(), name="revoke-token"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
OrganizationList,
|
OrganizationList,
|
||||||
@@ -30,44 +30,44 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', OrganizationList.as_view(), name='organization_list'),
|
re_path(r'^$', OrganizationList.as_view(), name='organization_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', OrganizationDetail.as_view(), name='organization_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', OrganizationDetail.as_view(), name='organization_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/users/$', OrganizationUsersList.as_view(), name='organization_users_list'),
|
re_path(r'^(?P<pk>[0-9]+)/users/$', OrganizationUsersList.as_view(), name='organization_users_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/admins/$', OrganizationAdminsList.as_view(), name='organization_admins_list'),
|
re_path(r'^(?P<pk>[0-9]+)/admins/$', OrganizationAdminsList.as_view(), name='organization_admins_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/inventories/$', OrganizationInventoriesList.as_view(), name='organization_inventories_list'),
|
re_path(r'^(?P<pk>[0-9]+)/inventories/$', OrganizationInventoriesList.as_view(), name='organization_inventories_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/execution_environments/$', OrganizationExecutionEnvironmentsList.as_view(), name='organization_execution_environments_list'),
|
re_path(r'^(?P<pk>[0-9]+)/execution_environments/$', OrganizationExecutionEnvironmentsList.as_view(), name='organization_execution_environments_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/projects/$', OrganizationProjectsList.as_view(), name='organization_projects_list'),
|
re_path(r'^(?P<pk>[0-9]+)/projects/$', OrganizationProjectsList.as_view(), name='organization_projects_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/job_templates/$', OrganizationJobTemplatesList.as_view(), name='organization_job_templates_list'),
|
re_path(r'^(?P<pk>[0-9]+)/job_templates/$', OrganizationJobTemplatesList.as_view(), name='organization_job_templates_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/workflow_job_templates/$', OrganizationWorkflowJobTemplatesList.as_view(), name='organization_workflow_job_templates_list'),
|
re_path(r'^(?P<pk>[0-9]+)/workflow_job_templates/$', OrganizationWorkflowJobTemplatesList.as_view(), name='organization_workflow_job_templates_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/teams/$', OrganizationTeamsList.as_view(), name='organization_teams_list'),
|
re_path(r'^(?P<pk>[0-9]+)/teams/$', OrganizationTeamsList.as_view(), name='organization_teams_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', OrganizationCredentialList.as_view(), name='organization_credential_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', OrganizationCredentialList.as_view(), name='organization_credential_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', OrganizationActivityStreamList.as_view(), name='organization_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', OrganizationActivityStreamList.as_view(), name='organization_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notification_templates/$', OrganizationNotificationTemplatesList.as_view(), name='organization_notification_templates_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notification_templates/$', OrganizationNotificationTemplatesList.as_view(), name='organization_notification_templates_list'),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
||||||
OrganizationNotificationTemplatesStartedList.as_view(),
|
OrganizationNotificationTemplatesStartedList.as_view(),
|
||||||
name='organization_notification_templates_started_list',
|
name='organization_notification_templates_started_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
||||||
OrganizationNotificationTemplatesErrorList.as_view(),
|
OrganizationNotificationTemplatesErrorList.as_view(),
|
||||||
name='organization_notification_templates_error_list',
|
name='organization_notification_templates_error_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
||||||
OrganizationNotificationTemplatesSuccessList.as_view(),
|
OrganizationNotificationTemplatesSuccessList.as_view(),
|
||||||
name='organization_notification_templates_success_list',
|
name='organization_notification_templates_success_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_approvals/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_approvals/$',
|
||||||
OrganizationNotificationTemplatesApprovalList.as_view(),
|
OrganizationNotificationTemplatesApprovalList.as_view(),
|
||||||
name='organization_notification_templates_approvals_list',
|
name='organization_notification_templates_approvals_list',
|
||||||
),
|
),
|
||||||
url(r'^(?P<pk>[0-9]+)/instance_groups/$', OrganizationInstanceGroupsList.as_view(), name='organization_instance_groups_list'),
|
re_path(r'^(?P<pk>[0-9]+)/instance_groups/$', OrganizationInstanceGroupsList.as_view(), name='organization_instance_groups_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/galaxy_credentials/$', OrganizationGalaxyCredentialsList.as_view(), name='organization_galaxy_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/galaxy_credentials/$', OrganizationGalaxyCredentialsList.as_view(), name='organization_galaxy_credentials_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', OrganizationObjectRolesList.as_view(), name='organization_object_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', OrganizationObjectRolesList.as_view(), name='organization_object_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', OrganizationAccessList.as_view(), name='organization_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', OrganizationAccessList.as_view(), name='organization_access_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/applications/$', OrganizationApplicationList.as_view(), name='organization_applications_list'),
|
re_path(r'^(?P<pk>[0-9]+)/applications/$', OrganizationApplicationList.as_view(), name='organization_applications_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
ProjectList,
|
ProjectList,
|
||||||
@@ -24,30 +24,32 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', ProjectList.as_view(), name='project_list'),
|
re_path(r'^$', ProjectList.as_view(), name='project_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', ProjectDetail.as_view(), name='project_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', ProjectDetail.as_view(), name='project_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/playbooks/$', ProjectPlaybooks.as_view(), name='project_playbooks'),
|
re_path(r'^(?P<pk>[0-9]+)/playbooks/$', ProjectPlaybooks.as_view(), name='project_playbooks'),
|
||||||
url(r'^(?P<pk>[0-9]+)/inventories/$', ProjectInventories.as_view(), name='project_inventories'),
|
re_path(r'^(?P<pk>[0-9]+)/inventories/$', ProjectInventories.as_view(), name='project_inventories'),
|
||||||
url(r'^(?P<pk>[0-9]+)/scm_inventory_sources/$', ProjectScmInventorySources.as_view(), name='project_scm_inventory_sources'),
|
re_path(r'^(?P<pk>[0-9]+)/scm_inventory_sources/$', ProjectScmInventorySources.as_view(), name='project_scm_inventory_sources'),
|
||||||
url(r'^(?P<pk>[0-9]+)/teams/$', ProjectTeamsList.as_view(), name='project_teams_list'),
|
re_path(r'^(?P<pk>[0-9]+)/teams/$', ProjectTeamsList.as_view(), name='project_teams_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/update/$', ProjectUpdateView.as_view(), name='project_update_view'),
|
re_path(r'^(?P<pk>[0-9]+)/update/$', ProjectUpdateView.as_view(), name='project_update_view'),
|
||||||
url(r'^(?P<pk>[0-9]+)/project_updates/$', ProjectUpdatesList.as_view(), name='project_updates_list'),
|
re_path(r'^(?P<pk>[0-9]+)/project_updates/$', ProjectUpdatesList.as_view(), name='project_updates_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', ProjectActivityStreamList.as_view(), name='project_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', ProjectActivityStreamList.as_view(), name='project_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/schedules/$', ProjectSchedulesList.as_view(), name='project_schedules_list'),
|
re_path(r'^(?P<pk>[0-9]+)/schedules/$', ProjectSchedulesList.as_view(), name='project_schedules_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notification_templates_error/$', ProjectNotificationTemplatesErrorList.as_view(), name='project_notification_templates_error_list'),
|
re_path(
|
||||||
url(
|
r'^(?P<pk>[0-9]+)/notification_templates_error/$', ProjectNotificationTemplatesErrorList.as_view(), name='project_notification_templates_error_list'
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
||||||
ProjectNotificationTemplatesSuccessList.as_view(),
|
ProjectNotificationTemplatesSuccessList.as_view(),
|
||||||
name='project_notification_templates_success_list',
|
name='project_notification_templates_success_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
||||||
ProjectNotificationTemplatesStartedList.as_view(),
|
ProjectNotificationTemplatesStartedList.as_view(),
|
||||||
name='project_notification_templates_started_list',
|
name='project_notification_templates_started_list',
|
||||||
),
|
),
|
||||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', ProjectObjectRolesList.as_view(), name='project_object_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', ProjectObjectRolesList.as_view(), name='project_object_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', ProjectAccessList.as_view(), name='project_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', ProjectAccessList.as_view(), name='project_access_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', ProjectCopy.as_view(), name='project_copy'),
|
re_path(r'^(?P<pk>[0-9]+)/copy/$', ProjectCopy.as_view(), name='project_copy'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
ProjectUpdateList,
|
ProjectUpdateList,
|
||||||
@@ -15,13 +15,13 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', ProjectUpdateList.as_view(), name='project_update_list'),
|
re_path(r'^$', ProjectUpdateList.as_view(), name='project_update_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', ProjectUpdateDetail.as_view(), name='project_update_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', ProjectUpdateDetail.as_view(), name='project_update_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/cancel/$', ProjectUpdateCancel.as_view(), name='project_update_cancel'),
|
re_path(r'^(?P<pk>[0-9]+)/cancel/$', ProjectUpdateCancel.as_view(), name='project_update_cancel'),
|
||||||
url(r'^(?P<pk>[0-9]+)/stdout/$', ProjectUpdateStdout.as_view(), name='project_update_stdout'),
|
re_path(r'^(?P<pk>[0-9]+)/stdout/$', ProjectUpdateStdout.as_view(), name='project_update_stdout'),
|
||||||
url(r'^(?P<pk>[0-9]+)/scm_inventory_updates/$', ProjectUpdateScmInventoryUpdates.as_view(), name='project_update_scm_inventory_updates'),
|
re_path(r'^(?P<pk>[0-9]+)/scm_inventory_updates/$', ProjectUpdateScmInventoryUpdates.as_view(), name='project_update_scm_inventory_updates'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notifications/$', ProjectUpdateNotificationsList.as_view(), name='project_update_notifications_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notifications/$', ProjectUpdateNotificationsList.as_view(), name='project_update_notifications_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/events/$', ProjectUpdateEventsList.as_view(), name='project_update_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/events/$', ProjectUpdateEventsList.as_view(), name='project_update_events_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import RoleList, RoleDetail, RoleUsersList, RoleTeamsList, RoleParentsList, RoleChildrenList
|
from awx.api.views import RoleList, RoleDetail, RoleUsersList, RoleTeamsList, RoleParentsList, RoleChildrenList
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', RoleList.as_view(), name='role_list'),
|
re_path(r'^$', RoleList.as_view(), name='role_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', RoleDetail.as_view(), name='role_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', RoleDetail.as_view(), name='role_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/users/$', RoleUsersList.as_view(), name='role_users_list'),
|
re_path(r'^(?P<pk>[0-9]+)/users/$', RoleUsersList.as_view(), name='role_users_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/teams/$', RoleTeamsList.as_view(), name='role_teams_list'),
|
re_path(r'^(?P<pk>[0-9]+)/teams/$', RoleTeamsList.as_view(), name='role_teams_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/parents/$', RoleParentsList.as_view(), name='role_parents_list'),
|
re_path(r'^(?P<pk>[0-9]+)/parents/$', RoleParentsList.as_view(), name='role_parents_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/children/$', RoleChildrenList.as_view(), name='role_children_list'),
|
re_path(r'^(?P<pk>[0-9]+)/children/$', RoleChildrenList.as_view(), name='role_children_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import ScheduleList, ScheduleDetail, ScheduleUnifiedJobsList, ScheduleCredentialsList
|
from awx.api.views import ScheduleList, ScheduleDetail, ScheduleUnifiedJobsList, ScheduleCredentialsList
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', ScheduleList.as_view(), name='schedule_list'),
|
re_path(r'^$', ScheduleList.as_view(), name='schedule_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', ScheduleDetail.as_view(), name='schedule_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', ScheduleDetail.as_view(), name='schedule_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/jobs/$', ScheduleUnifiedJobsList.as_view(), name='schedule_unified_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/jobs/$', ScheduleUnifiedJobsList.as_view(), name='schedule_unified_jobs_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', ScheduleCredentialsList.as_view(), name='schedule_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', ScheduleCredentialsList.as_view(), name='schedule_credentials_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import SystemJobList, SystemJobDetail, SystemJobCancel, SystemJobNotificationsList, SystemJobEventsList
|
from awx.api.views import SystemJobList, SystemJobDetail, SystemJobCancel, SystemJobNotificationsList, SystemJobEventsList
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', SystemJobList.as_view(), name='system_job_list'),
|
re_path(r'^$', SystemJobList.as_view(), name='system_job_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', SystemJobDetail.as_view(), name='system_job_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', SystemJobDetail.as_view(), name='system_job_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/cancel/$', SystemJobCancel.as_view(), name='system_job_cancel'),
|
re_path(r'^(?P<pk>[0-9]+)/cancel/$', SystemJobCancel.as_view(), name='system_job_cancel'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notifications/$', SystemJobNotificationsList.as_view(), name='system_job_notifications_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notifications/$', SystemJobNotificationsList.as_view(), name='system_job_notifications_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/events/$', SystemJobEventsList.as_view(), name='system_job_events_list'),
|
re_path(r'^(?P<pk>[0-9]+)/events/$', SystemJobEventsList.as_view(), name='system_job_events_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
SystemJobTemplateList,
|
SystemJobTemplateList,
|
||||||
@@ -16,22 +16,22 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', SystemJobTemplateList.as_view(), name='system_job_template_list'),
|
re_path(r'^$', SystemJobTemplateList.as_view(), name='system_job_template_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', SystemJobTemplateDetail.as_view(), name='system_job_template_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', SystemJobTemplateDetail.as_view(), name='system_job_template_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/launch/$', SystemJobTemplateLaunch.as_view(), name='system_job_template_launch'),
|
re_path(r'^(?P<pk>[0-9]+)/launch/$', SystemJobTemplateLaunch.as_view(), name='system_job_template_launch'),
|
||||||
url(r'^(?P<pk>[0-9]+)/jobs/$', SystemJobTemplateJobsList.as_view(), name='system_job_template_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/jobs/$', SystemJobTemplateJobsList.as_view(), name='system_job_template_jobs_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/schedules/$', SystemJobTemplateSchedulesList.as_view(), name='system_job_template_schedules_list'),
|
re_path(r'^(?P<pk>[0-9]+)/schedules/$', SystemJobTemplateSchedulesList.as_view(), name='system_job_template_schedules_list'),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
||||||
SystemJobTemplateNotificationTemplatesStartedList.as_view(),
|
SystemJobTemplateNotificationTemplatesStartedList.as_view(),
|
||||||
name='system_job_template_notification_templates_started_list',
|
name='system_job_template_notification_templates_started_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
||||||
SystemJobTemplateNotificationTemplatesErrorList.as_view(),
|
SystemJobTemplateNotificationTemplatesErrorList.as_view(),
|
||||||
name='system_job_template_notification_templates_error_list',
|
name='system_job_template_notification_templates_error_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
||||||
SystemJobTemplateNotificationTemplatesSuccessList.as_view(),
|
SystemJobTemplateNotificationTemplatesSuccessList.as_view(),
|
||||||
name='system_job_template_notification_templates_success_list',
|
name='system_job_template_notification_templates_success_list',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
TeamList,
|
TeamList,
|
||||||
@@ -17,15 +17,15 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', TeamList.as_view(), name='team_list'),
|
re_path(r'^$', TeamList.as_view(), name='team_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', TeamDetail.as_view(), name='team_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', TeamDetail.as_view(), name='team_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/projects/$', TeamProjectsList.as_view(), name='team_projects_list'),
|
re_path(r'^(?P<pk>[0-9]+)/projects/$', TeamProjectsList.as_view(), name='team_projects_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/users/$', TeamUsersList.as_view(), name='team_users_list'),
|
re_path(r'^(?P<pk>[0-9]+)/users/$', TeamUsersList.as_view(), name='team_users_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', TeamCredentialsList.as_view(), name='team_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', TeamCredentialsList.as_view(), name='team_credentials_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/roles/$', TeamRolesList.as_view(), name='team_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/roles/$', TeamRolesList.as_view(), name='team_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', TeamObjectRolesList.as_view(), name='team_object_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', TeamObjectRolesList.as_view(), name='team_object_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', TeamActivityStreamList.as_view(), name='team_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', TeamActivityStreamList.as_view(), name='team_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', TeamAccessList.as_view(), name='team_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', TeamAccessList.as_view(), name='team_access_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls import include, url
|
from django.urls import include, re_path
|
||||||
|
|
||||||
from awx.api.generics import LoggedLoginView, LoggedLogoutView
|
from awx.api.generics import LoggedLoginView, LoggedLogoutView
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
@@ -28,6 +28,7 @@ from awx.api.views import (
|
|||||||
OAuth2TokenList,
|
OAuth2TokenList,
|
||||||
ApplicationOAuth2TokenList,
|
ApplicationOAuth2TokenList,
|
||||||
OAuth2ApplicationDetail,
|
OAuth2ApplicationDetail,
|
||||||
|
MeshVisualizer,
|
||||||
)
|
)
|
||||||
|
|
||||||
from awx.api.views.metrics import MetricsView
|
from awx.api.views.metrics import MetricsView
|
||||||
@@ -73,77 +74,78 @@ from .workflow_approval import urls as workflow_approval_urls
|
|||||||
|
|
||||||
|
|
||||||
v2_urls = [
|
v2_urls = [
|
||||||
url(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'),
|
re_path(r'^$', ApiV2RootView.as_view(), name='api_v2_root_view'),
|
||||||
url(r'^credential_types/', include(credential_type_urls)),
|
re_path(r'^credential_types/', include(credential_type_urls)),
|
||||||
url(r'^credential_input_sources/', include(credential_input_source_urls)),
|
re_path(r'^credential_input_sources/', include(credential_input_source_urls)),
|
||||||
url(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'),
|
re_path(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'),
|
||||||
url(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'),
|
re_path(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'),
|
||||||
url(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'),
|
re_path(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'),
|
||||||
url(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
|
re_path(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
|
||||||
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
|
re_path(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
|
||||||
url(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
|
re_path(r'^applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
|
||||||
url(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
|
re_path(r'^applications/(?P<pk>[0-9]+)/$', OAuth2ApplicationDetail.as_view(), name='o_auth2_application_detail'),
|
||||||
url(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='application_o_auth2_token_list'),
|
re_path(r'^applications/(?P<pk>[0-9]+)/tokens/$', ApplicationOAuth2TokenList.as_view(), name='application_o_auth2_token_list'),
|
||||||
url(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
|
re_path(r'^tokens/$', OAuth2TokenList.as_view(), name='o_auth2_token_list'),
|
||||||
url(r'^', include(oauth2_urls)),
|
re_path(r'^', include(oauth2_urls)),
|
||||||
url(r'^metrics/$', MetricsView.as_view(), name='metrics_view'),
|
re_path(r'^metrics/$', MetricsView.as_view(), name='metrics_view'),
|
||||||
url(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'),
|
re_path(r'^ping/$', ApiV2PingView.as_view(), name='api_v2_ping_view'),
|
||||||
url(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'),
|
re_path(r'^config/$', ApiV2ConfigView.as_view(), name='api_v2_config_view'),
|
||||||
url(r'^config/subscriptions/$', ApiV2SubscriptionView.as_view(), name='api_v2_subscription_view'),
|
re_path(r'^config/subscriptions/$', ApiV2SubscriptionView.as_view(), name='api_v2_subscription_view'),
|
||||||
url(r'^config/attach/$', ApiV2AttachView.as_view(), name='api_v2_attach_view'),
|
re_path(r'^config/attach/$', ApiV2AttachView.as_view(), name='api_v2_attach_view'),
|
||||||
url(r'^auth/$', AuthView.as_view()),
|
re_path(r'^auth/$', AuthView.as_view()),
|
||||||
url(r'^me/$', UserMeList.as_view(), name='user_me_list'),
|
re_path(r'^me/$', UserMeList.as_view(), name='user_me_list'),
|
||||||
url(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),
|
re_path(r'^dashboard/$', DashboardView.as_view(), name='dashboard_view'),
|
||||||
url(r'^dashboard/graphs/jobs/$', DashboardJobsGraphView.as_view(), name='dashboard_jobs_graph_view'),
|
re_path(r'^dashboard/graphs/jobs/$', DashboardJobsGraphView.as_view(), name='dashboard_jobs_graph_view'),
|
||||||
url(r'^settings/', include('awx.conf.urls')),
|
re_path(r'^mesh_visualizer/', MeshVisualizer.as_view(), name='mesh_visualizer_view'),
|
||||||
url(r'^instances/', include(instance_urls)),
|
re_path(r'^settings/', include('awx.conf.urls')),
|
||||||
url(r'^instance_groups/', include(instance_group_urls)),
|
re_path(r'^instances/', include(instance_urls)),
|
||||||
url(r'^schedules/', include(schedule_urls)),
|
re_path(r'^instance_groups/', include(instance_group_urls)),
|
||||||
url(r'^organizations/', include(organization_urls)),
|
re_path(r'^schedules/', include(schedule_urls)),
|
||||||
url(r'^users/', include(user_urls)),
|
re_path(r'^organizations/', include(organization_urls)),
|
||||||
url(r'^execution_environments/', include(execution_environment_urls)),
|
re_path(r'^users/', include(user_urls)),
|
||||||
url(r'^projects/', include(project_urls)),
|
re_path(r'^execution_environments/', include(execution_environment_urls)),
|
||||||
url(r'^project_updates/', include(project_update_urls)),
|
re_path(r'^projects/', include(project_urls)),
|
||||||
url(r'^teams/', include(team_urls)),
|
re_path(r'^project_updates/', include(project_update_urls)),
|
||||||
url(r'^inventories/', include(inventory_urls)),
|
re_path(r'^teams/', include(team_urls)),
|
||||||
url(r'^hosts/', include(host_urls)),
|
re_path(r'^inventories/', include(inventory_urls)),
|
||||||
url(r'^groups/', include(group_urls)),
|
re_path(r'^hosts/', include(host_urls)),
|
||||||
url(r'^inventory_sources/', include(inventory_source_urls)),
|
re_path(r'^groups/', include(group_urls)),
|
||||||
url(r'^inventory_updates/', include(inventory_update_urls)),
|
re_path(r'^inventory_sources/', include(inventory_source_urls)),
|
||||||
url(r'^credentials/', include(credential_urls)),
|
re_path(r'^inventory_updates/', include(inventory_update_urls)),
|
||||||
url(r'^roles/', include(role_urls)),
|
re_path(r'^credentials/', include(credential_urls)),
|
||||||
url(r'^job_templates/', include(job_template_urls)),
|
re_path(r'^roles/', include(role_urls)),
|
||||||
url(r'^jobs/', include(job_urls)),
|
re_path(r'^job_templates/', include(job_template_urls)),
|
||||||
url(r'^job_host_summaries/', include(job_host_summary_urls)),
|
re_path(r'^jobs/', include(job_urls)),
|
||||||
url(r'^job_events/', include(job_event_urls)),
|
re_path(r'^job_host_summaries/', include(job_host_summary_urls)),
|
||||||
url(r'^ad_hoc_commands/', include(ad_hoc_command_urls)),
|
re_path(r'^job_events/', include(job_event_urls)),
|
||||||
url(r'^ad_hoc_command_events/', include(ad_hoc_command_event_urls)),
|
re_path(r'^ad_hoc_commands/', include(ad_hoc_command_urls)),
|
||||||
url(r'^system_job_templates/', include(system_job_template_urls)),
|
re_path(r'^ad_hoc_command_events/', include(ad_hoc_command_event_urls)),
|
||||||
url(r'^system_jobs/', include(system_job_urls)),
|
re_path(r'^system_job_templates/', include(system_job_template_urls)),
|
||||||
url(r'^notification_templates/', include(notification_template_urls)),
|
re_path(r'^system_jobs/', include(system_job_urls)),
|
||||||
url(r'^notifications/', include(notification_urls)),
|
re_path(r'^notification_templates/', include(notification_template_urls)),
|
||||||
url(r'^workflow_job_templates/', include(workflow_job_template_urls)),
|
re_path(r'^notifications/', include(notification_urls)),
|
||||||
url(r'^workflow_jobs/', include(workflow_job_urls)),
|
re_path(r'^workflow_job_templates/', include(workflow_job_template_urls)),
|
||||||
url(r'^labels/', include(label_urls)),
|
re_path(r'^workflow_jobs/', include(workflow_job_urls)),
|
||||||
url(r'^workflow_job_template_nodes/', include(workflow_job_template_node_urls)),
|
re_path(r'^labels/', include(label_urls)),
|
||||||
url(r'^workflow_job_nodes/', include(workflow_job_node_urls)),
|
re_path(r'^workflow_job_template_nodes/', include(workflow_job_template_node_urls)),
|
||||||
url(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'),
|
re_path(r'^workflow_job_nodes/', include(workflow_job_node_urls)),
|
||||||
url(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'),
|
re_path(r'^unified_job_templates/$', UnifiedJobTemplateList.as_view(), name='unified_job_template_list'),
|
||||||
url(r'^activity_stream/', include(activity_stream_urls)),
|
re_path(r'^unified_jobs/$', UnifiedJobList.as_view(), name='unified_job_list'),
|
||||||
url(r'^workflow_approval_templates/', include(workflow_approval_template_urls)),
|
re_path(r'^activity_stream/', include(activity_stream_urls)),
|
||||||
url(r'^workflow_approvals/', include(workflow_approval_urls)),
|
re_path(r'^workflow_approval_templates/', include(workflow_approval_template_urls)),
|
||||||
|
re_path(r'^workflow_approvals/', include(workflow_approval_urls)),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
app_name = 'api'
|
app_name = 'api'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', ApiRootView.as_view(), name='api_root_view'),
|
re_path(r'^$', ApiRootView.as_view(), name='api_root_view'),
|
||||||
url(r'^(?P<version>(v2))/', include(v2_urls)),
|
re_path(r'^(?P<version>(v2))/', include(v2_urls)),
|
||||||
url(r'^login/$', LoggedLoginView.as_view(template_name='rest_framework/login.html', extra_context={'inside_login_context': True}), name='login'),
|
re_path(r'^login/$', LoggedLoginView.as_view(template_name='rest_framework/login.html', extra_context={'inside_login_context': True}), name='login'),
|
||||||
url(r'^logout/$', LoggedLogoutView.as_view(next_page='/api/', redirect_field_name='next'), name='logout'),
|
re_path(r'^logout/$', LoggedLogoutView.as_view(next_page='/api/', redirect_field_name='next'), name='logout'),
|
||||||
url(r'^o/', include(oauth2_root_urls)),
|
re_path(r'^o/', include(oauth2_root_urls)),
|
||||||
]
|
]
|
||||||
if settings.SETTINGS_MODULE == 'awx.settings.development':
|
if settings.SETTINGS_MODULE == 'awx.settings.development':
|
||||||
from awx.api.swagger import SwaggerSchemaView
|
from awx.api.swagger import SwaggerSchemaView
|
||||||
|
|
||||||
urlpatterns += [url(r'^swagger/$', SwaggerSchemaView.as_view(), name='swagger_view')]
|
urlpatterns += [re_path(r'^swagger/$', SwaggerSchemaView.as_view(), name='swagger_view')]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
UserList,
|
UserList,
|
||||||
@@ -21,20 +21,20 @@ from awx.api.views import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', UserList.as_view(), name='user_list'),
|
re_path(r'^$', UserList.as_view(), name='user_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', UserDetail.as_view(), name='user_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', UserDetail.as_view(), name='user_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/teams/$', UserTeamsList.as_view(), name='user_teams_list'),
|
re_path(r'^(?P<pk>[0-9]+)/teams/$', UserTeamsList.as_view(), name='user_teams_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/organizations/$', UserOrganizationsList.as_view(), name='user_organizations_list'),
|
re_path(r'^(?P<pk>[0-9]+)/organizations/$', UserOrganizationsList.as_view(), name='user_organizations_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/admin_of_organizations/$', UserAdminOfOrganizationsList.as_view(), name='user_admin_of_organizations_list'),
|
re_path(r'^(?P<pk>[0-9]+)/admin_of_organizations/$', UserAdminOfOrganizationsList.as_view(), name='user_admin_of_organizations_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/projects/$', UserProjectsList.as_view(), name='user_projects_list'),
|
re_path(r'^(?P<pk>[0-9]+)/projects/$', UserProjectsList.as_view(), name='user_projects_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', UserCredentialsList.as_view(), name='user_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', UserCredentialsList.as_view(), name='user_credentials_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/roles/$', UserRolesList.as_view(), name='user_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/roles/$', UserRolesList.as_view(), name='user_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', UserActivityStreamList.as_view(), name='user_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', UserActivityStreamList.as_view(), name='user_activity_stream_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', UserAccessList.as_view(), name='user_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', UserAccessList.as_view(), name='user_access_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
|
re_path(r'^(?P<pk>[0-9]+)/applications/$', OAuth2ApplicationList.as_view(), name='o_auth2_application_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/tokens/$', OAuth2UserTokenList.as_view(), name='o_auth2_token_list'),
|
re_path(r'^(?P<pk>[0-9]+)/tokens/$', OAuth2UserTokenList.as_view(), name='o_auth2_token_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/authorized_tokens/$', UserAuthorizedTokenList.as_view(), name='user_authorized_token_list'),
|
re_path(r'^(?P<pk>[0-9]+)/authorized_tokens/$', UserAuthorizedTokenList.as_view(), name='user_authorized_token_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/personal_tokens/$', UserPersonalTokenList.as_view(), name='user_personal_token_list'),
|
re_path(r'^(?P<pk>[0-9]+)/personal_tokens/$', UserPersonalTokenList.as_view(), name='user_personal_token_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver
|
from awx.api.views import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^webhook_key/$', WebhookKeyView.as_view(), name='webhook_key'),
|
re_path(r'^webhook_key/$', WebhookKeyView.as_view(), name='webhook_key'),
|
||||||
url(r'^github/$', GithubWebhookReceiver.as_view(), name='webhook_receiver_github'),
|
re_path(r'^github/$', GithubWebhookReceiver.as_view(), name='webhook_receiver_github'),
|
||||||
url(r'^gitlab/$', GitlabWebhookReceiver.as_view(), name='webhook_receiver_gitlab'),
|
re_path(r'^gitlab/$', GitlabWebhookReceiver.as_view(), name='webhook_receiver_gitlab'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import WorkflowApprovalList, WorkflowApprovalDetail, WorkflowApprovalApprove, WorkflowApprovalDeny
|
from awx.api.views import WorkflowApprovalList, WorkflowApprovalDetail, WorkflowApprovalApprove, WorkflowApprovalDeny
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', WorkflowApprovalList.as_view(), name='workflow_approval_list'),
|
re_path(r'^$', WorkflowApprovalList.as_view(), name='workflow_approval_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalDetail.as_view(), name='workflow_approval_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalDetail.as_view(), name='workflow_approval_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/approve/$', WorkflowApprovalApprove.as_view(), name='workflow_approval_approve'),
|
re_path(r'^(?P<pk>[0-9]+)/approve/$', WorkflowApprovalApprove.as_view(), name='workflow_approval_approve'),
|
||||||
url(r'^(?P<pk>[0-9]+)/deny/$', WorkflowApprovalDeny.as_view(), name='workflow_approval_deny'),
|
re_path(r'^(?P<pk>[0-9]+)/deny/$', WorkflowApprovalDeny.as_view(), name='workflow_approval_deny'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import WorkflowApprovalTemplateDetail, WorkflowApprovalTemplateJobsList
|
from awx.api.views import WorkflowApprovalTemplateDetail, WorkflowApprovalTemplateJobsList
|
||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalTemplateDetail.as_view(), name='workflow_approval_template_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowApprovalTemplateDetail.as_view(), name='workflow_approval_template_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/approvals/$', WorkflowApprovalTemplateJobsList.as_view(), name='workflow_approval_template_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/approvals/$', WorkflowApprovalTemplateJobsList.as_view(), name='workflow_approval_template_jobs_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
WorkflowJobList,
|
WorkflowJobList,
|
||||||
@@ -16,14 +16,14 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', WorkflowJobList.as_view(), name='workflow_job_list'),
|
re_path(r'^$', WorkflowJobList.as_view(), name='workflow_job_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobDetail.as_view(), name='workflow_job_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowJobDetail.as_view(), name='workflow_job_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobWorkflowNodesList.as_view(), name='workflow_job_workflow_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobWorkflowNodesList.as_view(), name='workflow_job_workflow_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobLabelList.as_view(), name='workflow_job_label_list'),
|
re_path(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobLabelList.as_view(), name='workflow_job_label_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/cancel/$', WorkflowJobCancel.as_view(), name='workflow_job_cancel'),
|
re_path(r'^(?P<pk>[0-9]+)/cancel/$', WorkflowJobCancel.as_view(), name='workflow_job_cancel'),
|
||||||
url(r'^(?P<pk>[0-9]+)/relaunch/$', WorkflowJobRelaunch.as_view(), name='workflow_job_relaunch'),
|
re_path(r'^(?P<pk>[0-9]+)/relaunch/$', WorkflowJobRelaunch.as_view(), name='workflow_job_relaunch'),
|
||||||
url(r'^(?P<pk>[0-9]+)/notifications/$', WorkflowJobNotificationsList.as_view(), name='workflow_job_notifications_list'),
|
re_path(r'^(?P<pk>[0-9]+)/notifications/$', WorkflowJobNotificationsList.as_view(), name='workflow_job_notifications_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobActivityStreamList.as_view(), name='workflow_job_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobActivityStreamList.as_view(), name='workflow_job_activity_stream_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
WorkflowJobNodeList,
|
WorkflowJobNodeList,
|
||||||
@@ -14,12 +14,12 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', WorkflowJobNodeList.as_view(), name='workflow_job_node_list'),
|
re_path(r'^$', WorkflowJobNodeList.as_view(), name='workflow_job_node_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobNodeDetail.as_view(), name='workflow_job_node_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowJobNodeDetail.as_view(), name='workflow_job_node_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/success_nodes/$', WorkflowJobNodeSuccessNodesList.as_view(), name='workflow_job_node_success_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/success_nodes/$', WorkflowJobNodeSuccessNodesList.as_view(), name='workflow_job_node_success_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobNodeFailureNodesList.as_view(), name='workflow_job_node_failure_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobNodeFailureNodesList.as_view(), name='workflow_job_node_failure_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobNodeAlwaysNodesList.as_view(), name='workflow_job_node_always_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobNodeAlwaysNodesList.as_view(), name='workflow_job_node_always_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobNodeCredentialsList.as_view(), name='workflow_job_node_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobNodeCredentialsList.as_view(), name='workflow_job_node_credentials_list'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import include, url
|
from django.urls import include, re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
WorkflowJobTemplateList,
|
WorkflowJobTemplateList,
|
||||||
@@ -24,39 +24,39 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', WorkflowJobTemplateList.as_view(), name='workflow_job_template_list'),
|
re_path(r'^$', WorkflowJobTemplateList.as_view(), name='workflow_job_template_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateDetail.as_view(), name='workflow_job_template_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateDetail.as_view(), name='workflow_job_template_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/workflow_jobs/$', WorkflowJobTemplateJobsList.as_view(), name='workflow_job_template_jobs_list'),
|
re_path(r'^(?P<pk>[0-9]+)/workflow_jobs/$', WorkflowJobTemplateJobsList.as_view(), name='workflow_job_template_jobs_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/launch/$', WorkflowJobTemplateLaunch.as_view(), name='workflow_job_template_launch'),
|
re_path(r'^(?P<pk>[0-9]+)/launch/$', WorkflowJobTemplateLaunch.as_view(), name='workflow_job_template_launch'),
|
||||||
url(r'^(?P<pk>[0-9]+)/copy/$', WorkflowJobTemplateCopy.as_view(), name='workflow_job_template_copy'),
|
re_path(r'^(?P<pk>[0-9]+)/copy/$', WorkflowJobTemplateCopy.as_view(), name='workflow_job_template_copy'),
|
||||||
url(r'^(?P<pk>[0-9]+)/schedules/$', WorkflowJobTemplateSchedulesList.as_view(), name='workflow_job_template_schedules_list'),
|
re_path(r'^(?P<pk>[0-9]+)/schedules/$', WorkflowJobTemplateSchedulesList.as_view(), name='workflow_job_template_schedules_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/survey_spec/$', WorkflowJobTemplateSurveySpec.as_view(), name='workflow_job_template_survey_spec'),
|
re_path(r'^(?P<pk>[0-9]+)/survey_spec/$', WorkflowJobTemplateSurveySpec.as_view(), name='workflow_job_template_survey_spec'),
|
||||||
url(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobTemplateWorkflowNodesList.as_view(), name='workflow_job_template_workflow_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/workflow_nodes/$', WorkflowJobTemplateWorkflowNodesList.as_view(), name='workflow_job_template_workflow_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'),
|
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', WorkflowJobTemplateActivityStreamList.as_view(), name='workflow_job_template_activity_stream_list'),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_started/$',
|
||||||
WorkflowJobTemplateNotificationTemplatesStartedList.as_view(),
|
WorkflowJobTemplateNotificationTemplatesStartedList.as_view(),
|
||||||
name='workflow_job_template_notification_templates_started_list',
|
name='workflow_job_template_notification_templates_started_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_error/$',
|
||||||
WorkflowJobTemplateNotificationTemplatesErrorList.as_view(),
|
WorkflowJobTemplateNotificationTemplatesErrorList.as_view(),
|
||||||
name='workflow_job_template_notification_templates_error_list',
|
name='workflow_job_template_notification_templates_error_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_success/$',
|
||||||
WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(),
|
WorkflowJobTemplateNotificationTemplatesSuccessList.as_view(),
|
||||||
name='workflow_job_template_notification_templates_success_list',
|
name='workflow_job_template_notification_templates_success_list',
|
||||||
),
|
),
|
||||||
url(
|
re_path(
|
||||||
r'^(?P<pk>[0-9]+)/notification_templates_approvals/$',
|
r'^(?P<pk>[0-9]+)/notification_templates_approvals/$',
|
||||||
WorkflowJobTemplateNotificationTemplatesApprovalList.as_view(),
|
WorkflowJobTemplateNotificationTemplatesApprovalList.as_view(),
|
||||||
name='workflow_job_template_notification_templates_approvals_list',
|
name='workflow_job_template_notification_templates_approvals_list',
|
||||||
),
|
),
|
||||||
url(r'^(?P<pk>[0-9]+)/access_list/$', WorkflowJobTemplateAccessList.as_view(), name='workflow_job_template_access_list'),
|
re_path(r'^(?P<pk>[0-9]+)/access_list/$', WorkflowJobTemplateAccessList.as_view(), name='workflow_job_template_access_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/object_roles/$', WorkflowJobTemplateObjectRolesList.as_view(), name='workflow_job_template_object_roles_list'),
|
re_path(r'^(?P<pk>[0-9]+)/object_roles/$', WorkflowJobTemplateObjectRolesList.as_view(), name='workflow_job_template_object_roles_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobTemplateLabelList.as_view(), name='workflow_job_template_label_list'),
|
re_path(r'^(?P<pk>[0-9]+)/labels/$', WorkflowJobTemplateLabelList.as_view(), name='workflow_job_template_label_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'workflow_job_templates'}),
|
re_path(r'^(?P<pk>[0-9]+)/', include('awx.api.urls.webhooks'), {'model_kwarg': 'workflow_job_templates'}),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ansible, Inc.
|
# Copyright (c) 2017 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.urls import re_path
|
||||||
|
|
||||||
from awx.api.views import (
|
from awx.api.views import (
|
||||||
WorkflowJobTemplateNodeList,
|
WorkflowJobTemplateNodeList,
|
||||||
@@ -15,13 +15,13 @@ from awx.api.views import (
|
|||||||
|
|
||||||
|
|
||||||
urls = [
|
urls = [
|
||||||
url(r'^$', WorkflowJobTemplateNodeList.as_view(), name='workflow_job_template_node_list'),
|
re_path(r'^$', WorkflowJobTemplateNodeList.as_view(), name='workflow_job_template_node_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateNodeDetail.as_view(), name='workflow_job_template_node_detail'),
|
re_path(r'^(?P<pk>[0-9]+)/$', WorkflowJobTemplateNodeDetail.as_view(), name='workflow_job_template_node_detail'),
|
||||||
url(r'^(?P<pk>[0-9]+)/success_nodes/$', WorkflowJobTemplateNodeSuccessNodesList.as_view(), name='workflow_job_template_node_success_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/success_nodes/$', WorkflowJobTemplateNodeSuccessNodesList.as_view(), name='workflow_job_template_node_success_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobTemplateNodeFailureNodesList.as_view(), name='workflow_job_template_node_failure_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/failure_nodes/$', WorkflowJobTemplateNodeFailureNodesList.as_view(), name='workflow_job_template_node_failure_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobTemplateNodeAlwaysNodesList.as_view(), name='workflow_job_template_node_always_nodes_list'),
|
re_path(r'^(?P<pk>[0-9]+)/always_nodes/$', WorkflowJobTemplateNodeAlwaysNodesList.as_view(), name='workflow_job_template_node_always_nodes_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobTemplateNodeCredentialsList.as_view(), name='workflow_job_template_node_credentials_list'),
|
re_path(r'^(?P<pk>[0-9]+)/credentials/$', WorkflowJobTemplateNodeCredentialsList.as_view(), name='workflow_job_template_node_credentials_list'),
|
||||||
url(r'^(?P<pk>[0-9]+)/create_approval_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'),
|
re_path(r'^(?P<pk>[0-9]+)/create_approval_template/$', WorkflowJobTemplateNodeCreateApproval.as_view(), name='workflow_job_template_node_create_approval'),
|
||||||
]
|
]
|
||||||
|
|
||||||
__all__ = ['urls']
|
__all__ = ['urls']
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from django.views.decorators.csrf import csrf_exempt
|
|||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
@@ -62,7 +62,7 @@ import pytz
|
|||||||
from wsgiref.util import FileWrapper
|
from wsgiref.util import FileWrapper
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.tasks import send_notifications, update_inventory_computed_fields
|
from awx.main.tasks.system import send_notifications, update_inventory_computed_fields
|
||||||
from awx.main.access import get_user_queryset, HostAccess
|
from awx.main.access import get_user_queryset, HostAccess
|
||||||
from awx.api.generics import (
|
from awx.api.generics import (
|
||||||
APIView,
|
APIView,
|
||||||
@@ -105,7 +105,6 @@ from awx.api.permissions import (
|
|||||||
ProjectUpdatePermission,
|
ProjectUpdatePermission,
|
||||||
InventoryInventorySourcesUpdatePermission,
|
InventoryInventorySourcesUpdatePermission,
|
||||||
UserPermission,
|
UserPermission,
|
||||||
InstanceGroupTowerPermission,
|
|
||||||
VariableDataPermission,
|
VariableDataPermission,
|
||||||
WorkflowApprovalPermission,
|
WorkflowApprovalPermission,
|
||||||
IsSystemAdminOrAuditor,
|
IsSystemAdminOrAuditor,
|
||||||
@@ -113,7 +112,7 @@ from awx.api.permissions import (
|
|||||||
from awx.api import renderers
|
from awx.api import renderers
|
||||||
from awx.api import serializers
|
from awx.api import serializers
|
||||||
from awx.api.metadata import RoleMetadata
|
from awx.api.metadata import RoleMetadata
|
||||||
from awx.main.constants import ACTIVE_STATES
|
from awx.main.constants import ACTIVE_STATES, SURVEY_TYPE_MAPPING
|
||||||
from awx.main.scheduler.dag_workflow import WorkflowDAG
|
from awx.main.scheduler.dag_workflow import WorkflowDAG
|
||||||
from awx.api.views.mixin import (
|
from awx.api.views.mixin import (
|
||||||
ControlledByScmMixin,
|
ControlledByScmMixin,
|
||||||
@@ -157,8 +156,10 @@ from awx.api.views.inventory import ( # noqa
|
|||||||
InventoryAccessList,
|
InventoryAccessList,
|
||||||
InventoryObjectRolesList,
|
InventoryObjectRolesList,
|
||||||
InventoryJobTemplateList,
|
InventoryJobTemplateList,
|
||||||
|
InventoryLabelList,
|
||||||
InventoryCopy,
|
InventoryCopy,
|
||||||
)
|
)
|
||||||
|
from awx.api.views.mesh_visualizer import MeshVisualizer # noqa
|
||||||
from awx.api.views.root import ( # noqa
|
from awx.api.views.root import ( # noqa
|
||||||
ApiRootView,
|
ApiRootView,
|
||||||
ApiOAuthAuthorizationRootView,
|
ApiOAuthAuthorizationRootView,
|
||||||
@@ -171,6 +172,7 @@ from awx.api.views.root import ( # noqa
|
|||||||
)
|
)
|
||||||
from awx.api.views.webhooks import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver # noqa
|
from awx.api.views.webhooks import WebhookKeyView, GithubWebhookReceiver, GitlabWebhookReceiver # noqa
|
||||||
from awx.api.pagination import UnifiedJobEventPagination
|
from awx.api.pagination import UnifiedJobEventPagination
|
||||||
|
from awx.main.utils import set_environ
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('awx.api.views')
|
logger = logging.getLogger('awx.api.views')
|
||||||
@@ -406,6 +408,8 @@ class InstanceInstanceGroupsList(InstanceGroupMembershipMixin, SubListCreateAtta
|
|||||||
def is_valid_relation(self, parent, sub, created=False):
|
def is_valid_relation(self, parent, sub, created=False):
|
||||||
if parent.node_type == 'control':
|
if parent.node_type == 'control':
|
||||||
return {'msg': _(f"Cannot change instance group membership of control-only node: {parent.hostname}.")}
|
return {'msg': _(f"Cannot change instance group membership of control-only node: {parent.hostname}.")}
|
||||||
|
if parent.node_type == 'hop':
|
||||||
|
return {'msg': _(f"Cannot change instance group membership of hop node: {parent.hostname}.")}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -416,6 +420,10 @@ class InstanceHealthCheck(GenericAPIView):
|
|||||||
serializer_class = serializers.InstanceHealthCheckSerializer
|
serializer_class = serializers.InstanceHealthCheckSerializer
|
||||||
permission_classes = (IsSystemAdminOrAuditor,)
|
permission_classes = (IsSystemAdminOrAuditor,)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
# FIXME: For now, we don't have a good way of checking the health of a hop node.
|
||||||
|
return super().get_queryset().exclude(node_type='hop')
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
data = self.get_serializer(data=request.data).to_representation(obj)
|
data = self.get_serializer(data=request.data).to_representation(obj)
|
||||||
@@ -425,7 +433,7 @@ class InstanceHealthCheck(GenericAPIView):
|
|||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
|
|
||||||
if obj.node_type == 'execution':
|
if obj.node_type == 'execution':
|
||||||
from awx.main.tasks import execution_node_health_check
|
from awx.main.tasks.system import execution_node_health_check
|
||||||
|
|
||||||
runner_data = execution_node_health_check(obj.hostname)
|
runner_data = execution_node_health_check(obj.hostname)
|
||||||
obj.refresh_from_db()
|
obj.refresh_from_db()
|
||||||
@@ -435,7 +443,7 @@ class InstanceHealthCheck(GenericAPIView):
|
|||||||
if extra_field in runner_data:
|
if extra_field in runner_data:
|
||||||
data[extra_field] = runner_data[extra_field]
|
data[extra_field] = runner_data[extra_field]
|
||||||
else:
|
else:
|
||||||
from awx.main.tasks import cluster_node_health_check
|
from awx.main.tasks.system import cluster_node_health_check
|
||||||
|
|
||||||
if settings.CLUSTER_HOST_ID == obj.hostname:
|
if settings.CLUSTER_HOST_ID == obj.hostname:
|
||||||
cluster_node_health_check(obj.hostname)
|
cluster_node_health_check(obj.hostname)
|
||||||
@@ -472,7 +480,6 @@ class InstanceGroupDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAP
|
|||||||
name = _("Instance Group Detail")
|
name = _("Instance Group Detail")
|
||||||
model = models.InstanceGroup
|
model = models.InstanceGroup
|
||||||
serializer_class = serializers.InstanceGroupSerializer
|
serializer_class = serializers.InstanceGroupSerializer
|
||||||
permission_classes = (InstanceGroupTowerPermission,)
|
|
||||||
|
|
||||||
def update_raw_data(self, data):
|
def update_raw_data(self, data):
|
||||||
if self.get_object().is_container_group:
|
if self.get_object().is_container_group:
|
||||||
@@ -503,6 +510,8 @@ class InstanceGroupInstanceList(InstanceGroupMembershipMixin, SubListAttachDetac
|
|||||||
def is_valid_relation(self, parent, sub, created=False):
|
def is_valid_relation(self, parent, sub, created=False):
|
||||||
if sub.node_type == 'control':
|
if sub.node_type == 'control':
|
||||||
return {'msg': _(f"Cannot change instance group membership of control-only node: {sub.hostname}.")}
|
return {'msg': _(f"Cannot change instance group membership of control-only node: {sub.hostname}.")}
|
||||||
|
if sub.node_type == 'hop':
|
||||||
|
return {'msg': _(f"Cannot change instance group membership of hop node: {sub.hostname}.")}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -1547,8 +1556,9 @@ class CredentialExternalTest(SubDetailAPIView):
|
|||||||
backend_kwargs[field_name] = value
|
backend_kwargs[field_name] = value
|
||||||
backend_kwargs.update(request.data.get('metadata', {}))
|
backend_kwargs.update(request.data.get('metadata', {}))
|
||||||
try:
|
try:
|
||||||
obj.credential_type.plugin.backend(**backend_kwargs)
|
with set_environ(**settings.AWX_TASK_ENV):
|
||||||
return Response({}, status=status.HTTP_202_ACCEPTED)
|
obj.credential_type.plugin.backend(**backend_kwargs)
|
||||||
|
return Response({}, status=status.HTTP_202_ACCEPTED)
|
||||||
except requests.exceptions.HTTPError as exc:
|
except requests.exceptions.HTTPError as exc:
|
||||||
message = 'HTTP {}'.format(exc.response.status_code)
|
message = 'HTTP {}'.format(exc.response.status_code)
|
||||||
return Response({'inputs': message}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'inputs': message}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
@@ -2458,8 +2468,6 @@ class JobTemplateSurveySpec(GenericAPIView):
|
|||||||
obj_permission_type = 'admin'
|
obj_permission_type = 'admin'
|
||||||
serializer_class = serializers.EmptySerializer
|
serializer_class = serializers.EmptySerializer
|
||||||
|
|
||||||
ALLOWED_TYPES = {'text': str, 'textarea': str, 'password': str, 'multiplechoice': str, 'multiselect': str, 'integer': int, 'float': float}
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
return Response(obj.display_survey_spec())
|
return Response(obj.display_survey_spec())
|
||||||
@@ -2530,17 +2538,17 @@ class JobTemplateSurveySpec(GenericAPIView):
|
|||||||
# Type-specific validation
|
# Type-specific validation
|
||||||
# validate question type <-> default type
|
# validate question type <-> default type
|
||||||
qtype = survey_item["type"]
|
qtype = survey_item["type"]
|
||||||
if qtype not in JobTemplateSurveySpec.ALLOWED_TYPES:
|
if qtype not in SURVEY_TYPE_MAPPING:
|
||||||
return Response(
|
return Response(
|
||||||
dict(
|
dict(
|
||||||
error=_("'{survey_item[type]}' in survey question {idx} is not one of '{allowed_types}' allowed question types.").format(
|
error=_("'{survey_item[type]}' in survey question {idx} is not one of '{allowed_types}' allowed question types.").format(
|
||||||
allowed_types=', '.join(JobTemplateSurveySpec.ALLOWED_TYPES.keys()), **context
|
allowed_types=', '.join(SURVEY_TYPE_MAPPING.keys()), **context
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
)
|
)
|
||||||
if 'default' in survey_item and survey_item['default'] != '':
|
if 'default' in survey_item and survey_item['default'] != '':
|
||||||
if not isinstance(survey_item['default'], JobTemplateSurveySpec.ALLOWED_TYPES[qtype]):
|
if not isinstance(survey_item['default'], SURVEY_TYPE_MAPPING[qtype]):
|
||||||
type_label = 'string'
|
type_label = 'string'
|
||||||
if qtype in ['integer', 'float']:
|
if qtype in ['integer', 'float']:
|
||||||
type_label = qtype
|
type_label = qtype
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import logging
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
@@ -16,17 +16,21 @@ from rest_framework.response import Response
|
|||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models import (
|
from awx.main.models import ActivityStream, Inventory, JobTemplate, Role, User, InstanceGroup, InventoryUpdateEvent, InventoryUpdate
|
||||||
ActivityStream,
|
|
||||||
Inventory,
|
from awx.main.models.label import Label
|
||||||
JobTemplate,
|
|
||||||
Role,
|
from awx.api.generics import (
|
||||||
User,
|
ListCreateAPIView,
|
||||||
InstanceGroup,
|
RetrieveUpdateDestroyAPIView,
|
||||||
InventoryUpdateEvent,
|
SubListAPIView,
|
||||||
InventoryUpdate,
|
SubListAttachDetachAPIView,
|
||||||
|
ResourceAccessList,
|
||||||
|
CopyAPIView,
|
||||||
|
DeleteLastUnattachLabelMixin,
|
||||||
|
SubListCreateAttachDetachAPIView,
|
||||||
)
|
)
|
||||||
from awx.api.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView, SubListAPIView, SubListAttachDetachAPIView, ResourceAccessList, CopyAPIView
|
|
||||||
|
|
||||||
from awx.api.serializers import (
|
from awx.api.serializers import (
|
||||||
InventorySerializer,
|
InventorySerializer,
|
||||||
@@ -35,6 +39,7 @@ from awx.api.serializers import (
|
|||||||
InstanceGroupSerializer,
|
InstanceGroupSerializer,
|
||||||
InventoryUpdateEventSerializer,
|
InventoryUpdateEventSerializer,
|
||||||
JobTemplateSerializer,
|
JobTemplateSerializer,
|
||||||
|
LabelSerializer,
|
||||||
)
|
)
|
||||||
from awx.api.views.mixin import RelatedJobsPreventDeleteMixin, ControlledByScmMixin
|
from awx.api.views.mixin import RelatedJobsPreventDeleteMixin, ControlledByScmMixin
|
||||||
|
|
||||||
@@ -152,6 +157,30 @@ class InventoryJobTemplateList(SubListAPIView):
|
|||||||
return qs.filter(inventory=parent)
|
return qs.filter(inventory=parent)
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryLabelList(DeleteLastUnattachLabelMixin, SubListCreateAttachDetachAPIView, SubListAPIView):
|
||||||
|
|
||||||
|
model = Label
|
||||||
|
serializer_class = LabelSerializer
|
||||||
|
parent_model = Inventory
|
||||||
|
relationship = 'labels'
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
# If a label already exists in the database, attach it instead of erroring out
|
||||||
|
# that it already exists
|
||||||
|
if 'id' not in request.data and 'name' in request.data and 'organization' in request.data:
|
||||||
|
existing = Label.objects.filter(name=request.data['name'], organization_id=request.data['organization'])
|
||||||
|
if existing.exists():
|
||||||
|
existing = existing[0]
|
||||||
|
request.data['id'] = existing.id
|
||||||
|
del request.data['name']
|
||||||
|
del request.data['organization']
|
||||||
|
if Label.objects.filter(inventory_labels=self.kwargs['pk']).count() > 100:
|
||||||
|
return Response(
|
||||||
|
dict(msg=_('Maximum number of labels for {} reached.'.format(self.parent_model._meta.verbose_name_raw))), status=status.HTTP_400_BAD_REQUEST
|
||||||
|
)
|
||||||
|
return super(InventoryLabelList, self).post(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class InventoryCopy(CopyAPIView):
|
class InventoryCopy(CopyAPIView):
|
||||||
|
|
||||||
model = Inventory
|
model = Inventory
|
||||||
|
|||||||
25
awx/api/views/mesh_visualizer.py
Normal file
25
awx/api/views/mesh_visualizer.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Copyright (c) 2018 Red Hat, Inc.
|
||||||
|
# All Rights Reserved.
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from awx.api.generics import APIView, Response
|
||||||
|
from awx.api.permissions import IsSystemAdminOrAuditor
|
||||||
|
from awx.api.serializers import InstanceLinkSerializer, InstanceNodeSerializer
|
||||||
|
from awx.main.models import InstanceLink, Instance
|
||||||
|
|
||||||
|
|
||||||
|
class MeshVisualizer(APIView):
|
||||||
|
|
||||||
|
name = _("Mesh Visualizer")
|
||||||
|
permission_classes = (IsSystemAdminOrAuditor,)
|
||||||
|
swagger_topic = "System Configuration"
|
||||||
|
|
||||||
|
def get(self, request, format=None):
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'nodes': InstanceNodeSerializer(Instance.objects.all(), many=True).data,
|
||||||
|
'links': InstanceLinkSerializer(InstanceLink.objects.select_related('target', 'source'), many=True).data,
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response(data)
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from django.db.models import Count
|
|||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from rest_framework.permissions import SAFE_METHODS
|
from rest_framework.permissions import SAFE_METHODS
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import logging
|
|||||||
# Django
|
# Django
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import operator
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_str
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@@ -123,6 +123,7 @@ class ApiVersionRootView(APIView):
|
|||||||
data['workflow_approvals'] = reverse('api:workflow_approval_list', request=request)
|
data['workflow_approvals'] = reverse('api:workflow_approval_list', request=request)
|
||||||
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request)
|
data['workflow_job_template_nodes'] = reverse('api:workflow_job_template_node_list', request=request)
|
||||||
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request)
|
data['workflow_job_nodes'] = reverse('api:workflow_job_node_list', request=request)
|
||||||
|
data['mesh_visualizer'] = reverse('api:mesh_visualizer_view', request=request)
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
@@ -149,13 +150,13 @@ class ApiV2PingView(APIView):
|
|||||||
response = {'ha': is_ha_environment(), 'version': get_awx_version(), 'active_node': settings.CLUSTER_HOST_ID, 'install_uuid': settings.INSTALL_UUID}
|
response = {'ha': is_ha_environment(), 'version': get_awx_version(), 'active_node': settings.CLUSTER_HOST_ID, 'install_uuid': settings.INSTALL_UUID}
|
||||||
|
|
||||||
response['instances'] = []
|
response['instances'] = []
|
||||||
for instance in Instance.objects.all():
|
for instance in Instance.objects.exclude(node_type='hop'):
|
||||||
response['instances'].append(
|
response['instances'].append(
|
||||||
dict(
|
dict(
|
||||||
node=instance.hostname,
|
node=instance.hostname,
|
||||||
node_type=instance.node_type,
|
node_type=instance.node_type,
|
||||||
uuid=instance.uuid,
|
uuid=instance.uuid,
|
||||||
heartbeat=instance.modified,
|
heartbeat=instance.last_seen,
|
||||||
capacity=instance.capacity,
|
capacity=instance.capacity,
|
||||||
version=instance.version,
|
version=instance.version,
|
||||||
)
|
)
|
||||||
@@ -204,7 +205,7 @@ class ApiV2SubscriptionView(APIView):
|
|||||||
elif isinstance(exc, (ValueError, OSError)) and exc.args:
|
elif isinstance(exc, (ValueError, OSError)) and exc.args:
|
||||||
msg = exc.args[0]
|
msg = exc.args[0]
|
||||||
else:
|
else:
|
||||||
logger.exception(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
logger.exception(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
||||||
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
return Response(validated)
|
return Response(validated)
|
||||||
@@ -245,7 +246,7 @@ class ApiV2AttachView(APIView):
|
|||||||
elif isinstance(exc, (ValueError, OSError)) and exc.args:
|
elif isinstance(exc, (ValueError, OSError)) and exc.args:
|
||||||
msg = exc.args[0]
|
msg = exc.args[0]
|
||||||
else:
|
else:
|
||||||
logger.exception(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
logger.exception(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
||||||
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({"error": msg}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
for sub in validated:
|
for sub in validated:
|
||||||
if sub['pool_id'] == pool_id:
|
if sub['pool_id'] == pool_id:
|
||||||
@@ -321,7 +322,7 @@ class ApiV2ConfigView(APIView):
|
|||||||
try:
|
try:
|
||||||
data_actual = json.dumps(request.data)
|
data_actual = json.dumps(request.data)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.info(smart_text(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username))
|
logger.info(smart_str(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username))
|
||||||
return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
license_data = json.loads(data_actual)
|
license_data = json.loads(data_actual)
|
||||||
@@ -345,7 +346,7 @@ class ApiV2ConfigView(APIView):
|
|||||||
try:
|
try:
|
||||||
license_data_validated = get_licenser().license_from_manifest(license_data)
|
license_data_validated = get_licenser().license_from_manifest(license_data)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
logger.warning(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
||||||
return Response({"error": _("Invalid License")}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({"error": _("Invalid License")}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
else:
|
else:
|
||||||
license_data_validated = get_licenser().validate()
|
license_data_validated = get_licenser().validate()
|
||||||
@@ -356,7 +357,7 @@ class ApiV2ConfigView(APIView):
|
|||||||
settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host())
|
settings.TOWER_URL_BASE = "{}://{}".format(request.scheme, request.get_host())
|
||||||
return Response(license_data_validated)
|
return Response(license_data_validated)
|
||||||
|
|
||||||
logger.warning(smart_text(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
logger.warning(smart_str(u"Invalid subscription submitted."), extra=dict(actor=request.user.username))
|
||||||
return Response({"error": _("Invalid subscription")}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({"error": _("Invalid subscription")}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
def delete(self, request):
|
def delete(self, request):
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import logging
|
|||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
@@ -16,7 +16,7 @@ from awx.api import serializers
|
|||||||
from awx.api.generics import APIView, GenericAPIView
|
from awx.api.generics import APIView, GenericAPIView
|
||||||
from awx.api.permissions import WebhookKeyPermission
|
from awx.api.permissions import WebhookKeyPermission
|
||||||
from awx.main.models import Job, JobTemplate, WorkflowJob, WorkflowJobTemplate
|
from awx.main.models import Job, JobTemplate, WorkflowJob, WorkflowJobTemplate
|
||||||
|
from awx.main.constants import JOB_VARIABLE_PREFIXES
|
||||||
|
|
||||||
logger = logging.getLogger('awx.api.views.webhooks')
|
logger = logging.getLogger('awx.api.views.webhooks')
|
||||||
|
|
||||||
@@ -136,15 +136,16 @@ class WebhookReceiverBase(APIView):
|
|||||||
'webhook_credential': obj.webhook_credential,
|
'webhook_credential': obj.webhook_credential,
|
||||||
'webhook_guid': event_guid,
|
'webhook_guid': event_guid,
|
||||||
},
|
},
|
||||||
'extra_vars': {
|
'extra_vars': {},
|
||||||
'tower_webhook_event_type': event_type,
|
|
||||||
'tower_webhook_event_guid': event_guid,
|
|
||||||
'tower_webhook_event_ref': event_ref,
|
|
||||||
'tower_webhook_status_api': status_api,
|
|
||||||
'tower_webhook_payload': request.data,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name in JOB_VARIABLE_PREFIXES:
|
||||||
|
kwargs['extra_vars']['{}_webhook_event_type'.format(name)] = event_type
|
||||||
|
kwargs['extra_vars']['{}_webhook_event_guid'.format(name)] = event_guid
|
||||||
|
kwargs['extra_vars']['{}_webhook_event_ref'.format(name)] = event_ref
|
||||||
|
kwargs['extra_vars']['{}_webhook_status_api'.format(name)] = status_api
|
||||||
|
kwargs['extra_vars']['{}_webhook_payload'.format(name)] = request.data
|
||||||
|
|
||||||
new_job = obj.create_unified_job(**kwargs)
|
new_job = obj.create_unified_job(**kwargs)
|
||||||
new_job.signal_start()
|
new_job.signal_start()
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ from django.utils.module_loading import autodiscover_modules
|
|||||||
# AWX
|
# AWX
|
||||||
from .registry import settings_registry
|
from .registry import settings_registry
|
||||||
|
|
||||||
default_app_config = 'awx.conf.apps.ConfConfig'
|
|
||||||
|
|
||||||
|
|
||||||
def register(setting, **kwargs):
|
def register(setting, **kwargs):
|
||||||
settings_registry.register(setting, **kwargs)
|
settings_registry.register(setting, **kwargs)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
# from django.core import checks
|
# from django.core import checks
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class ConfConfig(AppConfig):
|
class ConfConfig(AppConfig):
|
||||||
@@ -12,6 +14,9 @@ class ConfConfig(AppConfig):
|
|||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
self.module.autodiscover()
|
self.module.autodiscover()
|
||||||
from .settings import SettingsWrapper
|
|
||||||
|
|
||||||
SettingsWrapper.initialize()
|
if not set(sys.argv) & {'migrate', 'check_migrations'}:
|
||||||
|
|
||||||
|
from .settings import SettingsWrapper
|
||||||
|
|
||||||
|
SettingsWrapper.initialize()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Django
|
# Django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.conf import fields, register
|
from awx.conf import fields, register
|
||||||
|
|||||||
@@ -7,12 +7,15 @@ from collections import OrderedDict
|
|||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.core.validators import URLValidator, _lazy_re_compile
|
from django.core.validators import URLValidator, _lazy_re_compile
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, DateTimeField, EmailField, IntegerField, ListField, NullBooleanField # noqa
|
from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, DateTimeField, EmailField, IntegerField, ListField # noqa
|
||||||
from rest_framework.serializers import PrimaryKeyRelatedField # noqa
|
from rest_framework.serializers import PrimaryKeyRelatedField # noqa
|
||||||
|
|
||||||
|
# AWX
|
||||||
|
from awx.main.constants import CONTAINER_VOLUMES_MOUNT_TYPES, MAX_ISOLATED_PATH_COLON_DELIMITER
|
||||||
|
|
||||||
logger = logging.getLogger('awx.conf.fields')
|
logger = logging.getLogger('awx.conf.fields')
|
||||||
|
|
||||||
# Use DRF fields to convert/validate settings:
|
# Use DRF fields to convert/validate settings:
|
||||||
@@ -62,11 +65,11 @@ class StringListBooleanField(ListField):
|
|||||||
try:
|
try:
|
||||||
if isinstance(value, (list, tuple)):
|
if isinstance(value, (list, tuple)):
|
||||||
return super(StringListBooleanField, self).to_representation(value)
|
return super(StringListBooleanField, self).to_representation(value)
|
||||||
elif value in NullBooleanField.TRUE_VALUES:
|
elif value in BooleanField.TRUE_VALUES:
|
||||||
return True
|
return True
|
||||||
elif value in NullBooleanField.FALSE_VALUES:
|
elif value in BooleanField.FALSE_VALUES:
|
||||||
return False
|
return False
|
||||||
elif value in NullBooleanField.NULL_VALUES:
|
elif value in BooleanField.NULL_VALUES:
|
||||||
return None
|
return None
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str):
|
||||||
return self.child.to_representation(value)
|
return self.child.to_representation(value)
|
||||||
@@ -79,11 +82,11 @@ class StringListBooleanField(ListField):
|
|||||||
try:
|
try:
|
||||||
if isinstance(data, (list, tuple)):
|
if isinstance(data, (list, tuple)):
|
||||||
return super(StringListBooleanField, self).to_internal_value(data)
|
return super(StringListBooleanField, self).to_internal_value(data)
|
||||||
elif data in NullBooleanField.TRUE_VALUES:
|
elif data in BooleanField.TRUE_VALUES:
|
||||||
return True
|
return True
|
||||||
elif data in NullBooleanField.FALSE_VALUES:
|
elif data in BooleanField.FALSE_VALUES:
|
||||||
return False
|
return False
|
||||||
elif data in NullBooleanField.NULL_VALUES:
|
elif data in BooleanField.NULL_VALUES:
|
||||||
return None
|
return None
|
||||||
elif isinstance(data, str):
|
elif isinstance(data, str):
|
||||||
return self.child.run_validation(data)
|
return self.child.run_validation(data)
|
||||||
@@ -109,6 +112,49 @@ class StringListPathField(StringListField):
|
|||||||
self.fail('type_error', input_type=type(paths))
|
self.fail('type_error', input_type=type(paths))
|
||||||
|
|
||||||
|
|
||||||
|
class StringListIsolatedPathField(StringListField):
|
||||||
|
# Valid formats
|
||||||
|
# '/etc/pki/ca-trust'
|
||||||
|
# '/etc/pki/ca-trust:/etc/pki/ca-trust'
|
||||||
|
# '/etc/pki/ca-trust:/etc/pki/ca-trust:O'
|
||||||
|
|
||||||
|
default_error_messages = {
|
||||||
|
'type_error': _('Expected list of strings but got {input_type} instead.'),
|
||||||
|
'path_error': _('{path} is not a valid path choice. You must provide an absolute path.'),
|
||||||
|
'mount_error': _('{scontext} is not a valid mount option. Allowed types are {mount_types}'),
|
||||||
|
'syntax_error': _('Invalid syntax. A string HOST-DIR[:CONTAINER-DIR[:OPTIONS]] is expected but got {path}.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_internal_value(self, paths):
|
||||||
|
|
||||||
|
if isinstance(paths, (list, tuple)):
|
||||||
|
for p in paths:
|
||||||
|
if not isinstance(p, str):
|
||||||
|
self.fail('type_error', input_type=type(p))
|
||||||
|
if not p.startswith('/'):
|
||||||
|
self.fail('path_error', path=p)
|
||||||
|
|
||||||
|
if p.count(':'):
|
||||||
|
if p.count(':') > MAX_ISOLATED_PATH_COLON_DELIMITER:
|
||||||
|
self.fail('syntax_error', path=p)
|
||||||
|
try:
|
||||||
|
src, dest, scontext = p.split(':')
|
||||||
|
except ValueError:
|
||||||
|
scontext = 'z'
|
||||||
|
src, dest = p.split(':')
|
||||||
|
finally:
|
||||||
|
for sp in [src, dest]:
|
||||||
|
if not len(sp):
|
||||||
|
self.fail('syntax_error', path=sp)
|
||||||
|
if not sp.startswith('/'):
|
||||||
|
self.fail('path_error', path=sp)
|
||||||
|
if scontext not in CONTAINER_VOLUMES_MOUNT_TYPES:
|
||||||
|
self.fail('mount_error', scontext=scontext, mount_types=CONTAINER_VOLUMES_MOUNT_TYPES)
|
||||||
|
return super(StringListIsolatedPathField, self).to_internal_value(sorted(paths))
|
||||||
|
else:
|
||||||
|
self.fail('type_error', input_type=type(paths))
|
||||||
|
|
||||||
|
|
||||||
class URLField(CharField):
|
class URLField(CharField):
|
||||||
# these lines set up a custom regex that allow numbers in the
|
# these lines set up a custom regex that allow numbers in the
|
||||||
# top-level domain
|
# top-level domain
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import jsonfield.fields
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
import awx.main.fields
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ class Migration(migrations.Migration):
|
|||||||
('created', models.DateTimeField(default=None, editable=False)),
|
('created', models.DateTimeField(default=None, editable=False)),
|
||||||
('modified', models.DateTimeField(default=None, editable=False)),
|
('modified', models.DateTimeField(default=None, editable=False)),
|
||||||
('key', models.CharField(max_length=255)),
|
('key', models.CharField(max_length=255)),
|
||||||
('value', jsonfield.fields.JSONField(null=True)),
|
('value', awx.main.fields.JSONBlob(null=True)),
|
||||||
(
|
(
|
||||||
'user',
|
'user',
|
||||||
models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True),
|
models.ForeignKey(related_name='settings', default=None, editable=False, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
import awx.main.fields
|
import awx.main.fields
|
||||||
|
|
||||||
|
|
||||||
@@ -9,4 +10,4 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
dependencies = [('conf', '0002_v310_copy_tower_settings')]
|
dependencies = [('conf', '0002_v310_copy_tower_settings')]
|
||||||
|
|
||||||
operations = [migrations.AlterField(model_name='setting', name='value', field=awx.main.fields.JSONField(null=True))]
|
operations = [migrations.AlterField(model_name='setting', name='value', field=awx.main.fields.JSONBlob(null=True))]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from django.utils.timezone import now
|
|||||||
|
|
||||||
|
|
||||||
def fill_ldap_group_type_params(apps, schema_editor):
|
def fill_ldap_group_type_params(apps, schema_editor):
|
||||||
group_type = settings.AUTH_LDAP_GROUP_TYPE
|
group_type = getattr(settings, 'AUTH_LDAP_GROUP_TYPE', None)
|
||||||
Setting = apps.get_model('conf', 'Setting')
|
Setting = apps.get_model('conf', 'Setting')
|
||||||
|
|
||||||
group_type_params = {'name_attr': 'cn', 'member_attr': 'member'}
|
group_type_params = {'name_attr': 'cn', 'member_attr': 'member'}
|
||||||
@@ -17,7 +17,7 @@ def fill_ldap_group_type_params(apps, schema_editor):
|
|||||||
else:
|
else:
|
||||||
entry = Setting(key='AUTH_LDAP_GROUP_TYPE_PARAMS', value=group_type_params, created=now(), modified=now())
|
entry = Setting(key='AUTH_LDAP_GROUP_TYPE_PARAMS', value=group_type_params, created=now(), modified=now())
|
||||||
|
|
||||||
init_attrs = set(inspect.getargspec(group_type.__init__).args[1:])
|
init_attrs = set(inspect.getfullargspec(group_type.__init__).args[1:])
|
||||||
for k in list(group_type_params.keys()):
|
for k in list(group_type_params.keys()):
|
||||||
if k not in init_attrs:
|
if k not in init_attrs:
|
||||||
del group_type_params[k]
|
del group_type_params[k]
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import json
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
from awx.main.fields import JSONBlob
|
||||||
from awx.main.models.base import CreatedModifiedModel, prevent_search
|
from awx.main.models.base import CreatedModifiedModel, prevent_search
|
||||||
from awx.main.fields import JSONField
|
|
||||||
from awx.main.utils import encrypt_field
|
from awx.main.utils import encrypt_field
|
||||||
from awx.conf import settings_registry
|
from awx.conf import settings_registry
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ __all__ = ['Setting']
|
|||||||
class Setting(CreatedModifiedModel):
|
class Setting(CreatedModifiedModel):
|
||||||
|
|
||||||
key = models.CharField(max_length=255)
|
key = models.CharField(max_length=255)
|
||||||
value = JSONField(null=True)
|
value = JSONBlob(null=True)
|
||||||
user = prevent_search(models.ForeignKey('auth.User', related_name='settings', default=None, null=True, editable=False, on_delete=models.CASCADE))
|
user = prevent_search(models.ForeignKey('auth.User', related_name='settings', default=None, null=True, editable=False, on_delete=models.CASCADE))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import logging
|
|||||||
# Django
|
# Django
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from awx.conf.license import get_license
|
from awx.conf.license import get_license
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from uuid import uuid4
|
|||||||
from django.conf import LazySettings
|
from django.conf import LazySettings
|
||||||
from django.core.cache.backends.locmem import LocMemCache
|
from django.core.cache.backends.locmem import LocMemCache
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.fields import empty
|
from rest_framework.fields import empty
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import time
|
|||||||
from django.conf import LazySettings
|
from django.conf import LazySettings
|
||||||
from django.core.cache.backends.locmem import LocMemCache
|
from django.core.cache.backends.locmem import LocMemCache
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from awx.conf import models, fields
|
from awx.conf import models, fields
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Copyright (c) 2016 Ansible, Inc.
|
# Copyright (c) 2016 Ansible, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
|
from django.urls import re_path
|
||||||
|
|
||||||
from django.conf.urls import url
|
|
||||||
from awx.conf.views import SettingCategoryList, SettingSingletonDetail, SettingLoggingTest
|
from awx.conf.views import SettingCategoryList, SettingSingletonDetail, SettingLoggingTest
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', SettingCategoryList.as_view(), name='setting_category_list'),
|
re_path(r'^$', SettingCategoryList.as_view(), name='setting_category_list'),
|
||||||
url(r'^(?P<category_slug>[a-z0-9-]+)/$', SettingSingletonDetail.as_view(), name='setting_singleton_detail'),
|
re_path(r'^(?P<category_slug>[a-z0-9-]+)/$', SettingSingletonDetail.as_view(), name='setting_singleton_detail'),
|
||||||
url(r'^logging/test/$', SettingLoggingTest.as_view(), name='setting_logging_test'),
|
re_path(r'^logging/test/$', SettingLoggingTest.as_view(), name='setting_logging_test'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from socket import SHUT_RDWR
|
|||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
@@ -26,7 +26,7 @@ from awx.api.generics import APIView, GenericAPIView, ListAPIView, RetrieveUpdat
|
|||||||
from awx.api.permissions import IsSystemAdminOrAuditor
|
from awx.api.permissions import IsSystemAdminOrAuditor
|
||||||
from awx.api.versioning import reverse
|
from awx.api.versioning import reverse
|
||||||
from awx.main.utils import camelcase_to_underscore
|
from awx.main.utils import camelcase_to_underscore
|
||||||
from awx.main.tasks import handle_setting_changes
|
from awx.main.tasks.system import handle_setting_changes
|
||||||
from awx.conf.models import Setting
|
from awx.conf.models import Setting
|
||||||
from awx.conf.serializers import SettingCategorySerializer, SettingSingletonSerializer
|
from awx.conf.serializers import SettingCategorySerializer, SettingSingletonSerializer
|
||||||
from awx.conf import settings_registry
|
from awx.conf import settings_registry
|
||||||
|
|||||||
@@ -4856,7 +4856,7 @@ msgid "Exception connecting to PagerDuty: {}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: awx/main/notifications/pagerduty_backend.py:87
|
#: awx/main/notifications/pagerduty_backend.py:87
|
||||||
#: awx/main/notifications/slack_backend.py:48
|
#: awx/main/notifications/slack_backend.py:49
|
||||||
#: awx/main/notifications/twilio_backend.py:47
|
#: awx/main/notifications/twilio_backend.py:47
|
||||||
msgid "Exception sending messages: {}"
|
msgid "Exception sending messages: {}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,3 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -40,7 +37,7 @@ msgstr "secondes"
|
|||||||
|
|
||||||
#: awx/api/conf.py:29
|
#: awx/api/conf.py:29
|
||||||
msgid "Maximum number of simultaneous logged in sessions"
|
msgid "Maximum number of simultaneous logged in sessions"
|
||||||
msgstr "Le nombre maximum de sessions actives en simultané"
|
msgstr "Nombre maximum de sessions actives en simultané"
|
||||||
|
|
||||||
#: awx/api/conf.py:30
|
#: awx/api/conf.py:30
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -2255,7 +2252,6 @@ msgid ""
|
|||||||
"Maximum number of messages to update the UI live job output with per second. "
|
"Maximum number of messages to update the UI live job output with per second. "
|
||||||
"Value of 0 means no limit."
|
"Value of 0 means no limit."
|
||||||
msgstr "Nombre maximal de messages pour mettre à jour la sortie du Job dans l'interface live utilisateur, par seconde. La valeur de 0 signifie qu'il n'y a pas de limite."
|
msgstr "Nombre maximal de messages pour mettre à jour la sortie du Job dans l'interface live utilisateur, par seconde. La valeur de 0 signifie qu'il n'y a pas de limite."
|
||||||
|
|
||||||
#: awx/main/conf.py:380
|
#: awx/main/conf.py:380
|
||||||
msgid "Maximum Scheduled Jobs"
|
msgid "Maximum Scheduled Jobs"
|
||||||
msgstr "Nombre max. de tâches planifiées"
|
msgstr "Nombre max. de tâches planifiées"
|
||||||
@@ -2812,7 +2808,7 @@ msgstr "URL du coffre HashiCorp"
|
|||||||
#: awx/main/models/credential/__init__.py:920
|
#: awx/main/models/credential/__init__.py:920
|
||||||
#: awx/main/models/credential/__init__.py:939
|
#: awx/main/models/credential/__init__.py:939
|
||||||
msgid "Token"
|
msgid "Token"
|
||||||
msgstr "Token"
|
msgstr "Jeton"
|
||||||
|
|
||||||
#: awx/main/credential_plugins/hashivault.py:25
|
#: awx/main/credential_plugins/hashivault.py:25
|
||||||
msgid "The access token used to authenticate to the Vault server"
|
msgid "The access token used to authenticate to the Vault server"
|
||||||
@@ -3724,7 +3720,7 @@ msgstr "interne : à la non-importation pour l'hôte"
|
|||||||
|
|
||||||
#: awx/main/models/events.py:193
|
#: awx/main/models/events.py:193
|
||||||
msgid "Play Started"
|
msgid "Play Started"
|
||||||
msgstr "Scène démarrée"
|
msgstr "Play Démarrage"
|
||||||
|
|
||||||
#: awx/main/models/events.py:194
|
#: awx/main/models/events.py:194
|
||||||
msgid "Playbook Complete"
|
msgid "Playbook Complete"
|
||||||
@@ -3981,7 +3977,7 @@ msgid ""
|
|||||||
"The host would be marked enabled. If power_state where any value other than "
|
"The host would be marked enabled. If power_state where any value other than "
|
||||||
"powered_on then the host would be disabled when imported. If the key is not "
|
"powered_on then the host would be disabled when imported. If the key is not "
|
||||||
"found then the host will be enabled"
|
"found then the host will be enabled"
|
||||||
msgstr "Utilisé uniquement lorsque enabled_var est défini. Valeur lorsque l'hôte est considéré comme activé. Par exemple, si enabled_var=\"status.power_state \" et enabled_value=\"powered_on\" avec les variables de l'hôte:{ \"status\" : { \"power_state\" : \"powered_on\", \"created\" : \"2020-08-04T18:13:04+00:00\", \"healthy\" : true }, \"name\" : \"foobar\", \"ip_address\" : \"192.168.2.1\"}, l'hôte serait marqué comme étant activé. Si power_state contient une valeur autre que power_on, alors l'hôte sera désactivé lors de l'importation. Si la clé n'est pas trouvée, alors l'hôte sera activé"
|
msgstr "Utilisé uniquement lorsque enabled_var est défini. Valeur lorsque l'hôte est considéré comme activé. Par exemple, si enabled_var=\"status.power_state \" et enabled_value=\"powered_on\" avec les variables de l'hôte:{ \"status\": { \"power_state\": \"powered_on\", \"created\": \"2020-08-04T18:13:04+00:00\", \"healthy\": true },\"name\" : \"foobar\", \"ip_address\" : \"192.168.2.1\"}, l'hôte serait marqué comme étant activé. Si power_state contient une valeur autre que power_on, alors l'hôte sera désactivé lors de l'importation. Si la clé n'est pas trouvée, alors l'hôte sera activé"
|
||||||
|
|
||||||
#: awx/main/models/inventory.py:878
|
#: awx/main/models/inventory.py:878
|
||||||
msgid "Regex where only matching hosts will be imported."
|
msgid "Regex where only matching hosts will be imported."
|
||||||
@@ -4301,7 +4297,7 @@ msgstr "Utilisé pour une vérification plus rigoureuse de l'accès à une appli
|
|||||||
#: awx/main/models/oauth.py:74
|
#: awx/main/models/oauth.py:74
|
||||||
msgid ""
|
msgid ""
|
||||||
"Set to Public or Confidential depending on how secure the client device is."
|
"Set to Public or Confidential depending on how secure the client device is."
|
||||||
msgstr "Défini sur sur Public ou Confidentiel selon le degré de sécurité du périphérique client."
|
msgstr "Définir sur sur Public ou Confidentiel selon le degré de sécurité du périphérique client."
|
||||||
|
|
||||||
#: awx/main/models/oauth.py:76
|
#: awx/main/models/oauth.py:76
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -4555,7 +4551,7 @@ msgstr "Utilisation"
|
|||||||
|
|
||||||
#: awx/main/models/rbac.py:52
|
#: awx/main/models/rbac.py:52
|
||||||
msgid "Approve"
|
msgid "Approve"
|
||||||
msgstr "Approbation"
|
msgstr "Approuver"
|
||||||
|
|
||||||
#: awx/main/models/rbac.py:56
|
#: awx/main/models/rbac.py:56
|
||||||
msgid "Can manage all aspects of the system"
|
msgid "Can manage all aspects of the system"
|
||||||
@@ -5147,7 +5143,7 @@ msgstr "Au moins %(min_certs)d certificats sont requis, seulement %(cert_count)d
|
|||||||
#: awx/main/validators.py:152
|
#: awx/main/validators.py:152
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Only one certificate is allowed, %(cert_count)d provided."
|
msgid "Only one certificate is allowed, %(cert_count)d provided."
|
||||||
msgstr "Un seul certificat est autorisé, %(cert_count)d ont été fournis."
|
msgstr "Un seul certificat est autorisé, %(cert_count) ont été fournis."
|
||||||
|
|
||||||
#: awx/main/validators.py:154
|
#: awx/main/validators.py:154
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -5633,7 +5629,7 @@ msgstr "Nom de l'organisation GitHub"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"The name of your GitHub organization, as used in your organization's URL: "
|
"The name of your GitHub organization, as used in your organization's URL: "
|
||||||
"https://github.com/<yourorg>/."
|
"https://github.com/<yourorg>/."
|
||||||
msgstr "Nom de votre organisation GitHub, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<votreorg>/."
|
msgstr "Nom de votre organisation GitHub, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<yourorg>/."
|
||||||
|
|
||||||
#: awx/sso/conf.py:762
|
#: awx/sso/conf.py:762
|
||||||
msgid "GitHub Organization OAuth2 Organization Map"
|
msgid "GitHub Organization OAuth2 Organization Map"
|
||||||
@@ -5653,7 +5649,7 @@ msgid ""
|
|||||||
"<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and "
|
"<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and "
|
||||||
"secret (Client Secret). Provide this URL as the callback URL for your "
|
"secret (Client Secret). Provide this URL as the callback URL for your "
|
||||||
"application."
|
"application."
|
||||||
msgstr "Créez une application appartenant à une organisation sur https://github.com/organizations/<votreorg>/settings/applications et obtenez une clé OAuth2 (ID client) et un secret (secret client). Entrez cette URL comme URL de rappel de votre application."
|
msgstr "Créez une application appartenant à une organisation sur https://github.com/organizations/<yourorg>/settings/applications et obtenez une clé OAuth2 (ID client) et un secret (secret client). Entrez cette URL comme URL de rappel de votre application."
|
||||||
|
|
||||||
#: awx/sso/conf.py:797 awx/sso/conf.py:809 awx/sso/conf.py:820
|
#: awx/sso/conf.py:797 awx/sso/conf.py:809 awx/sso/conf.py:820
|
||||||
#: awx/sso/conf.py:832 awx/sso/conf.py:843 awx/sso/conf.py:855
|
#: awx/sso/conf.py:832 awx/sso/conf.py:843 awx/sso/conf.py:855
|
||||||
@@ -5789,7 +5785,7 @@ msgstr "Nom de l'organisation GitHub Enterprise"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"The name of your GitHub Enterprise organization, as used in your "
|
"The name of your GitHub Enterprise organization, as used in your "
|
||||||
"organization's URL: https://github.com/<yourorg>/."
|
"organization's URL: https://github.com/<yourorg>/."
|
||||||
msgstr "Nom de votre organisation GitHub Enterprise, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<votreorg>/."
|
msgstr "Nom de votre organisation GitHub Enterprise, tel qu'utilisé dans l'URL de votre organisation : https://github.com/<yourorg>/."
|
||||||
|
|
||||||
#: awx/sso/conf.py:1030
|
#: awx/sso/conf.py:1030
|
||||||
msgid "GitHub Enterprise Organization OAuth2 Organization Map"
|
msgid "GitHub Enterprise Organization OAuth2 Organization Map"
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
# SOME DESCRIPTIVE TITLE.
|
|
||||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
|
||||||
# This file is distributed under the same license as the PACKAGE package.
|
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -596,7 +593,7 @@ msgstr "指定された変数 {} には置き換えるデータベースの値
|
|||||||
|
|
||||||
#: awx/api/serializers.py:3739
|
#: awx/api/serializers.py:3739
|
||||||
msgid "\"$encrypted$ is a reserved keyword, may not be used for {}.\""
|
msgid "\"$encrypted$ is a reserved keyword, may not be used for {}.\""
|
||||||
msgstr "\"$encrypted$ は予約されたキーワードで、{} には使用できません。\""
|
msgstr "\"$encrypted は予約されたキーワードで {} には使用できません。\""
|
||||||
|
|
||||||
#: awx/api/serializers.py:4212
|
#: awx/api/serializers.py:4212
|
||||||
msgid "A project is required to run a job."
|
msgid "A project is required to run a job."
|
||||||
@@ -824,7 +821,7 @@ msgstr "ポリシーインスタンスの割合"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Minimum percentage of all instances that will be automatically assigned to "
|
"Minimum percentage of all instances that will be automatically assigned to "
|
||||||
"this group when new instances come online."
|
"this group when new instances come online."
|
||||||
msgstr "新規インスタンスがオンラインになると、このグループに自動的に最小限割り当てられるインスタンスの割合を選択します。"
|
msgstr "新規インスタンスがオンラインになると、このグループに自動的に最小限割り当てられるインスタンスの割合"
|
||||||
|
|
||||||
#: awx/api/serializers.py:4853
|
#: awx/api/serializers.py:4853
|
||||||
msgid "Policy Instance Minimum"
|
msgid "Policy Instance Minimum"
|
||||||
@@ -1253,7 +1250,7 @@ msgstr "デフォルトで指定されている選択項目は、一覧から回
|
|||||||
msgid ""
|
msgid ""
|
||||||
"$encrypted$ is a reserved keyword for password question defaults, survey "
|
"$encrypted$ is a reserved keyword for password question defaults, survey "
|
||||||
"question {idx} is type {survey_item[type]}."
|
"question {idx} is type {survey_item[type]}."
|
||||||
msgstr "$encrypted$ は、デフォルト設定されているパスワードの質問に予約されたキーワードで、Survey の質問 {idx} は {survey_item[type]} タイプです。"
|
msgstr "$encrypted$ はパスワードの質問のデフォルトの予約されたキーワードで、Survey の質問 {idx} はタイプ {survey_item[type]} です。"
|
||||||
|
|
||||||
#: awx/api/views/__init__.py:2567
|
#: awx/api/views/__init__.py:2567
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
@@ -3638,7 +3635,7 @@ msgstr "ホスト OK"
|
|||||||
|
|
||||||
#: awx/main/models/events.py:169
|
#: awx/main/models/events.py:169
|
||||||
msgid "Host Failure"
|
msgid "Host Failure"
|
||||||
msgstr "ホストの失敗"
|
msgstr "ホストの障害"
|
||||||
|
|
||||||
#: awx/main/models/events.py:170 awx/main/models/events.py:767
|
#: awx/main/models/events.py:170 awx/main/models/events.py:767
|
||||||
msgid "Host Skipped"
|
msgid "Host Skipped"
|
||||||
@@ -4694,7 +4691,7 @@ msgstr "取り消されました"
|
|||||||
|
|
||||||
#: awx/main/models/unified_jobs.py:84
|
#: awx/main/models/unified_jobs.py:84
|
||||||
msgid "Never Updated"
|
msgid "Never Updated"
|
||||||
msgstr "更新されていません"
|
msgstr "未更新"
|
||||||
|
|
||||||
#: awx/main/models/unified_jobs.py:88
|
#: awx/main/models/unified_jobs.py:88
|
||||||
msgid "OK"
|
msgid "OK"
|
||||||
@@ -6261,4 +6258,3 @@ msgstr "%s が現在アップグレード中です。"
|
|||||||
#: awx/ui/urls.py:24
|
#: awx/ui/urls.py:24
|
||||||
msgid "This page will refresh when complete."
|
msgid "This page will refresh when complete."
|
||||||
msgstr "このページは完了すると更新されます。"
|
msgstr "このページは完了すると更新されます。"
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user