11import logging
22from http import HTTPStatus
3- from time import sleep
43
54from celery import shared_task
6- from django .core .cache import cache
75from django .core .exceptions import ObjectDoesNotExist
8- from django .utils .translation import gettext as _
9- from openwisp_notifications .signals import notify
106from requests .exceptions import RequestException
117from swapper import load_model
128
139from openwisp_controller .config .api .zerotier_service import ZerotierService
1410from openwisp_utils .tasks import OpenwispCeleryTask
1511
1612from .settings import API_TASK_RETRY_OPTIONS
13+ from .utils import handle_error_notification , handle_recovery_notification
1714
1815logger = logging .getLogger (__name__ )
1916
@@ -27,48 +24,6 @@ class OpenwispApiTask(OpenwispCeleryTask):
2724 HTTPStatus .GATEWAY_TIMEOUT , # 504
2825 ]
2926
30- def _send_api_task_notification (self , type , ** kwargs ):
31- vpn = kwargs .get ("instance" )
32- action = kwargs .get ("action" ).replace ("_" , " " )
33- status_code = kwargs .get ("status_code" )
34- # Adding some delay here to prevent overlapping
35- # of the django success message container
36- # with the ow-notification container
37- # https://github.com/openwisp/openwisp-notifications/issues/264
38- sleep (2 )
39- message_map = {
40- "error" : {
41- "verb" : _ ("encountered an unrecoverable error" ),
42- "message" : _ (
43- "Unable to perform {action} operation on the "
44- "{target} VPN server due to an "
45- "unrecoverable error "
46- "(status code: {status_code})"
47- ),
48- "level" : "error" ,
49- },
50- "recovery" : {
51- "verb" : _ ("has been completed successfully" ),
52- "message" : _ ("The {action} operation on {target} {verb}." ),
53- "level" : "info" ,
54- },
55- }
56- meta = message_map [type ]
57- notify .send (
58- type = "generic_message" ,
59- sender = vpn ,
60- target = vpn ,
61- action = action ,
62- verb = meta ["verb" ],
63- message = meta ["message" ].format (
64- action = action ,
65- target = str (vpn ),
66- status_code = status_code ,
67- verb = meta ["verb" ],
68- ),
69- level = meta ["level" ],
70- )
71-
7227 def handle_api_call (self , fn , * args , send_notification = True , ** kwargs ):
7328 """
7429 This method handles API calls and their responses
@@ -105,13 +60,10 @@ def handle_api_call(self, fn, *args, send_notification=True, **kwargs):
10560 response .raise_for_status ()
10661 logger .info (info_msg )
10762 if send_notification :
108- task_result = cache .get (task_key )
109- if task_result == "error" :
110- self ._send_api_task_notification ("recovery" , ** kwargs )
111- cache .set (task_key , "success" , None )
63+ handle_recovery_notification (task_key , ** kwargs )
11264 except RequestException as e :
11365 if response .status_code in self ._RECOVERABLE_API_CODES :
114- retry_logger = logger .warn
66+ retry_logger = logger .warning
11567 # When retry limit is reached, use error logging
11668 if self .request .retries == self .max_retries :
11769 retry_logger = logger .error
@@ -122,12 +74,7 @@ def handle_api_call(self, fn, *args, send_notification=True, **kwargs):
12274 raise e
12375 logger .error (f"{ err_msg } , Error: { e } " )
12476 if send_notification :
125- task_result = cache .get (task_key )
126- if task_result in (None , "success" ):
127- cache .set (task_key , "error" , None )
128- self ._send_api_task_notification (
129- "error" , status_code = response .status_code , ** kwargs
130- )
77+ handle_error_notification (task_key , exception = e , ** kwargs )
13178 return (response , updated_config ) if updated_config else response
13279
13380
@@ -150,6 +97,8 @@ def trigger_zerotier_server_update(self, config, vpn_id):
15097 network_id ,
15198 instance = vpn ,
15299 action = "update" ,
100+ # notification kwargs
101+ sleep_time = 5 ,
153102 info = (
154103 f"Successfully updated the configuration of "
155104 f"ZeroTier VPN Server with UUID: { vpn_id } "
@@ -189,6 +138,8 @@ def trigger_zerotier_server_update_member(self, vpn_id, ip=None, node_id=None):
189138 member_ip ,
190139 instance = vpn ,
191140 action = "update_member" ,
141+ # notification kwargs
142+ sleep_time = 5 ,
192143 info = (
193144 f"Successfully updated ZeroTier network member: { node_id } , "
194145 f"ZeroTier network: { network_id } , "
@@ -216,7 +167,7 @@ def trigger_zerotier_server_remove_member(self, node_id=None, **vpn_kwargs):
216167 network_id = vpn_kwargs .get ("network_id" )
217168 try :
218169 vpn = Vpn .objects .get (pk = vpn_id )
219- notification_kwargs = dict (instance = vpn , action = "remove_member" )
170+ notification_kwargs = dict (instance = vpn , action = "remove_member" , sleep_time = 5 )
220171 # When a ZeroTier VPN server is deleted
221172 # and this is followed by the deletion of ZeroTier VPN clients
222173 # we won't have access to the VPN server instance. Therefore, we should
@@ -264,6 +215,7 @@ def trigger_zerotier_server_join(self, vpn_id):
264215 network_id ,
265216 instance = vpn ,
266217 action = "network_join" ,
218+ sleep_time = 5 ,
267219 info = (
268220 f"Successfully joined the ZeroTier network: { network_id } , "
269221 f"ZeroTier VPN Server UUID: { vpn_id } "
0 commit comments