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 @@
-
+
Name |
{{ object.name }} |
+
+ Utilization |
+ {% utilization_graph object.get_utilization %} |
+
Description |
{{ object.description }} |
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 @@
-
+
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 @@
-
+
{% 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 @@
{{ object.cluster }} |
- LUN Groups |
+ Datastores |
- {% for lun_group in object.storage_lun_groups.all %}
- {{ lun_group}}
+ {% for datastore in object.datastores.all %}
+ {{ datastore }}
{% if not forloop.last %}, {% endif %}
{% endfor %}
|
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 @@
+
+
+
+
+ {% if object.vmdks.all %}
+
+
+ {% 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 %}
+
+
+
+ {% 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(),