diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index ebfb781e0..9f9b0f6a6 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -16,6 +16,7 @@ from dcim.models import ( from extras.api.customfields import CustomFieldModelSerializer from tenancy.api.serializers import NestedTenantSerializer from utilities.api import ChoiceFieldSerializer, ValidatedModelSerializer +from virtualization.models import Cluster # @@ -446,6 +447,15 @@ class DeviceIPAddressSerializer(serializers.ModelSerializer): fields = ['id', 'url', 'family', 'address'] +# Cannot import virtualization.api.NestedClusterSerializer due to circular dependency +class NestedClusterSerializer(serializers.ModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail') + + class Meta: + model = Cluster + fields = ['id', 'url', 'name'] + + class DeviceSerializer(CustomFieldModelSerializer): device_type = NestedDeviceTypeSerializer() device_role = NestedDeviceRoleSerializer() @@ -459,13 +469,14 @@ class DeviceSerializer(CustomFieldModelSerializer): primary_ip4 = DeviceIPAddressSerializer() primary_ip6 = DeviceIPAddressSerializer() parent_device = serializers.SerializerMethodField() + cluster = NestedClusterSerializer() class Meta: model = Device fields = [ 'id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag', 'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6', - 'comments', 'custom_fields', + 'cluster', 'comments', 'custom_fields', ] def get_parent_device(self, obj): diff --git a/netbox/dcim/migrations/0042_device_cluster.py b/netbox/dcim/migrations/0042_device_cluster.py new file mode 100644 index 000000000..a3c2b7859 --- /dev/null +++ b/netbox/dcim/migrations/0042_device_cluster.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-08-16 21:06 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('virtualization', '0001_initial'), + ('dcim', '0041_napalm_integration'), + ] + + operations = [ + migrations.AddField( + model_name='device', + name='cluster', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='devices', to='virtualization.Cluster'), + ), + ] diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 9f72fc83e..d6e68df9b 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -808,6 +808,13 @@ class Device(CreatedUpdatedModel, CustomFieldModel): 'ipam.IPAddress', related_name='primary_ip6_for', on_delete=models.SET_NULL, blank=True, null=True, verbose_name='Primary IPv6' ) + cluster = models.ForeignKey( + to='virtualization.Cluster', + on_delete=models.SET_NULL, + related_name='devices', + blank=True, + null=True + ) comments = models.TextField(blank=True) custom_field_values = GenericRelation(CustomFieldValue, content_type_field='obj_type', object_id_field='obj_id') images = GenericRelation(ImageAttachment) diff --git a/netbox/templates/virtualization/cluster.html b/netbox/templates/virtualization/cluster.html index c5d514713..23834e0c4 100644 --- a/netbox/templates/virtualization/cluster.html +++ b/netbox/templates/virtualization/cluster.html @@ -4,6 +4,13 @@ {% block content %}
+
diff --git a/netbox/virtualization/migrations/0001_initial.py b/netbox/virtualization/migrations/0001_initial.py index 1f812d209..57b8dc4e0 100644 --- a/netbox/virtualization/migrations/0001_initial.py +++ b/netbox/virtualization/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.4 on 2017-08-16 19:27 +# Generated by Django 1.11.4 on 2017-08-16 21:06 from __future__ import unicode_literals import dcim.fields @@ -13,9 +13,9 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('ipam', '0018_remove_service_uniqueness_constraint'), ('tenancy', '0003_unicode_literals'), ('dcim', '0041_napalm_integration'), + ('ipam', '0018_remove_service_uniqueness_constraint'), ] operations = [ @@ -27,7 +27,6 @@ class Migration(migrations.Migration): ('last_updated', models.DateTimeField(auto_now=True)), ('name', models.CharField(max_length=100, unique=True)), ('comments', models.TextField(blank=True)), - ('devices', models.ManyToManyField(to='dcim.Device')), ], options={ 'ordering': ['name'], diff --git a/netbox/virtualization/models.py b/netbox/virtualization/models.py index 042bdf904..7cdd46158 100644 --- a/netbox/virtualization/models.py +++ b/netbox/virtualization/models.py @@ -89,9 +89,6 @@ class Cluster(CreatedUpdatedModel, CustomFieldModel): blank=True, null=True ) - devices = models.ManyToManyField( - to='dcim.Device' - ) comments = models.TextField( blank=True ) diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 4be2d2563..8d6388445 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -6,6 +6,7 @@ from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.views.generic import View +from dcim.models import Device from utilities.views import ( BulkDeleteView, BulkEditView, BulkImportView, ComponentCreateView, ComponentDeleteView, ComponentEditView, ObjectDeleteView, ObjectEditView, ObjectListView, @@ -95,9 +96,11 @@ class ClusterView(View): def get(self, request, pk): cluster = get_object_or_404(Cluster, pk=pk) + devices = Device.objects.filter(cluster=cluster) return render(request, 'virtualization/cluster.html', { 'cluster': cluster, + 'devices': devices, })