16 changed files with 416 additions and 56 deletions
-
58abonapp/__init__.py
-
1abonapp/admin.py
-
108abonapp/fields.py
-
31abonapp/formfields.py
-
2abonapp/forms.py
-
42abonapp/migrations/0014_auto_20170330_1452.py
-
30abonapp/models.py
-
5abonapp/templates/abonapp/addAbon.html
-
2abonapp/templates/abonapp/editAbon.html
-
60abonapp/views.py
-
4agent/core.py
-
31agent/mod_mikrotik.py
-
92dhcp_lever.py
-
2mydefs.py
-
2requirements.txt
-
2taskapp/locale/ru/LC_MESSAGES/django.po
@ -1 +1,59 @@ |
|||||
|
from django.conf import settings |
||||
|
|
||||
|
from netaddr import mac_unix, mac_eui48 |
||||
|
|
||||
|
import importlib |
||||
|
import warnings |
||||
|
|
||||
|
class mac_linux(mac_unix): |
||||
|
"""MAC format with zero-padded all upper-case hex and colon separated""" |
||||
|
word_fmt = '%.2X' |
||||
|
|
||||
|
def default_dialect(eui_obj=None): |
||||
|
# Check to see if a default dialect class has been specified in settings, |
||||
|
# using 'module.dialect_cls' string and use importlib and getattr to retrieve dialect class. 'module' is the module and |
||||
|
# 'dialect_cls' is the class name of the custom dialect. The dialect must either be defined or imported by the module's |
||||
|
# __init__.py if the module is a package. |
||||
|
from .fields import MACAddressField # Remove import at v1.4 |
||||
|
if hasattr(settings, 'MACADDRESS_DEFAULT_DIALECT') and not MACAddressField.dialect: |
||||
|
module, dialect_cls = settings.MACADDRESS_DEFAULT_DIALECT.split('.') |
||||
|
dialect = getattr(importlib.import_module(module), dialect_cls, mac_linux) |
||||
|
return dialect |
||||
|
else: |
||||
|
if MACAddressField.dialect: # Remove this "if" statement at v1.4 |
||||
|
warnings.warn( |
||||
|
"The set_dialect class method on MACAddressField has been deprecated, in favor of the default_dialect " |
||||
|
"utility function and settings.MACADDRESS_DEFAULT_DIALECT. See macaddress.__init__.py source or the " |
||||
|
"project README for more information.", |
||||
|
DeprecationWarning, |
||||
|
) |
||||
|
return MACAddressField.dialect |
||||
|
if eui_obj: |
||||
|
return eui_obj.dialect |
||||
|
else: |
||||
|
return mac_linux |
||||
|
|
||||
|
def format_mac(eui_obj, dialect): |
||||
|
# Format a EUI instance as a string using the supplied dialect class, allowing custom string classes by |
||||
|
# passing directly or as a string, a la 'module.dialect_cls', where 'module' is the module and 'dialect_cls' |
||||
|
# is the class name of the custom dialect. The dialect must either be defined or imported by the module's __init__.py if |
||||
|
# the module is a package. |
||||
|
if not isinstance(dialect, mac_eui48): |
||||
|
if isinstance(dialect, str): |
||||
|
module, dialect_cls = dialect.split('.') |
||||
|
dialect = getattr(importlib.import_module(module), dialect_cls) |
||||
|
eui_obj.dialect = dialect |
||||
|
return str(eui_obj) |
||||
|
|
||||
|
|
||||
|
from pkg_resources import get_distribution, DistributionNotFound |
||||
|
import os.path |
||||
|
|
||||
|
try: |
||||
|
_dist = get_distribution('django-macaddress') |
||||
|
except DistributionNotFound: |
||||
|
__version__ = 'Please install this project with setup.py' |
||||
|
else: |
||||
|
__version__ = _dist.version |
||||
|
VERSION = __version__ # synonym |
||||
default_app_config = 'abonapp.apps.AbonappConfig' |
default_app_config = 'abonapp.apps.AbonappConfig' |
||||
@ -0,0 +1,108 @@ |
|||||
|
# |
||||
|
# I got it on https://github.com/django-macaddress/django-macaddress |
||||
|
# |
||||
|
from django.core.exceptions import ValidationError |
||||
|
from django.db import models |
||||
|
from netaddr import EUI, AddrFormatError |
||||
|
from .formfields import MACAddressField as MACAddressFormField |
||||
|
from . import default_dialect |
||||
|
import warnings |
||||
|
|
||||
|
|
||||
|
class MACAddressField(models.Field): |
||||
|
description = "A MAC address validated by netaddr.EUI" |
||||
|
empty_strings_allowed = False |
||||
|
dialect = None |
||||
|
|
||||
|
def __init__(self, *args, **kwargs): |
||||
|
self.integer = kwargs.pop('integer', True) |
||||
|
if not self.integer: # If storing MAC address as string, set max_length to default (17) or use supplied kwarg value. |
||||
|
kwargs['max_length'] = kwargs.get('max_length', 17) |
||||
|
super(MACAddressField, self).__init__(*args, **kwargs) |
||||
|
|
||||
|
def deconstruct(self): |
||||
|
''' Django 1.7 migrations require this method |
||||
|
https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#field-deconstruction |
||||
|
''' |
||||
|
name, path, args, kwargs = super(MACAddressField, self).deconstruct() |
||||
|
kwargs['integer'] = self.integer |
||||
|
return name, path, args, kwargs |
||||
|
|
||||
|
@classmethod |
||||
|
def set_dialect(cls, new_dialect_clazz): |
||||
|
''' Setting dialect for EUI (MAC addresses) globally to this Field |
||||
|
class. |
||||
|
Class new_dialect_clazz should (finally) extend |
||||
|
netaddr.strategy.eui48.mac_eui48. |
||||
|
''' |
||||
|
warnings.warn( |
||||
|
"The set_dialect method has been deprecated, in favor of the default_dialect utility function and " |
||||
|
" settings.MACADDRESS_DEFAULT_DIALECT. See macaddress.__init__.py source or the project README for " |
||||
|
"more information.", |
||||
|
DeprecationWarning, |
||||
|
) |
||||
|
cls.dialect = new_dialect_clazz |
||||
|
|
||||
|
def get_prep_value(self, value): |
||||
|
if value is None: |
||||
|
return None |
||||
|
if not isinstance(value, EUI): |
||||
|
value = self.to_python(value) |
||||
|
if self.integer: |
||||
|
return int(value) |
||||
|
return str(value) |
||||
|
value.dialect = default_dialect(self) |
||||
|
if self.integer: |
||||
|
return int(value) |
||||
|
return str(value) |
||||
|
|
||||
|
def get_internal_type(self): |
||||
|
if self.integer: |
||||
|
return 'BigIntegerField' |
||||
|
return 'CharField' |
||||
|
|
||||
|
def from_db_value(self, value, expression, connection, context): |
||||
|
return self.to_python(value) |
||||
|
|
||||
|
def to_python(self, value): |
||||
|
if value is None: |
||||
|
return value |
||||
|
if isinstance(value, EUI): |
||||
|
value.dialect = default_dialect(value) |
||||
|
return value |
||||
|
try: |
||||
|
return EUI(value, version=48, dialect=default_dialect()) |
||||
|
except (TypeError, ValueError, AddrFormatError): |
||||
|
raise ValidationError( |
||||
|
"This value must be a valid MAC address.") |
||||
|
|
||||
|
def formfield(self, **kwargs): |
||||
|
defaults = {'form_class': MACAddressFormField} |
||||
|
defaults.update(kwargs) |
||||
|
return super(MACAddressField, self).formfield(**defaults) |
||||
|
|
||||
|
def get_prep_lookup(self, lookup_type, value): |
||||
|
# data is stored internally as integer so searching as string |
||||
|
# yeild 0 result. for example: useful for search in admin. |
||||
|
if lookup_type in ('exact', 'iexact', 'icontains', 'icontains'): |
||||
|
try: |
||||
|
return self.get_prep_value(value) |
||||
|
except AddrFormatError: |
||||
|
return None |
||||
|
elif lookup_type in ('in'): |
||||
|
try: |
||||
|
macs = [] |
||||
|
for mac in value: |
||||
|
macs += [self.get_prep_value(mac)] |
||||
|
return macs |
||||
|
except AddrFormatError: |
||||
|
return None |
||||
|
else: |
||||
|
raise TypeError('Lookup type %r not supported.' % lookup_type) |
||||
|
|
||||
|
|
||||
|
try: |
||||
|
from south.modelsinspector import add_introspection_rules |
||||
|
add_introspection_rules([], ["^macaddress\.fields\.MACAddressField"]) |
||||
|
except ImportError: |
||||
|
pass |
||||
@ -0,0 +1,31 @@ |
|||||
|
from django.forms import Field |
||||
|
from django.forms.fields import EMPTY_VALUES |
||||
|
#"From Django 1.8: The django.forms.util module has been renamed. Use django.forms.utils instead." |
||||
|
try: |
||||
|
from django.forms.utils import ValidationError |
||||
|
except ImportError: |
||||
|
from django.forms.util import ValidationError |
||||
|
|
||||
|
from netaddr import EUI, AddrFormatError |
||||
|
|
||||
|
|
||||
|
class MACAddressField(Field): |
||||
|
default_error_messages = { |
||||
|
'invalid': 'Enter a valid MAC Address.', |
||||
|
} |
||||
|
|
||||
|
def clean(self, value): |
||||
|
""" |
||||
|
Validates that EUI() can be called on the input. Returns the result |
||||
|
of EUI(). Returns None for empty values. |
||||
|
""" |
||||
|
value = super(MACAddressField, self).clean(value) |
||||
|
if value in EMPTY_VALUES: |
||||
|
return None |
||||
|
try: |
||||
|
value = EUI(str(value), version=48) |
||||
|
except (ValueError, TypeError, AddrFormatError): |
||||
|
raise ValidationError(self.error_messages['invalid']) |
||||
|
return value |
||||
|
|
||||
|
|
||||
@ -0,0 +1,42 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.9 on 2017-03-30 11:52 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
import abonapp.fields |
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('abonapp', '0013_abongroup_tariffs'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name='Opt82', |
||||
|
fields=[ |
||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('mac', abonapp.fields.MACAddressField(integer=True)), |
||||
|
('port', models.PositiveSmallIntegerField(default=0)), |
||||
|
], |
||||
|
options={ |
||||
|
'db_table': 'opt_82', |
||||
|
}, |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='abon', |
||||
|
name='extra_fields', |
||||
|
field=models.ManyToManyField(blank=True, to='abonapp.ExtraFieldsModel'), |
||||
|
), |
||||
|
migrations.AlterUniqueTogether( |
||||
|
name='opt82', |
||||
|
unique_together=set([('mac', 'port')]), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='abon', |
||||
|
name='opt82', |
||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='abonapp.Opt82'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,92 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
import os |
||||
|
import sys |
||||
|
import django |
||||
|
from django.core.exceptions import MultipleObjectsReturned, ValidationError |
||||
|
from django.utils.translation import ugettext as _ |
||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") |
||||
|
django.setup() |
||||
|
from agent import NasFailedResult, NasNetworkError |
||||
|
from abonapp.models import Abon, Opt82 |
||||
|
from ip_pool.models import IpPoolItem |
||||
|
|
||||
|
|
||||
|
def die(text): |
||||
|
print(text) |
||||
|
exit(1) |
||||
|
|
||||
|
|
||||
|
def get_82_opts(switch_mac, switch_port): |
||||
|
try: |
||||
|
opt82 = Opt82.objects.get(mac=switch_mac, port=switch_port) |
||||
|
except MultipleObjectsReturned: |
||||
|
Opt82.objects.filter(mac=switch_mac, port=switch_port)[1:].delete() |
||||
|
return get_82_opts(switch_mac, switch_port) |
||||
|
except Opt82.DoesNotExist: |
||||
|
opt82 = Opt82.objects.create(mac=switch_mac, port=switch_port) |
||||
|
return opt82 |
||||
|
|
||||
|
|
||||
|
def get_or_create_pool_item(ip): |
||||
|
try: |
||||
|
ip_item = IpPoolItem.objects.get(ip=ip) |
||||
|
except IpPoolItem.DoesNotExist: |
||||
|
ip_item = IpPoolItem.objects.create(ip=ip) |
||||
|
except MultipleObjectsReturned: |
||||
|
IpPoolItem.objects.filter(ip=ip)[1:].delete() |
||||
|
return get_or_create_pool_item(ip) |
||||
|
return ip_item |
||||
|
|
||||
|
|
||||
|
def dhcp_commit(client_ip, client_mac, switch_mac, switch_port): |
||||
|
opt82 = get_82_opts(switch_mac, switch_port) |
||||
|
if opt82 is None: |
||||
|
print(_("ERROR: opt82 with mac:%s and port:%d does not exist in db") % (switch_mac, switch_port)) |
||||
|
return |
||||
|
try: |
||||
|
abon = Abon.objects.get(opt82=opt82) |
||||
|
abon.ip_address = get_or_create_pool_item(client_ip) |
||||
|
Abon.is_dhcp = True |
||||
|
abon.save(update_fields=['ip_address']) |
||||
|
print(_('Ip address update for %s successfull') % abon.get_short_name()) |
||||
|
except Abon.DoesNotExist: |
||||
|
print('ERROR: abon with option82(%s-%d) does not exist' % (opt82.mac, opt82.port)) |
||||
|
|
||||
|
|
||||
|
def dhcp_expiry(client_ip): |
||||
|
try: |
||||
|
ip_item = IpPoolItem.objects.get(ip=client_ip) |
||||
|
abon = Abon.objects.get(ip_address=ip_item) |
||||
|
abon.ip_address = None |
||||
|
abon.save(update_fields=['ip_address']) |
||||
|
except IpPoolItem.DoesNotExist: |
||||
|
pass |
||||
|
except Abon.DoesNotExist: |
||||
|
pass |
||||
|
|
||||
|
|
||||
|
def dhcp_release(client_ip): |
||||
|
dhcp_expiry(client_ip) |
||||
|
|
||||
|
|
||||
|
def main(argv): |
||||
|
if len(argv) < 3: |
||||
|
die(_('Too few arguments, exiting...')) |
||||
|
action = argv[1] |
||||
|
if action == 'commit': |
||||
|
if len(argv) < 6: |
||||
|
die(_('Too few arguments, exiting...')) |
||||
|
dhcp_commit(argv[2], argv[3], argv[4], int(argv[5])) |
||||
|
elif action == 'expiry': |
||||
|
dhcp_expiry(argv[2]) |
||||
|
elif action == 'release': |
||||
|
dhcp_release(argv[2]) |
||||
|
|
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
try: |
||||
|
main(sys.argv) |
||||
|
except (NasNetworkError, NasFailedResult) as e: |
||||
|
print('NAS:', e) |
||||
|
except (ValidationError, ValueError) as e: |
||||
|
print('ERROR:', e) |
||||
@ -1,6 +1,8 @@ |
|||||
Django==1.9 |
Django==1.9 |
||||
Pillow |
Pillow |
||||
telepot |
telepot |
||||
|
# for mac address field |
||||
|
netaddr |
||||
# for testing required xmltodict |
# for testing required xmltodict |
||||
xmltodict |
xmltodict |
||||
mysqlclient |
mysqlclient |
||||
|
|||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue