From a01c9ff379172eb855ab4e3d9767137307222d62 Mon Sep 17 00:00:00 2001 From: Matt Layher Date: Fri, 29 Sep 2017 13:22:42 -0400 Subject: [PATCH 01/14] Minor LDAP documentation formatting cleanup --- docs/installation/ldap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation/ldap.md b/docs/installation/ldap.md index bb1618e32..3cbc0d32c 100644 --- a/docs/installation/ldap.md +++ b/docs/installation/ldap.md @@ -55,7 +55,7 @@ LDAP_IGNORE_CERT_ERRORS = True ## User Authentication !!! info - When using Windows Server, `2012 AUTH_LDAP_USER_DN_TEMPLATE` should be set to None. + When using Windows Server 2012, `AUTH_LDAP_USER_DN_TEMPLATE` should be set to None. ```python from django_auth_ldap.config import LDAPSearch @@ -79,7 +79,7 @@ AUTH_LDAP_USER_ATTR_MAP = { # User Groups for Permissions !!! Info - When using Microsoft Active Directory, Support for nested Groups can be activated by using `GroupOfNamesType()` instead of `NestedGroupOfNamesType()` for AUTH_LDAP_GROUP_TYPE. + When using Microsoft Active Directory, Support for nested Groups can be activated by using `GroupOfNamesType()` instead of `NestedGroupOfNamesType()` for `AUTH_LDAP_GROUP_TYPE`. ```python from django_auth_ldap.config import LDAPSearch, GroupOfNamesType From 881fdbe893b3f021bd92565f6c7056b73e592b77 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 12 Oct 2017 16:39:51 -0400 Subject: [PATCH 02/14] Post-release version bump --- netbox/netbox/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index e0f83964e..1e76893b7 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -13,7 +13,7 @@ except ImportError: ) -VERSION = '2.2.1' +VERSION = '2.2.2-dev' BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) From 4cb0be4df3cb01f4708c9ccc85f7a9ace69cde82 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Oct 2017 10:42:45 -0400 Subject: [PATCH 03/14] Fixes #1582: Add virtual_machine attribute to IPAddress --- netbox/ipam/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/netbox/ipam/models.py b/netbox/ipam/models.py index 791ba1b1a..73a522d63 100644 --- a/netbox/ipam/models.py +++ b/netbox/ipam/models.py @@ -440,7 +440,7 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel): self.get_status_display(), self.get_role_display(), self.device.identifier if self.device else None, - self.virtual_machine.name if self.device else None, + self.virtual_machine.name if self.virtual_machine else None, self.interface.name if self.interface else None, is_primary, self.description, @@ -452,6 +452,12 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel): return self.interface.device return None + @property + def virtual_machine(self): + if self.interface: + return self.interface.virtual_machine + return None + def get_status_class(self): return STATUS_CHOICE_CLASSES[self.status] From 6c27e6c4fe34b8983519b5d85a84742f6b8555fc Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Oct 2017 10:45:34 -0400 Subject: [PATCH 04/14] Fixes #1584: Colorized virtual machine role column --- netbox/virtualization/tables.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/netbox/virtualization/tables.py b/netbox/virtualization/tables.py index f7b7ffbe9..a8f9068ac 100644 --- a/netbox/virtualization/tables.py +++ b/netbox/virtualization/tables.py @@ -24,6 +24,10 @@ VIRTUALMACHINE_STATUS = """ {{ record.get_status_display }} """ +VIRTUALMACHINE_ROLE = """ + +""" + VIRTUALMACHINE_PRIMARY_IP = """ {{ record.primary_ip6.address.ip|default:"" }} {% if record.primary_ip6 and record.primary_ip4 %}
{% endif %} @@ -93,6 +97,7 @@ class VirtualMachineTable(BaseTable): name = tables.LinkColumn() status = tables.TemplateColumn(template_code=VIRTUALMACHINE_STATUS) cluster = tables.LinkColumn('virtualization:cluster', args=[Accessor('cluster.pk')]) + role = tables.TemplateColumn(VIRTUALMACHINE_ROLE) tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')]) class Meta(BaseTable.Meta): From 17493ff655bcbd8ec36f7e23d8a27d7bb3870908 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Oct 2017 10:53:25 -0400 Subject: [PATCH 05/14] Closes #1587: Add primary IP column for virtual machines in global search results --- netbox/netbox/views.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index 5ec81cb25..f41ff53c2 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -27,7 +27,7 @@ from tenancy.models import Tenant from tenancy.tables import TenantTable from virtualization.filters import ClusterFilter, VirtualMachineFilter from virtualization.models import Cluster, VirtualMachine -from virtualization.tables import ClusterTable, VirtualMachineTable +from virtualization.tables import ClusterTable, VirtualMachineDetailTable from .forms import SearchForm @@ -126,9 +126,11 @@ SEARCH_TYPES = OrderedDict(( 'url': 'virtualization:cluster_list', }), ('virtualmachine', { - 'queryset': VirtualMachine.objects.select_related('cluster', 'tenant', 'platform'), + 'queryset': VirtualMachine.objects.select_related( + 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', + ), 'filter': VirtualMachineFilter, - 'table': VirtualMachineTable, + 'table': VirtualMachineDetailTable, 'url': 'virtualization:virtualmachine_list', }), )) From 023ff6834aaab5aa895d5a7d41692cd5891f8b0c Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Oct 2017 11:50:06 -0400 Subject: [PATCH 06/14] Designated new Docker build repo; removed stale Heroku build repo --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d946215d5..26aa0ccfc 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,5 @@ Please see [the documentation](http://netbox.readthedocs.io/en/stable/) for inst ## Alternative Installations -* [Docker container](https://github.com/digitalocean/netbox-docker) -* [Heroku deployment](https://heroku.com/deploy?template=https://github.com/BILDQUADRAT/netbox/tree/heroku) (via [@mraerino](https://github.com/BILDQUADRAT/netbox/tree/heroku)) -* [Vagrant deployment](https://github.com/ryanmerolle/netbox-vagrant) +* [Docker container](https://github.com/ninech/netbox-docker) (via [@cimnine](https://github.com/cimnine)) +* [Vagrant deployment](https://github.com/ryanmerolle/netbox-vagrant) (via [@ryanmerolle](https://github.com/ryanmerolle)) From 60b4f1f89fbbf6ded72a95861673e95e9364d02b Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Oct 2017 12:14:19 -0400 Subject: [PATCH 07/14] Fixes #1585: Fixed slug-based filtering of virtual machines --- netbox/virtualization/filters.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filters.py index 870ac85c6..4ddad4d5b 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filters.py @@ -78,7 +78,7 @@ class VirtualMachineFilter(CustomFieldFilterSet): label='Cluster group (ID)', ) cluster_group = NullableModelMultipleChoiceFilter( - name='cluster__group__slug', + name='cluster__group', queryset=ClusterGroup.objects.all(), to_field_name='slug', label='Cluster group (slug)', @@ -88,12 +88,10 @@ class VirtualMachineFilter(CustomFieldFilterSet): label='Cluster (ID)', ) role_id = NullableModelMultipleChoiceFilter( - name='role_id', queryset=DeviceRole.objects.all(), label='Role (ID)', ) role = NullableModelMultipleChoiceFilter( - name='role__slug', queryset=DeviceRole.objects.all(), to_field_name='slug', label='Role (slug)', @@ -112,7 +110,6 @@ class VirtualMachineFilter(CustomFieldFilterSet): label='Platform (ID)', ) platform = NullableModelMultipleChoiceFilter( - name='platform', queryset=Platform.objects.all(), to_field_name='slug', label='Platform (slug)', From 91b6ebb0c00559bb07a5c5d1076ae851330fd319 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Oct 2017 14:19:41 -0400 Subject: [PATCH 08/14] Closes #1580: Allow cluster assignment when bulk importing devices --- netbox/dcim/forms.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 820477e24..f0b0f6d52 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -17,6 +17,7 @@ from utilities.forms import ( ExpandableNameField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField, FilterTreeNodeMultipleChoiceField, ) +from virtualization.models import Cluster from .formfields import MACAddressFormField from .models import ( DeviceBay, DeviceBayTemplate, CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_CONNECTED, ConsolePort, @@ -900,11 +901,20 @@ class DeviceCSVForm(BaseDeviceCSVForm): required=False, help_text='Mounted rack face' ) + cluster = forms.ModelChoiceField( + queryset=Cluster.objects.all(), + to_field_name='name', + required=False, + help_text='Virtualization cluster', + error_messages={ + 'invalid_choice': 'Invalid cluster name.', + } + ) class Meta(BaseDeviceCSVForm.Meta): fields = [ 'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'status', - 'site', 'rack_group', 'rack_name', 'position', 'face', + 'site', 'rack_group', 'rack_name', 'position', 'face', 'cluster', ] def clean(self): @@ -940,11 +950,19 @@ class ChildDeviceCSVForm(BaseDeviceCSVForm): device_bay_name = forms.CharField( help_text='Name of device bay', ) + cluster = forms.ModelChoiceField( + queryset=Cluster.objects.all(), + to_field_name='name', + help_text='Virtualization cluster', + error_messages={ + 'invalid_choice': 'Invalid cluster name.', + } + ) class Meta(BaseDeviceCSVForm.Meta): fields = [ 'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'status', - 'parent', 'device_bay_name', + 'parent', 'device_bay_name', 'cluster', ] def clean(self): From 34259d5d9dcd129ad40f32c2e4a81c7d3e4acbe2 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 13 Oct 2017 14:29:55 -0400 Subject: [PATCH 09/14] Removed deprecated xstr and expand_pattern functions --- netbox/dcim/views.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 387af4b61..13710c310 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -34,32 +34,6 @@ from .models import ( ) -EXPANSION_PATTERN = '\[(\d+-\d+)\]' - - -def xstr(s): - """ - Replace None with an empty string (for CSV export) - """ - return '' if s is None else str(s) - - -def expand_pattern(string): - """ - Expand a numeric pattern into a list of strings. Examples: - 'ge-0/0/[0-3]' => ['ge-0/0/0', 'ge-0/0/1', 'ge-0/0/2', 'ge-0/0/3'] - 'xe-0/[0-3]/[0-7]' => ['xe-0/0/0', 'xe-0/0/1', 'xe-0/0/2', ... 'xe-0/3/5', 'xe-0/3/6', 'xe-0/3/7'] - """ - lead, pattern, remnant = re.split(EXPANSION_PATTERN, string, maxsplit=1) - x, y = pattern.split('-') - for i in range(int(x), int(y) + 1): - if remnant: - for string in expand_pattern(remnant): - yield "{0}{1}{2}".format(lead, i, string) - else: - yield "{0}{1}".format(lead, i) - - class BulkDisconnectView(View): """ An extendable view for disconnection console/power/interface components in bulk. From 5fc3eac0f669fccd0fae89ce84aa862bbcbe9af2 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 16 Oct 2017 10:13:39 +0000 Subject: [PATCH 10/14] Avoid creating repeated graph nodes where device matches multiple regexps Fixes #1498 --- netbox/extras/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netbox/extras/models.py b/netbox/extras/models.py index 5181e88e9..1e7a73166 100644 --- a/netbox/extras/models.py +++ b/netbox/extras/models.py @@ -274,6 +274,7 @@ class TopologyMap(models.Model): # Construct the graph graph = graphviz.Graph() graph.graph_attr['ranksep'] = '1' + seen = set() for i, device_set in enumerate(self.device_sets): subgraph = graphviz.Graph(name='sg{}'.format(i)) @@ -288,6 +289,9 @@ class TopologyMap(models.Model): devices = [] for query in device_set.strip(';').split(';'): # Split regexes on semicolons devices += Device.objects.filter(name__regex=query).select_related('device_role') + # Remove duplicate devices + devices = [d for d in devices if d.id not in seen] + seen.update([d.id for d in devices]) for d in devices: bg_color = '#{}'.format(d.device_role.color) fg_color = '#{}'.format(foreground_color(d.device_role.color)) From 047f22e1103ad530c78701b3d9929e96a88b4b38 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Mon, 16 Oct 2017 16:44:15 -0400 Subject: [PATCH 11/14] Fixes #1605: Added clusters and virtual machines to object list for global search --- netbox/netbox/forms.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netbox/netbox/forms.py b/netbox/netbox/forms.py index 72a3ab8de..0521f2d2f 100644 --- a/netbox/netbox/forms.py +++ b/netbox/netbox/forms.py @@ -30,6 +30,10 @@ OBJ_TYPE_CHOICES = ( ('Tenancy', ( ('tenant', 'Tenants'), )), + ('Virtualization', ( + ('cluster', 'Clusters'), + ('virtualmachine', 'Virtual machines'), + )), ) From 6f2f8697aec9470c036e400c5550ec6dce3a1907 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 17 Oct 2017 09:23:53 -0400 Subject: [PATCH 12/14] Fixes #1609: Added missing virtual_machine field to IP address interface serializer --- netbox/ipam/api/serializers.py | 13 ++++++++++++- netbox/ipam/api/views.py | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index a5b64fca6..36394dad2 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -240,12 +240,22 @@ class WritablePrefixSerializer(CustomFieldModelSerializer): # IP addresses # +class IPAddressInterfaceSerializer(InterfaceSerializer): + virtual_machine = NestedVirtualMachineSerializer() + + class Meta(InterfaceSerializer.Meta): + fields = [ + 'id', 'device', 'virtual_machine', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', + 'mgmt_only', 'description', 'is_connected', 'interface_connection', 'circuit_termination', + ] + + class IPAddressSerializer(CustomFieldModelSerializer): vrf = NestedVRFSerializer() tenant = NestedTenantSerializer() status = ChoiceFieldSerializer(choices=IPADDRESS_STATUS_CHOICES) role = ChoiceFieldSerializer(choices=IPADDRESS_ROLE_CHOICES) - interface = InterfaceSerializer() + interface = IPAddressInterfaceSerializer() class Meta: model = IPAddress @@ -262,6 +272,7 @@ class NestedIPAddressSerializer(serializers.ModelSerializer): model = IPAddress fields = ['id', 'url', 'family', 'address'] + IPAddressSerializer._declared_fields['nat_inside'] = NestedIPAddressSerializer() IPAddressSerializer._declared_fields['nat_outside'] = NestedIPAddressSerializer() diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index dabb518ae..b615b470f 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -151,7 +151,7 @@ class IPAddressViewSet(WritableSerializerMixin, CustomFieldModelViewSet): queryset = IPAddress.objects.select_related( 'vrf__tenant', 'tenant', 'nat_inside' ).prefetch_related( - 'interface__device' + 'interface__device', 'interface__virtual_machine' ) serializer_class = serializers.IPAddressSerializer write_serializer_class = serializers.WritableIPAddressSerializer From 34f1a9ebfb6faa4c98fb6792fb3994a18f860990 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 17 Oct 2017 09:59:35 -0400 Subject: [PATCH 13/14] Fixes #1579: Devices already assigned to a cluster cannot be added to a different cluster --- netbox/templates/virtualization/cluster_add_devices.html | 7 ++++++- netbox/virtualization/forms.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/netbox/templates/virtualization/cluster_add_devices.html b/netbox/templates/virtualization/cluster_add_devices.html index 2029ea5b8..0a792e0c4 100644 --- a/netbox/templates/virtualization/cluster_add_devices.html +++ b/netbox/templates/virtualization/cluster_add_devices.html @@ -59,6 +59,7 @@