From 3bb1d96a9b98ec8027e26fa996aee2f6efc289a1 Mon Sep 17 00:00:00 2001 From: ns Date: Sat, 14 Apr 2018 01:42:35 +0600 Subject: [PATCH] Move dhcp manager to view --- abonapp/urls.py | 3 ++- abonapp/views.py | 50 +++++++++++++++++++++++++++++++++++++++--- agent/commands/dhcp.py | 28 ++++++++++++----------- dhcp_lever.py | 47 ++++++++++++++++++++++++++++++++------- 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/abonapp/urls.py b/abonapp/urls.py index a4bb543..d63a6ad 100644 --- a/abonapp/urls.py +++ b/abonapp/urls.py @@ -65,5 +65,6 @@ urlpatterns = [ # Api's url(r'^api/abons$', views.abons), - url(r'^api/abon_filter$', views.search_abon) + url(r'^api/abon_filter$', views.search_abon), + url(r'^api/dhcp_lever/$', views.DhcpLever.as_view()) ] diff --git a/abonapp/views.py b/abonapp/views.py index 7e431e6..e89de0d 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -1,3 +1,4 @@ +from typing import Dict, Optional from django.contrib.gis.shortcuts import render_to_text from django.core.exceptions import PermissionDenied from django.db import IntegrityError, ProgrammingError, transaction @@ -12,6 +13,7 @@ from django.views.generic import ListView, UpdateView, CreateView from django.conf import settings from jsonview.decorators import json_view +from agent.commands.dhcp import dhcp_commit, dhcp_expiry, dhcp_release from statistics.models import StatCache from tariff_app.models import Tariff from agent import NasFailedResult, Transmitter, NasNetworkError @@ -26,8 +28,7 @@ from statistics.models import getModel from group_app.models import Group from guardian.shortcuts import get_objects_for_user, assign_perm from guardian.decorators import permission_required_or_403 as permission_required -from djing.global_base_views import OrderingMixin, BaseListWithFiltering -from djing import ping +from djing.global_base_views import OrderingMixin, BaseListWithFiltering, HashAuthView, AllowedSubnetMixin PAGINATION_ITEMS_PER_PAGE = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) @@ -697,7 +698,7 @@ def abon_ping(request): tm = Transmitter() ping_result = tm.ping(ip) if ping_result is None: - if ping(ip, 10): + if mydefs.ping(ip, 10): status = True text = ' %s' % _('ping ok') else: @@ -1118,3 +1119,46 @@ def search_abon(request): results = models.Abon.objects.filter(fio__icontains=word)[:8] results = [{'id': usr.pk, 'text': "%s: %s" % (usr.username, usr.fio)} for usr in results] return results + + +class DhcpLever(AllowedSubnetMixin, HashAuthView): + # + # Api view for dhcp event + # + http_method_names = ['get'] + + @method_decorator(json_view) + def get(self, request, *args, **kwargs): + data = request.GET.copy() + r = self.on_dhcp_event(data) + if r is not None: + return {'text': r} + return {'status': 'ok'} + + @staticmethod + def on_dhcp_event(data: Dict) -> Optional[str]: + ''' + data = { + 'client_ip': ip2int('127.0.0.1'), + 'client_mac': 'aa:bb:cc:dd:ee:ff', + 'switch_mac': 'aa:bb:cc:dd:ee:ff', + 'switch_port': 3, + 'cmd': 'commit' + } + ''' + r = None + try: + action = data['cmd'] + if action == 'commit': + r = dhcp_commit( + data['client_ip'], data['client_mac'], + data['switch_mac'], data['switch_port'] + ) + elif action == 'expiry': + r = dhcp_expiry(data['client_ip']) + elif action == 'release': + r = dhcp_release(data['client_ip']) + except mydefs.LogicError as e: + print('LogicError', e) + r = str(e) + return r diff --git a/agent/commands/dhcp.py b/agent/commands/dhcp.py index f8a4adf..31e89b7 100644 --- a/agent/commands/dhcp.py +++ b/agent/commands/dhcp.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- +from typing import Optional from django.core.exceptions import MultipleObjectsReturned from abonapp.models import Abon from devapp.models import Device, Port -def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: int) -> None: +def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: int) -> Optional[str]: try: dev = Device.objects.get(mac_addr=switch_mac) mngr_class = dev.get_manager_klass() @@ -21,31 +22,32 @@ def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: i if not abon.is_access(): print('D:', 'User %s is not access to service' % abon.username) return - abon.ip_address = client_ip - abon.save(update_fields=['ip_address']) - abon.sync_with_nas(created=False) + if abon.ip_address != client_ip: + abon.ip_address = client_ip + abon.save(update_fields=['ip_address']) + abon.sync_with_nas(created=False) except Abon.DoesNotExist: - print('N:', "User with device '%s' does not exist" % dev) + return "User with device with mac '%s' does not exist" % switch_mac except Device.DoesNotExist: - print('N:', 'Device with mac %s not found' % switch_mac) + return 'Device with mac %s not found' % switch_mac except Port.DoesNotExist: - print('N:', 'Port %(switch_port)d on device with mac %(switch_mac)s does not exist' % { + return 'Port %(switch_port)d on device with mac %(switch_mac)s does not exist' % { 'switch_port': int(switch_port), 'switch_mac': switch_mac - }) + } except MultipleObjectsReturned as e: - print('E:', 'MultipleObjectsReturned:', type(e), e, switch_port, dev) + return 'MultipleObjectsReturned:' + ' '.join([type(e), e, str(switch_port)]) -def dhcp_expiry(client_ip): +def dhcp_expiry(client_ip) -> Optional[str]: try: abon = Abon.objects.get(ip_address=client_ip) abon.ip_address = None abon.save(update_fields=['ip_address']) abon.sync_with_nas(created=False) except Abon.DoesNotExist: - pass + return "Subscriber with ip %s does not exist" % client_ip -def dhcp_release(client_ip): - dhcp_expiry(client_ip) +def dhcp_release(client_ip) -> Optional[str]: + return dhcp_expiry(client_ip) diff --git a/dhcp_lever.py b/dhcp_lever.py index 5322f49..e649194 100755 --- a/dhcp_lever.py +++ b/dhcp_lever.py @@ -1,6 +1,12 @@ #!/usr/bin/env python3 import sys -import socket +from urllib.error import HTTPError +from urllib.parse import urlencode +from urllib.request import urlopen +from hashlib import sha256 + +API_AUTH_SECRET = 'your api key' +SERVER_DOMAIN = 'http://localhost:8000' def die(text): @@ -19,21 +25,46 @@ obj = { ''' -def send_to(data, addr='127.0.0.1', port=5436): - from pickle import dumps +def calc_hash(data): + if type(data) is str: + result_data = data.encode('utf-8') + else: + result_data = bytes(data) + return sha256(result_data).hexdigest() + + +def make_sign(data: dict): + vars_to_hash = [str(v) for v in data.values()] + vars_to_hash.sort() + vars_to_hash.append(API_AUTH_SECRET) + return calc_hash('_'.join(vars_to_hash)) + + +def send_to(data, server=SERVER_DOMAIN): + sign = make_sign(data) + data.update({'sign': sign}) try: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.connect((addr, port)) - data = dumps(data) - s.send(data) + with urlopen("%s/abons/api/dhcp_lever/?%s" % (server, urlencode(data))) as r: + html = r.read() + print(html) except ConnectionRefusedError: print('ERROR: connection refused') + except HTTPError as e: + print('ERROR:', e) if __name__ == "__main__": argv = sys.argv if len(argv) < 3: - die('Too few arguments, exiting...') + die( + 'Too few arguments, exiting...\n' + 'Usage:\n' + 'COMMIT: ./dhcp_lever.py commit 192.168.1.100 ff:12:c5:9f:12:56 98:45:28:85:25:1a 3\n' + 'EXPIRY or RELEASE: ./dhcp_lever.py [release |commit]' + ) + if API_AUTH_SECRET == 'your api key': + raise NotImplementedError('You must specified secret api key') + action = argv[1] if action == 'commit': if len(argv) < 6: