diff --git a/README.md b/README.md index 80204ff..3fb0150 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ THIS PLUGIN IS UNDER DEVELOPMENT AND MAY CHANGE. A [Netbox](https://github.com/netbox-community/netbox) plugin for storage related documentation where virtualization is used. -4 new object types are introduced: +5 new object types are introduced: - Storage Pools: a pool that is created on a storage. Currently this storage has to be a Netbox Device. - LUN: tied to a Storage Pool - - LUN Groups: a collection of LUNs for easier management of Storage Sessions. + - Datastores: created on LUN(s) - Storage Sessions: the "source" of a session is a Netbox Virtualization Cluster, the "destination" is the LUN Group + - VMDK: can be assigned to a VM and a datastore diff --git a/netbox_storage/__init__.py b/netbox_storage/__init__.py index d0e5c77..0d72a92 100644 --- a/netbox_storage/__init__.py +++ b/netbox_storage/__init__.py @@ -5,7 +5,7 @@ class NetBoxStorageConfig(PluginConfig): name = 'netbox_storage' verbose_name = ' NetBox Storage' description = 'Netbox Storage Administration Plugin' - version = '0.1' + version = '0.2' base_url = 'storage' diff --git a/netbox_storage/api/serializers.py b/netbox_storage/api/serializers.py index 7c7bd4c..83639ca 100644 --- a/netbox_storage/api/serializers.py +++ b/netbox_storage/api/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from ..models import StoragePool, StorageLUN, StorageSession, StorageLUNGroup +from ..models import StoragePool, LUN, StorageSession, Datastore, VMDK from virtualization.api.serializers import NestedClusterSerializer from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer @@ -19,13 +19,23 @@ class Meta: fields = ('id', 'url', 'display', 'name') -class NestedStorageLUNSerializer(WritableNestedSerializer): +class NestedLUNSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField( - view_name='plugins-api:netbox_storage-api:storagelun-detail' + view_name='plugins-api:netbox_storage-api:lun-detail' ) class Meta: - model = StorageLUN + model = LUN + fields = ('id', 'url', 'display', 'name') + + +class NestedDatastoreSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField( + view_name='plugins-api:netbox_storage-api:datastore-detail' + ) + + class Meta: + model = Datastore fields = ('id', 'url', 'display', 'name') @@ -39,13 +49,13 @@ class Meta: fields = ('id', 'url', 'display', 'name') -class NestedStorageLUNGroupSerializer(WritableNestedSerializer): +class NestedVMDKSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField( - view_name='plugins-api:netbox_storage-api:storagelungroup-detail' + view_name='plugins-api:netbox_storage-api:vmdk-detail' ) class Meta: - model = StorageLUNGroup + model = VMDK fields = ('id', 'url', 'display', 'name') @@ -66,14 +76,14 @@ class Meta: ) -class StorageLUNSerializer(NetBoxModelSerializer): +class LUNSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField( - view_name='plugins-api:netbox_storage-api:storagelun-detail' + view_name='plugins-api:netbox_storage-api:lun-detail' ) storage_pool = NestedStoragePoolSerializer() class Meta: - model = StorageLUN + model = LUN fields = ( 'id', 'url', 'display', 'name', 'size', 'storage_pool', 'description', 'tags', 'custom_fields', @@ -81,6 +91,19 @@ class Meta: ) +class DatastoreSerializer(NetBoxModelSerializer): + url = serializers.HyperlinkedIdentityField( + view_name='plugins-api:netbox_storage-api:datastore-detail' + ) + + class Meta: + model = Datastore + fields = ( + 'id', 'url', 'display', 'name', 'lun', + 'description', 'tags', 'custom_fields', 'created', 'last_updated', + ) + + class StorageSessionSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField( view_name='plugins-api:netbox_storage-api:storagesession-detail' @@ -90,19 +113,20 @@ class StorageSessionSerializer(NetBoxModelSerializer): class Meta: model = StorageSession fields = ( - 'id', 'url', 'display', 'name', 'cluster', 'storage_lun_groups', + 'id', 'url', 'display', 'name', 'cluster', 'datastores', 'description', 'tags', 'custom_fields', 'created', 'last_updated', ) -class StorageLUNGroupSerializer(NetBoxModelSerializer): +class VMDKSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField( - view_name='plugins-api:netbox_storage-api:storagelungroup-detail' + view_name='plugins-api:netbox_storage-api:vmdk-detail' ) + datastore = NestedDatastoreSerializer() class Meta: - model = StorageLUNGroup + model = VMDK fields = ( - 'id', 'url', 'display', 'name', 'storage_lun', - 'description', 'tags', 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'display', 'vm', 'name', 'datastore', + 'size', 'tags', 'custom_fields', 'created', 'last_updated', ) diff --git a/netbox_storage/api/urls.py b/netbox_storage/api/urls.py index 25e81fc..fdbfe81 100644 --- a/netbox_storage/api/urls.py +++ b/netbox_storage/api/urls.py @@ -6,8 +6,9 @@ router = NetBoxRouter() router.register('storagepool', views.StoragePoolViewSet) -router.register('storagelun', views.StorageLUNViewSet) +router.register('lun', views.LUNViewSet) +router.register('datastore', views.DatastoreViewSet) router.register('storagesession', views.StorageSessionViewSet) -router.register('storagelungroup', views.StorageLUNGroupViewSet) +router.register('vmdk', views.VMDKViewSet) urlpatterns = router.urls diff --git a/netbox_storage/api/views.py b/netbox_storage/api/views.py index 5b93cf9..659f7f6 100644 --- a/netbox_storage/api/views.py +++ b/netbox_storage/api/views.py @@ -1,7 +1,7 @@ from netbox.api.viewsets import NetBoxModelViewSet from .. import filtersets, models -from .serializers import StoragePoolSerializer, StorageLUNSerializer, StorageSessionSerializer, StorageLUNGroupSerializer +from .serializers import StoragePoolSerializer, LUNSerializer, StorageSessionSerializer, DatastoreSerializer, VMDKSerializer class StoragePoolViewSet(NetBoxModelViewSet): @@ -9,22 +9,29 @@ class StoragePoolViewSet(NetBoxModelViewSet): serializer_class = StoragePoolSerializer -class StorageLUNViewSet(NetBoxModelViewSet): - queryset = models.StorageLUN.objects.prefetch_related( +class LUNViewSet(NetBoxModelViewSet): + queryset = models.LUN.objects.prefetch_related( 'storage_pool', 'tags' ) - serializer_class = StorageLUNSerializer + serializer_class = LUNSerializer -class StorageLUNGroupViewSet(NetBoxModelViewSet): - queryset = models.StorageLUNGroup.objects.prefetch_related( - 'storage_lun', 'tags' +class DatastoreViewSet(NetBoxModelViewSet): + queryset = models.Datastore.objects.prefetch_related( + 'lun', 'tags' ) - serializer_class = StorageLUNGroupSerializer + serializer_class = DatastoreSerializer class StorageSessionViewSet(NetBoxModelViewSet): queryset = models.StorageSession.objects.prefetch_related( - 'cluster', 'storage_lun_groups', 'tags' + 'cluster', 'datastores', 'tags' ) serializer_class = StorageSessionSerializer + + +class VMDKViewSet(NetBoxModelViewSet): + queryset = models.VMDK.objects.prefetch_related( + 'datastore', 'vm', 'tags' + ) + serializer_class = VMDKSerializer diff --git a/netbox_storage/filtersets.py b/netbox_storage/filtersets.py index 73247e4..1208716 100644 --- a/netbox_storage/filtersets.py +++ b/netbox_storage/filtersets.py @@ -1,5 +1,5 @@ from netbox.filtersets import NetBoxModelFilterSet -from .models import StorageLUN, StorageSession, StorageLUNGroup +from .models import LUN, StorageSession, Datastore # class StorageLUNFilterSet(NetBoxModelFilterSet): diff --git a/netbox_storage/forms.py b/netbox_storage/forms.py index ff67ca1..fc7f867 100644 --- a/netbox_storage/forms.py +++ b/netbox_storage/forms.py @@ -1,54 +1,71 @@ from django import forms from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelCSVForm from utilities.forms.fields import DynamicModelChoiceField, CSVModelChoiceField, DynamicModelMultipleChoiceField -from ipam.models import IPAddress from dcim.models import Device -from virtualization.models import Cluster -from .models import StoragePool, StorageSession, StorageLUN, StorageLUNGroup +from virtualization.models import Cluster, VirtualMachine +from .models import StoragePool, StorageSession, LUN, Datastore, VMDK # # Regular forms # class StoragePoolForm(NetBoxModelForm): + device = DynamicModelChoiceField( + queryset=Device.objects.all() + ) class Meta: model = StoragePool fields = ('name', 'size', 'device', 'description', 'tags') -class StorageLUNForm(NetBoxModelForm): +class LUNForm(NetBoxModelForm): storage_pool = DynamicModelChoiceField( queryset=StoragePool.objects.all() ) class Meta: - model = StorageLUN + model = LUN fields = ('storage_pool', 'name', 'size', 'description') -class StorageLUNGroupForm(NetBoxModelForm): - storage_lun = DynamicModelMultipleChoiceField( - queryset=StorageLUN.objects.all() +class DatastoreForm(NetBoxModelForm): + lun = DynamicModelMultipleChoiceField( + queryset=LUN.objects.all() ) class Meta: - model = StorageLUN - fields = ('storage_lun', 'name', 'description') + model = LUN + fields = ('lun', 'name', 'description') class StorageSessionForm(NetBoxModelForm): cluster = DynamicModelChoiceField( queryset=Cluster.objects.all(), ) - storage_lun_groups = DynamicModelMultipleChoiceField( - queryset=StorageLUNGroup.objects.all() + datastores = DynamicModelMultipleChoiceField( + queryset=Datastore.objects.all() ) class Meta: model = StorageSession fields = ( - 'name', 'cluster', 'storage_lun_groups', 'description' + 'name', 'cluster', 'datastores', 'description' + ) + + +class VMDKForm(NetBoxModelForm): + datastore = DynamicModelChoiceField( + queryset=Datastore.objects.all(), + ) + vm = DynamicModelChoiceField( + queryset=VirtualMachine.objects.all(), + ) + + class Meta: + model = VMDK + fields = ( + 'vm', 'datastore', 'name', 'size', ) diff --git a/netbox_storage/migrations/0001_initial.py b/netbox_storage/migrations/0001_initial.py index 7f085b3..b5a9051 100644 --- a/netbox_storage/migrations/0001_initial.py +++ b/netbox_storage/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.1.6 on 2023-02-06 11:00 +# Generated by Django 4.1.6 on 2023-02-08 16:56 from django.db import migrations, models import django.db.models.deletion @@ -11,21 +11,20 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('dcim', '0167_module_status'), ('virtualization', '0034_standardize_description_comments'), ('extras', '0084_staging'), + ('dcim', '0167_module_status'), ] operations = [ migrations.CreateModel( - name='StorageLUN', + name='Datastore', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), ('name', models.CharField(max_length=100)), - ('size', models.PositiveIntegerField()), ('description', models.TextField(blank=True)), ], options={ @@ -33,19 +32,20 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='StorageLUNGroup', + name='VMDK', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), ('name', models.CharField(max_length=100)), - ('description', models.TextField(blank=True)), - ('storage_lun', models.ManyToManyField(related_name='lun_groups', to='netbox_storage.storagelun')), + ('size', models.PositiveIntegerField()), + ('datastore', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vmdks', to='netbox_storage.datastore')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ('vm', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vmdks', to='virtualization.virtualmachine')), ], options={ - 'ordering': ('name',), + 'ordering': ('datastore', 'name'), }, ), migrations.CreateModel( @@ -58,7 +58,7 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=100)), ('description', models.TextField(blank=True)), ('cluster', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='storage_sessions', to='virtualization.cluster')), - ('storage_lun_groups', models.ManyToManyField(related_name='storage_sessions', to='netbox_storage.storagelungroup')), + ('datastores', models.ManyToManyField(related_name='storage_sessions', to='netbox_storage.datastore')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -82,18 +82,32 @@ class Migration(migrations.Migration): 'ordering': ('name',), }, ), + migrations.CreateModel( + name='LUN', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), + ('created', models.DateTimeField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ('name', models.CharField(max_length=100)), + ('size', models.PositiveIntegerField()), + ('description', models.TextField(blank=True)), + ('storage_pool', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='luns', to='netbox_storage.storagepool')), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ], + options={ + 'ordering': ('name',), + 'unique_together': {('storage_pool', 'name')}, + }, + ), migrations.AddField( - model_name='storagelun', - name='storage_pool', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='luns', to='netbox_storage.storagepool'), + model_name='datastore', + name='lun', + field=models.ManyToManyField(related_name='lun_groups', to='netbox_storage.lun'), ), migrations.AddField( - model_name='storagelun', + model_name='datastore', name='tags', field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'), ), - migrations.AlterUniqueTogether( - name='storagelun', - unique_together={('storage_pool', 'name')}, - ), ] diff --git a/netbox_storage/models.py b/netbox_storage/models.py index 72d388d..c45827e 100644 --- a/netbox_storage/models.py +++ b/netbox_storage/models.py @@ -36,7 +36,7 @@ def get_utilization(self): return min(utilization, 100) -class StorageLUN(NetBoxModel): +class LUN(NetBoxModel): storage_pool = models.ForeignKey( to=StoragePool, on_delete=models.PROTECT, @@ -58,12 +58,12 @@ def __str__(self): return f'{self.name}' def get_absolute_url(self): - return reverse('plugins:netbox_storage:storagelun', args=[self.pk]) + return reverse('plugins:netbox_storage:lun', args=[self.pk]) -class StorageLUNGroup(NetBoxModel): - storage_lun = models.ManyToManyField( - to=StorageLUN, +class Datastore(NetBoxModel): + lun = models.ManyToManyField( + to=LUN, related_name='lun_groups' ) name = models.CharField( @@ -80,7 +80,17 @@ def __str__(self): return f'{self.name}' def get_absolute_url(self): - return reverse('plugins:netbox_storage:storagelungroup', args=[self.pk]) + return reverse('plugins:netbox_storage:datastore', args=[self.pk]) + + def get_utilization(self): + sum_lun_size = self.lun.all().aggregate(Sum('size'))['size__sum'] + sum_vmdk_size = self.vmdks.all().aggregate(Sum('size'))['size__sum'] + if sum_lun_size and sum_vmdk_size: + utilization = float(sum_vmdk_size) / float(sum_lun_size) * 100 + else: + utilization = 0 + + return min(utilization, 100) class StorageSession(NetBoxModel): @@ -92,8 +102,8 @@ class StorageSession(NetBoxModel): on_delete=models.PROTECT, related_name='storage_sessions' ) - storage_lun_groups = models.ManyToManyField( - to=StorageLUNGroup, + datastores = models.ManyToManyField( + to=Datastore, related_name='storage_sessions' ) description = models.TextField( @@ -108,3 +118,29 @@ def __str__(self): def get_absolute_url(self): return reverse('plugins:netbox_storage:storagesession', args=[self.pk]) + + +class VMDK(NetBoxModel): + vm = models.ForeignKey( + to='virtualization.virtualmachine', + on_delete=models.PROTECT, + related_name='vmdks' + ) + name = models.CharField( + max_length=100 + ) + datastore = models.ForeignKey( + to=Datastore, + related_name='vmdks', + on_delete=models.PROTECT + ) + size = models.PositiveIntegerField() + + class Meta: + ordering = ('datastore', 'name',) + + def __str__(self): + return f'{self.vm}-{self.datastore}-{self.name}' + + def get_absolute_url(self): + return reverse('plugins:netbox_storage:vmdk', args=[self.pk]) diff --git a/netbox_storage/navigation.py b/netbox_storage/navigation.py index 9915d80..d4a4059 100644 --- a/netbox_storage/navigation.py +++ b/netbox_storage/navigation.py @@ -16,18 +16,18 @@ # ) ] -storageluns_buttons = [ +lun_buttons = [ PluginMenuButton( - link='plugins:netbox_storage:storagelun_add', + link='plugins:netbox_storage:lun_add', title='Add', icon_class='mdi mdi-plus-thick', color=ButtonColorChoices.GREEN ) ] -storagelungroups_buttons = [ +datastore_buttons = [ PluginMenuButton( - link='plugins:netbox_storage:storagelungroup_add', + link='plugins:netbox_storage:datastore_add', title='Add', icon_class='mdi mdi-plus-thick', color=ButtonColorChoices.GREEN @@ -43,6 +43,15 @@ ) ] +vmdk_button = [ + PluginMenuButton( + link='plugins:netbox_storage:vmdk_add', + title='Add', + icon_class='mdi mdi-plus-thick', + color=ButtonColorChoices.GREEN + ) +] + menu_items = ( PluginMenuItem( link='plugins:netbox_storage:storagepool_list', @@ -50,18 +59,23 @@ buttons=storagepool_buttons ), PluginMenuItem( - link='plugins:netbox_storage:storagelun_list', - link_text='Storage LUNs', - buttons=storageluns_buttons + link='plugins:netbox_storage:lun_list', + link_text='LUNs', + buttons=lun_buttons ), PluginMenuItem( - link='plugins:netbox_storage:storagelungroup_list', - link_text='Storage LUN Groups', - buttons=storagelungroups_buttons + link='plugins:netbox_storage:datastore_list', + link_text='Datastores', + buttons=datastore_buttons ), PluginMenuItem( link='plugins:netbox_storage:storagesession_list', link_text='Storage Sessions', buttons=storagesession_buttons ), + PluginMenuItem( + link='plugins:netbox_storage:vmdk_list', + link_text='VMDKs', + buttons=vmdk_button + ), ) diff --git a/netbox_storage/tables.py b/netbox_storage/tables.py index e3b0791..088c609 100644 --- a/netbox_storage/tables.py +++ b/netbox_storage/tables.py @@ -1,10 +1,10 @@ import django_tables2 as tables from netbox.tables import NetBoxTable, columns -from .models import StoragePool, StorageSession, StorageLUNGroup, StorageLUN +from .models import StoragePool, StorageSession, Datastore, LUN, VMDK -class StorageUtilizationColumn(columns.UtilizationColumn): +class UtilizationColumn(columns.UtilizationColumn): template_code = """ {% load helpers %} {% if record.pk %} @@ -17,7 +17,7 @@ class StoragePoolTable(NetBoxTable): name = tables.Column( linkify=True ) - utilization = StorageUtilizationColumn( + utilization = UtilizationColumn( accessor='get_utilization', orderable=False ) @@ -34,7 +34,7 @@ class Meta(NetBoxTable.Meta): default_columns = ('name', 'device', 'size', 'utilization') -class StorageLUNTable(NetBoxTable): +class LUNTable(NetBoxTable): name = tables.Column( linkify=True ) @@ -43,7 +43,7 @@ class StorageLUNTable(NetBoxTable): ) class Meta(NetBoxTable.Meta): - model = StorageLUN + model = LUN fields = ( 'pk', 'id', 'name', 'storage_pool', 'size', 'description', 'actions', ) @@ -52,22 +52,26 @@ class Meta(NetBoxTable.Meta): ) -class StorageLUNGroupTable(NetBoxTable): +class DatastoreTable(NetBoxTable): name = tables.Column( linkify=True ) - storage_lun = columns.ManyToManyColumn( + lun = columns.ManyToManyColumn( linkify_item=True, verbose_name='LUNs' ) + utilization = UtilizationColumn( + accessor='get_utilization', + orderable=False + ) class Meta(NetBoxTable.Meta): - model = StorageLUNGroup + model = Datastore fields = ( - 'pk', 'id', 'name', 'storage_lun', 'description', 'actions', + 'pk', 'id', 'name', 'lun', 'utilization', 'description', 'actions', ) default_columns = ( - 'name', 'storage_lun', + 'name', 'lun', 'utilization', ) @@ -78,17 +82,39 @@ class StorageSessionTable(NetBoxTable): cluster = tables.Column( linkify=True, ) - storage_lun_groups = columns.ManyToManyColumn( + datastores = columns.ManyToManyColumn( linkify_item=True, - verbose_name='LUN Groups' + verbose_name='Datastores' ) class Meta(NetBoxTable.Meta): model = StorageSession fields = ( - 'pk', 'id', 'name', 'cluster', 'storage_lun_groups', 'description', + 'pk', 'id', 'name', 'cluster', 'datastores', 'description', + ) + default_columns = ( + 'name', 'cluster', 'datastores', + ) + + +class VMDKTable(NetBoxTable): + name = tables.Column( + linkify=True + ) + vm = tables.Column( + linkify=True + ) + datastore = tables.Column( + linkify=True + ) + + class Meta(NetBoxTable.Meta): + model = VMDK + + fields = ( + 'pk', 'id', 'vm', 'name', 'datastore', 'size', ) default_columns = ( - 'name', 'cluster', 'storage_lun_groups', + 'vm', 'datastore', 'name', 'size', ) diff --git a/netbox_storage/template_content.py b/netbox_storage/template_content.py new file mode 100644 index 0000000..1648178 --- /dev/null +++ b/netbox_storage/template_content.py @@ -0,0 +1,13 @@ +from extras.plugins import PluginTemplateExtension +from .models import VMDK + + +class VMVMDKCard(PluginTemplateExtension): + model = 'virtualization.virtualmachine' + + def left_page(self): + return self.render('netbox_storage/vm_vmdk_extend.html', + extra_context={'object': self.context['object']}) + + +template_extensions = [VMVMDKCard] diff --git a/netbox_storage/templates/netbox_storage/storagelungroup.html b/netbox_storage/templates/netbox_storage/datastore.html similarity index 86% rename from netbox_storage/templates/netbox_storage/storagelungroup.html rename to netbox_storage/templates/netbox_storage/datastore.html index 67a949f..7ae5f40 100644 --- a/netbox_storage/templates/netbox_storage/storagelungroup.html +++ b/netbox_storage/templates/netbox_storage/datastore.html @@ -6,13 +6,17 @@
-
Storage LUN Group
+
Datastore
+ + + + diff --git a/netbox_storage/templates/netbox_storage/storagelun.html b/netbox_storage/templates/netbox_storage/lun.html similarity index 97% rename from netbox_storage/templates/netbox_storage/storagelun.html rename to netbox_storage/templates/netbox_storage/lun.html index 16be1c5..6fa048d 100644 --- a/netbox_storage/templates/netbox_storage/storagelun.html +++ b/netbox_storage/templates/netbox_storage/lun.html @@ -6,7 +6,7 @@
-
Storage LUN
+
LUN
Name {{ object.name }}
Utilization{% utilization_graph object.get_utilization %}
Description {{ object.description }}
diff --git a/netbox_storage/templates/netbox_storage/storagepool.html b/netbox_storage/templates/netbox_storage/storagepool.html index 5a61c6d..e098413 100644 --- a/netbox_storage/templates/netbox_storage/storagepool.html +++ b/netbox_storage/templates/netbox_storage/storagepool.html @@ -43,7 +43,7 @@
Storage Pool
-
Storage Pool Allocations
+
LUNs
{% render_table luns_table %}
diff --git a/netbox_storage/templates/netbox_storage/storagesession.html b/netbox_storage/templates/netbox_storage/storagesession.html index db73142..9e14f5f 100644 --- a/netbox_storage/templates/netbox_storage/storagesession.html +++ b/netbox_storage/templates/netbox_storage/storagesession.html @@ -16,10 +16,10 @@
Storage Session
- + diff --git a/netbox_storage/templates/netbox_storage/vm_vmdk_extend.html b/netbox_storage/templates/netbox_storage/vm_vmdk_extend.html new file mode 100644 index 0000000..9ce196d --- /dev/null +++ b/netbox_storage/templates/netbox_storage/vm_vmdk_extend.html @@ -0,0 +1,48 @@ +
+
Attached VMDKs
+
+
+ {% if object.vmdks.all %} +
{{ object.cluster }}
LUN GroupsDatastores - {% for lun_group in object.storage_lun_groups.all %} - {{ lun_group}} + {% for datastore in object.datastores.all %} + {{ datastore }} {% if not forloop.last %}, {% endif %} {% endfor %}
+ + + + + + + + + {% for vmdk in object.vmdks.all %} + + + + + + + {% endfor %} +
DatastoreNameSize
{{ vmdk.datastore }}{{ vmdk.name }}{{ vmdk.size }} + + + + + + +
+ + {% else %} + + No VMDKs + + + {% endif %} +
+
+
diff --git a/netbox_storage/templates/netbox_storage/vmdk.html b/netbox_storage/templates/netbox_storage/vmdk.html new file mode 100644 index 0000000..26fe523 --- /dev/null +++ b/netbox_storage/templates/netbox_storage/vmdk.html @@ -0,0 +1,35 @@ +{% extends 'generic/object.html' %} + +{% block content %} +
+
+
+
VMDK
+
+ + + + + + + + + + + + + + + + + +
VM{{ object.vm }}
Datastore{{ object.datastore }}
Name{{ object.name }}
Size{{ object.size }}
+
+
+ {% include 'inc/panels/custom_fields.html' %} +
+
+ {% include 'inc/panels/tags.html' %} +
+
+{% endblock content %} \ No newline at end of file diff --git a/netbox_storage/urls.py b/netbox_storage/urls.py index 4c30732..0a9e4d8 100644 --- a/netbox_storage/urls.py +++ b/netbox_storage/urls.py @@ -16,24 +16,24 @@ 'model': models.StoragePool }), - # Storage LUNs - path('storagelun/', views.StorageLUNListView.as_view(), name='storagelun_list'), - path('storagelun/add/', views.StorageLUNEditView.as_view(), name='storagelun_add'), - path('storagelun//', views.StorageLUNView.as_view(), name='storagelun'), - path('storagelun//edit/', views.StorageLUNEditView.as_view(), name='storagelun_edit'), - path('storagelun//delete/', views.StorageLUNDeleteView.as_view(), name='storagelun_delete'), - path('storagelun//changelog/', ObjectChangeLogView.as_view(), name='storagelun_changelog', kwargs={ - 'model': models.StorageLUN + # LUNs + path('lun/', views.LUNListView.as_view(), name='lun_list'), + path('lun/add/', views.LUNEditView.as_view(), name='lun_add'), + path('lun//', views.LUNView.as_view(), name='lun'), + path('lun//edit/', views.LUNEditView.as_view(), name='lun_edit'), + path('lun//delete/', views.LUNDeleteView.as_view(), name='lun_delete'), + path('lun//changelog/', ObjectChangeLogView.as_view(), name='lun_changelog', kwargs={ + 'model': models.LUN }), - # Storage LUN groups - path('storagelungroup/', views.StorageLUNGroupListView.as_view(), name='storagelungroup_list'), - path('storagelungroup/add/', views.StorageLUNGroupEditView.as_view(), name='storagelungroup_add'), - path('storagelungroup//', views.StorageLUNGroupView.as_view(), name='storagelungroup'), - path('storagelungroup//edit/', views.StorageLUNGroupEditView.as_view(), name='storagelungroup_edit'), - path('storagelungroup//delete/', views.StorageLUNGroupDeleteView.as_view(), name='storagelungroup_delete'), - path('storagelungroup//changelog/', ObjectChangeLogView.as_view(), name='storagelungroup_changelog', kwargs={ - 'model': models.StorageLUNGroup + # Datastores + path('datastore/', views.DatastoreListView.as_view(), name='datastore_list'), + path('datastore/add/', views.DatastoreEditView.as_view(), name='datastore_add'), + path('datastore//', views.DatastoreView.as_view(), name='datastore'), + path('datastore//edit/', views.DatastoreEditView.as_view(), name='datastore_edit'), + path('datastore//delete/', views.DatastoreDeleteView.as_view(), name='datastore_delete'), + path('datastore//changelog/', ObjectChangeLogView.as_view(), name='datastore_changelog', kwargs={ + 'model': models.Datastore }), # Storage sessions @@ -45,4 +45,14 @@ path('storagesession//changelog/', ObjectChangeLogView.as_view(), name='storagesession_changelog', kwargs={ 'model': models.StorageSession }), + + # VMDK + path('vmdk/', views.VMDKListView.as_view(), name='vmdk_list'), + path('vmdk/add/', views.VMDKEditView.as_view(), name='vmdk_add'), + path('vmdk//', views.VMDKView.as_view(), name='vmdk'), + path('vmdk//edit/', views.VMDKEditView.as_view(), name='vmdk_edit'), + path('vmdk//delete/', views.VMDKDeleteView.as_view(), name='vmdk_delete'), + path('vmdk//changelog/', ObjectChangeLogView.as_view(), name='vmdk_changelog', kwargs={ + 'model': models.VMDK + }), ) diff --git a/netbox_storage/views.py b/netbox_storage/views.py index eb5b40d..186f548 100644 --- a/netbox_storage/views.py +++ b/netbox_storage/views.py @@ -10,7 +10,7 @@ class StoragePoolView(generic.ObjectView): queryset = models.StoragePool.objects.all() def get_extra_context(self, request, instance): - table = tables.StorageLUNTable(instance.luns.all()) + table = tables.LUNTable(instance.luns.all()) table.configure(request) return { @@ -39,38 +39,38 @@ class StoragePoolDeleteView(generic.ObjectDeleteView): # -# StorageLUN views +# LUN views # -class StorageLUNView(generic.ObjectView): - queryset = models.StorageLUN.objects.all() +class LUNView(generic.ObjectView): + queryset = models.LUN.objects.all() -class StorageLUNListView(generic.ObjectListView): - queryset = models.StorageLUN.objects.all() - table = tables.StorageLUNTable +class LUNListView(generic.ObjectListView): + queryset = models.LUN.objects.all() + table = tables.LUNTable # filterset = filtersets.StorageLUNFilterSet # filterset_form = forms.StorageLUNFilterForm -class StorageLUNEditView(generic.ObjectEditView): - queryset = models.StorageLUN.objects.all() - form = forms.StorageLUNForm +class LUNEditView(generic.ObjectEditView): + queryset = models.LUN.objects.all() + form = forms.LUNForm -class StorageLUNDeleteView(generic.ObjectDeleteView): - queryset = models.StorageLUN.objects.all() +class LUNDeleteView(generic.ObjectDeleteView): + queryset = models.LUN.objects.all() # # StorageLUNGroup views # -class StorageLUNGroupView(generic.ObjectView): - queryset = models.StorageLUNGroup.objects.all() +class DatastoreView(generic.ObjectView): + queryset = models.Datastore.objects.all() def get_extra_context(self, request, instance): - luns_table = tables.StorageLUNTable(instance.storage_lun.all()) + luns_table = tables.LUNTable(instance.lun.all()) luns_table.configure(request) sessions_table = tables.StorageSessionTable(instance.storage_sessions.all()) @@ -82,20 +82,20 @@ def get_extra_context(self, request, instance): } -class StorageLUNGroupListView(generic.ObjectListView): - queryset = models.StorageLUNGroup.objects.all() - table = tables.StorageLUNGroupTable +class DatastoreListView(generic.ObjectListView): + queryset = models.Datastore.objects.all() + table = tables.DatastoreTable # filterset = filtersets.StorageLUNGroupFilterSet # filterset_form = forms.StorageLUNGroupFilterForm -class StorageLUNGroupEditView(generic.ObjectEditView): - queryset = models.StorageLUNGroup.objects.all() - form = forms.StorageLUNGroupForm +class DatastoreEditView(generic.ObjectEditView): + queryset = models.Datastore.objects.all() + form = forms.DatastoreForm -class StorageLUNGroupDeleteView(generic.ObjectDeleteView): - queryset = models.StorageLUNGroup.objects.all() +class DatastoreDeleteView(generic.ObjectDeleteView): + queryset = models.Datastore.objects.all() # @@ -120,3 +120,27 @@ class StorageSessionEditView(generic.ObjectEditView): class StorageSessionDeleteView(generic.ObjectDeleteView): queryset = models.StorageSession.objects.all() + + +# +# VMDK views +# + +class VMDKView(generic.ObjectView): + queryset = models.VMDK.objects.all() + + +class VMDKListView(generic.ObjectListView): + queryset = models.VMDK.objects.all() + table = tables.VMDKTable + # filterset = filtersets.StorageSessionFilterSet + # filterset_form = forms.StorageSessionFilterForm + + +class VMDKEditView(generic.ObjectEditView): + queryset = models.VMDK.objects.all() + form = forms.VMDKForm + + +class VMDKDeleteView(generic.ObjectDeleteView): + queryset = models.VMDK.objects.all() diff --git a/setup.py b/setup.py index 1118ae7..aca5ed4 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='netbox-storage', - version='0.1', + version='0.2', description='NetBox storage plugin', install_requires=[], packages=find_packages(),