django-restit 4.0.2__py3-none-any.whl → 4.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_restit-4.0.2.dist-info → django_restit-4.0.5.dist-info}/METADATA +1 -1
- {django_restit-4.0.2.dist-info → django_restit-4.0.5.dist-info}/RECORD +15 -10
- pushit/rpc/__init__.py +2 -0
- pushit/rpc/githooks.py +61 -0
- pushit/rpc/legacy.py +126 -0
- pushit/rpc/products.py +15 -0
- pushit/tq.py +6 -0
- pushit/utils.py +58 -0
- rest/__init__.py +1 -1
- rest/decorators.py +15 -3
- rest/log.py +7 -16
- rest/rpc.py +7 -0
- rest/urls.py +3 -1
- pushit/rpc.py +0 -334
- {django_restit-4.0.2.dist-info → django_restit-4.0.5.dist-info}/LICENSE.md +0 -0
- {django_restit-4.0.2.dist-info → django_restit-4.0.5.dist-info}/WHEEL +0 -0
@@ -331,12 +331,17 @@ pushit/admin.py,sha256=69HdDZU_Iz8Fm72M8r8FUztsZvW37zdGwVmj8VTqr0c,451
|
|
331
331
|
pushit/migrations/0001_initial.py,sha256=kYF1ksOlKf9ElrlagGhpNf5GbKEq6SORWGreMH9A7as,4555
|
332
332
|
pushit/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
333
333
|
pushit/models.py,sha256=jrfreqBTThe0GvSbu16ACBMIGcZQX1534ECxVVtbVBk,5076
|
334
|
-
pushit/rpc.py,sha256=
|
334
|
+
pushit/rpc/__init__.py,sha256=13ibfbWNdjoNxzCzF8QxasSzFgs8IZJPc05XhErOBCw,88
|
335
|
+
pushit/rpc/githooks.py,sha256=p81qKjIcrFeQll1fKnm2pGRURWxKhT9TlH8PEHoc9po,1874
|
336
|
+
pushit/rpc/legacy.py,sha256=9xsZH1S70htIb0bwKENfhTe-uHvyqSTiPiwYTlLWS3E,5028
|
337
|
+
pushit/rpc/products.py,sha256=JFNN0VYsZQ9VJ5RZ3vD0m2hhsXEIB5Koz66inlMzx6Y,378
|
335
338
|
pushit/static/js/models_pushit.js,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
339
|
+
pushit/tq.py,sha256=i3uxKfXf3bjkb1XhGWILKxxL0YwsX0TIbYjkXGbbcWU,131
|
340
|
+
pushit/utils.py,sha256=5NcWELJJjmiY2N7SiSh-qonJbLgVtFAu-EMkcFJ5St4,1966
|
336
341
|
rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
337
342
|
rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
|
338
343
|
rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
|
339
|
-
rest/__init__.py,sha256=
|
344
|
+
rest/__init__.py,sha256=Khb1uCxKcOF2h84rJaf2ZhOpxZujpN9mAvCExA7fTlc,120
|
340
345
|
rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
|
341
346
|
rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
|
342
347
|
rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
|
@@ -344,7 +349,7 @@ rest/crypto/aes.py,sha256=f7UgiTGCfgjCc7dL94vnxkPhq_5NzooI-kw0B8_nA58,3605
|
|
344
349
|
rest/crypto/privpub.py,sha256=_FioylVcbMmDP80yPYjURmafEiDmEAMkskbc7WF10ac,4082
|
345
350
|
rest/crypto/util.py,sha256=9xrXpdI7Q9L4B6N_UKkf0tyQCSNLIxPRoEVAyJraS3Y,3955
|
346
351
|
rest/datem.py,sha256=Tv8wF2PX0Ktr1wLgGEj6o0OW45RSkD9XDLnLRk8bRjc,7784
|
347
|
-
rest/decorators.py,sha256=
|
352
|
+
rest/decorators.py,sha256=OROP0VRNEk7FMk2WwLPnJ8olwyFX92bAsvQ7tg2tE3U,15597
|
348
353
|
rest/encryption.py,sha256=x6Kiez0tVqfxK26MSsRL3k8OS05ni1gEX2aj3I0S9V0,788
|
349
354
|
rest/extra/__init__.py,sha256=YzmNsch5H5FFLkUK9mIAKyoRK_rJCA9HGb0kubp4h30,54
|
350
355
|
rest/extra/json_metadata.py,sha256=p_ffzmANmOFix_oC3voR6_NNTjcn7-T7aXcH-I4_Npg,1078
|
@@ -353,7 +358,7 @@ rest/forms.py,sha256=66Wm5cdy8tKib_mGicjq_yd-gNVMFWRECnrDksnNnwU,6316
|
|
353
358
|
rest/helpers.py,sha256=ahTTAnsHPeBQTcxs7u-Yfjh5lP_hefDoBcIio12cYZg,23837
|
354
359
|
rest/joke.py,sha256=0PpKaX2iN7jlS62kgjfmmqkFBYLPURz15aQ8R7OJkJ8,260
|
355
360
|
rest/jwtoken.py,sha256=1ruZGPTXnodb85ywPd8ZmRiRYCskopA8EhcbX7Adixc,2298
|
356
|
-
rest/log.py,sha256=
|
361
|
+
rest/log.py,sha256=hd1_4HBOS395sfXJIL6BTw9yekm1SLgBwYx_PdfIhKA,20930
|
357
362
|
rest/mail.py,sha256=Y7EhkFAIcX4ieSJ7KLPeECmzYQEGAjWtkLlFvD87bhA,7754
|
358
363
|
rest/mailman.py,sha256=v5O1G5s3HiAKmz-J1z0uT6_q3xsONPpxVl9saEyQQ2I,9174
|
359
364
|
rest/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -369,7 +374,7 @@ rest/middleware/session_store.py,sha256=X_i06TnZLW1srV0vkjjLhZ7fl1G56PswXxRpVzdF
|
|
369
374
|
rest/models.py,sha256=oVaAMiHCFJRERat2e3ejDs5TTKCiZNSe6muG6hgN6uI,76845
|
370
375
|
rest/regexes.yaml,sha256=VoGb4E-P_K9f82Yzcpltgzekpt9usRtwu9PYlo46nUw,149463
|
371
376
|
rest/requestex.py,sha256=eD1eCPhLl7fj0oUKpESCTIr8O7mjOyBUsRXVMQ1h3W8,14894
|
372
|
-
rest/rpc.py,sha256=
|
377
|
+
rest/rpc.py,sha256=KMih2Z4Z0Pqgwmcy_14nKqMCKJ9lGDJ6-vwMA2NSlyQ,3713
|
373
378
|
rest/search.py,sha256=i7rnZZhlnuAT0isyVcMHEqGjbiz7EIArgjzzg7xwK-s,7645
|
374
379
|
rest/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
375
380
|
rest/serializers/collection.py,sha256=qpEQWl_mf_X72zFP8yNwJsDUTmc0h59KTfeFDs_Li1I,1644
|
@@ -393,7 +398,7 @@ rest/templates/rest_html.html,sha256=wGZV3j_tB9rzzJlsMxidUQ5ex_uRPyU_s8GCmHLXiqk
|
|
393
398
|
rest/ua.py,sha256=iKoLdDFzwrmo_QfKxQoM88wPgvJabIIZPhxvIDfo5J0,185122
|
394
399
|
rest/uberdict.py,sha256=ivDpzfchQqX8dM2_TtuyMW7NNO-j7zDmxkdKixQxvU4,17064
|
395
400
|
rest/url_docs.py,sha256=O8O_CQso3fB-7o-huidIT1BRGv5R6lDW-yKHnsGyAPk,11881
|
396
|
-
rest/urls.py,sha256=
|
401
|
+
rest/urls.py,sha256=U3eD9kI19wp-NkkXCiAjdQe560fslskQngStRcGDS0I,1787
|
397
402
|
rest/views.py,sha256=IxG3RF5txtQg7ov4H_Iymozq3NjeJ-GQNMsmdmsmExM,1056
|
398
403
|
sessionlog/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
399
404
|
sessionlog/README.md,sha256=vQEVJ_8u3Vv19VwPfscjCiHFu61ZSrEM-KIuBpUXhws,62
|
@@ -441,7 +446,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
441
446
|
ws4redis/settings.py,sha256=lF-6nzv7SWjmFgmontpZKdSBhp8q4FhvFOcEYZGR8pc,1411
|
442
447
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
443
448
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
444
|
-
django_restit-4.0.
|
445
|
-
django_restit-4.0.
|
446
|
-
django_restit-4.0.
|
447
|
-
django_restit-4.0.
|
449
|
+
django_restit-4.0.5.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
450
|
+
django_restit-4.0.5.dist-info/METADATA,sha256=kGdo8wXQiGHWRi1D8ix5E6DV-LIjWSpMYpL91X7L8kg,7525
|
451
|
+
django_restit-4.0.5.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
452
|
+
django_restit-4.0.5.dist-info/RECORD,,
|
pushit/rpc/__init__.py
ADDED
pushit/rpc/githooks.py
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
from rest import decorators as rd
|
2
|
+
from rest import views as rv
|
3
|
+
from rest import settings
|
4
|
+
from rest import helpers as rh
|
5
|
+
from taskqueue.models import Task
|
6
|
+
from pushit import utils
|
7
|
+
import time
|
8
|
+
|
9
|
+
|
10
|
+
@rd.urlPOST('hooks/git_update')
|
11
|
+
def rest_on_git_hook(request):
|
12
|
+
sec_key = request.DATA.get("token")
|
13
|
+
git_key = settings.get("GIT_KEY", "hookswhat")
|
14
|
+
hook_request = None
|
15
|
+
|
16
|
+
req_key = request.DATA.getHeader("HTTP_X_GITLAB_TOKEN")
|
17
|
+
if req_key is not None:
|
18
|
+
hook_request = utils.parseGitLab(request)
|
19
|
+
else:
|
20
|
+
req_key = request.DATA.getHeader("HTTP_X_HUB_SIGNATURE_256")
|
21
|
+
if req_key is not None:
|
22
|
+
hook_request = utils.parseGithub(request)
|
23
|
+
|
24
|
+
if sec_key != git_key and req_key is None:
|
25
|
+
rh.error("GIT HOOK NO TOKEN", request.META)
|
26
|
+
return rv.restPermissionDenied(request)
|
27
|
+
|
28
|
+
git_projects = settings.get("GIT_PROJECTS", None)
|
29
|
+
|
30
|
+
if hook_request.name not in git_projects:
|
31
|
+
return rv.restStatus(request, False, error="no config for project")
|
32
|
+
|
33
|
+
proj_info = utils.getProjectForBranch(git_projects.get(hook_request.name), hook_request.branch)
|
34
|
+
if proj_info is None:
|
35
|
+
return rv.restStatus(request, False, error="no branch for project")
|
36
|
+
|
37
|
+
if hook_request.kind == "push":
|
38
|
+
on_git_push_request(proj_info, hook_request)
|
39
|
+
|
40
|
+
return rv.restStatus(request, True)
|
41
|
+
|
42
|
+
|
43
|
+
def on_git_push_request(info, hook_request):
|
44
|
+
branch = info.get("branch")
|
45
|
+
cmd = info.get("updater")
|
46
|
+
use_tq = info.get("use_tq", False)
|
47
|
+
|
48
|
+
if use_tq:
|
49
|
+
data = dict(branch=branch, update_cmd=cmd)
|
50
|
+
Task.Publish("pushit", "run_update", data, channel="tq_updater")
|
51
|
+
else:
|
52
|
+
asyncUpdater(cmd, branch)
|
53
|
+
|
54
|
+
|
55
|
+
@rd.rest_async
|
56
|
+
def asyncUpdater(cmd, branch):
|
57
|
+
import random
|
58
|
+
# randomize the hit so we avoid collisions (gitlabs issues)
|
59
|
+
time.sleep(random.randint(2, 15))
|
60
|
+
utils.updateCode(cmd, branch)
|
61
|
+
|
pushit/rpc/legacy.py
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
from pushit.models import Product, Release
|
2
|
+
from rest import decorators as rd
|
3
|
+
|
4
|
+
|
5
|
+
@rd.urlPOST (r'^product$')
|
6
|
+
@rd.urlPOST (r'^product/(?P<product_id>\d+)$')
|
7
|
+
@rd.urlPOST (r'^product/uuid/(?P<uuid>\w+)$')
|
8
|
+
@rd.login_optional
|
9
|
+
def updateProduct(request, product_id=None, uuid=None):
|
10
|
+
if not request.member:
|
11
|
+
return restPermissionDenied(request)
|
12
|
+
product = None
|
13
|
+
if not product_id and not uuid:
|
14
|
+
product = Product.createFromRequest(request, owner=request.member, group=request.group)
|
15
|
+
elif product_id:
|
16
|
+
product = Product.objects.filter(pk=product_id).last()
|
17
|
+
elif uuid:
|
18
|
+
product = Product.objects.filter(oid=uuid).last()
|
19
|
+
|
20
|
+
if not product:
|
21
|
+
return restStatus(request, False, error="unknown product")
|
22
|
+
if product.owner != request.member or (product.group and not request.member.isMemberOf(product.group)):
|
23
|
+
if not request.user.is_staff:
|
24
|
+
return restPermissionDenied(request)
|
25
|
+
product.saveFromRequest(request, owner=request.member)
|
26
|
+
return restGet(request, product, **Product.getGraph("default"))
|
27
|
+
|
28
|
+
|
29
|
+
@rd.urlGET (r'^product/(?P<product_id>\d+)$')
|
30
|
+
@rd.urlGET (r'^product/uuid/(?P<uuid>\w+)$')
|
31
|
+
@rd.login_optional
|
32
|
+
def getProduct(request, product_id=None, uuid=None):
|
33
|
+
product = None
|
34
|
+
if product_id:
|
35
|
+
product = Product.objects.filter(pk=product_id).last()
|
36
|
+
elif uuid:
|
37
|
+
product = Product.objects.filter(oid=uuid).last()
|
38
|
+
else:
|
39
|
+
return restNotFound(request)
|
40
|
+
|
41
|
+
if not product:
|
42
|
+
return restStatus(request, False, error="unknown product")
|
43
|
+
if not product.is_public and not request.member:
|
44
|
+
return restPermissionDenied(request, "not logged in")
|
45
|
+
return product.restGet(request)
|
46
|
+
|
47
|
+
|
48
|
+
@rd.urlGET (r'^product$')
|
49
|
+
@rd.login_optional
|
50
|
+
def listProducts(request):
|
51
|
+
if not request.member:
|
52
|
+
return restPermissionDenied(request)
|
53
|
+
if not request.member.is_staff:
|
54
|
+
return restPermissionDenied(request)
|
55
|
+
|
56
|
+
kind = request.DATA.get("kind")
|
57
|
+
qset = Product.objects.filter(archived=False)
|
58
|
+
if kind:
|
59
|
+
qset = qset.filter(kind=kind)
|
60
|
+
|
61
|
+
return restList(request, qset, **Product.getGraph("default"))
|
62
|
+
|
63
|
+
|
64
|
+
@rd.urlPOST (r'^release$')
|
65
|
+
@rd.urlPOST (r'^release/(?P<release_id>\d+)$')
|
66
|
+
@rd.login_optional
|
67
|
+
def updateRelease(request, release_id=None):
|
68
|
+
if not request.member:
|
69
|
+
return restPermissionDenied(request)
|
70
|
+
|
71
|
+
if not release_id:
|
72
|
+
auto_version = request.DATA.get("auto_version", False)
|
73
|
+
prod_uuid = request.DATA.get(["product", "product_uuid"])
|
74
|
+
product = None
|
75
|
+
if prod_uuid:
|
76
|
+
product = Product.objects.filter(oid=prod_uuid).last()
|
77
|
+
else:
|
78
|
+
prod_id = request.DATA.get("product_id")
|
79
|
+
if prod_id:
|
80
|
+
product = Product.objects.filter(pk=prod_id).last()
|
81
|
+
if not product:
|
82
|
+
return restStatus(request, False, error="product required")
|
83
|
+
version_num = request.DATA.get("version_num", field_type=int)
|
84
|
+
last_release = Release.objects.filter(product=product).order_by("-version_num").first()
|
85
|
+
|
86
|
+
if not version_num:
|
87
|
+
if last_release and auto_version:
|
88
|
+
version_num = last_release.version_num + 1
|
89
|
+
elif auto_version:
|
90
|
+
version_num = 1
|
91
|
+
else:
|
92
|
+
return restStatus(request, False, error="no version info supplied, try auto_version=1")
|
93
|
+
elif last_release and version_num <= last_release.version_num:
|
94
|
+
return restStatus(request, False, error="version is not greater then last")
|
95
|
+
|
96
|
+
release = Release.createFromRequest(request, product=product, owner=request.member, group=request.group, version_num=version_num)
|
97
|
+
else:
|
98
|
+
release = Release.objects.filter(pk=release_id).last()
|
99
|
+
if not release:
|
100
|
+
return restStatus(request, False, error="unknown release")
|
101
|
+
if release.owner != request.member or (release.product.group and not request.member.isMemberOf(release.product.group)):
|
102
|
+
if not request.user.is_staff:
|
103
|
+
return restPermissionDenied(request)
|
104
|
+
release.saveFromRequest(request, owner=request.member)
|
105
|
+
if request.DATA.get("make_current"):
|
106
|
+
release.makeCurrent()
|
107
|
+
elif request.DATA.get("make_beta"):
|
108
|
+
release.makeCurrent()
|
109
|
+
return restGet(request, release, **Release.getGraph("default"))
|
110
|
+
|
111
|
+
|
112
|
+
@rd.urlGET (r'^release/(?P<release_id>\d+)$')
|
113
|
+
@rd.login_optional
|
114
|
+
def getRelease(request, release_id):
|
115
|
+
release = Release.objects.filter(pk=release_id).last()
|
116
|
+
if not release:
|
117
|
+
return restStatus(request, False, error="unknown release")
|
118
|
+
if not release.product.is_public and not request.member:
|
119
|
+
return restPermissionDenied(request, "not logged in")
|
120
|
+
return restGet(request, release, **Release.getGraph("default"))
|
121
|
+
|
122
|
+
|
123
|
+
def reportRestIssue(subject, message, perm="rest_errors", email_only=False):
|
124
|
+
# notifyWithPermission(perm, subject, message=None, template=None, context=None, email_only=False)
|
125
|
+
# notify email only
|
126
|
+
Member.notifyWithPermission(perm, subject, message, email_only=email_only)
|
pushit/rpc/products.py
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
from rest import decorators as rd
|
2
|
+
from rest import views as rv
|
3
|
+
from pushit.models import Product, Release
|
4
|
+
|
5
|
+
|
6
|
+
@rd.url('product')
|
7
|
+
@rd.url('product/<int:pk>')
|
8
|
+
def rest_on_product(request, pk=None):
|
9
|
+
return Product.on_rest_request(request, pk)
|
10
|
+
|
11
|
+
|
12
|
+
@rd.url('release')
|
13
|
+
@rd.url('release/<int:pk>')
|
14
|
+
def rest_on_release(request, pk=None):
|
15
|
+
return Release.on_rest_request(request, pk)
|
pushit/tq.py
ADDED
pushit/utils.py
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
from rest import settings
|
2
|
+
from rest import log
|
3
|
+
from objict import objict
|
4
|
+
import os
|
5
|
+
import subprocess
|
6
|
+
|
7
|
+
logger = log.getLogger("pushit", filename="pushit.log")
|
8
|
+
|
9
|
+
|
10
|
+
def updateCode(update_cmd, branch, update_user="ec2-user"):
|
11
|
+
if settings.PUSHIT_TEST_SUDO:
|
12
|
+
cmd = ["sudo", "-lU", update_user, update_cmd, branch]
|
13
|
+
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
14
|
+
out, err = process.communicate()
|
15
|
+
if err.strip():
|
16
|
+
logger.warning("WARNING: cannot run {}, we don't have sudo rights".format(update_cmd))
|
17
|
+
logger.warning("WARNING: add {} to your sudo user".format(update_cmd))
|
18
|
+
return
|
19
|
+
# - lock it so we kill any updates in progress and start a new one
|
20
|
+
cmd = ["sudo", "-u", update_user, update_cmd, branch]
|
21
|
+
logger.info("updating...", cmd)
|
22
|
+
subprocess.Popen(cmd, close_fds=True)
|
23
|
+
|
24
|
+
|
25
|
+
def parseGitLab(request):
|
26
|
+
info = objict(vendor="gitlab")
|
27
|
+
info.name = request.DATA.get("project.name")
|
28
|
+
info.kind = request.DATA.get("object_kind")
|
29
|
+
if "ref" in request.DATA:
|
30
|
+
info.branch = request.DATA.get("ref").split('/')[-1]
|
31
|
+
if info.kind == "merge_request":
|
32
|
+
info.state = request.DATA.get("object_attributes.state", None)
|
33
|
+
if info.state == "merged":
|
34
|
+
info.kind = "merged"
|
35
|
+
return info
|
36
|
+
|
37
|
+
|
38
|
+
def parseGithub(request):
|
39
|
+
info = objict(vendor="github")
|
40
|
+
info.name = request.DATA.get("repository.name")
|
41
|
+
info.kind = request.DATA.getHeader("HTTP_X_GITHUB_EVENT")
|
42
|
+
if "ref" in request.DATA:
|
43
|
+
info.branch = request.DATA.get("ref").split('/')[-1]
|
44
|
+
logger.info("github request", info)
|
45
|
+
return info
|
46
|
+
|
47
|
+
|
48
|
+
def getProjectForBranch(proj_info, branch):
|
49
|
+
if proj_info is None:
|
50
|
+
return None
|
51
|
+
if isinstance(proj_info, list):
|
52
|
+
for pi in proj_info:
|
53
|
+
if pi["branch"] == branch:
|
54
|
+
return pi
|
55
|
+
return None
|
56
|
+
if proj_info["branch"] == branch:
|
57
|
+
return proj_info
|
58
|
+
return None
|
rest/__init__.py
CHANGED
rest/decorators.py
CHANGED
@@ -18,12 +18,14 @@ from datetime import datetime
|
|
18
18
|
from auditlog.models import PersistentLog
|
19
19
|
|
20
20
|
import importlib
|
21
|
+
import pkgutil
|
21
22
|
import threading
|
22
23
|
import traceback
|
23
24
|
|
24
25
|
REST_METRICS = settings.get("REST_METRICS", False)
|
25
26
|
REST_METRICS_BY_ENDPOINT = settings.get("REST_METRICS_BY_ENDPOINT", False)
|
26
27
|
REST_METRICS_IGNORE = settings.get("REST_METRICS_IGNORE", [])
|
28
|
+
REST_MODULE_NAME = settings.get("REST_MODULE_NAME", "rpc")
|
27
29
|
|
28
30
|
|
29
31
|
# background task (no return)
|
@@ -130,6 +132,12 @@ def dispatcher(request, *args, **kwargs):
|
|
130
132
|
return restStatus(request, False, error="endpoint not found", error_code=404)
|
131
133
|
|
132
134
|
|
135
|
+
def _load_module(mod):
|
136
|
+
if pkgutil.find_loader(mod) is not None:
|
137
|
+
return importlib.import_module(mod)
|
138
|
+
return None
|
139
|
+
|
140
|
+
|
133
141
|
def _url_method(pattern, method=None, *args, **kwargs):
|
134
142
|
"""
|
135
143
|
Register a view handler for a specific HTTP method
|
@@ -150,13 +158,17 @@ def _url_method(pattern, method=None, *args, **kwargs):
|
|
150
158
|
# print module.__name__
|
151
159
|
root_name = module.__name__.split('.')[0]
|
152
160
|
# print "importing {0}.rpc".format(root_name)
|
153
|
-
|
161
|
+
rmodule = _load_module(f"{root_name}.{REST_MODULE_NAME}")
|
162
|
+
if rmodule is not None:
|
163
|
+
rpc_root_module = rmodule
|
154
164
|
# print "{0}/{1}".format(rpc_root_module.__name__, pattern)
|
155
|
-
elif not module.__name__.endswith(".
|
165
|
+
elif not module.__name__.endswith(f".{REST_MODULE_NAME}") and module.__name__.count('.'):
|
156
166
|
# print module.__name__
|
157
167
|
root_name = module.__name__.split('.')[0]
|
158
168
|
# print "importing {0}.rpc".format(root_name)
|
159
|
-
|
169
|
+
rmodule = _load_module(f"{root_name}.{REST_MODULE_NAME}")
|
170
|
+
if rmodule is not None:
|
171
|
+
rpc_root_module = rmodule
|
160
172
|
lmethod = method
|
161
173
|
if lmethod is None:
|
162
174
|
lmethod = "ALL"
|
rest/log.py
CHANGED
@@ -12,7 +12,11 @@ import sys
|
|
12
12
|
import threading
|
13
13
|
import time
|
14
14
|
import traceback
|
15
|
+
from .settings_helper import settings
|
15
16
|
|
17
|
+
LOG_FOLDER = settings.LOG_ROOT
|
18
|
+
if LOG_FOLDER is None:
|
19
|
+
LOG_FOLDER = os.path.join(settings.BASE_DIR, "var", "logs")
|
16
20
|
|
17
21
|
COLOR_LOGS = True
|
18
22
|
MAX_LOG_SIZE = 10485760
|
@@ -21,19 +25,6 @@ MAX_LOG_SIZE = 10485760
|
|
21
25
|
ROTATE_LEFT_OVER_BYTES = 50000
|
22
26
|
LOG_COUNT = 3
|
23
27
|
|
24
|
-
REST_FOLDER = os.path.realpath(__file__)
|
25
|
-
# now work backwards until we find folder with "django"
|
26
|
-
ROOT = None
|
27
|
-
CUR_FOLDER = REST_FOLDER
|
28
|
-
while ROOT is None:
|
29
|
-
if os.path.exists(os.path.join(CUR_FOLDER, "django")):
|
30
|
-
ROOT = CUR_FOLDER
|
31
|
-
else:
|
32
|
-
CUR_FOLDER = os.path.dirname(CUR_FOLDER)
|
33
|
-
|
34
|
-
VAR_FOLDER = os.path.join(ROOT, "var", "logs")
|
35
|
-
PATH = VAR_FOLDER
|
36
|
-
|
37
28
|
|
38
29
|
class RestLogManager(object):
|
39
30
|
def __init__(self):
|
@@ -121,8 +112,8 @@ def getLogger(
|
|
121
112
|
LOG_MANAGER.loggers[name] = rest_logger
|
122
113
|
if set_master:
|
123
114
|
LOG_MANAGER.master = rest_logger
|
124
|
-
if not os.path.exists(
|
125
|
-
mkdir(
|
115
|
+
if not os.path.exists(LOG_FOLDER):
|
116
|
+
mkdir(LOG_FOLDER)
|
126
117
|
except Exception as err:
|
127
118
|
print((str(err)))
|
128
119
|
print((str(traceback.format_exc())))
|
@@ -160,7 +151,7 @@ class RestLoggerStream(object):
|
|
160
151
|
if not os.path.exists(self.filename):
|
161
152
|
path, fname = os.path.split(filename)
|
162
153
|
if not len(path):
|
163
|
-
self.filename = os.path.join(
|
154
|
+
self.filename = os.path.join(LOG_FOLDER, filename)
|
164
155
|
self.max_bytes = max_bytes
|
165
156
|
self.stream = None
|
166
157
|
self.is_stdout = False
|
rest/rpc.py
CHANGED
@@ -31,6 +31,13 @@ def on_get_version(request):
|
|
31
31
|
return views.restStatus(request, True, {"data": version.VERSION})
|
32
32
|
|
33
33
|
|
34
|
+
@url(r'^versions$')
|
35
|
+
def on_get_version(request):
|
36
|
+
from rest import __version__ as restit_version
|
37
|
+
versions = dict(project=version.VERSION, restit=restit_version)
|
38
|
+
return views.restStatus(request, True, {"data": versions})
|
39
|
+
|
40
|
+
|
34
41
|
@url(r'^joke$')
|
35
42
|
def on_get_joke(request):
|
36
43
|
return views.restGet(request, {"joke": joke.getRandomJoke()})
|
rest/urls.py
CHANGED
@@ -24,7 +24,9 @@ urlpatterns = [
|
|
24
24
|
def load_app(app, root_module=None):
|
25
25
|
module = None
|
26
26
|
try:
|
27
|
-
module = loadModule(app
|
27
|
+
module = loadModule(f"{app}.rpc")
|
28
|
+
if module is None:
|
29
|
+
module = loadModule(f"{app}.rurl")
|
28
30
|
except ImportError as err:
|
29
31
|
print("**** failed to load {0}.rpc! ****".format(app))
|
30
32
|
print("**** missing dependencies ****")
|
pushit/rpc.py
DELETED
@@ -1,334 +0,0 @@
|
|
1
|
-
from django.db import models
|
2
|
-
|
3
|
-
|
4
|
-
from account.models import Member
|
5
|
-
|
6
|
-
from rest.views import *
|
7
|
-
from rest.decorators import *
|
8
|
-
from rest import search
|
9
|
-
from rest import helpers
|
10
|
-
from rest import crypto
|
11
|
-
from rest import log
|
12
|
-
from rest import settings
|
13
|
-
|
14
|
-
|
15
|
-
logger = log.getLogger("pushit", filename="pushit.log")
|
16
|
-
|
17
|
-
from objict import objict
|
18
|
-
|
19
|
-
from pushit.models import Product, Release
|
20
|
-
|
21
|
-
import json
|
22
|
-
|
23
|
-
import base64
|
24
|
-
|
25
|
-
from datetime import datetime, timedelta
|
26
|
-
import time
|
27
|
-
|
28
|
-
@urlPOST (r'^product$')
|
29
|
-
@urlPOST (r'^product/(?P<product_id>\d+)$')
|
30
|
-
@urlPOST (r'^product/uuid/(?P<uuid>\w+)$')
|
31
|
-
@login_optional
|
32
|
-
def updateProduct(request, product_id=None, uuid=None):
|
33
|
-
if not request.member:
|
34
|
-
return restPermissionDenied(request)
|
35
|
-
product = None
|
36
|
-
if not product_id and not uuid:
|
37
|
-
product = Product.createFromRequest(request, owner=request.member, group=request.group)
|
38
|
-
elif product_id:
|
39
|
-
product = Product.objects.filter(pk=product_id).last()
|
40
|
-
elif uuid:
|
41
|
-
product = Product.objects.filter(oid=uuid).last()
|
42
|
-
|
43
|
-
if not product:
|
44
|
-
return restStatus(request, False, error="unknown product")
|
45
|
-
if product.owner != request.member or (product.group and not request.member.isMemberOf(product.group)):
|
46
|
-
if not request.user.is_staff:
|
47
|
-
return restPermissionDenied(request)
|
48
|
-
product.saveFromRequest(request, owner=request.member)
|
49
|
-
return restGet(request, product, **Product.getGraph("default"))
|
50
|
-
|
51
|
-
@urlGET (r'^product/(?P<product_id>\d+)$')
|
52
|
-
@urlGET (r'^product/uuid/(?P<uuid>\w+)$')
|
53
|
-
@login_optional
|
54
|
-
def getProduct(request, product_id=None, uuid=None):
|
55
|
-
product = None
|
56
|
-
if product_id:
|
57
|
-
product = Product.objects.filter(pk=product_id).last()
|
58
|
-
elif uuid:
|
59
|
-
product = Product.objects.filter(oid=uuid).last()
|
60
|
-
else:
|
61
|
-
return restNotFound(request)
|
62
|
-
|
63
|
-
if not product:
|
64
|
-
return restStatus(request, False, error="unknown product")
|
65
|
-
if not product.is_public and not request.member:
|
66
|
-
return restPermissionDenied(request, "not logged in")
|
67
|
-
return product.restGet(request)
|
68
|
-
|
69
|
-
@urlGET (r'^product$')
|
70
|
-
@login_optional
|
71
|
-
def listProducts(request):
|
72
|
-
if not request.member:
|
73
|
-
return restPermissionDenied(request)
|
74
|
-
if not request.member.is_staff:
|
75
|
-
return restPermissionDenied(request)
|
76
|
-
|
77
|
-
kind = request.DATA.get("kind")
|
78
|
-
qset = Product.objects.filter(archived=False)
|
79
|
-
if kind:
|
80
|
-
qset = qset.filter(kind=kind)
|
81
|
-
|
82
|
-
return restList(request, qset, **Product.getGraph("default"))
|
83
|
-
|
84
|
-
@urlPOST (r'^release$')
|
85
|
-
@urlPOST (r'^release/(?P<release_id>\d+)$')
|
86
|
-
@login_optional
|
87
|
-
def updateRelease(request, release_id=None):
|
88
|
-
if not request.member:
|
89
|
-
return restPermissionDenied(request)
|
90
|
-
|
91
|
-
if not release_id:
|
92
|
-
auto_version = request.DATA.get("auto_version", False)
|
93
|
-
prod_uuid = request.DATA.get(["product", "product_uuid"])
|
94
|
-
product = None
|
95
|
-
if prod_uuid:
|
96
|
-
product = Product.objects.filter(oid=prod_uuid).last()
|
97
|
-
else:
|
98
|
-
prod_id = request.DATA.get("product_id")
|
99
|
-
if prod_id:
|
100
|
-
product = Product.objects.filter(pk=prod_id).last()
|
101
|
-
if not product:
|
102
|
-
return restStatus(request, False, error="product required")
|
103
|
-
version_num = request.DATA.get("version_num", field_type=int)
|
104
|
-
last_release = Release.objects.filter(product=product).order_by("-version_num").first()
|
105
|
-
|
106
|
-
if not version_num:
|
107
|
-
if last_release and auto_version:
|
108
|
-
version_num = last_release.version_num + 1
|
109
|
-
elif auto_version:
|
110
|
-
version_num = 1
|
111
|
-
else:
|
112
|
-
return restStatus(request, False, error="no version info supplied, try auto_version=1")
|
113
|
-
elif last_release and version_num <= last_release.version_num:
|
114
|
-
return restStatus(request, False, error="version is not greater then last")
|
115
|
-
|
116
|
-
release = Release.createFromRequest(request, product=product, owner=request.member, group=request.group, version_num=version_num)
|
117
|
-
else:
|
118
|
-
release = Release.objects.filter(pk=release_id).last()
|
119
|
-
if not release:
|
120
|
-
return restStatus(request, False, error="unknown release")
|
121
|
-
if release.owner != request.member or (release.product.group and not request.member.isMemberOf(release.product.group)):
|
122
|
-
if not request.user.is_staff:
|
123
|
-
return restPermissionDenied(request)
|
124
|
-
release.saveFromRequest(request, owner=request.member)
|
125
|
-
if request.DATA.get("make_current"):
|
126
|
-
release.makeCurrent()
|
127
|
-
elif request.DATA.get("make_beta"):
|
128
|
-
release.makeCurrent()
|
129
|
-
return restGet(request, release, **Release.getGraph("default"))
|
130
|
-
|
131
|
-
@urlGET (r'^release/(?P<release_id>\d+)$')
|
132
|
-
@login_optional
|
133
|
-
def getRelease(request, release_id):
|
134
|
-
release = Release.objects.filter(pk=release_id).last()
|
135
|
-
if not release:
|
136
|
-
return restStatus(request, False, error="unknown release")
|
137
|
-
if not release.product.is_public and not request.member:
|
138
|
-
return restPermissionDenied(request, "not logged in")
|
139
|
-
return restGet(request, release, **Release.getGraph("default"))
|
140
|
-
|
141
|
-
def reportRestIssue(subject, message, perm="rest_errors", email_only=False):
|
142
|
-
# notifyWithPermission(perm, subject, message=None, template=None, context=None, email_only=False)
|
143
|
-
# notify email only
|
144
|
-
Member.notifyWithPermission(perm, subject, message, email_only=email_only)
|
145
|
-
|
146
|
-
from random import randint
|
147
|
-
@rest_async
|
148
|
-
def update_code(git_updater, updater_md5=None, branch=None):
|
149
|
-
# randomize the hit so we avoid collisions (gitlabs issues)
|
150
|
-
time.sleep(randint(1, 10))
|
151
|
-
import os
|
152
|
-
import subprocess
|
153
|
-
# check md5sum
|
154
|
-
if updater_md5:
|
155
|
-
cur_md5 = crypto.getFileMD5(git_updater)
|
156
|
-
if cur_md5.lower() != updater_md5.lower():
|
157
|
-
reportRestIssue("md5 check failed", "{}\ncould not be executed, md5 check failed".format(git_updater))
|
158
|
-
return
|
159
|
-
|
160
|
-
# TODO
|
161
|
-
# - check for errors and permissions
|
162
|
-
if settings.PUSHIT_TEST_SUDO:
|
163
|
-
cmd = ["sudo", "-lU", "ec2-user", git_updater, branch]
|
164
|
-
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
165
|
-
out, err = process.communicate()
|
166
|
-
if err.strip():
|
167
|
-
logger.warning("WARNING: cannot run {}, we don't have sudo rights".format(git_updater))
|
168
|
-
logger.warning("WARNING: add {} to your sudo user".format(git_updater))
|
169
|
-
return
|
170
|
-
# - lock it so we kill any updates in progress and start a new one
|
171
|
-
cmd = ["sudo", "-u", "ec2-user", git_updater, branch]
|
172
|
-
logger.info("updating...", cmd)
|
173
|
-
subprocess.Popen(cmd, close_fds=True)
|
174
|
-
|
175
|
-
@rest_async
|
176
|
-
def new_release(product, tag, url, msg):
|
177
|
-
version_str = tag
|
178
|
-
if tag.startswith("v"):
|
179
|
-
version_str = tag[1:]
|
180
|
-
|
181
|
-
rev = tag.split('.')[-1]
|
182
|
-
if not rev.isdigit():
|
183
|
-
return False
|
184
|
-
token = product.getProperty("git_token", "XXXXX")
|
185
|
-
release = Release(product=product, version_num=int(rev), version_str=version_str, notes=msg)
|
186
|
-
release.owner = product.owner
|
187
|
-
release_url = "{}/repository/{}/archive.zip?private_token={}".format(url, tag, token)
|
188
|
-
release.save()
|
189
|
-
logger.info(release_url)
|
190
|
-
release.set_media(release_url, True)
|
191
|
-
release.makeCurrent()
|
192
|
-
|
193
|
-
def on_git_merge_request(info, request):
|
194
|
-
state = request.DATA.get("object_attributes.state")
|
195
|
-
target_branch = request.DATA.get("object_attributes.target_branch")
|
196
|
-
|
197
|
-
git_branch = info.get("branch")
|
198
|
-
git_updater = info.get("updater")
|
199
|
-
git_updater_md5 = info.get("updater_md5", None)
|
200
|
-
|
201
|
-
if target_branch == git_branch:
|
202
|
-
reportRestIssue(
|
203
|
-
"{} update({}) on: {}".format(info.get("project", "n/a"), settings.get("SERVER_NAME", "unknown"), git_branch),
|
204
|
-
"<pre>{}</pre>".format(helpers.dictToString(request.DATA.asDict(), True)),
|
205
|
-
"git_updates", email_only=True)
|
206
|
-
update_code(git_updater, git_updater_md5, git_branch)
|
207
|
-
|
208
|
-
def on_git_push_request(info, hook_request):
|
209
|
-
git_branch = info.get("branch")
|
210
|
-
git_updater = info.get("updater")
|
211
|
-
git_updater_md5 = info.get("updater_md5", None)
|
212
|
-
update_code(git_updater, git_updater_md5, git_branch)
|
213
|
-
|
214
|
-
def on_git_new_release(info, request):
|
215
|
-
project = request.DATA.get("project.name")
|
216
|
-
logger.info("NEW RELEASE FOR {}".format(project))
|
217
|
-
product = Product.objects.filter(name=project).last()
|
218
|
-
if not product:
|
219
|
-
logger.info("PRODUCT NOT FOUND")
|
220
|
-
return
|
221
|
-
tag = request.DATA.get("ref").split('/')[-1]
|
222
|
-
msg = request.DATA.get("message")
|
223
|
-
url = request.DATA.get("project.web_url")
|
224
|
-
if product and msg:
|
225
|
-
new_release(product, tag, url, msg)
|
226
|
-
|
227
|
-
|
228
|
-
def parseGitLab(request):
|
229
|
-
info = objict(vendor="gitlab")
|
230
|
-
info.name = request.DATA.get("project.name")
|
231
|
-
info.kind = request.DATA.get("object_kind")
|
232
|
-
if "ref" in request.DATA:
|
233
|
-
info.branch = request.DATA.get("ref").split('/')[-1]
|
234
|
-
if info.kind == "merge_request":
|
235
|
-
info.state = request.DATA.get("object_attributes.state", None)
|
236
|
-
if info.state == "merged":
|
237
|
-
info.kind = "merged"
|
238
|
-
return info
|
239
|
-
|
240
|
-
|
241
|
-
def parseGithub(request):
|
242
|
-
info = objict(vendor="github")
|
243
|
-
info.name = request.DATA.get("repository.name")
|
244
|
-
info.kind = request.DATA.getHeader("HTTP_X_GITHUB_EVENT")
|
245
|
-
if "ref" in request.DATA:
|
246
|
-
info.branch = request.DATA.get("ref").split('/')[-1]
|
247
|
-
logger.info("github request", info)
|
248
|
-
return info
|
249
|
-
|
250
|
-
|
251
|
-
def getProjectForBranch(proj_info, branch):
|
252
|
-
if proj_info is None:
|
253
|
-
return None
|
254
|
-
if type(proj_info) is list:
|
255
|
-
for pi in proj_info:
|
256
|
-
if pi["branch"] == branch:
|
257
|
-
return pi
|
258
|
-
return None
|
259
|
-
if project_info["branch"] == branch:
|
260
|
-
return proj_info
|
261
|
-
return None
|
262
|
-
|
263
|
-
|
264
|
-
@urlPOST (r'^hooks/git_update$')
|
265
|
-
def on_git_hook(request):
|
266
|
-
sec_key = request.DATA.get("token")
|
267
|
-
git_key = settings.get("GIT_KEY", "hookswhat")
|
268
|
-
is_gitlab = True
|
269
|
-
hook_request = None
|
270
|
-
req_key = request.DATA.getHeader("HTTP_X_GITLAB_TOKEN")
|
271
|
-
if req_key is not None:
|
272
|
-
logger.info("GITLAB Detected")
|
273
|
-
hook_request = parseGitLab(request)
|
274
|
-
else:
|
275
|
-
req_key = request.DATA.getHeader("HTTP_X_HUB_SIGNATURE_256")
|
276
|
-
if req_key is not None:
|
277
|
-
is_gitlab = False
|
278
|
-
logger.info("GITHUB Detected")
|
279
|
-
hook_request = parseGithub(request)
|
280
|
-
|
281
|
-
if sec_key != git_key:
|
282
|
-
if req_key is None:
|
283
|
-
logger.warning("NO TOKEN")
|
284
|
-
logger.warning(request.META)
|
285
|
-
return restPermissionDenied(request)
|
286
|
-
|
287
|
-
git_projects = settings.get("GIT_PROJECTS", None)
|
288
|
-
|
289
|
-
if hook_request.name not in git_projects:
|
290
|
-
return restStatus(request, False, error="no config for project")
|
291
|
-
|
292
|
-
proj_info = getProjectForBranch(git_projects.get(hook_request.name), hook_request.branch)
|
293
|
-
if proj_info is None:
|
294
|
-
logger.info("no branch for project", hook_request)
|
295
|
-
return restStatus(request, False, error="no branch for project")
|
296
|
-
|
297
|
-
if hook_request.kind == "push":
|
298
|
-
on_git_push_request(proj_info, hook_request)
|
299
|
-
|
300
|
-
# kind = request.DATA.get("object_kind")
|
301
|
-
# project = request.DATA.get("project.name")
|
302
|
-
|
303
|
-
# git_projects = settings.get("GIT_PROJECTS", None)
|
304
|
-
# if git_projects and project in git_projects:
|
305
|
-
# proj_info = git_projects.get(project)
|
306
|
-
# # now lets handle different kinds
|
307
|
-
# if kind == "merge_request":
|
308
|
-
# # now check the state
|
309
|
-
# state = request.DATA.get("object_attributes.state", None)
|
310
|
-
# if state != "merged":
|
311
|
-
# return restStatus(request, True)
|
312
|
-
# if type(proj_info) is list:
|
313
|
-
# for info in proj_info:
|
314
|
-
# info["project"] = project
|
315
|
-
# on_git_merge_request(info, request)
|
316
|
-
# else:
|
317
|
-
# on_git_merge_request(proj_info, request)
|
318
|
-
# elif kind == "push":
|
319
|
-
# if type(proj_info) is list:
|
320
|
-
# for info in proj_info:
|
321
|
-
# info["project"] = project
|
322
|
-
# on_git_push_request(info, request)
|
323
|
-
# else:
|
324
|
-
# proj_info["project"] = project
|
325
|
-
# on_git_push_request(proj_info, request)
|
326
|
-
# elif kind == "tag_push":
|
327
|
-
# on_git_new_release(proj_info, request)
|
328
|
-
# elif kind == "tag_push":
|
329
|
-
# proj_info = git_projects.get(project)
|
330
|
-
# on_git_new_release(proj_info, request)
|
331
|
-
# else:
|
332
|
-
# helpers.log_print("No Config for Project {}".format(project))
|
333
|
-
return restStatus(request, True)
|
334
|
-
|
File without changes
|
File without changes
|