From a75040c79ad3a0d42e00e697bd7d0ab5f89b9c4f Mon Sep 17 00:00:00 2001 From: yoneyan Date: Sun, 31 Mar 2024 17:56:48 +0900 Subject: [PATCH] [add] Added database structure. --- dsbd/settings.py | 8 +- ip/__init__.py | 0 ip/admin.py | 44 ++++++++ ip/apps.py | 6 ++ ip/migrations/0001_initial.py | 81 ++++++++++++++ ip/migrations/0002_initial.py | 52 +++++++++ ip/migrations/__init__.py | 0 ip/models.py | 130 +++++++++++++++++++++++ noc/__init__.py | 0 noc/admin.py | 16 +++ noc/apps.py | 6 ++ noc/migrations/0001_initial.py | 34 ++++++ noc/migrations/__init__.py | 0 noc/models.py | 19 ++++ router/__init__.py | 0 router/admin.py | 27 +++++ router/apps.py | 6 ++ router/migrations/0001_initial.py | 52 +++++++++ router/migrations/__init__.py | 0 router/models.py | 33 ++++++ service/__init__.py | 0 service/admin.py | 36 +++++++ service/apps.py | 6 ++ service/migrations/0001_initial.py | 87 +++++++++++++++ service/migrations/__init__.py | 0 service/models.py | 164 +++++++++++++++++++++++++++++ 26 files changed, 805 insertions(+), 2 deletions(-) create mode 100644 ip/__init__.py create mode 100644 ip/admin.py create mode 100644 ip/apps.py create mode 100644 ip/migrations/0001_initial.py create mode 100644 ip/migrations/0002_initial.py create mode 100644 ip/migrations/__init__.py create mode 100644 ip/models.py create mode 100644 noc/__init__.py create mode 100644 noc/admin.py create mode 100644 noc/apps.py create mode 100644 noc/migrations/0001_initial.py create mode 100644 noc/migrations/__init__.py create mode 100644 noc/models.py create mode 100644 router/__init__.py create mode 100644 router/admin.py create mode 100644 router/apps.py create mode 100644 router/migrations/0001_initial.py create mode 100644 router/migrations/__init__.py create mode 100644 router/models.py create mode 100644 service/__init__.py create mode 100644 service/admin.py create mode 100644 service/apps.py create mode 100644 service/migrations/0001_initial.py create mode 100644 service/migrations/__init__.py create mode 100644 service/models.py diff --git a/dsbd/settings.py b/dsbd/settings.py index 24c069e..eabcafd 100644 --- a/dsbd/settings.py +++ b/dsbd/settings.py @@ -62,6 +62,10 @@ def _import_ldap_group_type(group_type_name): 'custom_admin', 'notice', 'ticket', + 'noc', + 'router', + 'ip', + 'service', ] MIDDLEWARE = [ @@ -179,7 +183,7 @@ def _import_ldap_group_type(group_type_name): import socket hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) - INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + ["127.0.0.1",] + INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + ["127.0.0.1", ] MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware') LOGIN_URL = "sign_in" @@ -234,4 +238,4 @@ def _import_ldap_group_type(group_type_name): MESSAGE_TAGS = { messages.ERROR: 'danger', -} \ No newline at end of file +} diff --git a/ip/__init__.py b/ip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ip/admin.py b/ip/admin.py new file mode 100644 index 0000000..b40f558 --- /dev/null +++ b/ip/admin.py @@ -0,0 +1,44 @@ +from django.contrib import admin + +from .models import IP, JPNICUser + + +class TermInlineIPAdmin(admin.TabularInline): + model = IP.jpnic_user.through + extra = 1 + + +class TermInlineJPNICUserAdmin(admin.TabularInline): + model = JPNICUser.ip.through + extra = 1 + + +@admin.register(IP) +class IP(admin.ModelAdmin): + fieldsets = ( + (None, {'fields': ('is_active', 'service',)}), + ('ip', {'fields': ('ip_address', 'subnet', 'start_at', 'end_at', 'plan', 'use_case')}), + ('Important dates', {'fields': ('created_at', 'updated_at',)}), + ) + list_display = ('id', 'is_active', 'service', 'ip_address', 'subnet', 'start_at', 'end_at') + list_filter = ('is_active', 'end_at',) + search_fields = ('ip_address',) + + inlines = (TermInlineIPAdmin,) + + +@admin.register(JPNICUser) +class JPNICUser(admin.ModelAdmin): + fieldsets = ( + (None, {'fields': ('group', 'is_active',)}), + ('Common', {'fields': ('hidden', 'handle_type', 'jpnic_handle')}), + ('Personal info', {'fields': ( + 'name', 'name_jp', 'email', 'org', 'org_en', 'postcode', 'address', 'address_jp', + 'dept', 'dept_en', 'title', 'title_en', 'tel', 'fax', 'country')}), + ('Important dates', {'fields': ('created_at', 'updated_at',)}), + ) + list_display = ('id', 'is_active', 'group', 'jpnic_handle', 'name', 'org') + list_filter = ('is_active', 'group') + search_fields = ('name', 'group', 'org') + + inlines = (TermInlineJPNICUserAdmin,) diff --git a/ip/apps.py b/ip/apps.py new file mode 100644 index 0000000..2cd3d87 --- /dev/null +++ b/ip/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CustomAdmin(AppConfig): + name = "ip" + verbose_name = "IP" diff --git a/ip/migrations/0001_initial.py b/ip/migrations/0001_initial.py new file mode 100644 index 0000000..7393d32 --- /dev/null +++ b/ip/migrations/0001_initial.py @@ -0,0 +1,81 @@ +# Generated by Django 5.0.3 on 2024-03-31 08:50 + +import django.utils.timezone +import dsbd.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='IP', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('is_active', models.BooleanField(default=True, verbose_name='有効')), + ('ip_address', models.GenericIPAddressField(unique=True, verbose_name='IP Address')), + ('subnet', models.IntegerField(default=32, verbose_name='サブネット')), + ('start_at', models.DateTimeField(blank=True, null=True, verbose_name='開通日')), + ('end_at', models.DateTimeField(blank=True, null=True, verbose_name='解約日')), + ('plan', models.JSONField(blank=True, null=True, verbose_name='プラン')), + ('use_case', dsbd.models.MediumTextField(default='', verbose_name='使用用途')), + ], + options={ + 'verbose_name': 'IP', + 'verbose_name_plural': 'IPs', + 'ordering': ('id',), + }, + ), + migrations.CreateModel( + name='IPJPNICUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('user_type', models.CharField(choices=[('admin', '管理者'), ('tech1', '技術担当者1'), ('tech2', '技術担当者2'), ('tech3', '技術担当者3'), ('tech4', '技術担当者4'), ('tech5', '技術担当者5')], default='admin', max_length=255, verbose_name='タイプ')), + ], + options={ + 'verbose_name': 'IP・JPNIC User', + 'verbose_name_plural': 'IP・JPNIC Users', + }, + ), + migrations.CreateModel( + name='JPNICUser', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('is_active', models.BooleanField(default=True, verbose_name='有効')), + ('hidden', models.BooleanField(default=False, verbose_name='隠蔽')), + ('handle_type', models.CharField(choices=[('group_handle', 'グループハンドル'), ('jpnic_handle', 'JPNICハンドル')], default='jpnic_handle', max_length=255, verbose_name='ハンドルタイプ')), + ('jpnic_handle', models.CharField(blank=True, max_length=100, verbose_name='JPNIC Handle')), + ('name', models.CharField(max_length=150, verbose_name='name')), + ('name_jp', models.CharField(max_length=150, verbose_name='name(japanese)')), + ('email', models.EmailField(max_length=150, verbose_name='E-Mail')), + ('org', models.CharField(max_length=150, unique=True, verbose_name='Org')), + ('org_jp', models.CharField(max_length=150, verbose_name='Org(japanese)')), + ('postcode', models.CharField(default='', max_length=20, verbose_name='郵便番号')), + ('address', models.CharField(default='', max_length=250, verbose_name='住所')), + ('address_jp', models.CharField(default='', max_length=250, verbose_name='住所(Japanese)')), + ('dept', models.CharField(blank=True, default='', max_length=250, verbose_name='部署')), + ('dept_jp', models.CharField(blank=True, default='', max_length=250, verbose_name='部署(Japanese)')), + ('title', models.CharField(blank=True, default='', max_length=250, verbose_name='役職')), + ('title_jp', models.CharField(blank=True, default='', max_length=250, verbose_name='役職(Japanese)')), + ('tel', models.CharField(default='', max_length=30, verbose_name='tel')), + ('fax', models.CharField(default='', max_length=30, verbose_name='fax')), + ('country', models.CharField(default='Japan', max_length=100, verbose_name='居住国')), + ], + options={ + 'verbose_name': 'JPNIC User', + 'verbose_name_plural': 'JPNIC Users', + 'ordering': ('id',), + }, + ), + ] diff --git a/ip/migrations/0002_initial.py b/ip/migrations/0002_initial.py new file mode 100644 index 0000000..78b5c01 --- /dev/null +++ b/ip/migrations/0002_initial.py @@ -0,0 +1,52 @@ +# Generated by Django 5.0.3 on 2024-03-31 08:50 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('custom_auth', '0004_group_users_alter_user_groups'), + ('ip', '0001_initial'), + ('service', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='ip', + name='service', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='IPService', to='service.service'), + ), + migrations.AddField( + model_name='ipjpnicuser', + name='ip', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ip.ip'), + ), + migrations.AddField( + model_name='jpnicuser', + name='group', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='custom_auth.group'), + ), + migrations.AddField( + model_name='jpnicuser', + name='ip', + field=models.ManyToManyField(blank=True, related_name='jpnic_set', through='ip.IPJPNICUser', to='ip.ip'), + ), + migrations.AddField( + model_name='ipjpnicuser', + name='jpnic_user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ip.jpnicuser'), + ), + migrations.AddField( + model_name='ip', + name='jpnic_user', + field=models.ManyToManyField(blank=True, related_name='jpnic_user_set', through='ip.IPJPNICUser', to='ip.jpnicuser'), + ), + migrations.AlterUniqueTogether( + name='ipjpnicuser', + unique_together={('jpnic_user', 'ip')}, + ), + ] diff --git a/ip/migrations/__init__.py b/ip/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ip/models.py b/ip/models.py new file mode 100644 index 0000000..29ae720 --- /dev/null +++ b/ip/models.py @@ -0,0 +1,130 @@ +from django.db import models +from django.utils import timezone + +from custom_auth.models import Group +from dsbd.models import MediumTextField +from service.models import Service + +SERVICE_L2 = "2000" +SERVICE_L3_STATIC = "3S00" +SERVICE_L3_BGP = "3B00" +SERVICE_TRANSIT = "IP3B" +SERVICE_COLO_L2 = "CL20" +SERVICE_COLO_L3_STATIC = "CL3S" +SERVICE_COLO_L3_BGP = "CL3B" +SERVICE_ETC = "ET00" + +SERVICE_CHOICES = ( + (SERVICE_L2, "L2"), + (SERVICE_L3_STATIC, "L3 Static"), + (SERVICE_L3_BGP, "L3 BGP"), + (SERVICE_TRANSIT, "トランジット提供"), + (SERVICE_COLO_L2, "コロケーションサービス(L2)"), + (SERVICE_COLO_L3_STATIC, "コロケーションサービス(L3 Static)"), + (SERVICE_COLO_L3_BGP, "コロケーションサービス(L3 BGP)"), + (SERVICE_ETC, "その他"), +) + + +class IP(models.Model): + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + is_active = models.BooleanField("有効", default=True) + service = models.ForeignKey(Service, on_delete=models.SET_NULL, related_name="IPService", null=True, blank=True) + ip_address = models.GenericIPAddressField("IP Address", unique=True) + subnet = models.IntegerField("サブネット", default=32) + start_at = models.DateTimeField("開通日", null=True, blank=True) + end_at = models.DateTimeField("解約日", null=True, blank=True) + plan = models.JSONField("プラン", null=True, blank=True) + use_case = MediumTextField("使用用途", default="") + jpnic_user = models.ManyToManyField( + "JPNICUser", + blank=True, + through='IPJPNICUser', + through_fields=('ip', 'jpnic_user'), + related_name="jpnic_user_set", + ) + + class Meta: + ordering = ("id",) + verbose_name = "IP" + verbose_name_plural = "IPs" + + +HANDLE_TYPE_GROUP = "group_handle" +HANDLE_TYPE_JPNIC = "jpnic_handle" + +HANDLE_TYPE_CHOICES = ( + (HANDLE_TYPE_GROUP, "グループハンドル"), + (HANDLE_TYPE_JPNIC, "JPNICハンドル"), +) + + +class JPNICUser(models.Model): + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + group = models.ForeignKey(Group, on_delete=models.CASCADE) + is_active = models.BooleanField("有効", default=True) + hidden = models.BooleanField("隠蔽", default=False) + handle_type = models.CharField("ハンドルタイプ", max_length=255, choices=HANDLE_TYPE_CHOICES, default=HANDLE_TYPE_JPNIC) + jpnic_handle = models.CharField("JPNIC Handle", max_length=100, blank=True) + name = models.CharField("name", max_length=150) + name_jp = models.CharField("name(japanese)", max_length=150) + email = models.EmailField("E-Mail", max_length=150) + org = models.CharField("Org", max_length=150, unique=True) + org_jp = models.CharField("Org(japanese)", max_length=150) + postcode = models.CharField("郵便番号", max_length=20, default="") + address = models.CharField("住所", max_length=250, default="") + address_jp = models.CharField("住所(Japanese)", max_length=250, default="") + dept = models.CharField("部署", max_length=250, default="", blank=True) + dept_jp = models.CharField("部署(Japanese)", max_length=250, default="", blank=True) + title = models.CharField("役職", max_length=250, default="", blank=True) + title_jp = models.CharField("役職(Japanese)", max_length=250, default="", blank=True) + tel = models.CharField("tel", max_length=30, default="") + fax = models.CharField("fax", max_length=30, default="") + country = models.CharField("居住国", max_length=100, default="Japan") + ip = models.ManyToManyField( + "IP", + blank=True, + through='IPJPNICUser', + through_fields=('jpnic_user', 'ip'), + related_name="jpnic_set", + ) + + class Meta: + ordering = ("id",) + verbose_name = "JPNIC User" + verbose_name_plural = "JPNIC Users" + + +JPNIC_USER_TYPE_ADMIN = "admin" +JPNIC_USER_TYPE_TECH_1 = "tech1" +JPNIC_USER_TYPE_TECH_2 = "tech2" +JPNIC_USER_TYPE_TECH_3 = "tech3" +JPNIC_USER_TYPE_TECH_4 = "tech4" +JPNIC_USER_TYPE_TECH_5 = "tech5" + +JPNIC_USER_TYPE_CHOICES = ( + (JPNIC_USER_TYPE_ADMIN, "管理者"), + (JPNIC_USER_TYPE_TECH_1, "技術担当者1"), + (JPNIC_USER_TYPE_TECH_2, "技術担当者2"), + (JPNIC_USER_TYPE_TECH_3, "技術担当者3"), + (JPNIC_USER_TYPE_TECH_4, "技術担当者4"), + (JPNIC_USER_TYPE_TECH_5, "技術担当者5"), +) + + +class IPJPNICUser(models.Model): + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + jpnic_user = models.ForeignKey(JPNICUser, on_delete=models.CASCADE) + ip = models.ForeignKey(IP, on_delete=models.CASCADE) + user_type = models.CharField("タイプ", max_length=255, choices=JPNIC_USER_TYPE_CHOICES, default=JPNIC_USER_TYPE_ADMIN) + + class Meta: + verbose_name = 'IP・JPNIC User' + verbose_name_plural = "IP・JPNIC Users" + unique_together = ('jpnic_user', 'ip') + + def __str__(self): + return "%s" % (self.id,) diff --git a/noc/__init__.py b/noc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/noc/admin.py b/noc/admin.py new file mode 100644 index 0000000..fde37d9 --- /dev/null +++ b/noc/admin.py @@ -0,0 +1,16 @@ +from django.contrib import admin + +from .models import NOC + + +@admin.register(NOC) +class NOC(admin.ModelAdmin): + fieldsets = ( + (None, {'fields': ('name', 'is_active', 'location', 'bandwidth',)}), + ('comment', {'fields': ('comment',)}), + ('Important dates', {'fields': ('created_at', 'updated_at',)}), + ) + list_display = ('id', 'name', 'is_active', 'location', 'bandwidth') + list_filter = ('is_active', ) + search_fields = ('name',) + diff --git a/noc/apps.py b/noc/apps.py new file mode 100644 index 0000000..fd8e3c3 --- /dev/null +++ b/noc/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CustomAdmin(AppConfig): + name = "noc" + verbose_name = "NOC" diff --git a/noc/migrations/0001_initial.py b/noc/migrations/0001_initial.py new file mode 100644 index 0000000..8cd8196 --- /dev/null +++ b/noc/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 5.0.3 on 2024-03-31 08:50 + +import django.utils.timezone +import dsbd.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='NOC', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('name', models.CharField(default='', max_length=255, verbose_name='名前')), + ('is_active', models.BooleanField(default=True, verbose_name='有効')), + ('location', models.CharField(blank=True, default='', max_length=255, verbose_name='場所')), + ('bandwidth', models.IntegerField(default=1000, verbose_name='帯域幅')), + ('comment', dsbd.models.MediumTextField(blank=True, default='', verbose_name='コメント')), + ], + options={ + 'verbose_name': 'NOC', + 'verbose_name_plural': 'NOCs', + 'ordering': ('id',), + }, + ), + ] diff --git a/noc/migrations/__init__.py b/noc/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/noc/models.py b/noc/models.py new file mode 100644 index 0000000..51bc1b8 --- /dev/null +++ b/noc/models.py @@ -0,0 +1,19 @@ +from django.db import models +from django.utils import timezone + +from dsbd.models import MediumTextField + + +class NOC(models.Model): + class Meta: + ordering = ("id",) + verbose_name = "NOC" + verbose_name_plural = "NOCs" + + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + name = models.CharField("名前", default="", max_length=255) + is_active = models.BooleanField("有効", default=True) + location = models.CharField("場所", default="", max_length=255, blank=True) + bandwidth = models.IntegerField("帯域幅", default=1000) + comment = MediumTextField("コメント", default="", blank=True) diff --git a/router/__init__.py b/router/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/router/admin.py b/router/admin.py new file mode 100644 index 0000000..4f40292 --- /dev/null +++ b/router/admin.py @@ -0,0 +1,27 @@ +from django.contrib import admin + +from .models import TunnelRouter, TunnelIP + + +@admin.register(TunnelRouter) +class Router(admin.ModelAdmin): + fieldsets = ( + (None, {'fields': ('is_active', 'noc', 'hostname')}), + ('comment', {'fields': ('comment',)}), + ('Important dates', {'fields': ('created_at', 'updated_at',)}), + ) + list_display = ('id', 'is_active', 'noc', 'hostname') + list_filter = ('is_active',) + search_fields = ('is_active', 'hostname') + + +@admin.register(TunnelIP) +class TunnelIP(admin.ModelAdmin): + fieldsets = ( + (None, {'fields': ('is_active', 'tunnel_router', 'ip_address')}), + ('comment', {'fields': ('comment',)}), + ('Important dates', {'fields': ('created_at', 'updated_at',)}), + ) + list_display = ('id', 'is_active', 'tunnel_router', 'ip_address') + list_filter = ('is_active',) + search_fields = ('is_active', 'ip_address') diff --git a/router/apps.py b/router/apps.py new file mode 100644 index 0000000..9b31c20 --- /dev/null +++ b/router/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CustomAdmin(AppConfig): + name = "router" + verbose_name = "Router" diff --git a/router/migrations/0001_initial.py b/router/migrations/0001_initial.py new file mode 100644 index 0000000..ce8eb17 --- /dev/null +++ b/router/migrations/0001_initial.py @@ -0,0 +1,52 @@ +# Generated by Django 5.0.3 on 2024-03-31 08:50 + +import django.db.models.deletion +import django.utils.timezone +import dsbd.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('noc', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='TunnelRouter', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('is_active', models.BooleanField(default=True, verbose_name='有効')), + ('hostname', models.CharField(max_length=255, unique=True, verbose_name='ホスト名')), + ('comment', dsbd.models.MediumTextField(blank=True, default='', verbose_name='コメント')), + ('noc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='noc.noc')), + ], + options={ + 'verbose_name': 'Tunnel Router', + 'verbose_name_plural': 'Tunnel Routers', + 'ordering': ('id',), + }, + ), + migrations.CreateModel( + name='TunnelIP', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('is_active', models.BooleanField(default=True, verbose_name='有効')), + ('ip_address', models.GenericIPAddressField(unique=True, verbose_name='IPアドレス')), + ('comment', dsbd.models.MediumTextField(blank=True, default='', verbose_name='コメント')), + ('tunnel_router', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='router.tunnelrouter')), + ], + options={ + 'verbose_name': 'Tunnel IP', + 'verbose_name_plural': 'Tunnel IPs', + 'ordering': ('id',), + }, + ), + ] diff --git a/router/migrations/__init__.py b/router/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/router/models.py b/router/models.py new file mode 100644 index 0000000..489c478 --- /dev/null +++ b/router/models.py @@ -0,0 +1,33 @@ +from django.db import models +from django.utils import timezone + +from dsbd.models import MediumTextField +from noc.models import NOC + + +class TunnelRouter(models.Model): + class Meta: + ordering = ("id",) + verbose_name = "Tunnel Router" + verbose_name_plural = "Tunnel Routers" + + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + is_active = models.BooleanField("有効", default=True) + noc = models.ForeignKey(NOC, on_delete=models.CASCADE) + hostname = models.CharField("ホスト名", unique=True, max_length=255) + comment = MediumTextField("コメント", default="", blank=True) + + +class TunnelIP(models.Model): + class Meta: + ordering = ("id",) + verbose_name = "Tunnel IP" + verbose_name_plural = "Tunnel IPs" + + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + is_active = models.BooleanField("有効", default=True) + tunnel_router = models.ForeignKey(TunnelRouter, on_delete=models.CASCADE) + ip_address = models.GenericIPAddressField("IPアドレス", unique=True) + comment = MediumTextField("コメント", default="", blank=True) diff --git a/service/__init__.py b/service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/service/admin.py b/service/admin.py new file mode 100644 index 0000000..62128ed --- /dev/null +++ b/service/admin.py @@ -0,0 +1,36 @@ +from django.contrib import admin + +from .models import Service, Connection + + +@admin.register(Service) +class Service(admin.ModelAdmin): + fieldsets = ( + (None, {'fields': ('is_active', 'is_pass', 'allow_connection_add')}), + ('service', {'fields': ('service_type', 'service_number', 'start_at', 'end_at', 'asn')}), + ('bandwidth', + {'fields': ('ave_upstream', 'max_upstream', 'ave_downstream', 'max_downstream', 'max_bandwidth_as')}), + ('comment', {'fields': ('user_comment', 'admin_comment')}), + ('Important dates', {'fields': ('created_at', 'updated_at',)}), + ) + list_display = ('id', 'is_active', 'is_pass', 'group', 'start_at', 'end_at') + list_filter = ('end_at',) + search_fields = ('end_at', 'is_active', 'service_type') + + +@admin.register(Connection) +class Connection(admin.ModelAdmin): + fieldsets = ( + (None, + {'fields': ('is_active', 'is_open', 'service', 'connection_type', 'connection_number', 'connection_comment')}), + ('入力情報', + {'fields': ('ntt_type', 'ntt_comment', 'ipv4_route', 'ipv4_comment', 'ipv6_route', 'ipv6_comment', + 'start_at', 'end_at', 'is_monitor', 'term_location', 'hope_location')}), + ('Info', {'fields': ( + 'tunnel_ip', 'term_ip', 'link_v4_our', 'link_v4_your', 'link_v6_our', 'link_v6_your')}), + ('comment', {'fields': ('user_comment', 'admin_comment')}), + ('Important dates', {'fields': ('created_at', 'updated_at',)}), + ) + list_display = ('id', 'is_active', 'is_open', 'service', 'start_at', 'end_at') + list_filter = ('is_active', 'is_open', 'start_at', 'end_at',) + search_fields = ('is_active', 'service_type') diff --git a/service/apps.py b/service/apps.py new file mode 100644 index 0000000..e1c140e --- /dev/null +++ b/service/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CustomAdmin(AppConfig): + name = "service" + verbose_name = "Service" diff --git a/service/migrations/0001_initial.py b/service/migrations/0001_initial.py new file mode 100644 index 0000000..4b5997c --- /dev/null +++ b/service/migrations/0001_initial.py @@ -0,0 +1,87 @@ +# Generated by Django 5.0.3 on 2024-03-31 08:50 + +import django.db.models.deletion +import django.utils.timezone +import dsbd.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('custom_auth', '0004_group_users_alter_user_groups'), + ('router', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Service', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('service_type', models.IntegerField(choices=[('2000', 'L2'), ('3S00', 'L3 Static'), ('3B00', 'L3 BGP'), ('IP3B', 'トランジット提供'), ('CL20', 'コロケーションサービス(L2)'), ('CL3S', 'コロケーションサービス(L3 Static)'), ('CL3B', 'コロケーションサービス(L3 BGP)'), ('ET00', 'その他')], default='CL3B', verbose_name='サービスタイプ')), + ('service_number', models.IntegerField(default=0, verbose_name='サービス番号')), + ('service_comment', models.IntegerField(blank=True, default=0, verbose_name='サービス情報コメント')), + ('is_active', models.BooleanField(default=True, verbose_name='有効')), + ('is_pass', models.BooleanField(default=False, verbose_name='審査OK')), + ('allow_connection_add', models.BooleanField(default=True, verbose_name='接続追加許可')), + ('asn', models.IntegerField(blank=True, default=0, null=True, verbose_name='ASN')), + ('ave_upstream', models.IntegerField(default=10, verbose_name='平均アップロード帯域幅')), + ('max_upstream', models.IntegerField(default=20, verbose_name='最大アップロード帯域幅')), + ('ave_downstream', models.IntegerField(default=10, verbose_name='平均ダウンロード帯域幅')), + ('max_downstream', models.IntegerField(default=20, verbose_name='最大ダウンロード帯域幅')), + ('max_bandwidth_as', models.CharField(blank=True, default='', max_length=255, verbose_name='最大帯域幅AS')), + ('start_at', models.DateTimeField(blank=True, null=True, verbose_name='開通日')), + ('end_at', models.DateTimeField(blank=True, null=True, verbose_name='解約日')), + ('user_comment', dsbd.models.MediumTextField(blank=True, default='', verbose_name='ユーザコメント')), + ('admin_comment', dsbd.models.MediumTextField(blank=True, default='', verbose_name='管理者コメント')), + ('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ServiceGroup', to='custom_auth.group')), + ], + options={ + 'verbose_name': 'Service', + 'verbose_name_plural': 'Services', + 'ordering': ('id',), + }, + ), + migrations.CreateModel( + name='Connection', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='作成日')), + ('updated_at', models.DateTimeField(default=django.utils.timezone.now, verbose_name='更新日')), + ('connection_type', models.IntegerField(choices=[('EIP', 'EtherIP Tunnel'), ('GRE', 'GRE Tunnel'), ('IPT', 'IPT Tunnel'), ('CC0', 'Cross Connect'), ('ETC', 'ETC')], default='EIP', verbose_name='サービスタイプ')), + ('connection_number', models.IntegerField(default=0, verbose_name='接続番号')), + ('connection_comment', models.IntegerField(blank=True, default=0, verbose_name='接続情報コメント')), + ('is_active', models.BooleanField(default=True, verbose_name='有効')), + ('is_open', models.BooleanField(default=False, verbose_name='開通')), + ('hope_location', models.CharField(choices=[('east_japan', '東日本'), ('west_japan', '西日本'), ('anywhere', 'どちらでも')], default='anywhere', max_length=255, verbose_name='接続希望場所')), + ('term_location', models.CharField(blank=True, default='', max_length=255, verbose_name='接続終端場所')), + ('ntt_type', models.CharField(choices=[('type-1', 'はい(IPoEによりIPv6インターネットへ接続可能)'), ('type-2', 'はい(IPoEによりIPv6インターネットへ接続不可)'), ('type-3', 'はい(フレッツv6オプションの契約なし)'), ('type-4', 'いいえ(フレッツ以外でインターネットに接続可能)'), ('type-5', 'いいえ(IPv6でのインターネット接続不可)'), ('etc', 'etc')], default='type-1', max_length=255, verbose_name='NTT接続タイプ')), + ('ntt_comment', models.CharField(blank=True, default='', max_length=255, verbose_name='NTT接続コメント')), + ('ipv4_route', models.CharField(choices=[('full_route', 'Full Route'), ('default_route', 'Default Route'), ('full_route', 'Etc')], default='full_route', max_length=255, verbose_name='IPv4 Route')), + ('ipv4_comment', models.CharField(blank=True, default='', max_length=255, verbose_name='IPv4コメント')), + ('ipv6_route', models.CharField(choices=[('full_route', 'Full Route'), ('default_route', 'Default Route'), ('full_route', 'Etc')], default='full_route', max_length=255, verbose_name='IPv6 Route')), + ('ipv6_comment', models.CharField(blank=True, default='', max_length=255, verbose_name='IPv6コメント')), + ('is_monitor', models.BooleanField(default=False, verbose_name='監視の有無')), + ('link_v4_our', models.GenericIPAddressField(blank=True, null=True, verbose_name='IPv4接続(HomeNOC側)')), + ('link_v4_your', models.GenericIPAddressField(blank=True, null=True, verbose_name='IPv4(貴団体側)')), + ('link_v6_our', models.GenericIPAddressField(blank=True, null=True, verbose_name='IPv6接続(HomeNOC側)')), + ('link_v6_your', models.GenericIPAddressField(blank=True, null=True, verbose_name='IPv6(貴団体側)')), + ('term_ip', models.GenericIPAddressField(blank=True, null=True, verbose_name='終端先IP')), + ('start_at', models.DateTimeField(blank=True, null=True, verbose_name='開通日')), + ('end_at', models.DateTimeField(blank=True, null=True, verbose_name='解約日')), + ('user_comment', dsbd.models.MediumTextField(blank=True, default='', verbose_name='ユーザコメント')), + ('admin_comment', dsbd.models.MediumTextField(blank=True, default='', verbose_name='管理者コメント')), + ('tunnel_ip', models.ForeignKey(max_length=255, on_delete=django.db.models.deletion.CASCADE, related_name='ConnectionTunnelIP', to='router.tunnelip')), + ('service', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ConnectionService', to='service.service')), + ], + options={ + 'verbose_name': 'Connection', + 'verbose_name_plural': 'Connections', + 'ordering': ('id',), + }, + ), + ] diff --git a/service/migrations/__init__.py b/service/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/service/models.py b/service/models.py new file mode 100644 index 0000000..389400c --- /dev/null +++ b/service/models.py @@ -0,0 +1,164 @@ +from django.db import models +from django.db.models import Q +from django.utils import timezone + +from custom_auth.models import Group +from dsbd.models import MediumTextField +from router.models import TunnelIP + + +class ServiceManager(models.Manager): + def get_notice(self): + now = timezone.now() + notices = self.filter( + Q(start_at__lte=now), + Q(is_active=True), + Q(end_at__gt=timezone.now()) | Q(end_at__isnull=True) + ) + return notices + + +class Service(models.Model): + class Meta: + ordering = ("id",) + verbose_name = "Service" + verbose_name_plural = "Services" + + SERVICE_L2 = "2000" + SERVICE_L3_STATIC = "3S00" + SERVICE_L3_BGP = "3B00" + SERVICE_TRANSIT = "IP3B" + SERVICE_COLO_L2 = "CL20" + SERVICE_COLO_L3_STATIC = "CL3S" + SERVICE_COLO_L3_BGP = "CL3B" + SERVICE_ETC = "ET00" + + SERVICE_CHOICES = ( + (SERVICE_L2, "L2"), + (SERVICE_L3_STATIC, "L3 Static"), + (SERVICE_L3_BGP, "L3 BGP"), + (SERVICE_TRANSIT, "トランジット提供"), + (SERVICE_COLO_L2, "コロケーションサービス(L2)"), + (SERVICE_COLO_L3_STATIC, "コロケーションサービス(L3 Static)"), + (SERVICE_COLO_L3_BGP, "コロケーションサービス(L3 BGP)"), + (SERVICE_ETC, "その他"), + ) + + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + group = models.ForeignKey(Group, on_delete=models.SET_NULL, related_name="ServiceGroup", null=True, blank=True) + service_type = models.IntegerField("サービスタイプ", choices=SERVICE_CHOICES, default=SERVICE_COLO_L3_BGP) + service_number = models.IntegerField("サービス番号", default=0) + service_comment = models.IntegerField("サービス情報コメント", default=0, blank=True) + is_active = models.BooleanField("有効", default=True) + is_pass = models.BooleanField("審査OK", default=False) + allow_connection_add = models.BooleanField("接続追加許可", default=True) + asn = models.IntegerField("ASN", default=0, null=True, blank=True) + ave_upstream = models.IntegerField("平均アップロード帯域幅", default=10) + max_upstream = models.IntegerField("最大アップロード帯域幅", default=20) + ave_downstream = models.IntegerField("平均ダウンロード帯域幅", default=10) + max_downstream = models.IntegerField("最大ダウンロード帯域幅", default=20) + max_bandwidth_as = models.CharField("最大帯域幅AS", default="", blank=True, max_length=255) + start_at = models.DateTimeField("開通日", null=True, blank=True) + end_at = models.DateTimeField("解約日", null=True, blank=True) + user_comment = MediumTextField("ユーザコメント", default="", blank=True) + admin_comment = MediumTextField("管理者コメント", default="", blank=True) + + objects = ServiceManager() + + def __str__(self): + return "%s-%s%s" % (self.group.id, self.service_type, str(self.service_number).zfill(3),) + + +CONNECTION_EIP = "EIP" +CONNECTION_GRE = "GRE" +CONNECTION_IPT = "IPT" +CONNECTION_CC = "CC0" +CONNECTION_ETC = "ETC" + +CONNECTION_TYPE_CHOICES = ( + (CONNECTION_EIP, "EtherIP Tunnel"), + (CONNECTION_GRE, "GRE Tunnel"), + (CONNECTION_IPT, "IPT Tunnel"), + (CONNECTION_CC, "Cross Connect"), + (CONNECTION_ETC, "ETC"), +) + +NTT_TYPE1 = "type-1" +NTT_TYPE2 = "type-2" +NTT_TYPE3 = "type-3" +NTT_TYPE4 = "type-4" +NTT_TYPE5 = "type-5" +NTT_TYPE6 = "etc" + +NTT_CHOICES = ( + (NTT_TYPE1, "はい(IPoEによりIPv6インターネットへ接続可能)"), + (NTT_TYPE2, "はい(IPoEによりIPv6インターネットへ接続不可)"), + (NTT_TYPE3, "はい(フレッツv6オプションの契約なし)"), + (NTT_TYPE4, "いいえ(フレッツ以外でインターネットに接続可能)"), + (NTT_TYPE5, "いいえ(IPv6でのインターネット接続不可)"), + (NTT_TYPE6, "etc"), +) + +ROUTE_FULL_ROUTE = "full_route" +ROUTE_DEFAULT_ROUTE = "default_route" +ROUTE_ETC = "full_route" + +ROUTE_CHOICES = ( + (ROUTE_FULL_ROUTE, "Full Route"), + (ROUTE_DEFAULT_ROUTE, "Default Route"), + (ROUTE_ETC, "Etc"), +) + +HOPE_LOCATION_EAST_JAPAN = "east_japan" +HOPE_LOCATION_WEST_JAPAN = "west_japan" +HOPE_LOCATION_ANYWHERE = "anywhere" +HOPE_LOCATION_CHOICES = ( + (HOPE_LOCATION_EAST_JAPAN, "東日本"), + (HOPE_LOCATION_WEST_JAPAN, "西日本"), + (HOPE_LOCATION_ANYWHERE, "どちらでも"), +) + + +class Connection(models.Model): + class Meta: + ordering = ("id",) + verbose_name = "Connection" + verbose_name_plural = "Connections" + + created_at = models.DateTimeField("作成日", default=timezone.now) + updated_at = models.DateTimeField("更新日", default=timezone.now) + service = models.ForeignKey(Service, on_delete=models.SET_NULL, related_name="ConnectionService", null=True, blank=True) + connection_type = models.IntegerField("サービスタイプ", default=CONNECTION_EIP, choices=CONNECTION_TYPE_CHOICES) + connection_number = models.IntegerField("接続番号", default=0) + connection_comment = models.IntegerField("接続情報コメント", default=0, blank=True) + is_active = models.BooleanField("有効", default=True) + is_open = models.BooleanField("開通", default=False) + tunnel_ip = models.ForeignKey(TunnelIP, on_delete=models.CASCADE, related_name="ConnectionTunnelIP", max_length=255) + hope_location = models.CharField("接続希望場所", default=HOPE_LOCATION_ANYWHERE, choices=HOPE_LOCATION_CHOICES, max_length=255) + term_location = models.CharField("接続終端場所", default="", blank=True, max_length=255) + ntt_type = models.CharField("NTT接続タイプ", default=NTT_TYPE1, choices=NTT_CHOICES, max_length=255) + ntt_comment = models.CharField("NTT接続コメント", default="", blank=True, max_length=255) + ipv4_route = models.CharField("IPv4 Route", default=ROUTE_FULL_ROUTE, choices=ROUTE_CHOICES, max_length=255) + ipv4_comment = models.CharField("IPv4コメント", default="", blank=True, max_length=255) + ipv6_route = models.CharField("IPv6 Route", default=ROUTE_FULL_ROUTE, choices=ROUTE_CHOICES, max_length=255) + ipv6_comment = models.CharField("IPv6コメント", default="", blank=True, max_length=255) + is_monitor = models.BooleanField("監視の有無", default=False) + link_v4_our = models.GenericIPAddressField("IPv4接続(HomeNOC側)", null=True, blank=True) + link_v4_your = models.GenericIPAddressField("IPv4(貴団体側)", null=True, blank=True) + link_v6_our = models.GenericIPAddressField("IPv6接続(HomeNOC側)", null=True, blank=True) + link_v6_your = models.GenericIPAddressField("IPv6(貴団体側)", null=True, blank=True) + term_ip = models.GenericIPAddressField("終端先IP", null=True, blank=True) + start_at = models.DateTimeField("開通日", null=True, blank=True) + end_at = models.DateTimeField("解約日", null=True, blank=True) + user_comment = MediumTextField("ユーザコメント", default="", blank=True) + admin_comment = MediumTextField("管理者コメント", default="", blank=True) + + def __str__(self): + return "%s-%s%s-%s%s" % ( + self.service.group.id, + self.service.service_type, + str(self.service.service_number).zfill(3), + self.connection_type, + str(self.connection_number).zfill(3), + )