Compare commits
544
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ff4f98841 | ||
|
|
0a8c337b1e | ||
|
|
2dac0d1f53 | ||
|
|
73b627214d | ||
|
|
c79168453b | ||
|
|
299f72abca | ||
|
|
058125f0b1 | ||
|
|
130b0af8d8 | ||
|
|
6f7542ef27 | ||
|
|
919d1a3a28 | ||
|
|
3c4c32e72d | ||
|
|
3294e70b3f | ||
|
|
5908d8d282 | ||
|
|
32f8251a90 | ||
|
|
a3fec86eae | ||
|
|
672edccd70 | ||
|
|
f188e25453 | ||
|
|
d4a72ebf5d | ||
|
|
4492db4185 | ||
|
|
015edcd63d | ||
|
|
aaad6b2b7e | ||
|
|
3b6eccba80 | ||
|
|
44b730dbfc | ||
|
|
ea4ebb0de0 | ||
|
|
3b3e82f16a | ||
|
|
1430afe600 | ||
|
|
e3f01da175 | ||
|
|
7a5c7b6de9 | ||
|
|
c880172aa5 | ||
|
|
6b631fb3e3 | ||
|
|
712f3d50b5 | ||
|
|
f6875b498b | ||
|
|
2e728d4698 | ||
|
|
98a969fa04 | ||
|
|
154717aca7 | ||
|
|
cc0eb74090 | ||
|
|
e2f49a5b1f | ||
|
|
c8ceaab950 | ||
|
|
3fbf333d3d | ||
|
|
3cb09b34da | ||
|
|
1d9d723ce9 | ||
|
|
cf06bfd1bd | ||
|
|
df7340e578 | ||
|
|
7a02fb89f4 | ||
|
|
bfdf8b3b2a | ||
|
|
1ae2917263 | ||
|
|
1fea1c9e23 | ||
|
|
fa804dbed1 | ||
|
|
3b28145d0a | ||
|
|
e9bf6ba7b5 | ||
|
|
cc3394d5eb | ||
|
|
90156a4733 | ||
|
|
314a6f1bed | ||
|
|
eab0ddd697 | ||
|
|
3c1960f015 | ||
|
|
3ff4dd1fae | ||
|
|
dbeaf4c58c | ||
|
|
0f49484a43 | ||
|
|
b540c7b7e8 | ||
|
|
1012ea31ad | ||
|
|
a00baa490f | ||
|
|
bc9e331c68 | ||
|
|
57f58b0c9a | ||
|
|
496a6bd940 | ||
|
|
2bbdad3e47 | ||
|
|
91e0c992ec | ||
|
|
860de928ba | ||
|
|
9d82d61993 | ||
|
|
294af1945d | ||
|
|
430172911e | ||
|
|
38e00d6ac6 | ||
|
|
75004d16f9 | ||
|
|
47e6d6630d | ||
|
|
d9366b665b | ||
|
|
951bf0a807 | ||
|
|
4145db089f | ||
|
|
a2f6d43398 | ||
|
|
5e41927b8d | ||
|
|
ea9459f013 | ||
|
|
c2e34305eb | ||
|
|
a79a9623b6 | ||
|
|
cac74471aa | ||
|
|
afe668cca6 | ||
|
|
2785eecbf3 | ||
|
|
0833a20347 | ||
|
|
95945cd4cf | ||
|
|
fdb32538bf | ||
|
|
d2740d4b62 | ||
|
|
e26ba6d99d | ||
|
|
f419751206 | ||
|
|
70660fbd5a | ||
|
|
a94390916a | ||
|
|
5d6e5339ad | ||
|
|
b9cd8e3226 | ||
|
|
ce42b3dc33 | ||
|
|
3f25d83f64 | ||
|
|
45a67a11cf | ||
|
|
f0b700a688 | ||
|
|
8d6234927c | ||
|
|
189f81d95b | ||
|
|
c5d0fd8589 | ||
|
|
1a9ea98202 | ||
|
|
4938370eea | ||
|
|
b834ff10bf | ||
|
|
13c360b1b0 | ||
|
|
7804dd5993 | ||
|
|
87257fb0b5 | ||
|
|
56ccc83903 | ||
|
|
f658a018ac | ||
|
|
2608756622 | ||
|
|
6350dacd4e | ||
|
|
1629715732 | ||
|
|
01c1ce7534 | ||
|
|
ad0b611cb5 | ||
|
|
401ca9f935 | ||
|
|
d3a835e3fb | ||
|
|
e98c05ce08 | ||
|
|
9759416787 | ||
|
|
03b007a5a0 | ||
|
|
93f3646abc | ||
|
|
145e55df92 | ||
|
|
08796241a6 | ||
|
|
8e43ea9dbd | ||
|
|
a42eee7797 | ||
|
|
25caebeb0a | ||
|
|
e157a8c077 | ||
|
|
1d86eb582e | ||
|
|
04a216f643 | ||
|
|
533567b31d | ||
|
|
e568afc5e0 | ||
|
|
8865052752 | ||
|
|
f5f73fcacc | ||
|
|
b438956e96 | ||
|
|
e85c372ad8 | ||
|
|
e66c7034f0 | ||
|
|
8af967b4d3 | ||
|
|
b6e60764bd | ||
|
|
de1977fd2a | ||
|
|
60aafb55b8 | ||
|
|
2b410b5ff8 | ||
|
|
7a1021edfa | ||
|
|
a991b69547 | ||
|
|
9595ea326f | ||
|
|
78a95435ae | ||
|
|
a2973bcd82 | ||
|
|
90cb797d2e | ||
|
|
b496c8ee02 | ||
|
|
cbaf675f09 | ||
|
|
3b2f77df35 | ||
|
|
b4ab48be08 | ||
|
|
943781d54d | ||
|
|
54fd66196e | ||
|
|
12078b1439 | ||
|
|
1a8b54b718 | ||
|
|
749c971e1f | ||
|
|
822c42bd62 | ||
|
|
21e77ab0b3 | ||
|
|
d38cea53f8 | ||
|
|
2e5e3b0a26 | ||
|
|
4dbfeff967 | ||
|
|
441716bbbc | ||
|
|
09b52bc16c | ||
|
|
4f4de780ca | ||
|
|
7681aef96e | ||
|
|
a1d7d8005d | ||
|
|
31179d99de | ||
|
|
d8866b038a | ||
|
|
016ffbb1a9 | ||
|
|
8d90b3ef9d | ||
|
|
7e9b474f10 | ||
|
|
e06a02db13 | ||
|
|
540b5fea80 | ||
|
|
ee91dea395 | ||
|
|
1adc0ffc4a | ||
|
|
b123e260b0 | ||
|
|
aa6ce119b8 | ||
|
|
94e47be079 | ||
|
|
8abcd775ce | ||
|
|
a9a3cf69c6 | ||
|
|
87d8c52c48 | ||
|
|
f3672fed63 | ||
|
|
9f7fdbc198 | ||
|
|
2661593e69 | ||
|
|
6f1c8cd8ff | ||
|
|
a3fb4d843a | ||
|
|
e7b72b1754 | ||
|
|
7cb3d1917e | ||
|
|
0aebb19650 | ||
|
|
3c2e6fe2f1 | ||
|
|
78e9da8bd3 | ||
|
|
b31480b68c | ||
|
|
d556284977 | ||
|
|
d90696a1a5 | ||
|
|
b4eaf9eb5d | ||
|
|
333d065043 | ||
|
|
8aed35a67a | ||
|
|
4fd57edecd | ||
|
|
15e28502c1 | ||
|
|
035b878b3c | ||
|
|
0cbc34293e | ||
|
|
95c11fe68d | ||
|
|
cece5eae71 | ||
|
|
f659209cd6 | ||
|
|
decbfc1bb5 | ||
|
|
e9c7068b52 | ||
|
|
8be9e7dd13 | ||
|
|
f0e6339b3d | ||
|
|
e320f881d1 | ||
|
|
22557fb166 | ||
|
|
919065093d | ||
|
|
c9e66762df | ||
|
|
f1ffa5c949 | ||
|
|
4d5f3809d9 | ||
|
|
b2ef330fc9 | ||
|
|
2ba56cb00f | ||
|
|
d7ef0fcd3e | ||
|
|
c7eb2c5aba | ||
|
|
19e997f7ae | ||
|
|
5433b97b00 | ||
|
|
2a609b2143 | ||
|
|
dfd77e458a | ||
|
|
11d8176622 | ||
|
|
f9f831738d | ||
|
|
a435eac3e8 | ||
|
|
97a74fb2cf | ||
|
|
444039b64a | ||
|
|
7492061f58 | ||
|
|
a44ca7e825 | ||
|
|
f68b0ad00f | ||
|
|
9863662e34 | ||
|
|
7edecd7d1c | ||
|
|
5e9e5a1e7b | ||
|
|
6af4c36fae | ||
|
|
fa61ab2733 | ||
|
|
8764522525 | ||
|
|
b4545d6c99 | ||
|
|
ec2696ee43 | ||
|
|
52ba892d6f | ||
|
|
5478a1032c | ||
|
|
b11c840688 | ||
|
|
15994f11b1 | ||
|
|
b5c3aa1bdb | ||
|
|
623bc9b74e | ||
|
|
6a6b0a0167 | ||
|
|
ad9c6c7a2a | ||
|
|
25b602a3b8 | ||
|
|
ed70f03a83 | ||
|
|
e76fb6684c | ||
|
|
2454d77ce8 | ||
|
|
5432647293 | ||
|
|
14d2e869bb | ||
|
|
ce9072124d | ||
|
|
f78ffcc595 | ||
|
|
57d2559ad3 | ||
|
|
024736c887 | ||
|
|
73f57871b4 | ||
|
|
cf0c355416 | ||
|
|
54c53d4510 | ||
|
|
5e247e831c | ||
|
|
ecaa988b5f | ||
|
|
73c89d8d93 | ||
|
|
1a41a01dfa | ||
|
|
5d26a4dd05 | ||
|
|
956e7fc1d0 | ||
|
|
73101d8cb9 | ||
|
|
78cc6cbad3 | ||
|
|
ec5eadac06 | ||
|
|
f22a33ad1a | ||
|
|
f28a9096f7 | ||
|
|
0216a9f1e1 | ||
|
|
bb642c781a | ||
|
|
0af676ec39 | ||
|
|
e93f00321e | ||
|
|
565a381977 | ||
|
|
914e1c691f | ||
|
|
e153be4b58 | ||
|
|
6cacd1a2cf | ||
|
|
eecdb55ba0 | ||
|
|
4de2cbf1bc | ||
|
|
aff4debd79 | ||
|
|
022ad01ace | ||
|
|
cda89ea243 | ||
|
|
aa0939be6d | ||
|
|
e74b659b45 | ||
|
|
f522b69a68 | ||
|
|
ef7b47b0c5 | ||
|
|
3d8fc1d848 | ||
|
|
5820be065c | ||
|
|
5ee60c8324 | ||
|
|
4918d968b7 | ||
|
|
75e172c7c0 | ||
|
|
9ad042b371 | ||
|
|
ed240d3cd0 | ||
|
|
2da9e9390d | ||
|
|
47bf1d40f9 | ||
|
|
256cc8cd71 | ||
|
|
51769fb08a | ||
|
|
555b222d6b | ||
|
|
cf26fa90d3 | ||
|
|
0cce30b7d2 | ||
|
|
200fea731c | ||
|
|
0eca15a19b | ||
|
|
fbe38faf59 | ||
|
|
0015e105f9 | ||
|
|
3dc8cce37a | ||
|
|
090eeccf8c | ||
|
|
17a7e173fe | ||
|
|
8d52c43e68 | ||
|
|
3eb7fd44e5 | ||
|
|
8c09ab3c6e | ||
|
|
19665ea0b7 | ||
|
|
7d4a1897f7 | ||
|
|
72ab577431 | ||
|
|
535617594f | ||
|
|
1230cac914 | ||
|
|
a3d5c16484 | ||
|
|
29ea329ed5 | ||
|
|
d719af498c | ||
|
|
b118391dc6 | ||
|
|
17d2f3544c | ||
|
|
25ba693bbd | ||
|
|
e5406b6549 | ||
|
|
5fa8ad286f | ||
|
|
d3061eddaf | ||
|
|
883e028cae | ||
|
|
2f4b93d11c | ||
|
|
57d7e8feee | ||
|
|
dd3b0b7731 | ||
|
|
c86301c9b2 | ||
|
|
3079df9072 | ||
|
|
1c04605dc7 | ||
|
|
2b8a4ed46f | ||
|
|
622f2c8758 | ||
|
|
4e6637aba9 | ||
|
|
c6784759cd | ||
|
|
55f27433f9 | ||
|
|
2dd02f0632 | ||
|
|
5d4bc9e93b | ||
|
|
ccb69a43d2 | ||
|
|
36755ccfb0 | ||
|
|
27dff192f2 | ||
|
|
e9dad6bfe5 | ||
|
|
69d161c19b | ||
|
|
103dcc919e | ||
|
|
3eea2ea4a2 | ||
|
|
d0a948e93f | ||
|
|
2a3c71f939 | ||
|
|
8caa778ee0 | ||
|
|
5521b70e46 | ||
|
|
c8d784ae2b | ||
|
|
910170b594 | ||
|
|
4dee3442b0 | ||
|
|
b38f2a8b2f | ||
|
|
1e8afcbc44 | ||
|
|
9e2b51de60 | ||
|
|
eb0f467aad | ||
|
|
da4b86f4d3 | ||
|
|
b5ef38bc0d | ||
|
|
c5b7e9dcde | ||
|
|
b611d41e8a | ||
|
|
c3ba43b0fa | ||
|
|
dc0e006e0f | ||
|
|
0b66858969 | ||
|
|
16c8fba623 | ||
|
|
852fccd95c | ||
|
|
316d07db61 | ||
|
|
bf99f618f6 | ||
|
|
534f0cb7cb | ||
|
|
974f6820d4 | ||
|
|
6ccf910e29 | ||
|
|
aaf1ced21c | ||
|
|
d05a3e2dc6 | ||
|
|
8be8b44584 | ||
|
|
4a028c04c9 | ||
|
|
1f1d7ab75d | ||
|
|
e0e5d9e290 | ||
|
|
181eb67501 | ||
|
|
8af976c528 | ||
|
|
beba1f16b4 | ||
|
|
76d0cbdb8d | ||
|
|
6ff0bb31d3 | ||
|
|
e78825b99f | ||
|
|
33a9d6fec7 | ||
|
|
b01145e6bd | ||
|
|
06024c82c1 | ||
|
|
ce4a4838f1 | ||
|
|
f80cfbeba7 | ||
|
|
61e5966083 | ||
|
|
f49a606693 | ||
|
|
2b866b32bb | ||
|
|
97896b5170 | ||
|
|
3647ff15e1 | ||
|
|
267f753452 | ||
|
|
c33e463e09 | ||
|
|
40cfc3c9f5 | ||
|
|
632ba5257e | ||
|
|
7127effdaf | ||
|
|
ca3f7e964e | ||
|
|
904e779b59 | ||
|
|
63054b4a3a | ||
|
|
871f3c5ba8 | ||
|
|
9c706bb9b1 | ||
|
|
06c57ca837 | ||
|
|
39a3ec055b | ||
|
|
401cf8e1a7 | ||
|
|
f50d624d22 | ||
|
|
4aeee1acb5 | ||
|
|
b6a9cfed19 | ||
|
|
a67dcf763b | ||
|
|
0f58c2dcae | ||
|
|
9cb1418b0d | ||
|
|
f62e6ca651 | ||
|
|
0c6ddd4904 | ||
|
|
14d4dbfe97 | ||
|
|
50d0c2cd4d | ||
|
|
4fe45169c3 | ||
|
|
78d93a16eb | ||
|
|
b94bf528be | ||
|
|
11ad57bce4 | ||
|
|
495a55f8c1 | ||
|
|
c611360c04 | ||
|
|
ada418374b | ||
|
|
3bf7f2a195 | ||
|
|
2d22cab6e7 | ||
|
|
96dcbe1798 | ||
|
|
ac6dc5b426 | ||
|
|
b4f22ffeea | ||
|
|
ca3ed630ed | ||
|
|
e2d3868a9e | ||
|
|
47314620be | ||
|
|
f26f3f2665 | ||
|
|
938b37e920 | ||
|
|
2c5a989306 | ||
|
|
88a6dd9316 | ||
|
|
77742c1d6f | ||
|
|
ba16c6475a | ||
|
|
1735098b3a | ||
|
|
2fdaaa47ab | ||
|
|
bd4e4aed27 | ||
|
|
94a8240ad4 | ||
|
|
be03af61ea | ||
|
|
4da34c98f3 | ||
|
|
12253f0621 | ||
|
|
369954f5d2 | ||
|
|
4eee702dce | ||
|
|
e90daa2e61 | ||
|
|
cc8570d02f | ||
|
|
98e5ea965c | ||
|
|
7a98ab1c6d | ||
|
|
70973a63fb | ||
|
|
ad82f73c1d | ||
|
|
e08016c103 | ||
|
|
a65e99b199 | ||
|
|
4853150f07 | ||
|
|
a341e66c13 | ||
|
|
874779d230 | ||
|
|
779e8a8b0f | ||
|
|
8f35e88ce4 | ||
|
|
71e874cfb4 | ||
|
|
622b8942b5 | ||
|
|
7aeb7d094c | ||
|
|
4ee80f8b7e | ||
|
|
4859fa6877 | ||
|
|
a1d831cdf2 | ||
|
|
a3ee639d77 | ||
|
|
cd274aea81 | ||
|
|
aaa548eb21 | ||
|
|
99f05a055d | ||
|
|
e614d50f9c | ||
|
|
20526c829c | ||
|
|
c9ed33f108 | ||
|
|
4d728c8e68 | ||
|
|
ef3aed4ba2 | ||
|
|
8f30fdb88c | ||
|
|
d4b67906cd | ||
|
|
075fa32ea2 | ||
|
|
f71f678662 | ||
|
|
457857df32 | ||
|
|
49adc84f5c | ||
|
|
a2a9a8c3a0 | ||
|
|
a62db898aa | ||
|
|
a2a6e5c5fe | ||
|
|
b9307efba2 | ||
|
|
52ccff4086 | ||
|
|
7f59856da3 | ||
|
|
10dc913080 | ||
|
|
1d2f190459 | ||
|
|
859ab9cfaf | ||
|
|
924d3dabb9 | ||
|
|
b227337ced | ||
|
|
717ffb4b8a | ||
|
|
08121fc701 | ||
|
|
460f18d85a | ||
|
|
6c34d510e5 | ||
|
|
789fc8bcbc | ||
|
|
31e72f28b0 | ||
|
|
3d0b87998d | ||
|
|
6c7b9a4ad8 | ||
|
|
f4379b07ca | ||
|
|
55364da10b | ||
|
|
e28b34b49b | ||
|
|
7ce3167d57 | ||
|
|
b0b9ae068a | ||
|
|
54349b4e8a | ||
|
|
2483e71d98 | ||
|
|
6b46873009 | ||
|
|
685a76bdd1 | ||
|
|
933a8bf3c8 | ||
|
|
e228d20d0b | ||
|
|
19ec49778e | ||
|
|
17dbe04c4b | ||
|
|
e5404fa1b9 | ||
|
|
f6506aeeca | ||
|
|
795720dcd2 | ||
|
|
85962b11a6 | ||
|
|
c1229b348e | ||
|
|
06358c4c07 | ||
|
|
fffde38fed | ||
|
|
13bfc40c6a | ||
|
|
9024a1eab6 | ||
|
|
aa851a7779 | ||
|
|
ac3d20d072 | ||
|
|
02f16516f1 | ||
|
|
c8301113e5 | ||
|
|
73fd35ad40 | ||
|
|
996ed3d776 | ||
|
|
05feced28f | ||
|
|
fe844437fb | ||
|
|
3de05c08bc | ||
|
|
e6509e0932 | ||
|
|
ce95ed4854 | ||
|
|
3bf2d553c8 | ||
|
|
b3fb490c16 | ||
|
|
5e8c2c73fd | ||
|
|
a75aabbec6 | ||
|
|
583522a422 | ||
|
|
a9b4a95e0c | ||
|
|
8b68d52be0 | ||
|
|
8f52aca2b4 | ||
|
|
744f920854 | ||
|
|
fe43d274cb | ||
|
|
53f4c17a08 | ||
|
|
f728cdafb4 | ||
|
|
21b4b9b7fb |
@@ -0,0 +1,10 @@
|
|||||||
|
.git
|
||||||
|
.github
|
||||||
|
**/__pycache__
|
||||||
|
*.pyc
|
||||||
|
.pytest_cache
|
||||||
|
media
|
||||||
|
staticfiles
|
||||||
|
*.sqlite3
|
||||||
|
node_modules
|
||||||
|
.env
|
||||||
@@ -1,58 +1,98 @@
|
|||||||
name: Gitea Actions Demo
|
name: Dockerfile runner
|
||||||
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
|
run-name: Building and deploying to Prod 🚀
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- 'infra/production/dockerfile'
|
||||||
issue_comment:
|
issue_comment:
|
||||||
types: [created]
|
types: [created]
|
||||||
|
workflow_dispatch: # Enables the manual run UI button
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Explore-Gitea-Actions:
|
Explore-Gitea-Actions:
|
||||||
runs-on: ubuntu-latest
|
env:
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
|
DEBUG: True
|
||||||
|
ALLOWED_HOSTS: "django.geeraert.eu"
|
||||||
|
container:
|
||||||
|
image: gitea.geeraert.eu/pi-ux-ce/custom-runner-debian-slim:1.0.6
|
||||||
|
volumes:
|
||||||
|
- act-toolcache:/opt/hostedtoolcache # this is where Runner store their cache default
|
||||||
|
runs-on: host-runner
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||||
|
|
||||||
|
- name: restore git folder if exist
|
||||||
|
run: if [ -d "/opt/hostedtoolcache/${{ github.event.repository.name }}/" ]; then cp -r /opt/hostedtoolcache/${{ github.event.repository.name }}/ ${{ gitea.workspace }}; fi
|
||||||
|
|
||||||
|
- name: Check Docker Version
|
||||||
|
run: whereis docker
|
||||||
|
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
clean: false
|
||||||
|
fetch-depth: 1
|
||||||
|
ref: 'main'
|
||||||
|
|
||||||
|
# - name: Manually check out repository code
|
||||||
|
# run: cd ${{ gitea.workspace }} ; git pull origin main
|
||||||
|
|
||||||
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||||
|
|
||||||
- name: List files in the repository
|
- name: List files in the repository
|
||||||
run: |
|
run: |
|
||||||
ls ${{ gitea.workspace }}
|
ls ${{ gitea.workspace }}
|
||||||
|
|
||||||
- name: Cache pip
|
- name: Compute next version
|
||||||
uses: actions/cache@v3
|
id: versioning
|
||||||
with:
|
run: |
|
||||||
path: /root/.cache/pip
|
latest="${{ vars.VERSION }}"
|
||||||
key: pip
|
next_version=$(echo "$latest" | awk -F. -v OFS=. '{$NF += 1 ; print}')
|
||||||
restore-keys: pip
|
echo "next_version=$next_version" >> $GITHUB_ENV
|
||||||
|
echo "Variables used :"
|
||||||
- name: inject cache into docker
|
echo "------------------------------------------------"
|
||||||
uses: reproducible-containers/buildkit-cache-dance@v3.1.0
|
echo "Next version: $next_version"
|
||||||
with:
|
|
||||||
cache-source: /root/.cache/pip
|
|
||||||
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Login to gitea
|
- name: Login to gitea
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: gitea.tryton.geeraert.eu
|
registry: gitea.geeraert.eu
|
||||||
username: ${{ secrets.USERNAME_GITEA }}
|
username: ${{ secrets.USERNAME_GITEA }}
|
||||||
password: ${{ secrets.PASSWORD_GITEA }}
|
password: ${{ secrets.PASSWORD_GITEA }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build image
|
||||||
uses: docker/build-push-action@v6
|
run: |
|
||||||
with:
|
docker build \
|
||||||
push: true
|
-f infra/production/dockerfile \
|
||||||
#build-contexts: pip_cache=${{steps.vars.outputs.pip-dir}}
|
--build-arg ALLOWED_HOSTS='django.geeraert.eu' \
|
||||||
tags: gitea.tryton.geeraert.eu/pi-ux-ce/django-python:latest
|
--build-arg DEBUG='True' \
|
||||||
cache-from: type=registry,ref=gitea.tryton.geeraert.eu/pi-ux-ce/django-python:buildcache
|
-t gitea.geeraert.eu/pi-ux-ce/django-python:latest \
|
||||||
cache-to: type=registry,ref=gitea.tryton.geeraert.eu/pi-ux-ce/django-python:buildcache,mode=max
|
-t gitea.geeraert.eu/pi-ux-ce/django-python:${{ env.next_version }} \
|
||||||
|
.
|
||||||
|
|
||||||
- name: drop the pod to force pulling the new image
|
- name: Push image
|
||||||
|
run: |
|
||||||
|
docker push gitea.geeraert.eu/pi-ux-ce/django-python:latest
|
||||||
|
docker push gitea.geeraert.eu/pi-ux-ce/django-python:${{ env.next_version }}
|
||||||
|
|
||||||
|
- name: Rollout Django to force pulling the new image
|
||||||
uses: actions-hub/kubectl@master
|
uses: actions-hub/kubectl@master
|
||||||
env:
|
env:
|
||||||
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
|
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
|
||||||
with:
|
with:
|
||||||
args: rollout restart deployment django -n django
|
args: rollout restart deployment django -n django
|
||||||
|
|
||||||
- run: echo "🍏 This job's status is ${{ job.status }}."
|
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||||
|
|
||||||
|
- name: update version in the variable
|
||||||
|
run: |
|
||||||
|
curl -X PUT -H "Content-Type: application/json" \
|
||||||
|
--user ${{ secrets.USERNAME_GITEA }}:${{ secrets.PASSWORD_GITEA }} \
|
||||||
|
https://gitea.geeraert.eu/api/v1/repos/pi-ux-ce/${{ github.event.repository.name }}/actions/variables/VERSION \
|
||||||
|
-d "{\"Value\":\"$next_version\"}"
|
||||||
|
|
||||||
|
- name: backup git for future use
|
||||||
|
run: cp -r ${{ gitea.workspace }} /opt/hostedtoolcache/${{ github.event.repository.name }}/
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
name: Dockerfile testing runner
|
||||||
|
run-name: Building and deploying to testing 🔎
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "testing"
|
||||||
|
paths:
|
||||||
|
- 'infra/testing/dockerfile'
|
||||||
|
tags-ignore:
|
||||||
|
- '*'
|
||||||
|
workflow_dispatch: # Enables the manual run UI button
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Explore-Gitea-Actions:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||||
|
- name: List files in the repository
|
||||||
|
run: |
|
||||||
|
ls ${{ gitea.workspace }}
|
||||||
|
- name: Compute next version
|
||||||
|
id: versioning
|
||||||
|
run: |
|
||||||
|
latest="${{ vars.VERSION_TESTING }}"
|
||||||
|
next_version=$(echo "$latest" | awk -F. -v OFS=. '{$NF += 1 ; print}')
|
||||||
|
echo "next_version=$next_version" >> $GITHUB_ENV
|
||||||
|
echo "Variables used :"
|
||||||
|
echo "------------------------------------------------"
|
||||||
|
echo "Next version: $next_version"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Login to gitea
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: gitea.geeraert.eu
|
||||||
|
username: ${{ secrets.USERNAME_GITEA }}
|
||||||
|
password: ${{ secrets.PASSWORD_GITEA }}
|
||||||
|
|
||||||
|
- name: Build image
|
||||||
|
run: |
|
||||||
|
docker build \
|
||||||
|
-f infra/testing/dockerfile \
|
||||||
|
--build-arg ALLOWED_HOSTS='django-testing.geeraert.eu' \
|
||||||
|
--build-arg DEBUG='True' \
|
||||||
|
--build-arg CACHE_BUST=${{ env.next_version }} \
|
||||||
|
-t gitea.geeraert.eu/pi-ux-ce/django-testing:latest \
|
||||||
|
-t gitea.geeraert.eu/pi-ux-ce/django-testing:${{ env.next_version }} \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Push image
|
||||||
|
run: |
|
||||||
|
docker push gitea.geeraert.eu/pi-ux-ce/django-testing:latest
|
||||||
|
docker push gitea.geeraert.eu/pi-ux-ce/django-testing:${{ env.next_version }}
|
||||||
|
|
||||||
|
- name: update version in the variable
|
||||||
|
run: |
|
||||||
|
curl -X PUT -H "Content-Type: application/json" \
|
||||||
|
--user ${{ secrets.USERNAME_GITEA }}:${{ secrets.PASSWORD_GITEA }} \
|
||||||
|
https://gitea.geeraert.eu/api/v1/repos/pi-ux-ce/${{ github.event.repository.name }}/actions/variables/VERSION_TESTING \
|
||||||
|
-d "{\"Value\":\"$next_version\"}"
|
||||||
|
|
||||||
|
- name: Rollout Django to force pulling the new image
|
||||||
|
uses: actions-hub/kubectl@master
|
||||||
|
env:
|
||||||
|
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
|
||||||
|
with:
|
||||||
|
args: rollout restart deployment django-testing -n django-testing
|
||||||
|
|
||||||
|
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: Gitea Actions Demo
|
name: Gitea Actions Demo
|
||||||
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
|
run-name: Deploying to Prod 🪂🛫
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
name: Gitea Actions Demo
|
||||||
|
run-name: Deploying to testing 🏗️🧪
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "testing"
|
||||||
|
tags-ignore:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Explore-Gitea-Actions:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||||
|
|
||||||
|
- name: Rollout Django to force pulling the new image
|
||||||
|
uses: actions-hub/kubectl@master
|
||||||
|
env:
|
||||||
|
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
|
||||||
|
with:
|
||||||
|
args: rollout restart deployment django-testing -n django-testing
|
||||||
|
|
||||||
|
- run: echo "🍏 This job's status is ${{ job.status }}."
|
||||||
+228
-3
@@ -1,4 +1,229 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[codz]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py.cover
|
||||||
|
*.lcov
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
# Pipfile.lock
|
||||||
|
|
||||||
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
# poetry.lock
|
||||||
|
# poetry.toml
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||||
|
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||||
|
# pdm.lock
|
||||||
|
# pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# pixi
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||||
|
# pixi.lock
|
||||||
|
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||||
|
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||||
|
.pixi/*
|
||||||
|
!.pixi/config.toml
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule*
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
*.rdb
|
||||||
|
*.aof
|
||||||
|
*.pid
|
||||||
|
|
||||||
|
# RabbitMQ
|
||||||
|
mnesia/
|
||||||
|
rabbitmq/
|
||||||
|
rabbitmq-data/
|
||||||
|
|
||||||
|
# ActiveMQ
|
||||||
|
activemq-data/
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.envrc
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
# .idea/
|
||||||
|
|
||||||
|
# Abstra
|
||||||
|
# Abstra is an AI-powered process automation framework.
|
||||||
|
# Ignore directories containing user credentials, local state, and settings.
|
||||||
|
# Learn more at https://abstra.io/docs
|
||||||
|
.abstra/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||||
|
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||||
|
# you could uncomment the following to ignore the entire vscode folder
|
||||||
|
# .vscode/
|
||||||
|
# Temporary file for partial code execution
|
||||||
|
tempCodeRunnerFile.py
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
|
||||||
|
# Marimo
|
||||||
|
marimo/_static/
|
||||||
|
marimo/_lsp/
|
||||||
|
__marimo__/
|
||||||
|
|
||||||
|
# Streamlit
|
||||||
|
.streamlit/secrets.toml
|
||||||
|
|
||||||
*/__pycache__/*
|
*/__pycache__/*
|
||||||
*/.idea
|
*/.idea/*
|
||||||
venv/*
|
*/venv/*
|
||||||
*__pycache__*
|
*/.env/*
|
||||||
|
Webcal-python/*
|
||||||
|
.idea/*
|
||||||
|
django_code/db.sqlite3
|
||||||
|
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Namespace
|
|
||||||
metadata:
|
|
||||||
name: django-python
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: django-webserver
|
|
||||||
namespace: django-python
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: django-python
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: django-python
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: django-python
|
|
||||||
image: gitea.tryton.geeraert.eu/pi-ux-ce/django-python:latest
|
|
||||||
imagePullPolicy: Always
|
|
||||||
ports:
|
|
||||||
- containerPort: 8000
|
|
||||||
name: webserver-port
|
|
||||||
volumeMounts:
|
|
||||||
## - name: django-python-code
|
|
||||||
# mountPath: /code
|
|
||||||
- name: servarr-data
|
|
||||||
mountPath: /data
|
|
||||||
readOnly: true
|
|
||||||
- name: secret-kubeconfig
|
|
||||||
mountPath: /kubeconfig
|
|
||||||
|
|
||||||
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpu: 100m
|
|
||||||
memory: 200Mi
|
|
||||||
volumes:
|
|
||||||
- name: django-python-code
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: django-python-code
|
|
||||||
- name: servarr-data
|
|
||||||
hostPath:
|
|
||||||
path: /data
|
|
||||||
- name: secret-kubeconfig
|
|
||||||
secret:
|
|
||||||
defaultMode: 420
|
|
||||||
secretName: kubeconfig
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: webserver
|
|
||||||
namespace: django-python
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 8000
|
|
||||||
protocol: TCP
|
|
||||||
selector:
|
|
||||||
app: django-python
|
|
||||||
@@ -1,13 +1,69 @@
|
|||||||
=======
|
=======
|
||||||
# Django_kube
|
# Django_kube
|
||||||
test
|
|
||||||
|
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
### Database migration
|
||||||
|
|
||||||
|
```
|
||||||
|
python django_code/manage.py makemigrations
|
||||||
|
python django_code/manage.py makemigrations redirect
|
||||||
|
python django_code/manage.py makemigrations cloudmanager
|
||||||
|
python django_code/manage.py makemigrations simpsons
|
||||||
|
python django_code/manage.py makemigrations job
|
||||||
|
python django_code/manage.py makemigrations telegram
|
||||||
|
python django_code/manage.py makemigrations podcast
|
||||||
|
python django_code/manage.py makemigrations streaming
|
||||||
|
|
||||||
|
python django_code/manage.py migrate
|
||||||
|
python django_code/manage.py migrate --database=cloudmanager_db
|
||||||
|
python django_code/manage.py migrate --database=simpsons_db
|
||||||
|
python django_code/manage.py migrate --database=redirect_db
|
||||||
|
python django_code/manage.py migrate --database=job_db
|
||||||
|
python django_code/manage.py migrate --database=telegram_db
|
||||||
|
python django_code/manage.py migrate --database=podcast_db
|
||||||
|
python django_code/manage.py migrate --database=streaming_db
|
||||||
|
```
|
||||||
|
### Database debug
|
||||||
|
|
||||||
|
```
|
||||||
|
create database django;
|
||||||
|
create database redirect;
|
||||||
|
create database cloudmanager;
|
||||||
|
create database simpsons;
|
||||||
|
create database job;
|
||||||
|
create database telegram;
|
||||||
|
create database podcast;
|
||||||
|
create database streaming;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
drop database redirect;
|
||||||
|
drop database cloudmanager;
|
||||||
|
drop database simpsons;
|
||||||
|
drop database job;
|
||||||
|
drop database telegram;
|
||||||
|
drop database podcast;
|
||||||
|
drop database streaming;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Setup virtualenv variables
|
||||||
|
edit venv/bin/activate or .env/bin/activate
|
||||||
|
|
||||||
|
and add the following code
|
||||||
|
```
|
||||||
|
export DB_HOST=localhost
|
||||||
|
export DB_PORT=5432
|
||||||
|
export DB_USERNAME=postgres
|
||||||
|
export DB_PASSWORD=example
|
||||||
|
export DB_DATABASE=cloudmanager
|
||||||
|
export CUSTOM_DB_DATABASE=cloudmanager
|
||||||
|
export ALLOWED_HOSTS="0.0.0.0,localhost,127.0.0.1"
|
||||||
|
export DEBUG=true
|
||||||
|
export bitwarden_access_token="PROVIDED IN BITWARDEN ADMIN INTERFACE"
|
||||||
|
export bitwarden_organization_id=""
|
||||||
|
```
|
||||||
|
|
||||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
|
||||||
|
|
||||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
|
||||||
|
|
||||||
## Add your files
|
## Add your files
|
||||||
|
|
||||||
@@ -16,14 +72,14 @@ Already a pro? Just edit this README.md and make it your own. Want to make it ea
|
|||||||
|
|
||||||
```
|
```
|
||||||
cd existing_repo
|
cd existing_repo
|
||||||
git remote add origin https://gitlab.tryton.geeraert.eu/pierre/django_kube.git
|
git remote add origin https://gitea.geeraert.eu/pi-ux-ce/Django_kube.git
|
||||||
git branch -M main
|
git branch -M main
|
||||||
git push -uf origin main
|
git push -uf origin main
|
||||||
```
|
```
|
||||||
|
|
||||||
## Integrate with your tools
|
## Integrate with your tools
|
||||||
|
|
||||||
- [ ] [Set up project integrations](https://gitlab.tryton.geeraert.eu/pierre/django_kube/-/settings/integrations)
|
- [ ] [Set up project integrations](https://gitlab.geeraert.eu/pierre/django_kube/-/settings/integrations)
|
||||||
|
|
||||||
## Collaborate with your team
|
## Collaborate with your team
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
import requests
|
||||||
|
import hashlib
|
||||||
|
from apps.bitwarden.utils import bitwardenUtils
|
||||||
|
import os
|
||||||
|
|
||||||
|
class betaserieUtils():
|
||||||
|
url = "https://api.betaseries.com/members/auth"
|
||||||
|
|
||||||
|
username_UID="7bc7ebd2-9c95-487f-9ba2-b47301591ef0"
|
||||||
|
password_UID="262c3246-203b-44e0-854b-b47301599730"
|
||||||
|
token_UID="2cf4be0f-f26f-473f-b8f1-b473016139e4"
|
||||||
|
|
||||||
|
#Adding __ to make the variable private and can't be access outside the class,
|
||||||
|
# only by the class itself ot the subclass
|
||||||
|
|
||||||
|
__bitwarden_access_token = os.environ.get('bitwarden_access_token')
|
||||||
|
__bitwarden_organization_id = os.environ.get('bitwarden_organization_id')
|
||||||
|
|
||||||
|
bw = bitwardenUtils(__bitwarden_access_token,__bitwarden_organization_id)
|
||||||
|
|
||||||
|
__betaserie_username = bw.read_value_secret(username_UID)
|
||||||
|
__betaserie_md5_password = bw.read_value_secret(password_UID)
|
||||||
|
__betaserie_apikey = bw.read_value_secret(token_UID)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'login': __betaserie_username, # username or email
|
||||||
|
'password': __betaserie_md5_password # MD5 hashed password
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'X-BetaSeries-Key': __betaserie_apikey,
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, data=payload)
|
||||||
|
|
||||||
|
#now set with the correct value
|
||||||
|
__betaserie_token = response.json()['token']
|
||||||
|
|
||||||
|
#set the __betaserie_token to the doct headers now
|
||||||
|
headers.update({'X-BetaSeries-Token': __betaserie_token})
|
||||||
|
|
||||||
|
def status_code(self):
|
||||||
|
print("Status code:", self.response.status_code)
|
||||||
|
print("Response:", self.response.json())
|
||||||
|
|
||||||
|
|
||||||
|
def identify_serie(self,serie_name,verbose=False):
|
||||||
|
#
|
||||||
|
# Usage
|
||||||
|
# show_id = beta.identify_serie("The simpsons")
|
||||||
|
# show_id = beta.identify_serie("The simpsons",verbose=True)
|
||||||
|
#
|
||||||
|
url = "https://api.betaseries.com/shows/search?title="+serie_name
|
||||||
|
|
||||||
|
response = requests.request("GET", url, headers=self.headers, data=self.payload)
|
||||||
|
if verbose:
|
||||||
|
print("Url request: "+str(url))
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
show_id = response.json()['shows'][0]['id']
|
||||||
|
|
||||||
|
return show_id
|
||||||
|
|
||||||
|
def poster_serie(self,serie_name,verbose=False):
|
||||||
|
#
|
||||||
|
# Usage
|
||||||
|
# poster_url = beta.poster_serie("The simpsons")
|
||||||
|
# poster_url = beta.poster_serie("The simpsons",verbose=True)
|
||||||
|
#
|
||||||
|
url = "https://api.betaseries.com/shows/search?title="+serie_name
|
||||||
|
|
||||||
|
response = requests.request("GET", url, headers=self.headers, data=self.payload)
|
||||||
|
if verbose:
|
||||||
|
print("Url request: "+str(url))
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
poster_url = response.json()['shows'][0]['images']['show']
|
||||||
|
|
||||||
|
return poster_url
|
||||||
|
|
||||||
|
|
||||||
|
def identify_episode(self,show_id,episode_number,verbose=False):
|
||||||
|
#
|
||||||
|
# Usage
|
||||||
|
# episode_id,episode_seen = beta.identify_episode(show_id,"S01E01",True)
|
||||||
|
#
|
||||||
|
url = "https://api.betaseries.com/episodes/search?show_id="+str(show_id)+"&number="+str(episode_number)
|
||||||
|
|
||||||
|
response = requests.request("GET", url, headers=self.headers, data=self.payload)
|
||||||
|
|
||||||
|
episode_id = response.json()['episode']['id']
|
||||||
|
episode_seen = response.json()['episode']['user']['seen']
|
||||||
|
if verbose:
|
||||||
|
print("Url request: "+str(url))
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
return episode_id,episode_seen
|
||||||
|
|
||||||
|
def mark_episodes_watched(self,episode_id,verbose=False):
|
||||||
|
#
|
||||||
|
# Usage
|
||||||
|
# response = beta.mark_episodes_watched(episode_id,True)
|
||||||
|
#
|
||||||
|
url = "https://api.betaseries.com/episodes/watched?id="+str(episode_id)+"&bulk=false"
|
||||||
|
|
||||||
|
response = requests.request("POST", url, headers=self.headers, data=self.payload)
|
||||||
|
if verbose:
|
||||||
|
print("Url request: "+str(url))
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
return response.status_code
|
||||||
|
|
||||||
|
def unmark_episodes_watched(self,episode_id,verbose=False):
|
||||||
|
#
|
||||||
|
# Usage
|
||||||
|
# response = beta.unmark_episodes_watched(episode_id,True)
|
||||||
|
#
|
||||||
|
url = "https://api.betaseries.com/episodes/watched?id="+str(episode_id)
|
||||||
|
|
||||||
|
response = requests.request("DELETE", url, headers=self.headers, data=self.payload)
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print("Url request: "+str(url))
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
return response.status_code
|
||||||
|
|
||||||
|
def series_information(self,show_id,verbose=False):
|
||||||
|
#
|
||||||
|
# Usage
|
||||||
|
#
|
||||||
|
url = "https://api.betaseries.com/shows/display?id="+str(show_id)
|
||||||
|
response = requests.request("GET", url, headers=self.headers, data=self.payload)
|
||||||
|
|
||||||
|
seasons_details = response.json()['show']['seasons_details']
|
||||||
|
|
||||||
|
#checking if the first season is season 0, and if so remove this season
|
||||||
|
if (seasons_details[0]['number']==0):
|
||||||
|
season_0_to_remove = seasons_details[0]
|
||||||
|
|
||||||
|
if verbose : print(season_0_to_remove)
|
||||||
|
|
||||||
|
seasons_details.remove(season_0_to_remove)
|
||||||
|
|
||||||
|
maximum_number_seasons = len(seasons_details)
|
||||||
|
|
||||||
|
if verbose : print("maximum_number_seasons: "+str(maximum_number_seasons))
|
||||||
|
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
print("Url request: "+str(url))
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
return seasons_details,maximum_number_seasons
|
||||||
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
from bitwarden_sdk import BitwardenClient, DeviceType, client_settings_from_dict
|
||||||
|
|
||||||
|
|
||||||
|
class bitwardenUtils():
|
||||||
|
#documentation
|
||||||
|
#https://github.com/external-secrets/bitwarden-sdk-server
|
||||||
|
state_path = "/tmp/state_file.txt"
|
||||||
|
client = BitwardenClient(
|
||||||
|
client_settings_from_dict(
|
||||||
|
{
|
||||||
|
"apiUrl": os.getenv("API_URL", "https://bitwarden.geeraert.eu/api"),
|
||||||
|
"deviceType": DeviceType.SDK,
|
||||||
|
"identityUrl": os.getenv("IDENTITY_URL", "https://bitwarden.geeraert.eu/identity"),
|
||||||
|
"userAgent": "Python",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def verbose(self):
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, __access_token, __organization_id):
|
||||||
|
self.__access_token = __access_token
|
||||||
|
self.__organization_id = __organization_id
|
||||||
|
self.client.auth().login_access_token(self.__access_token, self.state_path)
|
||||||
|
|
||||||
|
def create_project(self,project_name):
|
||||||
|
project = self.client.projects().create(self.__organization_id, project_name)
|
||||||
|
return project.data.id
|
||||||
|
|
||||||
|
def generate_strong_password(self):
|
||||||
|
# Note: using the generator does not require authentication with a server
|
||||||
|
return self.client.generators().generate() # using default params
|
||||||
|
|
||||||
|
def create_secret(self,project_id,secret_name,secret_value,description="description"):
|
||||||
|
secret = self.client.secrets().create(
|
||||||
|
self.__organization_id,
|
||||||
|
secret_name,
|
||||||
|
secret_value,
|
||||||
|
description,
|
||||||
|
[project_id],
|
||||||
|
)
|
||||||
|
return secret.data.id
|
||||||
|
|
||||||
|
|
||||||
|
def read_value_secret(self,secret_id):
|
||||||
|
return self.client.secrets().get_by_ids([secret_id]).data.data[0].value
|
||||||
|
|
||||||
|
def read_value_secrets(self,list_secret_id):
|
||||||
|
if not(isinstance(list_secret_id, list)):
|
||||||
|
print("this is not a list")
|
||||||
|
return 1
|
||||||
|
list_secret_value = []
|
||||||
|
for secret_value in self.client.secrets().get_by_ids(list_secret_id).data.data:
|
||||||
|
list_secret_value.append(secret_value.value)
|
||||||
|
return list_secret_value
|
||||||
|
|
||||||
|
def delete_secrets(self,list_secret_id):
|
||||||
|
if not(isinstance(list_secret_id, list)):
|
||||||
|
print("this is not a list")
|
||||||
|
return 1
|
||||||
|
try:
|
||||||
|
self.client.secrets().delete(list_secret_id)
|
||||||
|
status=0
|
||||||
|
except:
|
||||||
|
print("Cannot delete the secrets")
|
||||||
|
status=1
|
||||||
|
return status
|
||||||
|
|
||||||
|
def delete_projects(self,list_project_id):
|
||||||
|
if not(isinstance(list_project_id, list)):
|
||||||
|
print("this is not a list")
|
||||||
|
return 1
|
||||||
|
try:
|
||||||
|
self.client.projects().delete(list_project_id)
|
||||||
|
status=0
|
||||||
|
except:
|
||||||
|
print("Cannot delete the project")
|
||||||
|
status=1
|
||||||
|
return status
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
from django.contrib import admin,messages
|
||||||
|
from django.utils.translation import ngettext
|
||||||
|
from .models import Deployment_Data,Schedule_Day_Data,Schedule_Week_Data,Namespace_Data,Ingress_Data
|
||||||
|
from .utils import import_namespace,import_deployment,generate_default_day_schedule,generate_default_week_schedule,Check_server_supposed_XXX,retrieve_and_apply
|
||||||
|
from apps.kubernetes_connection.utils import scale_up,scale_down
|
||||||
|
from admin_extra_buttons.api import button
|
||||||
|
from core.admin import UniversalModelAdmin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(description="scale up")
|
||||||
|
def scale_up_deploy(modeladmin, request, queryset):
|
||||||
|
for query in queryset.values():
|
||||||
|
scale_up(namespace_name=query['namespace'],deploy_name=query['name'],replicas=query['replicas'])
|
||||||
|
modeladmin.message_user(
|
||||||
|
request,
|
||||||
|
ngettext(
|
||||||
|
"%d server was successfully scaled up.",
|
||||||
|
"%d servers were successfully scaled up.",
|
||||||
|
queryset.values().count(),
|
||||||
|
)
|
||||||
|
% queryset.values().count(),
|
||||||
|
messages.SUCCESS,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(description="scale down")
|
||||||
|
def scale_down_deploy(modeladmin, request, queryset):
|
||||||
|
for query in queryset.values():
|
||||||
|
scale_down(namespace_name=query['namespace'],deploy_name=query['name'])
|
||||||
|
modeladmin.message_user(
|
||||||
|
request,
|
||||||
|
ngettext(
|
||||||
|
"%d server was successfully scaled down.",
|
||||||
|
"%d servers were successfully scaled down.",
|
||||||
|
queryset.values().count(),
|
||||||
|
)
|
||||||
|
% queryset.values().count(),
|
||||||
|
messages.SUCCESS,
|
||||||
|
)
|
||||||
|
|
||||||
|
@admin.action(description="Expected False")
|
||||||
|
def Check_server_supposed_False(modeladmin, request, queryset):
|
||||||
|
servers_supposed_false = Check_server_supposed_XXX(False)
|
||||||
|
for server in servers_supposed_false:
|
||||||
|
messages.add_message(request, messages.INFO, server)
|
||||||
|
|
||||||
|
@admin.action(description="Expected True")
|
||||||
|
def Check_server_supposed_true(modeladmin, request, queryset):
|
||||||
|
servers_supposed_false = Check_server_supposed_XXX(True)
|
||||||
|
for server in servers_supposed_false:
|
||||||
|
messages.add_message(request, messages.INFO, server)
|
||||||
|
|
||||||
|
|
||||||
|
class ActiveAtHourFilter(admin.SimpleListFilter):
|
||||||
|
title = 'Active at hour'
|
||||||
|
parameter_name = 'active_at_hour'
|
||||||
|
|
||||||
|
def lookups(self, request, model_admin):
|
||||||
|
return [(str(h), f'{h:02d}:00') for h in range(24)]
|
||||||
|
|
||||||
|
def queryset(self, request, queryset):
|
||||||
|
if self.value() is not None:
|
||||||
|
hour = self.value()
|
||||||
|
return queryset.filter(**{f'schedule_day__state_at_{hour}': True})
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Deployment_Data)
|
||||||
|
class DeploymentDataAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ('name', 'namespace', 'schedule_week', 'schedule_day', 'replicas')
|
||||||
|
list_filter = (ActiveAtHourFilter,)
|
||||||
|
actions = [Check_server_supposed_False,Check_server_supposed_true,scale_up_deploy,scale_down_deploy]
|
||||||
|
ordering = ('name',)
|
||||||
|
@button()
|
||||||
|
def retrieve_and_apply(self, request):
|
||||||
|
# your business logic here
|
||||||
|
retrieve_and_apply()
|
||||||
|
self.message_user(request, 'Operation started')
|
||||||
|
|
||||||
|
@button()
|
||||||
|
def import_deployment(self, request):
|
||||||
|
# your business logic here
|
||||||
|
import_deployment()
|
||||||
|
self.message_user(request, 'Deployments imported')
|
||||||
|
|
||||||
|
@admin.register(Schedule_Day_Data)
|
||||||
|
class ScheduleDayAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ['name_schedule'] + [f'state_at_{h}' for h in range(24)]
|
||||||
|
@button()
|
||||||
|
def generate_default_day_schedule_admin(self, request):
|
||||||
|
generate_default_day_schedule()
|
||||||
|
generate_default_week_schedule()
|
||||||
|
self.message_user(request, 'Created default schedules')
|
||||||
|
|
||||||
|
@admin.register(Schedule_Week_Data)
|
||||||
|
class ScheduleWeekAdmin(UniversalModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
'name_schedule',
|
||||||
|
'state_Monday', 'state_Tuesday', 'state_Wednesday',
|
||||||
|
'state_Thursday', 'state_Friday', 'state_Saturday', 'state_Sunday',
|
||||||
|
)
|
||||||
|
@button()
|
||||||
|
def generate_default_day_schedule_admin(self, request):
|
||||||
|
generate_default_day_schedule()
|
||||||
|
generate_default_week_schedule()
|
||||||
|
self.message_user(request, 'Created default schedules')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Namespace_Data)
|
||||||
|
class NamespaceAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ('namespace',)
|
||||||
|
|
||||||
|
|
||||||
|
@button()
|
||||||
|
def import_namespace(self, request):
|
||||||
|
# your business logic here
|
||||||
|
import_namespace()
|
||||||
|
self.message_user(request, 'Namespaces imported')
|
||||||
|
|
||||||
|
@admin.register(Ingress_Data)
|
||||||
|
class IngressAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ('url','namespace')
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
class CloudmanagerConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'apps.cloudmanager'
|
||||||
|
label = 'cloudmanager'
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
class sql:
|
||||||
|
url = 'localhost'
|
||||||
|
port = 5432
|
||||||
|
user = 'postgres'
|
||||||
|
password = 'example'
|
||||||
|
database = 'cloudmanager'
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
#import psycopg2
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.views.decorators.http import require_POST
|
||||||
|
from apps.kubernetes_connection import apps as kubernetes_connection
|
||||||
|
import datetime
|
||||||
|
from apps.cloudmanager import credentials
|
||||||
|
import os
|
||||||
|
|
||||||
|
def hello(request):
|
||||||
|
kubernetes_connection.echoHello();
|
||||||
|
return HttpResponse('<h1>Hello cmm !</h1>')
|
||||||
|
|
||||||
|
def DB_generation(host_in,port_in,user_in,password_in,db_in):
|
||||||
|
db = psycopg2.connect(host=host_in, port=port_in, user=user_in, password=password_in,database=db_in)
|
||||||
|
return db
|
||||||
|
|
||||||
|
@require_POST
|
||||||
|
def change_schedule(request):
|
||||||
|
# HTMX sends these via standard POST data
|
||||||
|
schedule_id = request.POST.get('schedule_id')
|
||||||
|
server_name = request.POST.get('server_name')
|
||||||
|
|
||||||
|
if not schedule_id or not server_name:
|
||||||
|
return HttpResponse("<span style='color: red;'>Missing parameters.</span>", status=400)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# --- Your Core Logic Here ---
|
||||||
|
# e.g., Server.objects.filter(name=server_name).update(schedule_id=schedule_id)
|
||||||
|
print(f"Updating {server_name} to schedule profile {schedule_id}")
|
||||||
|
|
||||||
|
# Return a success message that will instantly inject into the server's status div
|
||||||
|
return HttpResponse("<span style='color: green;'>✓ Updated successfully!</span>")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return HttpResponse(f"<span style='color: red;'>Error: {str(e)}</span>", status=500)
|
||||||
|
|
||||||
|
def Launch_sql_query(sql,db):
|
||||||
|
# prepare a cursor object using cursor() method
|
||||||
|
cursor = db.cursor()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Execute the SQL command
|
||||||
|
cursor.execute(sql)
|
||||||
|
# Fetch all the rows in a list of lists.
|
||||||
|
results = cursor.fetchall()
|
||||||
|
result_machine = []
|
||||||
|
#result_machine_type = []
|
||||||
|
for row in results:
|
||||||
|
result_machine_type = []
|
||||||
|
namespace = row[0]
|
||||||
|
name = row[1]
|
||||||
|
replicas = row[2]
|
||||||
|
|
||||||
|
result_machine_type.append(namespace)
|
||||||
|
result_machine_type.append(name)
|
||||||
|
result_machine_type.append(replicas)
|
||||||
|
result_machine.append(result_machine_type)
|
||||||
|
return result_machine
|
||||||
|
|
||||||
|
except:
|
||||||
|
print ("Error: unable to fetch data")
|
||||||
|
|
||||||
|
|
||||||
|
#Return the day of the week as an integer, where Monday is 0 and Sunday is 6.
|
||||||
|
def Give_current_weekday():
|
||||||
|
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday','Saturday', 'Sunday']
|
||||||
|
weekday = days[datetime.datetime.today().weekday()]
|
||||||
|
return weekday
|
||||||
|
|
||||||
|
def Give_current_hour():
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
return now.hour
|
||||||
|
|
||||||
|
|
||||||
|
def Check_server_supposed_XXX(generated_db_in,wanted_status,Wanted_hour,Wanted_day):
|
||||||
|
sql_in=""
|
||||||
|
if wanted_status == "up":
|
||||||
|
sql_in = "select machine.namespace, machine.name, machine.replicas from scenario_hour,machine ,scenario_day_of_week where state_at_" + str(Wanted_hour) + "='1' and state_" + str(Wanted_day) + "='1' and machine.hour_behaviour_id=scenario_hour.id_scenario and machine.day_behaviour_id=scenario_day_of_week.id_scenario;"
|
||||||
|
elif wanted_status == "down":
|
||||||
|
sql_in = "select machine.namespace, machine.name, machine.replicas from scenario_hour,machine ,scenario_day_of_week where not(state_at_" + str(Wanted_hour) + "='1' and state_" + str(Wanted_day) + "='1') and machine.hour_behaviour_id=scenario_hour.id_scenario and machine.day_behaviour_id=scenario_day_of_week.id_scenario;"
|
||||||
|
else:
|
||||||
|
print("error value")
|
||||||
|
print(sql_in)
|
||||||
|
return_value = Launch_sql_query(sql_in, generated_db_in)
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
def Is_the_server_already_wanted_state(id_machine, wanted_state,instance_type):
|
||||||
|
#stopped/running
|
||||||
|
bool_result = ""
|
||||||
|
proxmox = function.proxmox_connection(credentials.proxmox.zeus.url_proxmox,credentials.proxmox.zeus.user,credentials.proxmox.zeus.password)
|
||||||
|
if str(function.check_state_mix(id_machine,wanted_state,proxmox,instance_type)) == str(wanted_state):
|
||||||
|
bool_result = True
|
||||||
|
else:
|
||||||
|
bool_result = False
|
||||||
|
return bool_result
|
||||||
|
|
||||||
|
def all_operations(request,wanted_state,list_machine):
|
||||||
|
for machine_target in list_machine:
|
||||||
|
print(machine_target[1])
|
||||||
|
|
||||||
|
info_to_display = ""
|
||||||
|
if wanted_state == "up":
|
||||||
|
kubernetes_connection.scale_up(request,namespace_name=machine_target[0],deploy_name=machine_target[1],replicas=machine_target[2]);
|
||||||
|
elif wanted_state == "down":
|
||||||
|
kubernetes_connection.scale_down(request,namespace_name=machine_target[0],deploy_name=machine_target[1]);
|
||||||
|
else:
|
||||||
|
print("Incorrect wanted state")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# if not(Is_the_server_already_wanted_state(machine_target[0], wanted_state,machine_target[1])):
|
||||||
|
# function.action(False,machine_target[0],operation_to_perform,machine_target[1])
|
||||||
|
# print(str(machine_target[0])+" is now "+str(wanted_state))
|
||||||
|
# elif Is_the_server_already_wanted_state(machine_target[0], wanted_state,machine_target[1]):
|
||||||
|
# info_to_display = "operation already performed for "+machine_target[2]
|
||||||
|
# print(info_to_display)
|
||||||
|
#return info_to_display
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def main(request):
|
||||||
|
|
||||||
|
#get credentials from the env
|
||||||
|
db_host = os.environ.get('DB_HOST')
|
||||||
|
db_port = os.environ.get('DB_PORT')
|
||||||
|
db_user = os.environ.get('DB_USERNAME')
|
||||||
|
db_password = os.environ.get('DB_PASSWORD')
|
||||||
|
db_name = os.environ.get('CUSTOM_DB_DATABASE',os.environ.get('DB_DATABASE'))
|
||||||
|
|
||||||
|
generated_db = DB_generation(db_host, db_port, db_user, db_password,db_name)
|
||||||
|
##operation:
|
||||||
|
## Server(s) supposed to be UP
|
||||||
|
|
||||||
|
list_servers_up = Check_server_supposed_XXX(generated_db, "up", Give_current_hour(),Give_current_weekday())
|
||||||
|
print("------------------------------------------")
|
||||||
|
print("-----------------UP-----------------------")
|
||||||
|
print("------------------------------------------")
|
||||||
|
print(list_servers_up)
|
||||||
|
print(all_operations(request,"up", list_servers_up))
|
||||||
|
|
||||||
|
|
||||||
|
## Server(s) supposed to be DOWN
|
||||||
|
list_servers_down = Check_server_supposed_XXX(generated_db, "down", Give_current_hour(),Give_current_weekday())
|
||||||
|
|
||||||
|
print("------------------------------------------")
|
||||||
|
print("----------------DOWN----------------------")
|
||||||
|
print("------------------------------------------")
|
||||||
|
print(list_servers_down)
|
||||||
|
print(all_operations(request,"down",list_servers_down))
|
||||||
|
|
||||||
|
|
||||||
|
# disconnect from server
|
||||||
|
generated_db.close()
|
||||||
|
|
||||||
|
#print(Is_the_server_already_wanted_state(112, "stopped"))
|
||||||
|
return HttpResponse('<h1>CMM executed!</h1>')
|
||||||
|
|
||||||
|
"""
|
||||||
|
TO DO:
|
||||||
|
EXTRACT TYPE OF MACHINE
|
||||||
|
CREATE FUNCTION TO CHECK IF A MACHINE IS ALREADY DOWN OR NOT
|
||||||
|
ADD FIELD IN SQL WITH PROJECT AND PUT DESCRIPTION -> ATTACH MACHINE TO PROJECT
|
||||||
|
|
||||||
|
"""
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-06-22 20:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Namespace_Data',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('namespace', models.CharField(max_length=100)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'namespace',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Schedule_Day_Data',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name_schedule', models.CharField(max_length=100, unique=True)),
|
||||||
|
('state_at_0', models.BooleanField()),
|
||||||
|
('state_at_1', models.BooleanField()),
|
||||||
|
('state_at_2', models.BooleanField()),
|
||||||
|
('state_at_3', models.BooleanField()),
|
||||||
|
('state_at_4', models.BooleanField()),
|
||||||
|
('state_at_5', models.BooleanField()),
|
||||||
|
('state_at_6', models.BooleanField()),
|
||||||
|
('state_at_7', models.BooleanField()),
|
||||||
|
('state_at_8', models.BooleanField()),
|
||||||
|
('state_at_9', models.BooleanField()),
|
||||||
|
('state_at_10', models.BooleanField()),
|
||||||
|
('state_at_11', models.BooleanField()),
|
||||||
|
('state_at_12', models.BooleanField()),
|
||||||
|
('state_at_13', models.BooleanField()),
|
||||||
|
('state_at_14', models.BooleanField()),
|
||||||
|
('state_at_15', models.BooleanField()),
|
||||||
|
('state_at_16', models.BooleanField()),
|
||||||
|
('state_at_17', models.BooleanField()),
|
||||||
|
('state_at_18', models.BooleanField()),
|
||||||
|
('state_at_19', models.BooleanField()),
|
||||||
|
('state_at_20', models.BooleanField()),
|
||||||
|
('state_at_21', models.BooleanField()),
|
||||||
|
('state_at_22', models.BooleanField()),
|
||||||
|
('state_at_23', models.BooleanField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'schedule_day',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Schedule_Week_Data',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name_schedule', models.CharField(max_length=100, unique=True)),
|
||||||
|
('state_Monday', models.BooleanField()),
|
||||||
|
('state_Tuesday', models.BooleanField()),
|
||||||
|
('state_Wednesday', models.BooleanField()),
|
||||||
|
('state_Thursday', models.BooleanField()),
|
||||||
|
('state_Friday', models.BooleanField()),
|
||||||
|
('state_Saturday', models.BooleanField()),
|
||||||
|
('state_Sunday', models.BooleanField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'schedule_week',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Deployment_Data',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=100)),
|
||||||
|
('namespace', models.CharField(max_length=100)),
|
||||||
|
('replicas', models.IntegerField()),
|
||||||
|
('schedule_day', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cloudmanager.schedule_day_data')),
|
||||||
|
('schedule_week', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cloudmanager.schedule_week_data')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'machine',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-09 12:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='actual_replica',
|
||||||
|
field=models.IntegerField(default=1),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-09-13 15:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0002_deployment_data_actual_replica'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateField(blank=True, null=True, verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 13:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0003_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 14:14
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0004_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(2026, 9, 14, 14, 14, 29, 566084, tzinfo=datetime.timezone.utc), verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 14:14
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0005_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(2026, 9, 14, 14, 14, 33, 642627, tzinfo=datetime.timezone.utc), verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 14:35
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0006_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(2026, 9, 14, 14, 35, 47, 473312, tzinfo=datetime.timezone.utc), verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 14:35
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0007_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(2026, 9, 14, 14, 35, 51, 657797, tzinfo=datetime.timezone.utc), verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 14:43
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0008_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(2026, 9, 14, 14, 43, 26, 985719, tzinfo=datetime.timezone.utc), verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 14:43
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0009_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(2026, 9, 14, 14, 43, 31, 55115, tzinfo=datetime.timezone.utc), verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 14:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0010_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-14 15:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0011_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='deployment_data',
|
||||||
|
name='do_not_touch_until',
|
||||||
|
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='do_not_touch_until'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-21 16:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0012_alter_deployment_data_do_not_touch_until'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Ingress_Data',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('url', models.CharField(max_length=100)),
|
||||||
|
('namespace', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='cloudmanager.namespace_data')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-21 21:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('cloudmanager', '0013_ingress_data'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ingress_data',
|
||||||
|
name='namespace',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
class Schedule_Week_Data(models.Model):
|
||||||
|
name_schedule = models.CharField(max_length=100,unique=True)
|
||||||
|
state_Monday = models.BooleanField()
|
||||||
|
state_Tuesday = models.BooleanField()
|
||||||
|
state_Wednesday = models.BooleanField()
|
||||||
|
state_Thursday = models.BooleanField()
|
||||||
|
state_Friday = models.BooleanField()
|
||||||
|
state_Saturday = models.BooleanField()
|
||||||
|
state_Sunday = models.BooleanField()
|
||||||
|
class Meta:
|
||||||
|
db_table = 'schedule_week'
|
||||||
|
def __str__(self):
|
||||||
|
return self.name_schedule
|
||||||
|
|
||||||
|
class Schedule_Day_Data(models.Model):
|
||||||
|
name_schedule = models.CharField(max_length=100,unique=True)
|
||||||
|
state_at_0 = models.BooleanField()
|
||||||
|
state_at_1 = models.BooleanField()
|
||||||
|
state_at_2 = models.BooleanField()
|
||||||
|
state_at_3 = models.BooleanField()
|
||||||
|
state_at_4 = models.BooleanField()
|
||||||
|
state_at_5 = models.BooleanField()
|
||||||
|
state_at_6 = models.BooleanField()
|
||||||
|
state_at_7 = models.BooleanField()
|
||||||
|
state_at_8 = models.BooleanField()
|
||||||
|
state_at_9 = models.BooleanField()
|
||||||
|
state_at_10 = models.BooleanField()
|
||||||
|
state_at_11 = models.BooleanField()
|
||||||
|
state_at_12 = models.BooleanField()
|
||||||
|
state_at_13 = models.BooleanField()
|
||||||
|
state_at_14 = models.BooleanField()
|
||||||
|
state_at_15 = models.BooleanField()
|
||||||
|
state_at_16 = models.BooleanField()
|
||||||
|
state_at_17 = models.BooleanField()
|
||||||
|
state_at_18 = models.BooleanField()
|
||||||
|
state_at_19 = models.BooleanField()
|
||||||
|
state_at_20 = models.BooleanField()
|
||||||
|
state_at_21 = models.BooleanField()
|
||||||
|
state_at_22 = models.BooleanField()
|
||||||
|
state_at_23 = models.BooleanField()
|
||||||
|
class Meta:
|
||||||
|
db_table = 'schedule_day'
|
||||||
|
def __str__(self):
|
||||||
|
return self.name_schedule
|
||||||
|
|
||||||
|
class Deployment_Data(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
namespace = models.CharField(max_length=100)
|
||||||
|
schedule_week = models.ForeignKey(Schedule_Week_Data,null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
|
schedule_day = models.ForeignKey(Schedule_Day_Data,null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
|
replicas = models.IntegerField()
|
||||||
|
actual_replica = models.IntegerField()
|
||||||
|
do_not_touch_until = models.DateTimeField('do_not_touch_until', default=timezone.now)
|
||||||
|
class Meta:
|
||||||
|
db_table = 'machine'
|
||||||
|
|
||||||
|
class Namespace_Data(models.Model):
|
||||||
|
namespace = models.CharField(max_length=100)
|
||||||
|
#deployments = models.ForeignKey(Schedule_Week_Data,null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
|
class Meta:
|
||||||
|
db_table = 'namespace'
|
||||||
|
def __str__(self):
|
||||||
|
return self.namespace
|
||||||
|
|
||||||
|
class Ingress_Data(models.Model):
|
||||||
|
url = models.CharField(max_length=100)
|
||||||
|
namespace = models.CharField(max_length=100,null=True, blank=True)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for django_code project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import hello,import_namespace_view,retrieve_and_apply_view,scale_up_gui,scale_down_gui,add_ingress,delete_ingress
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
################### cloudmanager ###################
|
||||||
|
path('', hello, name='hello'),
|
||||||
|
path('import_namespace', import_namespace_view, name='import_namespace'),
|
||||||
|
path('retrieve_and_apply_view', retrieve_and_apply_view, name='retrieve_and_apply_view'),
|
||||||
|
path('scale_up/<str:namespace_name>/<str:deploy_name>', scale_up_gui),
|
||||||
|
path('scale_down/<str:namespace_name>/<str:deploy_name>', scale_down_gui),
|
||||||
|
path('add_ingress', add_ingress),
|
||||||
|
path('delete_ingress', delete_ingress),
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
from django.utils import timezone
|
||||||
|
import datetime
|
||||||
|
from apps.kubernetes_connection.utils import get_namespace,get_deployments,scale_up,scale_down
|
||||||
|
from apps.cloudmanager.models import Schedule_Day_Data,Schedule_Week_Data,Namespace_Data,Deployment_Data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def import_namespace():
|
||||||
|
namespaces_list = get_namespace()
|
||||||
|
for namespace in namespaces_list:
|
||||||
|
if namespace[0]!="kube-system":
|
||||||
|
Namespace_Data.objects.get_or_create(namespace=namespace)
|
||||||
|
|
||||||
|
def import_deployment():
|
||||||
|
deployment_list = get_deployments()
|
||||||
|
Schedule_Day_Always_off,Schedule_Day_Always_on = generate_default_day_schedule()
|
||||||
|
Schedule_Week_Always_off,Schedule_Week_Always_on = generate_default_week_schedule()
|
||||||
|
|
||||||
|
for deployment in deployment_list:
|
||||||
|
#if the replicas is originally 0 , it means it is disabled so put the schedule as always off
|
||||||
|
if deployment[2] == 0:
|
||||||
|
schedule_object = Schedule_Day_Always_off
|
||||||
|
else:
|
||||||
|
schedule_object = Schedule_Day_Always_on
|
||||||
|
if deployment[0]!="kube-system":
|
||||||
|
Deployment_Data.objects.get_or_create(namespace=deployment[0],name=deployment[1],defaults={"replicas":deployment[2],"actual_replica":deployment[2],"schedule_day":schedule_object,"schedule_week":Schedule_Week_Always_on})
|
||||||
|
|
||||||
|
|
||||||
|
def generate_default_day_schedule():
|
||||||
|
Always_off,status = Schedule_Day_Data.objects.update_or_create(name_schedule="Always_off",defaults={"state_at_0" : False ,"state_at_1" : False ,"state_at_2" : False ,"state_at_3" : False ,"state_at_4" : False ,"state_at_5" : False ,"state_at_6" : False ,"state_at_7" : False ,"state_at_8" : False ,"state_at_9" : False ,"state_at_10" : False ,"state_at_11" : False ,"state_at_12" : False ,"state_at_13" : False ,"state_at_14" : False ,"state_at_15" : False ,"state_at_16" : False ,"state_at_17" : False ,"state_at_18" : False ,"state_at_19" : False ,"state_at_20" : False ,"state_at_21" : False ,"state_at_22" : False ,"state_at_23" : False})
|
||||||
|
Always_on,status = Schedule_Day_Data.objects.update_or_create(name_schedule="Always_on",defaults={"state_at_0" : True ,"state_at_1" : True ,"state_at_2" : True ,"state_at_3" : True ,"state_at_4" : True ,"state_at_5" : True ,"state_at_6" : True ,"state_at_7" : True ,"state_at_8" : True ,"state_at_9" : True ,"state_at_10" : True ,"state_at_11" : True ,"state_at_12" : True ,"state_at_13" : True ,"state_at_14" : True ,"state_at_15" : True ,"state_at_16" : True ,"state_at_17" : True ,"state_at_18" : True ,"state_at_19" : True ,"state_at_20" : True ,"state_at_21" : True ,"state_at_22" : True ,"state_at_23" : True})
|
||||||
|
return Always_off,Always_on
|
||||||
|
|
||||||
|
def generate_default_week_schedule():
|
||||||
|
Always_off,status = Schedule_Week_Data.objects.update_or_create(name_schedule="Always_off",defaults={"state_Monday" : False , "state_Tuesday" : False , "state_Wednesday" : False , "state_Thursday" : False , "state_Friday" : False , "state_Saturday" : False , "state_Sunday" : False})
|
||||||
|
Always_on,status = Schedule_Week_Data.objects.update_or_create(name_schedule="Always_on",defaults={"state_Monday" : True , "state_Tuesday" : True , "state_Wednesday" : True , "state_Thursday" : True , "state_Friday" : True , "state_Saturday" : True , "state_Sunday" : True})
|
||||||
|
return Always_off,Always_on
|
||||||
|
|
||||||
|
def Give_current_weekday():
|
||||||
|
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday','Saturday', 'Sunday']
|
||||||
|
weekday = days[datetime.datetime.today().weekday()]
|
||||||
|
return weekday
|
||||||
|
|
||||||
|
def Give_current_hour():
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
return now.hour
|
||||||
|
|
||||||
|
def get_current_replicas():
|
||||||
|
deployments_list = get_deployments()
|
||||||
|
for deployment in deployments_list:
|
||||||
|
if deployment[0]!="kube-system":
|
||||||
|
object,created = Deployment_Data.objects.update_or_create(namespace=deployment[0],name=deployment[1],defaults={"actual_replica":deployment[2]})
|
||||||
|
if created:
|
||||||
|
print("THIS DEPLOY: name: "+str(server[1])+" namespace: "+str(server[0])+" replicas: "+str(server[2])+" IS NEW !!!!!")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def Check_server_supposed_XXX(expected_status,verbose=False):
|
||||||
|
#just for testing
|
||||||
|
#expected_status = True
|
||||||
|
|
||||||
|
# Get week schedule
|
||||||
|
|
||||||
|
argument_week="state_"+str(Give_current_weekday())
|
||||||
|
query_week = {argument_week : expected_status}
|
||||||
|
|
||||||
|
schedules_week = Schedule_Week_Data.objects.filter(**query_week)
|
||||||
|
|
||||||
|
# Get day schedule
|
||||||
|
|
||||||
|
argument_day="state_at_"+str(Give_current_hour())
|
||||||
|
query_day = {argument_day : expected_status}
|
||||||
|
|
||||||
|
schedules_day = Schedule_Day_Data.objects.filter(**query_day)
|
||||||
|
|
||||||
|
if expected_status:
|
||||||
|
deployments = Deployment_Data.objects.filter(schedule_week__in=schedules_week, schedule_day__in=schedules_day)
|
||||||
|
else:
|
||||||
|
deployments = Deployment_Data.objects.filter(schedule_week__in=schedules_week) | Deployment_Data.objects.filter(schedule_day__in=schedules_day)
|
||||||
|
|
||||||
|
deployments_list = []
|
||||||
|
for deployment in deployments:
|
||||||
|
display_list = []
|
||||||
|
name = deployment.name
|
||||||
|
display_list.append(name)
|
||||||
|
if verbose : print("name: "+str(name))
|
||||||
|
namespace = deployment.namespace
|
||||||
|
display_list.append(namespace)
|
||||||
|
if verbose : print("namespace: "+str(namespace))
|
||||||
|
replicas = deployment.replicas
|
||||||
|
display_list.append(replicas)
|
||||||
|
if verbose : print("replicas: "+str(replicas))
|
||||||
|
#Adding the whole object as well for future use
|
||||||
|
display_list.append(deployment)
|
||||||
|
deployments_list.append(display_list)
|
||||||
|
|
||||||
|
return deployments_list
|
||||||
|
|
||||||
|
|
||||||
|
def retrieve_and_apply(verbose=False):
|
||||||
|
output = ""
|
||||||
|
output += str(Give_current_hour())
|
||||||
|
output += str("\n")
|
||||||
|
|
||||||
|
|
||||||
|
#Get current replica to compare with the replicas created at the start
|
||||||
|
get_current_replicas()
|
||||||
|
|
||||||
|
print("------------------------------------------")
|
||||||
|
print("-----------------UP-----------------------")
|
||||||
|
print("------------------------------------------")
|
||||||
|
servers_supposed_true = Check_server_supposed_XXX(True)
|
||||||
|
for server in servers_supposed_true:
|
||||||
|
#check if the expected replica (server[2]) match the current replica of the deployment (server[3].actual_replica)
|
||||||
|
if server[3].actual_replica == server[2]:
|
||||||
|
if verbose : print("name: "+str(server[1])+" namespace: "+str(server[0])+" already UP")
|
||||||
|
elif server[3].do_not_touch_until > timezone.now():
|
||||||
|
if verbose : print("name: "+str(server[1])+" namespace: "+str(server[0])+" is in freeze period")
|
||||||
|
else:
|
||||||
|
echo = "Starting -> name: "+str(server[1])+" namespace: "+str(server[0])+" replicas: "+str(server[2])
|
||||||
|
output += str(echo)
|
||||||
|
output += "\n"
|
||||||
|
print(echo)
|
||||||
|
|
||||||
|
scale_up(namespace_name=server[1],deploy_name=server[0],replicas=server[2])
|
||||||
|
|
||||||
|
print("------------------------------------------")
|
||||||
|
print("----------------DOWN----------------------")
|
||||||
|
print("------------------------------------------")
|
||||||
|
servers_supposed_false = Check_server_supposed_XXX(False)
|
||||||
|
for server in servers_supposed_false:
|
||||||
|
#check if the current replica of the deployment (server[3].actual_replica) is already 0 meaning the server is already down
|
||||||
|
if server[3].actual_replica == 0:
|
||||||
|
if verbose : print("name: "+str(server[1])+" namespace: "+str(server[0])+" already DOWN")
|
||||||
|
elif server[3].do_not_touch_until > timezone.now():
|
||||||
|
if verbose : print("name: "+str(server[1])+" namespace: "+str(server[0])+" is in freeze period")
|
||||||
|
else:
|
||||||
|
|
||||||
|
echo = "Shutting down -> name: "+str(server[1])+" namespace: "+str(server[0])+" replicas: "+str(server[2])
|
||||||
|
output += str(echo)
|
||||||
|
output += str("\n")
|
||||||
|
print(echo)
|
||||||
|
scale_down(namespace_name=server[1],deploy_name=server[0])
|
||||||
|
print("------------------------------------------")
|
||||||
|
return output
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
from django.http import HttpResponse
|
||||||
|
from django.shortcuts import render
|
||||||
|
from datetime import timedelta
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
from django.http import JsonResponse
|
||||||
|
|
||||||
|
from apps.import_aggregator.import_rest_framework import api_view, authentication_classes, permission_classes,TokenAuthentication,IsAuthenticated,Response,status
|
||||||
|
|
||||||
|
from .utils import import_namespace,retrieve_and_apply
|
||||||
|
from apps.kubernetes_connection.utils import scale_up,scale_down
|
||||||
|
from .models import Deployment_Data,Ingress_Data
|
||||||
|
|
||||||
|
def hello(request):
|
||||||
|
list_schedule = ['schedule1','schedule2']
|
||||||
|
list_servers_up = [['wiki', 'wikijs', 2], ['book', 'bookstack-db', 1]]
|
||||||
|
return render(request, 'cloudmanager/index.html', {'list_schedule':list_schedule,'list_servers_up':list_servers_up})
|
||||||
|
|
||||||
|
def import_namespace_view(request):
|
||||||
|
import_namespace()
|
||||||
|
return HttpResponse('<h1>Namespace imported!</h1>')
|
||||||
|
|
||||||
|
|
||||||
|
def retrieve_and_apply_view(request):
|
||||||
|
output = retrieve_and_apply()
|
||||||
|
return HttpResponse('<h1>'+output+'</h1>')
|
||||||
|
|
||||||
|
def scale_up_gui(request,namespace_name,deploy_name,replicas=1):
|
||||||
|
Deployment_Data.objects.filter(namespace=namespace_name,name=deploy_name).update(do_not_touch_until=timezone.now() + timedelta(hours=1))
|
||||||
|
scale_up(namespace_name=namespace_name,deploy_name=deploy_name,replicas=replicas)
|
||||||
|
return render(request, 'dashboard/start.html', {'namespace':namespace_name,'deployment': deploy_name, 'url': 'https://namespace.com'})
|
||||||
|
|
||||||
|
|
||||||
|
def scale_down_gui(request,namespace_name,deploy_name):
|
||||||
|
Deployment_Data.objects.filter(namespace=namespace_name,name=deploy_name).update(do_not_touch_until=timezone.now() + timedelta(hours=1))
|
||||||
|
scale_down(namespace_name=namespace_name,deploy_name=deploy_name)
|
||||||
|
return render(request, 'dashboard/shutdown.html',
|
||||||
|
{'namespace': namespace_name, 'deployment': deploy_name, 'url': 'https://namespace.com'})
|
||||||
|
|
||||||
|
|
||||||
|
@api_view(['POST'])
|
||||||
|
@authentication_classes([TokenAuthentication])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
def add_ingress(request):
|
||||||
|
url = request.POST.get('url')
|
||||||
|
namespace = request.POST.get('namespace')
|
||||||
|
print("URL: "+str(url))
|
||||||
|
print("NS: "+str(namespace))
|
||||||
|
|
||||||
|
try:
|
||||||
|
Ingress_Data.objects.update_or_create(url=url,namespace=namespace)
|
||||||
|
except Exception as exception:
|
||||||
|
return JsonResponse({"status": "error","reason":str(exception)})
|
||||||
|
|
||||||
|
return JsonResponse({"status": "added","url":str(url),"namespace":str(namespace)})
|
||||||
|
|
||||||
|
@api_view(['POST'])
|
||||||
|
@authentication_classes([TokenAuthentication])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
def delete_ingress(request):
|
||||||
|
url = request.POST.get('url')
|
||||||
|
namespace = request.POST.get('namespace')
|
||||||
|
print("URL: "+str(url))
|
||||||
|
print("NS: "+str(namespace))
|
||||||
|
|
||||||
|
try:
|
||||||
|
ingress_object = Ingress_Data.objects.filter(url=url,namespace=namespace)
|
||||||
|
except Exception as exception:
|
||||||
|
return JsonResponse({"status": "error","reason":str(exception)})
|
||||||
|
|
||||||
|
try:
|
||||||
|
ingress_object.delete()
|
||||||
|
except Exception as exception:
|
||||||
|
return JsonResponse({"status": "error","reason":str(exception)})
|
||||||
|
|
||||||
|
return JsonResponse({"status": "deleted","url":str(url),"namespace":str(namespace)})
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
|
||||||
|
def home(request):
|
||||||
|
thislist = ["apple", "banana", "cherry"]
|
||||||
|
return render(request, 'dashboard/home.html',{'thislist': thislist})
|
||||||
|
|
||||||
|
def about(request):
|
||||||
|
thislist = ["apple", "banana", "cherry"]
|
||||||
|
return render(request, 'dashboard/about.html',{'thislist': thislist})
|
||||||
|
|
||||||
|
def success(request):
|
||||||
|
return render(request, 'dashboard/start.html',{'deployment': 'django','url':'https://google.com'})
|
||||||
|
|
||||||
|
def scale_up(request,namespace_name,deploy_name):
|
||||||
|
baseurl = "{0}://{1}{2}".format(request.scheme, request.get_host(), request.path)
|
||||||
|
return render(request, 'dashboard/start.html', {'namespace':namespace_name,'deployment': deploy_name, 'url': 'https://namespace.com','baseurl': baseurl})
|
||||||
|
|
||||||
|
def scale_down(request,namespace_name,deploy_name):
|
||||||
|
baseurl = "{0}://{1}{2}".format(request.scheme, request.get_host(), request.path)
|
||||||
|
return render(request, 'dashboard/shutdown.html', {'namespace':namespace_name,'deployment': deploy_name, 'url': 'https://namespace.com','baseurl': baseurl})
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from rest_framework.decorators import api_view, authentication_classes, permission_classes
|
||||||
|
from rest_framework.authentication import TokenAuthentication
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from import_export import resources
|
||||||
|
from import_export.fields import Field
|
||||||
|
from .models import JobData
|
||||||
|
from django.utils.text import Truncator
|
||||||
|
from core.admin import UniversalModelAdmin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
||||||
|
|
||||||
|
class JobResource(resources.ModelResource):
|
||||||
|
# Map 'csv_column_name' from the file to 'model_variable_name' in your DB
|
||||||
|
job_position = Field(attribute='job_position',column_name='Job Position')
|
||||||
|
company = Field(attribute='company',column_name='Company')
|
||||||
|
URL = Field(attribute='URL',column_name='URL')
|
||||||
|
status = Field(attribute='status',column_name='Status')
|
||||||
|
date_saved = Field(attribute='date_saved',column_name='Date Saved')
|
||||||
|
date_applied = Field(attribute='date_applied',column_name='Date Applied')
|
||||||
|
type = Field(attribute='type',column_name='Type')
|
||||||
|
resume = Field(attribute='resume',column_name='Resume')
|
||||||
|
#cover_letter = Field(attribute='cover_letter',column_name='Cover Letter')
|
||||||
|
location = Field(attribute='location',column_name='Location')
|
||||||
|
job_description = Field(attribute='job_description',column_name='Job Description')
|
||||||
|
salary = Field(attribute='salary',column_name='Salary')
|
||||||
|
contact = Field(attribute='contact',column_name='Contact')
|
||||||
|
source = Field(attribute='source',column_name='Source')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = JobData
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(JobData)
|
||||||
|
class JobAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ('job_position','company','URL','status','date_saved','date_applied','type','resume','location','short_description','salary','contact','source')
|
||||||
|
#fields = ['job_position','company','URL','status','date_saved','date_applied','type','resume','cover_letter','location','job_description','salary ','contact','source']
|
||||||
|
resource_classes = [JobResource]
|
||||||
|
def short_description(self, obj):
|
||||||
|
return Truncator(obj.job_description).words(10, truncate=' ...')
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
class JobDashboardConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'apps.job_dashboard'
|
||||||
|
label = 'job'
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-06-22 20:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='JobData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('job_position', models.CharField(max_length=100, null=True)),
|
||||||
|
('company', models.CharField(max_length=100, null=True)),
|
||||||
|
('URL', models.URLField(max_length=1000, null=True)),
|
||||||
|
('status', models.CharField(choices=[('Rejected', 'Rejected'), ('Applied', 'Applied'), ('Negotiating', 'Negotiating'), ('Bookmarked', 'Bookmarked'), ('Accepted', 'Accepted')], max_length=100, null=True)),
|
||||||
|
('date_saved', models.CharField(max_length=100, null=True)),
|
||||||
|
('date_applied', models.CharField(max_length=100, null=True)),
|
||||||
|
('type', models.CharField(max_length=100, null=True)),
|
||||||
|
('resume', models.URLField(null=True)),
|
||||||
|
('location', models.CharField(max_length=100, null=True)),
|
||||||
|
('job_description', models.CharField(null=True)),
|
||||||
|
('salary', models.CharField(null=True)),
|
||||||
|
('contact', models.CharField(max_length=100, null=True)),
|
||||||
|
('source', models.CharField(max_length=100, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'job',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
status_CHOICES = (
|
||||||
|
('Rejected','Rejected'),
|
||||||
|
('Applied','Applied'),
|
||||||
|
('Negotiating','Negotiating'),
|
||||||
|
('Bookmarked','Bookmarked'),
|
||||||
|
('Accepted','Accepted')
|
||||||
|
)
|
||||||
|
|
||||||
|
class JobData(models.Model):
|
||||||
|
job_position = models.CharField(max_length=100, null=True)
|
||||||
|
company = models.CharField(max_length=100, null=True)
|
||||||
|
URL = models.URLField(max_length=1000,null=True)
|
||||||
|
status = models.CharField(max_length=100,choices=status_CHOICES, null=True)
|
||||||
|
date_saved = models.CharField(max_length=100, null=True)
|
||||||
|
date_applied = models.CharField(max_length=100, null=True)
|
||||||
|
type = models.CharField(max_length=100, null=True)
|
||||||
|
resume = models.URLField(max_length=200, null=True)
|
||||||
|
#cover_letter = models.URLField(max_length=200, null=True)
|
||||||
|
location = models.CharField(max_length=100, null=True)
|
||||||
|
job_description = models.CharField(null=True)
|
||||||
|
salary = models.CharField(null=True)
|
||||||
|
contact = models.CharField(max_length=100, null=True)
|
||||||
|
source = models.CharField(max_length=100, null=True)
|
||||||
|
class Meta:
|
||||||
|
db_table = 'job'
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for django_code project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.urls import path
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', admin.site.urls),
|
||||||
|
]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
+13
-8
@@ -14,18 +14,23 @@ import ruamel.yaml
|
|||||||
import yaml
|
import yaml
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
|
|
||||||
def hello(request):
|
def hello(request):
|
||||||
return HttpResponse('<h1>Hello k8s!</h1>')
|
return HttpResponse('<h1>Hello k8s!</h1>')
|
||||||
|
|
||||||
def scale_up(request,namespace_name,deploy_name):
|
def echoHello():
|
||||||
|
print("hello from k8s")
|
||||||
|
return "returned from k8s"
|
||||||
|
|
||||||
|
def scale_up(request,namespace_name,deploy_name,replicas=1):
|
||||||
config.load_kube_config(config_file='/kubeconfig/config')
|
config.load_kube_config(config_file='/kubeconfig/config')
|
||||||
api = client.AppsV1Api()
|
api = client.AppsV1Api()
|
||||||
deployment = api.read_namespaced_deployment(name=deploy_name, namespace=namespace_name)
|
deployment = api.read_namespaced_deployment(name=deploy_name, namespace=namespace_name)
|
||||||
deployment.spec.replicas = 1
|
deployment.spec.replicas = replicas
|
||||||
resp = api.patch_namespaced_deployment(
|
resp = api.patch_namespaced_deployment(
|
||||||
name=deploy_name, namespace=namespace_name, body=deployment);
|
name=deploy_name, namespace=namespace_name, body=deployment);
|
||||||
#return HttpResponse('<h1>Scaled up !</h1>')
|
#return HttpResponse('<h1>Scaled up !</h1>')
|
||||||
return render(request, 'start.html', {'namespace':namespace_name,'deployment': deploy_name, 'url': 'https://namespace.com'})
|
return render(request, 'dashboard/start.html', {'namespace':namespace_name,'deployment': deploy_name, 'url': 'https://namespace.com'})
|
||||||
|
|
||||||
|
|
||||||
def scale_down(request,namespace_name,deploy_name):
|
def scale_down(request,namespace_name,deploy_name):
|
||||||
@@ -36,7 +41,7 @@ def scale_down(request,namespace_name,deploy_name):
|
|||||||
resp = api.patch_namespaced_deployment(
|
resp = api.patch_namespaced_deployment(
|
||||||
name=deploy_name, namespace=namespace_name, body=deployment);
|
name=deploy_name, namespace=namespace_name, body=deployment);
|
||||||
#return HttpResponse('<h1>Scaled down !</h1>')
|
#return HttpResponse('<h1>Scaled down !</h1>')
|
||||||
return render(request, 'shutdown.html',
|
return render(request, 'dashboard/shutdown.html',
|
||||||
{'namespace': namespace_name, 'deployment': deploy_name, 'url': 'https://namespace.com'})
|
{'namespace': namespace_name, 'deployment': deploy_name, 'url': 'https://namespace.com'})
|
||||||
|
|
||||||
def nodes(request):
|
def nodes(request):
|
||||||
@@ -57,7 +62,7 @@ def nodes(request):
|
|||||||
'spec': {
|
'spec': {
|
||||||
|
|
||||||
'containers': [{
|
'containers': [{
|
||||||
'image': 'gitea.tryton.geeraert.eu/pi-ux-ce/bitwarden_cli:1.0.1',
|
'image': 'gitea.geeraert.eu/pi-ux-ce/bitwarden_cli:1.0.1',
|
||||||
# 'pod-running-timeout': '5m0s',
|
# 'pod-running-timeout': '5m0s',
|
||||||
'name': 'testpython',
|
'name': 'testpython',
|
||||||
'env': [
|
'env': [
|
||||||
@@ -91,7 +96,7 @@ def backup_job(request):
|
|||||||
'spec': {
|
'spec': {
|
||||||
|
|
||||||
'containers': [{
|
'containers': [{
|
||||||
'image': 'gitea.tryton.geeraert.eu/pi-ux-ce/bitwarden_cli:1.0.1',
|
'image': 'gitea.geeraert.eu/pi-ux-ce/bitwarden_cli:1.0.1',
|
||||||
'name': 'testpython',
|
'name': 'testpython',
|
||||||
'command': ['/bin/sh -c /config/export_bitwarden.sh'],
|
'command': ['/bin/sh -c /config/export_bitwarden.sh'],
|
||||||
'env': [
|
'env': [
|
||||||
@@ -119,8 +124,8 @@ def backup_job_yaml(request,sync_target):
|
|||||||
v1 = client.BatchV1Api()
|
v1 = client.BatchV1Api()
|
||||||
|
|
||||||
yaml_location = {
|
yaml_location = {
|
||||||
"synology" : "https://gitea.tryton.geeraert.eu/pi-ux-ce/Backup_kube/raw/branch/main/Infrequent_access/synology_pod.yaml",
|
"synology" : "https://gitea.geeraert.eu/pi-ux-ce/Backup_kube/raw/branch/main/Infrequent_access/synology_pod.yaml",
|
||||||
"openmediavault":"https://gitea.tryton.geeraert.eu/pi-ux-ce/Backup_kube/raw/branch/main/Infrequent_access/openmediavault_pod.yaml"
|
"openmediavault":"https://gitea.geeraert.eu/pi-ux-ce/Backup_kube/raw/branch/main/Infrequent_access/openmediavault_pod.yaml"
|
||||||
}
|
}
|
||||||
print(yaml_location[sync_target])
|
print(yaml_location[sync_target])
|
||||||
url_to_select=yaml_location[sync_target]
|
url_to_select=yaml_location[sync_target]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for django_code project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.urls import path
|
||||||
|
from apps.kubernetes_connection import apps as kubernetes_connection
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
################## kubernetes_connection#####
|
||||||
|
path('hello/', kubernetes_connection.hello),
|
||||||
|
path('nodes/', kubernetes_connection.nodes),
|
||||||
|
path('backup_job/', kubernetes_connection.backup_job),
|
||||||
|
path('backup_job_yaml/', kubernetes_connection.backup_job_yaml),
|
||||||
|
path('scale_up/<str:namespace_name>/<str:deploy_name>', kubernetes_connection.scale_up),
|
||||||
|
path('scale_down/<str:namespace_name>/<str:deploy_name>', kubernetes_connection.scale_down),
|
||||||
|
|
||||||
|
]
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
from kubernetes import client, config
|
||||||
|
|
||||||
|
|
||||||
|
def scale_up(namespace_name,deploy_name,replicas=1):
|
||||||
|
config.load_kube_config(config_file='/kubeconfig/config')
|
||||||
|
|
||||||
|
api = client.AppsV1Api()
|
||||||
|
deployment = api.read_namespaced_deployment(name=deploy_name, namespace=namespace_name)
|
||||||
|
deployment.spec.replicas = replicas
|
||||||
|
resp = api.patch_namespaced_deployment(
|
||||||
|
name=deploy_name, namespace=namespace_name, body=deployment);
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def scale_down(namespace_name,deploy_name):
|
||||||
|
config.load_kube_config(config_file='/kubeconfig/config')
|
||||||
|
api = client.AppsV1Api()
|
||||||
|
deployment = api.read_namespaced_deployment(name=deploy_name, namespace=namespace_name)
|
||||||
|
deployment.spec.replicas = 0
|
||||||
|
resp = api.patch_namespaced_deployment(
|
||||||
|
name=deploy_name, namespace=namespace_name, body=deployment);
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def import_Deployments():
|
||||||
|
config.load_kube_config(config_file='/kubeconfig/config')
|
||||||
|
api = client.AppsV1Api()
|
||||||
|
deployment = api.list_deployment_for_all_namespaces()
|
||||||
|
for i in range(1,len(deployment.items)):
|
||||||
|
print(deployment.items[i].spec.template.spec.containers[0].name)
|
||||||
|
|
||||||
|
len(deployment.items) #list all deployment inside the namespace
|
||||||
|
test.items[0].spec.template.spec.containers[0].name # name the first deploy within the namespace
|
||||||
|
test.items[2].spec.template.spec.containers[0].name # name the third deploy within the namespace
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_namespace(verbose=False):
|
||||||
|
config.load_kube_config(config_file='/kubeconfig/config')
|
||||||
|
core = client.CoreV1Api()
|
||||||
|
namespace = core.list_namespace()
|
||||||
|
namespace_list = []
|
||||||
|
for i in range(0,len(namespace.items)):
|
||||||
|
if verbose : print(namespace.items[i].metadata.name)
|
||||||
|
namespace_list.append(namespace.items[i].metadata.name)
|
||||||
|
return namespace_list
|
||||||
|
|
||||||
|
def get_deployments(verbose=False):
|
||||||
|
config.load_kube_config(config_file='/kubeconfig/config')
|
||||||
|
api = client.AppsV1Api()
|
||||||
|
namespaces_list = get_namespace()
|
||||||
|
deployments_list = []
|
||||||
|
for namespace in namespaces_list:
|
||||||
|
if verbose : print(namespace)
|
||||||
|
deployments = api.list_namespaced_deployment(namespace)
|
||||||
|
for deployment_index in range(0,len(deployments.items)):
|
||||||
|
deployment = deployments.items[deployment_index].metadata.name
|
||||||
|
replicas = deployments.items[deployment_index].spec.replicas
|
||||||
|
if verbose : print(" "+str(deployment)+" -- Replicas: "+str(replicas))
|
||||||
|
deployments_list.append([namespace,deployment,replicas])
|
||||||
|
return deployments_list
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from import_export import resources
|
||||||
|
from django.utils.html import format_html
|
||||||
|
from .models import podcastData
|
||||||
|
from core.admin import UniversalModelAdmin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
@admin.register(podcastData)
|
||||||
|
class PodcastAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ('podcast_name','clickable_links','enabled')
|
||||||
|
|
||||||
|
link_field = 'podcast_url'
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PodcastAggregatorConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'apps.podcast_aggregator'
|
||||||
|
label = 'podcast'
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-06-30 22:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='podcastData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('podcast_name', models.CharField(max_length=100, null=True)),
|
||||||
|
('podcast_url', models.CharField(max_length=100, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'podcasts',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-06-30 22:08
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('podcast', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='podcastdata',
|
||||||
|
name='enabled',
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class podcastData(models.Model):
|
||||||
|
podcast_name = models.CharField(max_length=100, null=True)
|
||||||
|
podcast_url = models.CharField(max_length=100, null=True)
|
||||||
|
enabled = models.BooleanField(default=True)
|
||||||
|
class Meta:
|
||||||
|
db_table = 'podcasts'
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for django_code project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.urls import path
|
||||||
|
from apps.podcast_aggregator import views as podcast_views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
################### cloudmanager ###################
|
||||||
|
path('', podcast_views.execute_podcast),
|
||||||
|
|
||||||
|
]
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import requests
|
||||||
|
import xmltodict
|
||||||
|
from urllib import request as urlrequest
|
||||||
|
import tempfile
|
||||||
|
#Django import
|
||||||
|
from apps.telegram_communication.utils import telegramUtils
|
||||||
|
from .models import podcastData
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proxy_url = 'http://gluetun-svc.gluetun.svc:8888'
|
||||||
|
proxy = urlrequest.ProxyHandler({
|
||||||
|
'http': proxy_url,
|
||||||
|
'https': proxy_url # Add the handler for HTTPS
|
||||||
|
})
|
||||||
|
|
||||||
|
proxies = {
|
||||||
|
"http" : proxy_url,
|
||||||
|
"https" : proxy_url
|
||||||
|
}
|
||||||
|
|
||||||
|
def rss_to_dict(url):
|
||||||
|
response = requests.get(url)
|
||||||
|
data = xmltodict.parse(response.content)
|
||||||
|
|
||||||
|
print(data['rss'])
|
||||||
|
|
||||||
|
title = data['rss']['channel']['title']
|
||||||
|
|
||||||
|
#Get the keys if needed of debug
|
||||||
|
#print(data['rss'].keys())
|
||||||
|
|
||||||
|
#use first object as it's ordered in a chronological order
|
||||||
|
|
||||||
|
|
||||||
|
today_object = data['rss']['channel']['item']
|
||||||
|
if isinstance(today_object, list):
|
||||||
|
today_object = data['rss']['channel']['item'][0]
|
||||||
|
|
||||||
|
today_title = today_object['title']
|
||||||
|
today_podcast_url = today_object['enclosure']['@url']
|
||||||
|
|
||||||
|
return title,today_title,today_podcast_url
|
||||||
|
|
||||||
|
def download_news_mp3(url_mp3, filename):
|
||||||
|
|
||||||
|
opener = urlrequest.build_opener(proxy)
|
||||||
|
|
||||||
|
urlrequest.install_opener(opener)
|
||||||
|
|
||||||
|
print("Downloading : " + filename +" -- " + url_mp3)
|
||||||
|
try:
|
||||||
|
|
||||||
|
urlrequest.urlretrieve(url_mp3, filename)
|
||||||
|
|
||||||
|
except:
|
||||||
|
print("Can't download " + filename +" -- " + url_mp3 + " == Cancelling")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def pretty_filename(filename,extension=''):
|
||||||
|
filename = filename.replace(' ', '_')
|
||||||
|
pretty_filename = filename.replace('/', '_')
|
||||||
|
if extension != '':
|
||||||
|
extension = str('.'+extension)
|
||||||
|
return pretty_filename+extension
|
||||||
|
|
||||||
|
def podcasts():
|
||||||
|
telegram = telegramUtils()
|
||||||
|
|
||||||
|
#clear all expired messages before
|
||||||
|
telegram.clear_expired_messages()
|
||||||
|
|
||||||
|
podcasts = podcastData.objects.filter(enabled=True)
|
||||||
|
for podcast in podcasts:
|
||||||
|
url = podcast.podcast_url
|
||||||
|
|
||||||
|
today_podcast = rss_to_dict(url)
|
||||||
|
print(today_podcast)
|
||||||
|
pretty_file_name = pretty_filename(today_podcast[1],'mp3')
|
||||||
|
|
||||||
|
temp = tempfile.TemporaryDirectory()
|
||||||
|
temp_path = temp.name.replace("\\", "/")
|
||||||
|
file_path = temp_path+"/"+pretty_file_name
|
||||||
|
download_news_mp3(today_podcast[2],file_path)
|
||||||
|
print(file_path)
|
||||||
|
telegram.send_document(file_path,str(today_podcast[0])+" "+str(today_podcast[1]))
|
||||||
|
|
||||||
|
#main()
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.http import HttpResponse
|
||||||
|
from .utils import podcasts
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
def execute_podcast(request):
|
||||||
|
podcasts()
|
||||||
|
return HttpResponse('<h1>Generating the podcast!</h1>')
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
from django.contrib import admin,messages
|
||||||
|
from django.utils.translation import ngettext
|
||||||
|
from django.utils import timezone
|
||||||
|
from prompt_toolkit.shortcuts import print_container
|
||||||
|
from import_export import resources
|
||||||
|
from .models import SimpsonsData,urlData
|
||||||
|
from .utils import mark_episode_watched,unwatch_all_episodes,generate_new_urls_for_episode
|
||||||
|
from core.admin import UniversalModelAdmin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
||||||
|
DB = 'simpsons_db'
|
||||||
|
|
||||||
|
@admin.action(description="Mark episode as seen")
|
||||||
|
def make_seen(modeladmin, request, queryset):
|
||||||
|
updated = queryset.update(seen="True",modified_at=timezone.now())
|
||||||
|
|
||||||
|
for query in queryset.values():
|
||||||
|
print(query)
|
||||||
|
season_number = query.get('season')
|
||||||
|
episode_number = query.get('episode')
|
||||||
|
mark_episode_watched(season_number,episode_number,"watched")
|
||||||
|
|
||||||
|
modeladmin.message_user(
|
||||||
|
request,
|
||||||
|
ngettext(
|
||||||
|
"%d episode was successfully marked as seen.",
|
||||||
|
"%d episodes were successfully marked as seen.",
|
||||||
|
updated,
|
||||||
|
)
|
||||||
|
% updated,
|
||||||
|
messages.SUCCESS,
|
||||||
|
)
|
||||||
|
|
||||||
|
@admin.action(description="Mark episode as not seen")
|
||||||
|
def make_unseen(modeladmin, request, queryset):
|
||||||
|
updated = queryset.update(seen="False")
|
||||||
|
for query in queryset.values():
|
||||||
|
print(query)
|
||||||
|
season_number = query.get('season')
|
||||||
|
episode_number = query.get('episode')
|
||||||
|
mark_episode_watched(season_number,episode_number,"unwatched")
|
||||||
|
|
||||||
|
modeladmin.message_user(
|
||||||
|
request,
|
||||||
|
ngettext(
|
||||||
|
"%d episode was successfully marked as not seen.",
|
||||||
|
"%d episodes were successfully marked as not seen.",
|
||||||
|
updated,
|
||||||
|
)
|
||||||
|
% updated,
|
||||||
|
messages.SUCCESS,
|
||||||
|
)
|
||||||
|
|
||||||
|
@admin.action(description="mark all of them as unseen on betaserie")
|
||||||
|
def unseen_betaserie(modeladmin, request, queryset):
|
||||||
|
unwatch_all_episodes()
|
||||||
|
|
||||||
|
@admin.action(description="generate new urls for episode")
|
||||||
|
def generate_new_urls(modeladmin, request, queryset):
|
||||||
|
generate_new_urls_for_episode()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SimpsonsData)
|
||||||
|
class EpisodeAdmin(UniversalModelAdmin):
|
||||||
|
list_display = [field.name for field in SimpsonsData._meta.fields if field.name != 'id']
|
||||||
|
list_display += ['clickable_links']
|
||||||
|
list_filter = ['seen','modified_at']
|
||||||
|
#list_filter = ['seen']
|
||||||
|
fields = ['season', 'episode', 'url', 'seen']
|
||||||
|
actions = [make_seen,make_unseen,unseen_betaserie,generate_new_urls]
|
||||||
|
search_fields = ['season', 'episode', 'url', 'seen']
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
return super().get_queryset(request).using(DB)
|
||||||
|
|
||||||
|
def save_model(self, request, obj, form, change):
|
||||||
|
obj.save(using=DB)
|
||||||
|
|
||||||
|
def delete_model(self, request, obj):
|
||||||
|
obj.delete(using=DB)
|
||||||
|
|
||||||
|
def delete_queryset(self, request, queryset):
|
||||||
|
queryset.using(DB).delete()
|
||||||
|
|
||||||
|
@admin.register(urlData)
|
||||||
|
class urldataAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ('url_example', 'prefix', 'infix', 'suffix','addedDate')
|
||||||
|
|
||||||
|
|
||||||
|
fieldsets = [
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
'fields': (('prefix', 'infix', 'suffix'), 'url_example')
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
class RandomSimpsonsConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'apps.random_simpsons'
|
||||||
|
label = 'simpsons'
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-06-22 20:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SimpsonsData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('season', models.IntegerField()),
|
||||||
|
('episode', models.IntegerField()),
|
||||||
|
('url', models.CharField(max_length=1000)),
|
||||||
|
('seen', models.BooleanField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'episodes',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-07-05 13:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='simpsonsdata',
|
||||||
|
name='modified_at',
|
||||||
|
field=models.DateTimeField(auto_now=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-07-05 13:40
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0002_simpsonsdata_modified_at'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='simpsonsdata',
|
||||||
|
name='modified_at',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(1970, 1, 1, 0, 0)),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 4.2.29 on 2026-07-05 13:43
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0003_alter_simpsonsdata_modified_at'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='simpsonsdata',
|
||||||
|
name='modified_at',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-07-07 08:35
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0004_remove_simpsonsdata_modified_at'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='simpsonsdata',
|
||||||
|
name='modified_at',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(1970, 1, 1, 0, 0)),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-07-07 08:40
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0005_simpsonsdata_modified_at'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='urlData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('url_example', models.CharField(max_length=1000)),
|
||||||
|
('prefix', models.CharField(max_length=1000)),
|
||||||
|
('infix', models.CharField(max_length=1000)),
|
||||||
|
('suffix', models.CharField(max_length=1000)),
|
||||||
|
('addedDate', models.DateField(auto_now_add=True, null=True, verbose_name='Published')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'redirectUrl',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-07-07 08:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0006_urldata'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='urldata',
|
||||||
|
name='infix',
|
||||||
|
field=models.CharField(help_text='8&episode=', max_length=1000),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='urldata',
|
||||||
|
name='prefix',
|
||||||
|
field=models.CharField(help_text='https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=', max_length=1000),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='urldata',
|
||||||
|
name='url_example',
|
||||||
|
field=models.CharField(help_text='https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=18&episode=5', max_length=1000),
|
||||||
|
),
|
||||||
|
]
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-07-07 09:28
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0007_alter_urldata_infix_alter_urldata_prefix_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='simpsonsdata',
|
||||||
|
name='modified_at',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='urldata',
|
||||||
|
name='infix',
|
||||||
|
field=models.CharField(blank=True, help_text='&episode=', max_length=1000, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='urldata',
|
||||||
|
name='prefix',
|
||||||
|
field=models.CharField(blank=True, help_text='https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=', max_length=1000, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='urldata',
|
||||||
|
name='suffix',
|
||||||
|
field=models.CharField(blank=True, max_length=1000, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-09-17 21:26
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('simpsons', '0008_alter_simpsonsdata_modified_at_alter_urldata_infix_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='simpsonsdata',
|
||||||
|
name='modified_at',
|
||||||
|
field=models.DateTimeField(default=datetime.datetime(1969, 12, 31, 23, 0, tzinfo=datetime.timezone.utc)),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
from django.db import models
|
||||||
|
from datetime import datetime
|
||||||
|
from django.utils.timezone import make_aware
|
||||||
|
|
||||||
|
EPOCH = make_aware(datetime(1970, 1, 1))
|
||||||
|
|
||||||
|
class SimpsonsData(models.Model):
|
||||||
|
season = models.IntegerField()
|
||||||
|
episode = models.IntegerField()
|
||||||
|
url = models.CharField(max_length=1000)
|
||||||
|
seen = models.BooleanField()
|
||||||
|
modified_at = models.DateTimeField(default=EPOCH)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'episodes'
|
||||||
|
|
||||||
|
class urlData(models.Model):
|
||||||
|
url_example = models.CharField(max_length=1000, help_text="https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=18&episode=5")
|
||||||
|
prefix = models.CharField(max_length=1000, help_text="https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=",blank=True, null=True)
|
||||||
|
infix = models.CharField(max_length=1000, help_text="&episode=",blank=True, null=True)
|
||||||
|
suffix = models.CharField(max_length=1000, help_text="" ,blank=True, null=True)
|
||||||
|
addedDate = models.DateField('Published', blank=True, null=True, auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'redirectUrl'
|
||||||
|
|
||||||
|
simpsons_data_object = SimpsonsData.objects.using('simpsons_db')
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for django_code project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.urls import path
|
||||||
|
from apps.random_simpsons import views as random_simpsons
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
################### Simpsons ###################
|
||||||
|
path('hello', random_simpsons.hello),
|
||||||
|
path('', random_simpsons.episode_generator),
|
||||||
|
path('download_file/', random_simpsons.download_file),
|
||||||
|
]
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
from django.db.models import Count
|
||||||
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
|
from celery.worker.state import active_requests
|
||||||
|
from requests.compat import str
|
||||||
|
from django.utils import timezone
|
||||||
|
from apps.betaserie.utils import betaserieUtils
|
||||||
|
from .models import simpsons_data_object,urlData
|
||||||
|
|
||||||
|
betaserie = betaserieUtils()
|
||||||
|
|
||||||
|
simpsons_id = 12
|
||||||
|
|
||||||
|
|
||||||
|
def mark_episode_watched(season,episode,action,verbose=False):
|
||||||
|
#mark episode as seen in DB
|
||||||
|
simpsons_data_object.filter(season=season, episode=episode).values('seen').update(seen=True,modified_at=timezone.now())
|
||||||
|
|
||||||
|
|
||||||
|
if verbose : print("season_number: "+str(season))
|
||||||
|
if verbose : print("episode_number: "+str(episode))
|
||||||
|
|
||||||
|
#mark episode as seen in betaserie
|
||||||
|
episode_number = "S"+str(season)+"E"+str(episode)
|
||||||
|
|
||||||
|
episode_id,episode_seen = betaserie.identify_episode(simpsons_id,episode_number)
|
||||||
|
|
||||||
|
if action == "watched":
|
||||||
|
betaserie.mark_episodes_watched(episode_id)
|
||||||
|
elif action == "unwatched":
|
||||||
|
betaserie.unmark_episodes_watched(episode_id)
|
||||||
|
else:
|
||||||
|
print("Parameter action not in range")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def unwatch_all_episodes():
|
||||||
|
maximum_number_of_seasons = simpsons_data_object.aggregate(unique_season=Count('season', distinct=True))['unique_season']
|
||||||
|
print("maximum_number_of_seasons: "+str(maximum_number_of_seasons))
|
||||||
|
for season in range(1,maximum_number_of_seasons+1):
|
||||||
|
maximum_number_of_episodes = simpsons_data_object.filter(season=season).count()
|
||||||
|
print("maximum_number_of_episodes for "+str(season)+": "+str(maximum_number_of_episodes))
|
||||||
|
for episode in range(1,maximum_number_of_episodes+1):
|
||||||
|
print("S"+str(season)+"E"+str(episode))
|
||||||
|
mark_episode_watched(season,episode,"unwatched")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_new_urls_for_episode(verbose=False):
|
||||||
|
# kisscartoons didn't work anymore so moving to another website with the format:
|
||||||
|
# URL.com/simpsons/season=XX&episode=XX
|
||||||
|
# example
|
||||||
|
# https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=33&episode=18
|
||||||
|
|
||||||
|
seasons_information,maximum_number_season = betaserie.series_information(simpsons_id)
|
||||||
|
|
||||||
|
|
||||||
|
#for the simpsons, there is a season 0 which increase the count of seasons by 1
|
||||||
|
# we need to remove this entry ,
|
||||||
|
# so we cannot trust the maximum_number_season coming from simpsons_series_information
|
||||||
|
|
||||||
|
# edit 26/08/2026
|
||||||
|
# I updated the function betaserie.series_information to remove this season 0
|
||||||
|
|
||||||
|
for season in range(1,maximum_number_season+1):
|
||||||
|
# the list doesn't start with season 0 anymore so we cannot use the season number as index
|
||||||
|
# we need to add -1
|
||||||
|
|
||||||
|
number_episodes_in_season = int(seasons_information[season-1]['episodes'])
|
||||||
|
|
||||||
|
for episode in range(1,number_episodes_in_season+1):
|
||||||
|
if verbose : print("Season: "+str(season))
|
||||||
|
if verbose : print("episode: "+str(episode))
|
||||||
|
|
||||||
|
new_url_object = urlData.objects.all().order_by('-addedDate').first()
|
||||||
|
new_url = str(new_url_object.prefix)+str(season)+str(new_url_object.infix)+str(episode)+str(new_url_object.suffix)
|
||||||
|
|
||||||
|
if verbose : print(new_url)
|
||||||
|
try:
|
||||||
|
obj,created = simpsons_data_object.get_or_create(
|
||||||
|
season=season,
|
||||||
|
episode=episode,
|
||||||
|
defaults={"url":new_url,"seen":"False"}
|
||||||
|
)
|
||||||
|
obj.url=new_url
|
||||||
|
obj.save()
|
||||||
|
except MultipleObjectsReturned:
|
||||||
|
print("duplicated object for season: "+str(episode)+" episode: "+str(episode)+", ignoring")
|
||||||
|
|
||||||
|
return 0
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
from django.http import HttpResponse
|
||||||
|
from django.db.models import Count
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from .models import SimpsonsData,simpsons_data_object
|
||||||
|
from .utils import mark_episode_watched
|
||||||
|
import random
|
||||||
|
import threading
|
||||||
|
|
||||||
|
def hello(request):
|
||||||
|
return HttpResponse('<h1>Hello Simpsons view!</h1>')
|
||||||
|
|
||||||
|
def episode_generator(request):
|
||||||
|
boolean_restart = True;
|
||||||
|
simpsons_object = {}
|
||||||
|
while (boolean_restart):
|
||||||
|
maximum_number_of_seasons = simpsons_data_object.aggregate(unique_season=Count('season', distinct=True))['unique_season']
|
||||||
|
|
||||||
|
random_season = random.randint(1, maximum_number_of_seasons)
|
||||||
|
print("random season: " + str(random_season))
|
||||||
|
|
||||||
|
simpsons_object = simpsons_data_object.filter(season=random_season)
|
||||||
|
|
||||||
|
maximum_number_of_episodes = simpsons_object.count()
|
||||||
|
|
||||||
|
random_episode = random.randint(1, maximum_number_of_episodes)
|
||||||
|
print("random episode: " + str(random_episode))
|
||||||
|
|
||||||
|
simpsons_object = simpsons_object.filter(episode=random_episode)
|
||||||
|
|
||||||
|
episode_seen = simpsons_object.values('seen')[0]['seen']
|
||||||
|
|
||||||
|
if not(episode_seen):
|
||||||
|
boolean_restart = False
|
||||||
|
else:
|
||||||
|
print("episode "+str(random_episode)+" from season "+str(random_season)+" already seen")
|
||||||
|
|
||||||
|
|
||||||
|
#Set episode as seen
|
||||||
|
# It will still update an already seem episode but it works and I'm lazy
|
||||||
|
|
||||||
|
|
||||||
|
#Mark episode as seen on betaseries
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=mark_episode_watched,
|
||||||
|
args=(random_season, random_episode, "watched"),
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
random_url = simpsons_object.values('url')[0]['url']
|
||||||
|
|
||||||
|
return redirect(str(random_url))
|
||||||
|
|
||||||
|
def download_file(request):
|
||||||
|
# fill these variables with real values
|
||||||
|
fl_path = '/data/download/sonarr'
|
||||||
|
filename = 'The.Boys.2019.S04E05.2160p.HDR10Plus.WEBRip.6CH.x265.HEVC-PSA.mkv'
|
||||||
|
|
||||||
|
# fl = open(fl_path, 'r')
|
||||||
|
# mime_type, _ = mimetypes.guess_type(fl_path)
|
||||||
|
|
||||||
|
# response = HttpResponse(fl, content_type=mime_type)
|
||||||
|
# response['Content-Disposition'] = "attachment; filename=%s" % filename
|
||||||
|
some_file = open('/data/kubernetes/Backup/nextcloud/notes/2024-07-28/Course.md', "r")
|
||||||
|
django_file = File(some_file)
|
||||||
|
return HttpResponse("<h1>Hello download!</h1><h1><a href='{{ MEDIA_URL }}{{ django_file.relative_path }}'>{{ django_file.name }}</a></h1><h1>bye download!</h1>")
|
||||||
|
# return response
|
||||||
|
|
||||||
|
def download_mo(request,file):
|
||||||
|
path_to_file = os.path.realpath(file)
|
||||||
|
response = FileResponse(open(path_to_file, 'rb'))
|
||||||
|
file_name = file[5:]
|
||||||
|
response['Content-Disposition'] = 'inline; filename=' + file_name
|
||||||
|
return response
|
||||||
|
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.core.files import File
|
||||||
|
from kubernetes import client, config
|
||||||
|
from celery import shared_task
|
||||||
|
|
||||||
|
from lxml import html
|
||||||
|
import requests
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import mimetypes
|
||||||
|
import ruamel.yaml
|
||||||
|
import yaml
|
||||||
|
from urllib import request as urlrequest
|
||||||
|
from urllib import parse as urlparse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proxy_url = 'http://gluetun-svc.gluetun.svc:8888'
|
||||||
|
proxy = urlrequest.ProxyHandler({
|
||||||
|
'http': proxy_url,
|
||||||
|
'https': proxy_url # Add the handler for HTTPS
|
||||||
|
})
|
||||||
|
|
||||||
|
proxies = {
|
||||||
|
"http" : proxy_url,
|
||||||
|
"https" : proxy_url
|
||||||
|
}
|
||||||
|
|
||||||
|
destination_folder = "/stash/"
|
||||||
|
|
||||||
|
def hello(request):
|
||||||
|
return HttpResponse('<h1>Hello stash!</h1>')
|
||||||
|
def form(request):
|
||||||
|
return render(request, 'stash/stash_form.html',{})
|
||||||
|
def album(request):
|
||||||
|
return render(request, 'stash/album_form.html',{})
|
||||||
|
def simple(request):
|
||||||
|
return render(request, 'stash/simple_form.html',{})
|
||||||
|
def check_and_create_destination_folder(name):
|
||||||
|
#check if the output directory exist and create if not
|
||||||
|
if not os.path.isdir(destination_folder):
|
||||||
|
os.makedirs(destination_folder)
|
||||||
|
|
||||||
|
#check if the named directory exist and create if not
|
||||||
|
destination_named_folder = os.path.join(destination_folder,name)
|
||||||
|
if not os.path.isdir(destination_named_folder):
|
||||||
|
os.makedirs(destination_named_folder)
|
||||||
|
|
||||||
|
return destination_named_folder
|
||||||
|
|
||||||
|
def album_form(request):
|
||||||
|
name = request.GET.get('name')
|
||||||
|
url = request.GET.get('url')
|
||||||
|
external_galleries = request.GET.get('external_galleries')
|
||||||
|
|
||||||
|
album_downloader.delay(name=name,url=url,external_galleries=external_galleries)
|
||||||
|
|
||||||
|
text_generated = "successfully sent to the album downloader"
|
||||||
|
return HttpResponse(text_generated, content_type="text/plain")
|
||||||
|
|
||||||
|
@shared_task()
|
||||||
|
def album_downloader(name,url,external_galleries):
|
||||||
|
print(name+" "+url+" "+external_galleries)
|
||||||
|
|
||||||
|
opener = urlrequest.build_opener(proxy)
|
||||||
|
urlrequest.install_opener(opener)
|
||||||
|
|
||||||
|
req = urlrequest.Request(url)
|
||||||
|
urlcurl = urlrequest.urlopen(req).read()
|
||||||
|
|
||||||
|
page = requests.get(url,proxies=proxies)
|
||||||
|
webpage = html.fromstring(page.content)
|
||||||
|
|
||||||
|
#create the prerequisites folder
|
||||||
|
destination_named_folder = check_and_create_destination_folder(name=name)
|
||||||
|
|
||||||
|
|
||||||
|
#get all URLs from the code source (searching for href tag on the code)
|
||||||
|
#https://stackoverflow.com/questions/21455349/xpath-query-get-attribute-href-from-a-tag
|
||||||
|
|
||||||
|
webpage_all_url = webpage.xpath('//a/@href')
|
||||||
|
|
||||||
|
#search for the href that contains the galleries
|
||||||
|
webpage_all_album_url = webpage.xpath("//a[contains(@href,'pornpics.com/galleries/')]/@href")
|
||||||
|
#print(webpage_all_album_url[3])
|
||||||
|
#print(webpage_all_album_url)
|
||||||
|
|
||||||
|
|
||||||
|
for album in webpage_all_album_url:
|
||||||
|
print("Album "+album)
|
||||||
|
print("")
|
||||||
|
page = requests.get(album,proxies=proxies)
|
||||||
|
webpage = html.fromstring(page.content)
|
||||||
|
|
||||||
|
images_list = webpage.xpath("//a[contains(@href,'cdni.pornpics.com/1280/')]/@href")
|
||||||
|
images_downloader.delay(name=name,images_url_list=images_list,destination_named_folder=destination_named_folder)
|
||||||
|
print(images_list)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@shared_task()
|
||||||
|
def images_downloader(name,images_url_list,destination_named_folder):
|
||||||
|
for image_url in images_url_list:
|
||||||
|
split = urlparse.urlsplit(image_url)
|
||||||
|
#filename = destination_folder + split.path.split("/")[-1]
|
||||||
|
filename = os.path.join(destination_named_folder,split.path.split("/")[-1])
|
||||||
|
|
||||||
|
|
||||||
|
print("downloading: "+filename+" -- "+image_url)
|
||||||
|
|
||||||
|
opener = urlrequest.build_opener(proxy)
|
||||||
|
|
||||||
|
urlrequest.install_opener(opener)
|
||||||
|
try:
|
||||||
|
urlrequest.urlretrieve(image_url, filename )
|
||||||
|
except:
|
||||||
|
print("Can't download "+filename+" -- "+image_url)
|
||||||
|
individual_image_downloader.delay(image_url=image_url, filename=filename)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@shared_task()
|
||||||
|
def individual_image_downloader(image_url, filename ):
|
||||||
|
print("Downloading again: "+filename+" -- "+image_url)
|
||||||
|
|
||||||
|
opener = urlrequest.build_opener(proxy)
|
||||||
|
|
||||||
|
urlrequest.install_opener(opener)
|
||||||
|
try:
|
||||||
|
urlrequest.urlretrieve(image_url, filename )
|
||||||
|
except:
|
||||||
|
print("Still Can't download "+filename+" -- "+image_url+" == Cancelling")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def simple_form(request):
|
||||||
|
name = request.GET.get('name')
|
||||||
|
reddit_downloader(username=name)
|
||||||
|
|
||||||
|
text_generated = "successfully sent to the reddit downloader"
|
||||||
|
return HttpResponse(text_generated, content_type="text/plain")
|
||||||
|
|
||||||
|
def reddit_downloader(username):
|
||||||
|
|
||||||
|
#create the prerequisites folder
|
||||||
|
destination_named_folder = check_and_create_destination_folder(name=username)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
url = "https://www.reddit.com/user/"+username+"/submitted/.json?limit=1000"
|
||||||
|
opener = urlrequest.build_opener(proxy)
|
||||||
|
urlrequest.install_opener(opener)
|
||||||
|
|
||||||
|
req = urlrequest.Request(url)
|
||||||
|
urlcurl = urlrequest.urlopen(req).read()
|
||||||
|
data = json.loads(urlcurl)
|
||||||
|
|
||||||
|
picture_list=[]
|
||||||
|
for children in data['data']['children']:
|
||||||
|
print("adding to the list : "+children['data']['url'])
|
||||||
|
picture_list.append(children['data']['url'])
|
||||||
|
|
||||||
|
images_downloader.delay(name=username,images_url_list=picture_list,destination_named_folder=destination_named_folder)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def redgif_donloader(username):
|
||||||
|
#on te front page of the user , https://www.redgifs.com/users/princesspizookie
|
||||||
|
# F12 and search network , find something that start as api.redgifs.com
|
||||||
|
# and the file is search?order=new&count=40&type=g
|
||||||
|
# copy as curl and you got the bearer
|
||||||
|
|
||||||
|
#curl curl 'https://api.redgifs.com/v2/users/princesspizookie/search?order=new&count=40&type=g'
|
||||||
|
#and you get the URLS , needs to be parsedw
|
||||||
|
return 0
|
||||||
|
def incremental(request):
|
||||||
|
return render(request, 'stash/incremental_form.html',{})
|
||||||
|
|
||||||
|
def incremental_form(request):
|
||||||
|
name = request.GET.get('name')
|
||||||
|
url = request.GET.get('url')
|
||||||
|
url_suffix = request.GET.get('url_suffix')
|
||||||
|
maximum_increment = int(request.GET.get('maximum_increment'))
|
||||||
|
minimum_increment = request.GET.get('minimum_increment')
|
||||||
|
|
||||||
|
increment_and_download.delay(minimum_increment=minimum_increment,maximum_increment=maximum_increment,url=url,url_suffix=url_suffix,name=name)
|
||||||
|
|
||||||
|
text_generated = "successfully sent to celery"
|
||||||
|
return HttpResponse(text_generated, content_type="text/plain")
|
||||||
|
|
||||||
|
@shared_task()
|
||||||
|
def increment_and_download(minimum_increment,maximum_increment,url,url_suffix,name):
|
||||||
|
if minimum_increment == None:
|
||||||
|
minimum_increment = 1
|
||||||
|
|
||||||
|
text_generated = ""
|
||||||
|
minimum_increment = int(minimum_increment)
|
||||||
|
maximum_increment = int(maximum_increment)
|
||||||
|
|
||||||
|
#check if the output directory exist and create if not
|
||||||
|
if not os.path.isdir(destination_folder):
|
||||||
|
os.makedirs(destination_folder)
|
||||||
|
|
||||||
|
#check if the named directory exist and create if not
|
||||||
|
destination_named_folder = os.path.join(destination_folder,name)
|
||||||
|
if not os.path.isdir(destination_named_folder):
|
||||||
|
os.makedirs(destination_named_folder)
|
||||||
|
|
||||||
|
print("\n downloading for "+name+" "+url+"XXX"+url_suffix)
|
||||||
|
|
||||||
|
for increment in range(minimum_increment,maximum_increment):
|
||||||
|
print("increment : "+str(increment)+"/"+str(maximum_increment))
|
||||||
|
if len(str(increment)) == 3:
|
||||||
|
increment_generated ='0' + str(increment)
|
||||||
|
elif len(str(increment)) == 2:
|
||||||
|
increment_generated ='00' + str(increment)
|
||||||
|
elif len(str(increment)) == 1:
|
||||||
|
increment_generated ='000' + str(increment)
|
||||||
|
|
||||||
|
url_generated = url+increment_generated+url_suffix
|
||||||
|
print(url_generated)
|
||||||
|
destination_filename = increment_generated+url_suffix
|
||||||
|
destination_file = os.path.join(destination_named_folder,destination_filename)
|
||||||
|
print(destination_file)
|
||||||
|
opener = urlrequest.build_opener(proxy)
|
||||||
|
urlrequest.install_opener(opener)
|
||||||
|
urlrequest.urlretrieve(url_generated, destination_file )
|
||||||
|
|
||||||
|
text_generated = "\n downloading for "+name+" "+url+increment_generated+url_suffix
|
||||||
|
print("download completed for "+name+" of "+str(maximum_increment)+" images")
|
||||||
|
return text_generated
|
||||||
|
def handle_survey_form(request):
|
||||||
|
config.load_kube_config(config_file='/kubeconfig/config')
|
||||||
|
v1 = client.BatchV1Api()
|
||||||
|
name = request.GET.get('name')
|
||||||
|
url = request.GET.get('url')
|
||||||
|
external_galleries = str(request.GET.get('external_galleries'))
|
||||||
|
|
||||||
|
stash_folder = "/stash"
|
||||||
|
|
||||||
|
if external_galleries:
|
||||||
|
print("external_galleries is not null")
|
||||||
|
performer_external_galleries = stash_folder+"/"+name+"_external_galleries.txt"
|
||||||
|
with open(performer_external_galleries, "a") as f:
|
||||||
|
f.write(external_galleries)
|
||||||
|
skip_searching_gallery = True
|
||||||
|
else:
|
||||||
|
print("external_galleries is null")
|
||||||
|
skip_searching_gallery = False
|
||||||
|
|
||||||
|
with open('django_code/stash_management/templates/template.stash-pornpics-dowloader.job.yml', 'r') as file:
|
||||||
|
#get the manifest in a variable template_manifest from the manifest file
|
||||||
|
template_manifest = yaml.safe_load(file)
|
||||||
|
|
||||||
|
#edit the container name
|
||||||
|
template_manifest['metadata']['name'] ="stash-pornpics-dowloader-"+name
|
||||||
|
template_manifest['spec']['template']['spec']['containers'][0]['name'] ="stash-pornpics-dowloader-"+name
|
||||||
|
|
||||||
|
#edit the command based on the input
|
||||||
|
command=['bash', '/config/download.sh', '--http_proxy', 'http://gluetun-svc.gluetun.svc:8888', '--BASE_URL', url, '--pornstars', name]
|
||||||
|
template_manifest['spec']['template']['spec']['containers'][0]['command']=command
|
||||||
|
|
||||||
|
|
||||||
|
#execute based on the value
|
||||||
|
api_response = v1.create_namespaced_job(body=template_manifest,namespace='stash')
|
||||||
|
return HttpResponse(api_response)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for django_code project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.urls import path
|
||||||
|
from apps.stash_management import apps as stashapp
|
||||||
|
from apps.stash_management import views as stashview
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
################## stash #####
|
||||||
|
path('', stashview.home),
|
||||||
|
path('hello/', stashapp.hello),
|
||||||
|
path('form/', stashapp.form),
|
||||||
|
path('incremental/', stashapp.incremental),
|
||||||
|
path('album/', stashapp.album),
|
||||||
|
path('album-form/', stashapp.album_form, name='submit_form'),
|
||||||
|
path('simple/', stashapp.simple),
|
||||||
|
path('simple-form/', stashapp.simple_form, name='submit_form'),
|
||||||
|
path('submit-form/', stashapp.handle_survey_form, name='submit_form'),
|
||||||
|
path('incremental-form/', stashapp.incremental_form, name='submit_form'),
|
||||||
|
]
|
||||||
@@ -5,4 +5,8 @@ from django.http import HttpResponse
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
|
||||||
def hello(request):
|
def hello(request):
|
||||||
return HttpResponse('<h1>Hello Django!</h1>')
|
return HttpResponse('<h1>Hello stash!</h1>')
|
||||||
|
|
||||||
|
|
||||||
|
def home(request):
|
||||||
|
return render(request, 'stash/listing.html')
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django.utils.html import format_html
|
||||||
|
from .models import StreamingSiteTestingData,StreamingRedirectData
|
||||||
|
from .utils import full_testing
|
||||||
|
from apps.website_redirection.utils import redirect_method
|
||||||
|
from urllib.parse import urlsplit, urlunsplit
|
||||||
|
from core.admin import UniversalModelAdmin
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(description="Add this show to streaming")
|
||||||
|
def re_redirect(modeladmin, request, queryset):
|
||||||
|
output_generated = ""
|
||||||
|
for query in queryset.values():
|
||||||
|
print(query)
|
||||||
|
key = "streaming"
|
||||||
|
value = query.get('url_display')
|
||||||
|
output_generated = output_generated + redirect_method(key,value)+";"
|
||||||
|
|
||||||
|
modeladmin.message_user(
|
||||||
|
request,
|
||||||
|
output_generated
|
||||||
|
)
|
||||||
|
|
||||||
|
@admin.action(description="check the URLs")
|
||||||
|
def check(modeladmin, request, queryset):
|
||||||
|
for query in queryset:
|
||||||
|
website_url = query.url
|
||||||
|
status=full_testing(website_url)[0]
|
||||||
|
result= full_testing(website_url)[1]
|
||||||
|
print(str(query.url)+": "+str(status)+" -> "+str(result))
|
||||||
|
query.status = status
|
||||||
|
query.result = result
|
||||||
|
query.save(update_fields=["status","result"])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.action(description="cleaning the url")
|
||||||
|
def urlcleaning(modeladmin, request, queryset):
|
||||||
|
for query in queryset:
|
||||||
|
# Split the URL into components
|
||||||
|
parsed = urlsplit(query.url)
|
||||||
|
|
||||||
|
# Rebuild using only scheme and netloc, adding a trailing slash at the end
|
||||||
|
base_url = urlunsplit((parsed.scheme, parsed.netloc, "/", "", ""))
|
||||||
|
query.url = base_url
|
||||||
|
query.save(update_fields=["url"])
|
||||||
|
print("Cleaning :"+str(base_url))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
@admin.register(StreamingSiteTestingData)
|
||||||
|
class streamingAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ['clickable_links','result_colored','newstatus']
|
||||||
|
fields = ['url']
|
||||||
|
actions = [check,urlcleaning]
|
||||||
|
|
||||||
|
def result_colored(self, obj):
|
||||||
|
colors = {
|
||||||
|
'REACHABLE': 'green',
|
||||||
|
'VPN REQUIRED': 'yellow',
|
||||||
|
'UNREACHABLE': 'red',
|
||||||
|
}
|
||||||
|
|
||||||
|
return format_html(
|
||||||
|
'<b style="background:{};">{}</b>',
|
||||||
|
colors[obj.result],
|
||||||
|
obj.result,
|
||||||
|
)
|
||||||
|
def newstatus(self, obj):
|
||||||
|
if obj.status != '200':
|
||||||
|
return format_html('<div style="width:100%%; height:100%%; background-color:orange;">{}</div>', obj.status)
|
||||||
|
#return obj.status
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(StreamingRedirectData)
|
||||||
|
class StreamingRedirectAdmin(UniversalModelAdmin):
|
||||||
|
list_display = ['name','image_tag','season','episode','randomViewing','clickable_links','addedDate','alias']
|
||||||
|
actions = [re_redirect]
|
||||||
|
|
||||||
|
#fields = ['name','season','episode','url_example','prefix','infix','suffix','alias','randomViewing','seasonInformation']
|
||||||
|
fieldsets = (
|
||||||
|
(
|
||||||
|
'Serie', {
|
||||||
|
'fields': ('name', 'season', 'episode','randomViewing')
|
||||||
|
}),
|
||||||
|
(
|
||||||
|
'url', {
|
||||||
|
|
||||||
|
'fields': (('prefix','infix','suffix'))
|
||||||
|
}),
|
||||||
|
(
|
||||||
|
'Information', {
|
||||||
|
"classes": ["collapse"],
|
||||||
|
'fields': ('seasonInformation','alias','betaserieShowId','maximumNumberSeason','poster_url')
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
link_field = 'url_display'
|
||||||
|
|
||||||
|
def image_tag(self,obj):
|
||||||
|
return format_html('<img src="{0}" style="width: 355px; height:200px;" />'.format(obj.poster_url))
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class StreamingConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'apps.streaming'
|
||||||
|
label = 'streaming'
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-08-05 12:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='streamingData',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('url', models.CharField(max_length=1000)),
|
||||||
|
('addedDate', models.DateField(auto_now_add=True, null=True, verbose_name='Published')),
|
||||||
|
('status', models.CharField(blank=True, max_length=1000, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'streaming',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-08-05 13:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('streaming', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='streamingdata',
|
||||||
|
name='result',
|
||||||
|
field=models.CharField(blank=True, max_length=1000, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-08-07 13:13
|
||||||
|
|
||||||
|
import apps.streaming.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('streaming', '0002_streamingdata_result'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='StreamingRedirectData',
|
||||||
|
fields=[
|
||||||
|
('name', models.CharField(help_text='Name of the show', max_length=1000, primary_key=True, serialize=False)),
|
||||||
|
('url_example', models.CharField(help_text='https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=18&episode=5', max_length=1000)),
|
||||||
|
('prefix', models.CharField(blank=True, help_text='https://www.1shows.org/tv/456-the-simpsons?streaming=true&season=', max_length=1000, null=True)),
|
||||||
|
('infix', models.CharField(blank=True, help_text='&episode=', max_length=1000, null=True)),
|
||||||
|
('suffix', models.CharField(blank=True, max_length=1000, null=True)),
|
||||||
|
('addedDate', models.DateField(auto_now_add=True, null=True, verbose_name='Published')),
|
||||||
|
('alias', models.CharField(default=apps.streaming.models.StreamingRedirectData.sanitize, max_length=1000)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'StreamingRedirect',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 4.2.30 on 2026-08-07 14:02
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('streaming', '0003_streamingredirectdata'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='streamingredirectdata',
|
||||||
|
name='episode_to_watch',
|
||||||
|
field=models.IntegerField(default=1),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='streamingredirectdata',
|
||||||
|
name='season_to_watch',
|
||||||
|
field=models.IntegerField(default=1),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='streamingredirectdata',
|
||||||
|
name='alias',
|
||||||
|
field=models.CharField(blank=True, max_length=1000, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user