1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Rename Cloud to ProviderNetwork

This commit is contained in:
Jeremy Stretch
2021-04-01 10:21:41 -04:00
parent 83c4577f6d
commit d57222328b
27 changed files with 219 additions and 217 deletions

View File

@ -1,7 +1,7 @@
# Circuits # Circuits
{!docs/models/circuits/provider.md!} {!docs/models/circuits/provider.md!}
{!docs/models/circuits/cloud.md!} {!docs/models/circuits/providernetwork.md!}
--- ---

View File

@ -2,9 +2,9 @@
The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites. The association of a circuit with a particular site and/or device is modeled separately as a circuit termination. A circuit may have up to two terminations, labeled A and Z. A single-termination circuit can be used when you don't know (or care) about the far end of a circuit (for example, an Internet access circuit which connects to a transit provider). A dual-termination circuit is useful for tracking circuits which connect two sites.
Each circuit termination is attached to either a site or a cloud. Site terminations may optionally be connected via a cable to a specific device interface or port within that site. Each termination must be assigned a port speed, and can optionally be assigned an upstream speed if it differs from the downstream speed (a common scenario with e.g. DOCSIS cable modems). Fields are also available to track cross-connect and patch panel details. Each circuit termination is attached to either a site or to a provider network. Site terminations may optionally be connected via a cable to a specific device interface or port within that site. Each termination must be assigned a port speed, and can optionally be assigned an upstream speed if it differs from the downstream speed (a common scenario with e.g. DOCSIS cable modems). Fields are also available to track cross-connect and patch panel details.
In adherence with NetBox's philosophy of closely modeling the real world, a circuit may be connected only to a physical interface. For example, circuits may not terminate to LAG interfaces, which are virtual in nature. In such cases, a separate physical circuit is associated with each LAG member interface and each needs to be modeled discretely. In adherence with NetBox's philosophy of closely modeling the real world, a circuit may be connected only to a physical interface. For example, circuits may not terminate to LAG interfaces, which are virtual in nature. In such cases, a separate physical circuit is associated with each LAG member interface and each needs to be modeled discretely.
!!! note !!! note
A circuit in NetBox represents a physical link, and cannot have more than two endpoints. When modeling a multi-point topology, each leg of the topology must be defined as a discrete circuit, with one end terminating within the provider's infrastructure. The cloud model is ideal for representing these networks. A circuit in NetBox represents a physical link, and cannot have more than two endpoints. When modeling a multi-point topology, each leg of the topology must be defined as a discrete circuit, with one end terminating within the provider's infrastructure. The provider network model is ideal for representing these networks.

View File

@ -1,5 +0,0 @@
# Clouds
A cloud represents an abstract portion of network topology, just like in a topology diagram. For example, a cloud may be used to represent a provider's MPLS network.
Each cloud must be assigned to a provider. A circuit may terminate to either a cloud or to a site.

View File

@ -0,0 +1,5 @@
# Provider Network
This model can be used to represent the boundary of a provider network, the details of which are unknown or unimportant to the NetBox user. For example, it might represent a provider's regional MPLS network to which multiple circuits provide connectivity.
Each provider network must be assigned to a provider. A circuit may terminate to either a provider network or to a site.

View File

@ -78,9 +78,9 @@ This release introduces the new SiteGroup model, which can be used to organize s
The ObjectChange model (which is used to record the creation, modification, and deletion of NetBox objects) now explicitly records the pre-change and post-change state of each object, rather than only the post-change state. This was done to present a more clear depiction of each change being made, and to prevent the erroneous association of a previous unlogged change with its successor. The ObjectChange model (which is used to record the creation, modification, and deletion of NetBox objects) now explicitly records the pre-change and post-change state of each object, rather than only the post-change state. This was done to present a more clear depiction of each change being made, and to prevent the erroneous association of a previous unlogged change with its successor.
#### Cloud Modeling for Circuits ([#5986](https://github.com/netbox-community/netbox/issues/5986)) #### Provider Network Modeling ([#5986](https://github.com/netbox-community/netbox/issues/5986))
A new Cloud model has been introduced to represent the boundary of a network that exists outside the scope of NetBox. This is analogous to using a cloud icon on a topology drawing to represent an abstracted network. Each cloud must be assigned to a provider, and circuits can terminate to either clouds or sites. The use of this model will likely be extended by future releases to support overlay and virtual circuit modeling. A new provider network model has been introduced to represent the boundary of a network that exists outside the scope of NetBox. Each instance of this model must be assigned to a provider, and circuits can now terminate to either provider networks or to sites. The use of this model will likely be extended by future releases to support overlay and virtual circuit modeling.
### Enhancements ### Enhancements
@ -130,9 +130,9 @@ A new Cloud model has been introduced to represent the boundary of a network tha
* Renamed RackGroup to Location * Renamed RackGroup to Location
* The `/dcim/rack-groups/` endpoint is now `/dcim/locations/` * The `/dcim/rack-groups/` endpoint is now `/dcim/locations/`
* circuits.CircuitTermination * circuits.CircuitTermination
* Added the `cloud` field * Added the `provider_network` field
* circuits.Cloud * circuits.ProviderNetwork
* Added the `/api/circuits/clouds/` endpoint * Added the `/api/circuits/provider-networks/` endpoint
* dcim.Device * dcim.Device
* Added the `location` field * Added the `location` field
* dcim.Interface * dcim.Interface

View File

@ -7,17 +7,17 @@ __all__ = [
'NestedCircuitSerializer', 'NestedCircuitSerializer',
'NestedCircuitTerminationSerializer', 'NestedCircuitTerminationSerializer',
'NestedCircuitTypeSerializer', 'NestedCircuitTypeSerializer',
'NestedCloudSerializer', 'NestedProviderNetworkSerializer',
'NestedProviderSerializer', 'NestedProviderSerializer',
] ]
# #
# Clouds # Provider networks
# #
class NestedCloudSerializer(WritableNestedSerializer): class NestedProviderNetworkSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:cloud-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:providernetwork-detail')
class Meta: class Meta:
model = Provider model = Provider

View File

@ -29,15 +29,15 @@ class ProviderSerializer(PrimaryModelSerializer):
# #
# Clouds # Provider networks
# #
class CloudSerializer(PrimaryModelSerializer): class ProviderNetworkSerializer(PrimaryModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:cloud-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:providernetwork-detail')
provider = NestedProviderSerializer() provider = NestedProviderSerializer()
class Meta: class Meta:
model = Cloud model = ProviderNetwork
fields = [ fields = [
'id', 'url', 'display', 'provider', 'name', 'description', 'comments', 'tags', 'custom_fields', 'created', 'id', 'url', 'display', 'provider', 'name', 'description', 'comments', 'tags', 'custom_fields', 'created',
'last_updated', 'last_updated',
@ -63,12 +63,12 @@ class CircuitTypeSerializer(OrganizationalModelSerializer):
class CircuitCircuitTerminationSerializer(WritableNestedSerializer, ConnectedEndpointSerializer): class CircuitCircuitTerminationSerializer(WritableNestedSerializer, ConnectedEndpointSerializer):
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
site = NestedSiteSerializer() site = NestedSiteSerializer()
cloud = NestedCloudSerializer() provider_network = NestedProviderNetworkSerializer()
class Meta: class Meta:
model = CircuitTermination model = CircuitTermination
fields = [ fields = [
'id', 'url', 'display', 'site', 'cloud', 'port_speed', 'upstream_speed', 'xconnect_id', 'id', 'url', 'display', 'site', 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id',
'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable',
] ]
@ -95,13 +95,13 @@ class CircuitTerminationSerializer(BaseModelSerializer, CableTerminationSerializ
url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail') url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail')
circuit = NestedCircuitSerializer() circuit = NestedCircuitSerializer()
site = NestedSiteSerializer(required=False) site = NestedSiteSerializer(required=False)
cloud = NestedCloudSerializer(required=False) provider_network = NestedProviderNetworkSerializer(required=False)
cable = NestedCableSerializer(read_only=True) cable = NestedCableSerializer(read_only=True)
class Meta: class Meta:
model = CircuitTermination model = CircuitTermination
fields = [ fields = [
'id', 'url', 'display', 'circuit', 'term_side', 'site', 'cloud', 'port_speed', 'upstream_speed', 'id', 'url', 'display', 'circuit', 'term_side', 'site', 'provider_network', 'port_speed', 'upstream_speed',
'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'cable_peer', 'cable_peer_type', 'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'cable_peer', 'cable_peer_type',
'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', '_occupied', 'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', '_occupied',
] ]

View File

@ -13,8 +13,8 @@ router.register('circuit-types', views.CircuitTypeViewSet)
router.register('circuits', views.CircuitViewSet) router.register('circuits', views.CircuitViewSet)
router.register('circuit-terminations', views.CircuitTerminationViewSet) router.register('circuit-terminations', views.CircuitTerminationViewSet)
# Clouds # Provider networks
router.register('clouds', views.CloudViewSet) router.register('provider-networks', views.ProviderNetworkViewSet)
app_name = 'circuits-api' app_name = 'circuits-api'
urlpatterns = router.urls urlpatterns = router.urls

View File

@ -68,10 +68,10 @@ class CircuitTerminationViewSet(PathEndpointMixin, ModelViewSet):
# #
# Clouds # Provider networks
# #
class CloudViewSet(CustomFieldModelViewSet): class ProviderNetworkViewSet(CustomFieldModelViewSet):
queryset = Cloud.objects.prefetch_related('tags') queryset = ProviderNetwork.objects.prefetch_related('tags')
serializer_class = serializers.CloudSerializer serializer_class = serializers.ProviderNetworkSerializer
filterset_class = filters.CloudFilterSet filterset_class = filters.ProviderNetworkFilterSet

View File

@ -15,7 +15,7 @@ __all__ = (
'CircuitFilterSet', 'CircuitFilterSet',
'CircuitTerminationFilterSet', 'CircuitTerminationFilterSet',
'CircuitTypeFilterSet', 'CircuitTypeFilterSet',
'CloudFilterSet', 'ProviderNetworkFilterSet',
'ProviderFilterSet', 'ProviderFilterSet',
) )
@ -80,7 +80,7 @@ class ProviderFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdated
) )
class CloudFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class ProviderNetworkFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -98,7 +98,7 @@ class CloudFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFil
tag = TagFilter() tag = TagFilter()
class Meta: class Meta:
model = Cloud model = ProviderNetwork
fields = ['id', 'name'] fields = ['id', 'name']
def search(self, queryset, name, value): def search(self, queryset, name, value):
@ -132,10 +132,10 @@ class CircuitFilterSet(BaseFilterSet, CustomFieldModelFilterSet, TenancyFilterSe
to_field_name='slug', to_field_name='slug',
label='Provider (slug)', label='Provider (slug)',
) )
cloud_id = django_filters.ModelMultipleChoiceFilter( provider_network_id = django_filters.ModelMultipleChoiceFilter(
field_name='terminations__cloud', field_name='terminations__provider_network',
queryset=Cloud.objects.all(), queryset=ProviderNetwork.objects.all(),
label='Cloud (ID)', label='ProviderNetwork (ID)',
) )
type_id = django_filters.ModelMultipleChoiceFilter( type_id = django_filters.ModelMultipleChoiceFilter(
queryset=CircuitType.objects.all(), queryset=CircuitType.objects.all(),
@ -226,9 +226,9 @@ class CircuitTerminationFilterSet(BaseFilterSet, CableTerminationFilterSet, Path
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label='Site (slug)',
) )
cloud_id = django_filters.ModelMultipleChoiceFilter( provider_network_id = django_filters.ModelMultipleChoiceFilter(
queryset=Cloud.objects.all(), queryset=ProviderNetwork.objects.all(),
label='Cloud (ID)', label='ProviderNetwork (ID)',
) )
class Meta: class Meta:

View File

@ -129,10 +129,10 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
# #
# Clouds # Provider networks
# #
class CloudForm(BootstrapMixin, CustomFieldModelForm): class ProviderNetworkForm(BootstrapMixin, CustomFieldModelForm):
provider = DynamicModelChoiceField( provider = DynamicModelChoiceField(
queryset=Provider.objects.all() queryset=Provider.objects.all()
) )
@ -143,16 +143,16 @@ class CloudForm(BootstrapMixin, CustomFieldModelForm):
) )
class Meta: class Meta:
model = Cloud model = ProviderNetwork
fields = [ fields = [
'provider', 'name', 'description', 'comments', 'tags', 'provider', 'name', 'description', 'comments', 'tags',
] ]
fieldsets = ( fieldsets = (
('Cloud', ('provider', 'name', 'description', 'tags')), ('Provider Network', ('provider', 'name', 'description', 'tags')),
) )
class CloudCSVForm(CustomFieldModelCSVForm): class ProviderNetworkCSVForm(CustomFieldModelCSVForm):
provider = CSVModelChoiceField( provider = CSVModelChoiceField(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
to_field_name='name', to_field_name='name',
@ -160,15 +160,15 @@ class CloudCSVForm(CustomFieldModelCSVForm):
) )
class Meta: class Meta:
model = Cloud model = ProviderNetwork
fields = [ fields = [
'provider', 'name', 'description', 'comments', 'provider', 'name', 'description', 'comments',
] ]
class CloudBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm): class ProviderNetworkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=Cloud.objects.all(), queryset=ProviderNetwork.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
) )
provider = DynamicModelChoiceField( provider = DynamicModelChoiceField(
@ -190,8 +190,8 @@ class CloudBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFo
] ]
class CloudFilterForm(BootstrapMixin, CustomFieldFilterForm): class ProviderNetworkFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Cloud model = ProviderNetwork
field_order = ['q', 'provider_id'] field_order = ['q', 'provider_id']
q = forms.CharField( q = forms.CharField(
required=False, required=False,
@ -357,7 +357,7 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
model = Circuit model = Circuit
field_order = [ field_order = [
'q', 'type_id', 'provider_id', 'cloud_id', 'status', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id', 'q', 'type_id', 'provider_id', 'provider_network_id', 'status', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id',
'commit_rate', 'commit_rate',
] ]
q = forms.CharField( q = forms.CharField(
@ -374,13 +374,13 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm
required=False, required=False,
label=_('Provider') label=_('Provider')
) )
cloud_id = DynamicModelMultipleChoiceField( provider_network_id = DynamicModelMultipleChoiceField(
queryset=Cloud.objects.all(), queryset=ProviderNetwork.objects.all(),
required=False, required=False,
query_params={ query_params={
'provider_id': '$provider_id' 'provider_id': '$provider_id'
}, },
label=_('Cloud') label=_('Provider network')
) )
status = forms.MultipleChoiceField( status = forms.MultipleChoiceField(
choices=CircuitStatusChoices, choices=CircuitStatusChoices,
@ -435,16 +435,16 @@ class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
}, },
required=False required=False
) )
cloud = DynamicModelChoiceField( provider_network = DynamicModelChoiceField(
queryset=Cloud.objects.all(), queryset=ProviderNetwork.objects.all(),
required=False required=False
) )
class Meta: class Meta:
model = CircuitTermination model = CircuitTermination
fields = [ fields = [
'term_side', 'region', 'site_group', 'site', 'cloud', 'mark_connected', 'port_speed', 'upstream_speed', 'term_side', 'region', 'site_group', 'site', 'provider_network', 'mark_connected', 'port_speed',
'xconnect_id', 'pp_info', 'description', 'upstream_speed', 'xconnect_id', 'pp_info', 'description',
] ]
help_texts = { help_texts = {
'port_speed': "Physical circuit speed", 'port_speed': "Physical circuit speed",
@ -460,4 +460,4 @@ class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['cloud'].widget.add_query_param('provider_id', self.instance.circuit.provider_id) self.fields['provider_network'].widget.add_query_param('provider_id', self.instance.circuit.provider_id)

View File

@ -12,9 +12,9 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
# Create the new Cloud model # Create the new ProviderNetwork model
migrations.CreateModel( migrations.CreateModel(
name='Cloud', name='ProviderNetwork',
fields=[ fields=[
('created', models.DateField(auto_now_add=True, null=True)), ('created', models.DateField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)),
@ -23,7 +23,7 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=100)), ('name', models.CharField(max_length=100)),
('description', models.CharField(blank=True, max_length=200)), ('description', models.CharField(blank=True, max_length=200)),
('comments', models.TextField(blank=True)), ('comments', models.TextField(blank=True)),
('provider', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='clouds', to='circuits.provider')), ('provider', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='networks', to='circuits.provider')),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
], ],
options={ options={
@ -31,19 +31,19 @@ class Migration(migrations.Migration):
}, },
), ),
migrations.AddConstraint( migrations.AddConstraint(
model_name='cloud', model_name='providernetwork',
constraint=models.UniqueConstraint(fields=('provider', 'name'), name='circuits_cloud_provider_name'), constraint=models.UniqueConstraint(fields=('provider', 'name'), name='circuits_providernetwork_provider_name'),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='cloud', name='providernetwork',
unique_together={('provider', 'name')}, unique_together={('provider', 'name')},
), ),
# Add cloud FK to CircuitTermination # Add ProviderNetwork FK to CircuitTermination
migrations.AddField( migrations.AddField(
model_name='circuittermination', model_name='circuittermination',
name='cloud', name='provider_network',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_terminations', to='circuits.cloud'), field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_terminations', to='circuits.providernetwork'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='circuittermination', model_name='circuittermination',

View File

@ -26,7 +26,7 @@ def cache_circuit_terminations(apps, schema_editor):
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('circuits', '0027_cloud'), ('circuits', '0027_providernetwork'),
] ]
operations = [ operations = [

View File

@ -15,7 +15,7 @@ __all__ = (
'Circuit', 'Circuit',
'CircuitTermination', 'CircuitTermination',
'CircuitType', 'CircuitType',
'Cloud', 'ProviderNetwork',
'Provider', 'Provider',
) )
@ -93,18 +93,22 @@ class Provider(PrimaryModel):
# #
# Clouds # Provider networks
# #
@extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks') @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
class Cloud(PrimaryModel): class ProviderNetwork(PrimaryModel):
"""
This represents a provider network which exists outside of NetBox, the details of which are unknown or
unimportant to the user.
"""
name = models.CharField( name = models.CharField(
max_length=100 max_length=100
) )
provider = models.ForeignKey( provider = models.ForeignKey(
to='circuits.Provider', to='circuits.Provider',
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='clouds' related_name='networks'
) )
description = models.CharField( description = models.CharField(
max_length=200, max_length=200,
@ -125,7 +129,7 @@ class Cloud(PrimaryModel):
constraints = ( constraints = (
models.UniqueConstraint( models.UniqueConstraint(
fields=('provider', 'name'), fields=('provider', 'name'),
name='circuits_cloud_provider_name' name='circuits_providernetwork_provider_name'
), ),
) )
unique_together = ('provider', 'name') unique_together = ('provider', 'name')
@ -134,7 +138,7 @@ class Cloud(PrimaryModel):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
return reverse('circuits:cloud', args=[self.pk]) return reverse('circuits:providernetwork', args=[self.pk])
def to_csv(self): def to_csv(self):
return ( return (
@ -308,8 +312,8 @@ class CircuitTermination(ChangeLoggedModel, PathEndpoint, CableTermination):
blank=True, blank=True,
null=True null=True
) )
cloud = models.ForeignKey( provider_network = models.ForeignKey(
to=Cloud, to=ProviderNetwork,
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='circuit_terminations', related_name='circuit_terminations',
blank=True, blank=True,
@ -348,23 +352,21 @@ class CircuitTermination(ChangeLoggedModel, PathEndpoint, CableTermination):
unique_together = ['circuit', 'term_side'] unique_together = ['circuit', 'term_side']
def __str__(self): def __str__(self):
if self.site: return str(self.site or self.provider_network)
return str(self.site)
return str(self.cloud)
def get_absolute_url(self): def get_absolute_url(self):
if self.site: if self.site:
return self.site.get_absolute_url() return self.site.get_absolute_url()
return self.cloud.get_absolute_url() return self.provider_network.get_absolute_url()
def clean(self): def clean(self):
super().clean() super().clean()
# Must define either site *or* cloud # Must define either site *or* provider network
if self.site is None and self.cloud is None: if self.site is None and self.provider_network is None:
raise ValidationError("A circuit termination must attach to either a site or a cloud.") raise ValidationError("A circuit termination must attach to either a site or a provider network.")
if self.site and self.cloud: if self.site and self.provider_network:
raise ValidationError("A circuit termination cannot attach to both a site and a cloud.") raise ValidationError("A circuit termination cannot attach to both a site and a provider network.")
def to_objectchange(self, action): def to_objectchange(self, action):
# Annotate the parent Circuit # Annotate the parent Circuit

View File

@ -30,10 +30,10 @@ class ProviderTable(BaseTable):
# #
# Clouds # Provider networks
# #
class CloudTable(BaseTable): class ProviderNetworkTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
name = tables.Column( name = tables.Column(
linkify=True linkify=True
@ -42,11 +42,11 @@ class CloudTable(BaseTable):
linkify=True linkify=True
) )
tags = TagColumn( tags = TagColumn(
url_name='circuits:cloud_list' url_name='circuits:providernetwork_list'
) )
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = Cloud model = ProviderNetwork
fields = ('pk', 'name', 'provider', 'description', 'tags') fields = ('pk', 'name', 'provider', 'description', 'tags')
default_columns = ('pk', 'name', 'provider', 'description') default_columns = ('pk', 'name', 'provider', 'description')

View File

@ -180,8 +180,8 @@ class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
} }
class CloudTest(APIViewTestCases.APIViewTestCase): class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
model = Cloud model = ProviderNetwork
brief_fields = ['display', 'id', 'name', 'url'] brief_fields = ['display', 'id', 'name', 'url']
@classmethod @classmethod
@ -192,24 +192,24 @@ class CloudTest(APIViewTestCases.APIViewTestCase):
) )
Provider.objects.bulk_create(providers) Provider.objects.bulk_create(providers)
clouds = ( provider_networks = (
Cloud(name='Cloud 1', provider=providers[0]), ProviderNetwork(name='Provider Network 1', provider=providers[0]),
Cloud(name='Cloud 2', provider=providers[0]), ProviderNetwork(name='Provider Network 2', provider=providers[0]),
Cloud(name='Cloud 3', provider=providers[0]), ProviderNetwork(name='Provider Network 3', provider=providers[0]),
) )
Cloud.objects.bulk_create(clouds) ProviderNetwork.objects.bulk_create(provider_networks)
cls.create_data = [ cls.create_data = [
{ {
'name': 'Cloud 4', 'name': 'Provider Network 4',
'provider': providers[0].pk, 'provider': providers[0].pk,
}, },
{ {
'name': 'Cloud 5', 'name': 'Provider Network 5',
'provider': providers[0].pk, 'provider': providers[0].pk,
}, },
{ {
'name': 'Cloud 6', 'name': 'Provider Network 6',
'provider': providers[0].pk, 'provider': providers[0].pk,
}, },
] ]

View File

@ -186,12 +186,12 @@ class CircuitTestCase(TestCase):
) )
Provider.objects.bulk_create(providers) Provider.objects.bulk_create(providers)
clouds = ( provider_networks = (
Cloud(name='Cloud 1', provider=providers[1]), ProviderNetwork(name='Provider Network 1', provider=providers[1]),
Cloud(name='Cloud 2', provider=providers[1]), ProviderNetwork(name='Provider Network 2', provider=providers[1]),
Cloud(name='Cloud 3', provider=providers[1]), ProviderNetwork(name='Provider Network 3', provider=providers[1]),
) )
Cloud.objects.bulk_create(clouds) ProviderNetwork.objects.bulk_create(provider_networks)
circuits = ( circuits = (
Circuit(provider=providers[0], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 1', install_date='2020-01-01', commit_rate=1000, status=CircuitStatusChoices.STATUS_ACTIVE), Circuit(provider=providers[0], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 1', install_date='2020-01-01', commit_rate=1000, status=CircuitStatusChoices.STATUS_ACTIVE),
@ -207,9 +207,9 @@ class CircuitTestCase(TestCase):
CircuitTermination(circuit=circuits[0], site=sites[0], term_side='A'), CircuitTermination(circuit=circuits[0], site=sites[0], term_side='A'),
CircuitTermination(circuit=circuits[1], site=sites[1], term_side='A'), CircuitTermination(circuit=circuits[1], site=sites[1], term_side='A'),
CircuitTermination(circuit=circuits[2], site=sites[2], term_side='A'), CircuitTermination(circuit=circuits[2], site=sites[2], term_side='A'),
CircuitTermination(circuit=circuits[3], cloud=clouds[0], term_side='A'), CircuitTermination(circuit=circuits[3], provider_network=provider_networks[0], term_side='A'),
CircuitTermination(circuit=circuits[4], cloud=clouds[1], term_side='A'), CircuitTermination(circuit=circuits[4], provider_network=provider_networks[1], term_side='A'),
CircuitTermination(circuit=circuits[5], cloud=clouds[2], term_side='A'), CircuitTermination(circuit=circuits[5], provider_network=provider_networks[2], term_side='A'),
)) ))
CircuitTermination.objects.bulk_create(circuit_terminations) CircuitTermination.objects.bulk_create(circuit_terminations)
@ -236,9 +236,9 @@ class CircuitTestCase(TestCase):
params = {'provider': [provider.slug]} params = {'provider': [provider.slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
def test_cloud(self): def test_provider_network(self):
clouds = Cloud.objects.all()[:2] provider_networks = ProviderNetwork.objects.all()[:2]
params = {'cloud_id': [clouds[0].pk, clouds[1].pk]} params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_type(self): def test_type(self):
@ -312,12 +312,12 @@ class CircuitTerminationTestCase(TestCase):
) )
Provider.objects.bulk_create(providers) Provider.objects.bulk_create(providers)
clouds = ( provider_networks = (
Cloud(name='Cloud 1', provider=providers[0]), ProviderNetwork(name='Provider Network 1', provider=providers[0]),
Cloud(name='Cloud 2', provider=providers[0]), ProviderNetwork(name='Provider Network 2', provider=providers[0]),
Cloud(name='Cloud 3', provider=providers[0]), ProviderNetwork(name='Provider Network 3', provider=providers[0]),
) )
Cloud.objects.bulk_create(clouds) ProviderNetwork.objects.bulk_create(provider_networks)
circuits = ( circuits = (
Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 1'), Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 1'),
@ -336,9 +336,9 @@ class CircuitTerminationTestCase(TestCase):
CircuitTermination(circuit=circuits[1], site=sites[2], term_side='Z', port_speed=2000, upstream_speed=2000, xconnect_id='JKL'), CircuitTermination(circuit=circuits[1], site=sites[2], term_side='Z', port_speed=2000, upstream_speed=2000, xconnect_id='JKL'),
CircuitTermination(circuit=circuits[2], site=sites[2], term_side='A', port_speed=3000, upstream_speed=3000, xconnect_id='MNO'), CircuitTermination(circuit=circuits[2], site=sites[2], term_side='A', port_speed=3000, upstream_speed=3000, xconnect_id='MNO'),
CircuitTermination(circuit=circuits[2], site=sites[0], term_side='Z', port_speed=3000, upstream_speed=3000, xconnect_id='PQR'), CircuitTermination(circuit=circuits[2], site=sites[0], term_side='Z', port_speed=3000, upstream_speed=3000, xconnect_id='PQR'),
CircuitTermination(circuit=circuits[3], cloud=clouds[0], term_side='A'), CircuitTermination(circuit=circuits[3], provider_network=provider_networks[0], term_side='A'),
CircuitTermination(circuit=circuits[4], cloud=clouds[1], term_side='A'), CircuitTermination(circuit=circuits[4], provider_network=provider_networks[1], term_side='A'),
CircuitTermination(circuit=circuits[5], cloud=clouds[2], term_side='A'), CircuitTermination(circuit=circuits[5], provider_network=provider_networks[2], term_side='A'),
)) ))
CircuitTermination.objects.bulk_create(circuit_terminations) CircuitTermination.objects.bulk_create(circuit_terminations)
@ -372,9 +372,9 @@ class CircuitTerminationTestCase(TestCase):
params = {'site': [sites[0].slug, sites[1].slug]} params = {'site': [sites[0].slug, sites[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
def test_cloud(self): def test_provider_network(self):
clouds = Cloud.objects.all()[:2] provider_networks = ProviderNetwork.objects.all()[:2]
params = {'cloud_id': [clouds[0].pk, clouds[1].pk]} params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_cabled(self): def test_cabled(self):
@ -388,9 +388,9 @@ class CircuitTerminationTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 7) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 7)
class CloudTestCase(TestCase): class ProviderNetworkTestCase(TestCase):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
filterset = CloudFilterSet filterset = ProviderNetworkFilterSet
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
@ -402,19 +402,19 @@ class CloudTestCase(TestCase):
) )
Provider.objects.bulk_create(providers) Provider.objects.bulk_create(providers)
clouds = ( provider_networks = (
Cloud(name='Cloud 1', provider=providers[0]), ProviderNetwork(name='Provider Network 1', provider=providers[0]),
Cloud(name='Cloud 2', provider=providers[1]), ProviderNetwork(name='Provider Network 2', provider=providers[1]),
Cloud(name='Cloud 3', provider=providers[2]), ProviderNetwork(name='Provider Network 3', provider=providers[2]),
) )
Cloud.objects.bulk_create(clouds) ProviderNetwork.objects.bulk_create(provider_networks)
def test_id(self): def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]} params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Cloud 1', 'Cloud 2']} params = {'name': ['Provider Network 1', 'Provider Network 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_provider(self): def test_provider(self):

View File

@ -135,8 +135,8 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
} }
class CloudTestCase(ViewTestCases.PrimaryObjectViewTestCase): class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
model = Cloud model = ProviderNetwork
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
@ -147,27 +147,27 @@ class CloudTestCase(ViewTestCases.PrimaryObjectViewTestCase):
) )
Provider.objects.bulk_create(providers) Provider.objects.bulk_create(providers)
Cloud.objects.bulk_create([ ProviderNetwork.objects.bulk_create([
Cloud(name='Cloud 1', provider=providers[0]), ProviderNetwork(name='Provider Network 1', provider=providers[0]),
Cloud(name='Cloud 2', provider=providers[0]), ProviderNetwork(name='Provider Network 2', provider=providers[0]),
Cloud(name='Cloud 3', provider=providers[0]), ProviderNetwork(name='Provider Network 3', provider=providers[0]),
]) ])
tags = cls.create_tags('Alpha', 'Bravo', 'Charlie') tags = cls.create_tags('Alpha', 'Bravo', 'Charlie')
cls.form_data = { cls.form_data = {
'name': 'Cloud X', 'name': 'Provider Network X',
'provider': providers[1].pk, 'provider': providers[1].pk,
'description': 'A new cloud', 'description': 'A new provider network',
'comments': 'Longer description goes here', 'comments': 'Longer description goes here',
'tags': [t.pk for t in tags], 'tags': [t.pk for t in tags],
} }
cls.csv_data = ( cls.csv_data = (
"name,provider,description", "name,provider,description",
"Cloud 4,Provider 1,Foo", "Provider Network 4,Provider 1,Foo",
"Cloud 5,Provider 1,Bar", "Provider Network 5,Provider 1,Bar",
"Cloud 6,Provider 1,Baz", "Provider Network 6,Provider 1,Baz",
) )
cls.bulk_edit_data = { cls.bulk_edit_data = {

View File

@ -20,17 +20,17 @@ urlpatterns = [
path('providers/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}), path('providers/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
path('providers/<int:pk>/journal/', ObjectJournalView.as_view(), name='provider_journal', kwargs={'model': Provider}), path('providers/<int:pk>/journal/', ObjectJournalView.as_view(), name='provider_journal', kwargs={'model': Provider}),
# Clouds # Provider networks
path('clouds/', views.CloudListView.as_view(), name='cloud_list'), path('provider-networks/', views.ProviderNetworkListView.as_view(), name='providernetwork_list'),
path('clouds/add/', views.CloudEditView.as_view(), name='cloud_add'), path('provider-networks/add/', views.ProviderNetworkEditView.as_view(), name='providernetwork_add'),
path('clouds/import/', views.CloudBulkImportView.as_view(), name='cloud_import'), path('provider-networks/import/', views.ProviderNetworkBulkImportView.as_view(), name='providernetwork_import'),
path('clouds/edit/', views.CloudBulkEditView.as_view(), name='cloud_bulk_edit'), path('provider-networks/edit/', views.ProviderNetworkBulkEditView.as_view(), name='providernetwork_bulk_edit'),
path('clouds/delete/', views.CloudBulkDeleteView.as_view(), name='cloud_bulk_delete'), path('provider-networks/delete/', views.ProviderNetworkBulkDeleteView.as_view(), name='providernetwork_bulk_delete'),
path('clouds/<int:pk>/', views.CloudView.as_view(), name='cloud'), path('provider-networks/<int:pk>/', views.ProviderNetworkView.as_view(), name='providernetwork'),
path('clouds/<int:pk>/edit/', views.CloudEditView.as_view(), name='cloud_edit'), path('provider-networks/<int:pk>/edit/', views.ProviderNetworkEditView.as_view(), name='providernetwork_edit'),
path('clouds/<int:pk>/delete/', views.CloudDeleteView.as_view(), name='cloud_delete'), path('provider-networks/<int:pk>/delete/', views.ProviderNetworkDeleteView.as_view(), name='providernetwork_delete'),
path('clouds/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='cloud_changelog', kwargs={'model': Cloud}), path('provider-networks/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providernetwork_changelog', kwargs={'model': ProviderNetwork}),
path('clouds/<int:pk>/journal/', ObjectJournalView.as_view(), name='cloud_journal', kwargs={'model': Cloud}), path('provider-networks/<int:pk>/journal/', ObjectJournalView.as_view(), name='providernetwork_journal', kwargs={'model': ProviderNetwork}),
# Circuit types # Circuit types
path('circuit-types/', views.CircuitTypeListView.as_view(), name='circuittype_list'), path('circuit-types/', views.CircuitTypeListView.as_view(), name='circuittype_list'),

View File

@ -77,23 +77,23 @@ class ProviderBulkDeleteView(generic.BulkDeleteView):
# #
# Clouds # Provider networks
# #
class CloudListView(generic.ObjectListView): class ProviderNetworkListView(generic.ObjectListView):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
filterset = filters.CloudFilterSet filterset = filters.ProviderNetworkFilterSet
filterset_form = forms.CloudFilterForm filterset_form = forms.ProviderNetworkFilterForm
table = tables.CloudTable table = tables.ProviderNetworkTable
class CloudView(generic.ObjectView): class ProviderNetworkView(generic.ObjectView):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
circuits = Circuit.objects.restrict(request.user, 'view').filter( circuits = Circuit.objects.restrict(request.user, 'view').filter(
Q(termination_a__cloud=instance.pk) | Q(termination_a__provider_network=instance.pk) |
Q(termination_z__cloud=instance.pk) Q(termination_z__provider_network=instance.pk)
).prefetch_related( ).prefetch_related(
'type', 'tenant', 'terminations__site' 'type', 'tenant', 'terminations__site'
) )
@ -108,32 +108,32 @@ class CloudView(generic.ObjectView):
} }
class CloudEditView(generic.ObjectEditView): class ProviderNetworkEditView(generic.ObjectEditView):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
model_form = forms.CloudForm model_form = forms.ProviderNetworkForm
class CloudDeleteView(generic.ObjectDeleteView): class ProviderNetworkDeleteView(generic.ObjectDeleteView):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
class CloudBulkImportView(generic.BulkImportView): class ProviderNetworkBulkImportView(generic.BulkImportView):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
model_form = forms.CloudCSVForm model_form = forms.ProviderNetworkCSVForm
table = tables.CloudTable table = tables.ProviderNetworkTable
class CloudBulkEditView(generic.BulkEditView): class ProviderNetworkBulkEditView(generic.BulkEditView):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
filterset = filters.CloudFilterSet filterset = filters.ProviderNetworkFilterSet
table = tables.CloudTable table = tables.ProviderNetworkTable
form = forms.CloudBulkEditForm form = forms.ProviderNetworkBulkEditForm
class CloudBulkDeleteView(generic.BulkDeleteView): class ProviderNetworkBulkDeleteView(generic.BulkDeleteView):
queryset = Cloud.objects.all() queryset = ProviderNetwork.objects.all()
filterset = filters.CloudFilterSet filterset = filters.ProviderNetworkFilterSet
table = tables.CloudTable table = tables.ProviderNetworkTable
# #

View File

@ -242,14 +242,14 @@ class Cable(PrimaryModel):
): ):
raise ValidationError("A front port cannot be connected to it corresponding rear port") raise ValidationError("A front port cannot be connected to it corresponding rear port")
# A CircuitTermination attached to a Cloud cannot have a Cable # A CircuitTermination attached to a ProviderNetwork cannot have a Cable
if isinstance(self.termination_a, CircuitTermination) and self.termination_a.cloud is not None: if isinstance(self.termination_a, CircuitTermination) and self.termination_a.provider_network is not None:
raise ValidationError({ raise ValidationError({
'termination_a_id': "Circuit terminations attached to a cloud may not be cabled." 'termination_a_id': "Circuit terminations attached to a provider network may not be cabled."
}) })
if isinstance(self.termination_b, CircuitTermination) and self.termination_b.cloud is not None: if isinstance(self.termination_b, CircuitTermination) and self.termination_b.provider_network is not None:
raise ValidationError({ raise ValidationError({
'termination_b_id': "Circuit terminations attached to a cloud may not be cabled." 'termination_b_id': "Circuit terminations attached to a provider network may not be cabled."
}) })
# Check for an existing Cable connected to either termination object # Check for an existing Cable connected to either termination object

View File

@ -479,13 +479,13 @@ class CableTestCase(TestCase):
device=self.patch_pannel, name='FP4', type='8p8c', rear_port=self.rear_port4, rear_port_position=1 device=self.patch_pannel, name='FP4', type='8p8c', rear_port=self.rear_port4, rear_port_position=1
) )
self.provider = Provider.objects.create(name='Provider 1', slug='provider-1') self.provider = Provider.objects.create(name='Provider 1', slug='provider-1')
cloud = Cloud.objects.create(name='Cloud 1', provider=self.provider) provider_network = ProviderNetwork.objects.create(name='Provider Network 1', provider=self.provider)
self.circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1') self.circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
self.circuit1 = Circuit.objects.create(provider=self.provider, type=self.circuittype, cid='1') self.circuit1 = Circuit.objects.create(provider=self.provider, type=self.circuittype, cid='1')
self.circuit2 = Circuit.objects.create(provider=self.provider, type=self.circuittype, cid='2') self.circuit2 = Circuit.objects.create(provider=self.provider, type=self.circuittype, cid='2')
self.circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit1, site=site, term_side='A') self.circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit1, site=site, term_side='A')
self.circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit1, site=site, term_side='Z') self.circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit1, site=site, term_side='Z')
self.circuittermination3 = CircuitTermination.objects.create(circuit=self.circuit2, cloud=cloud, term_side='A') self.circuittermination3 = CircuitTermination.objects.create(circuit=self.circuit2, provider_network=provider_network, term_side='A')
def test_cable_creation(self): def test_cable_creation(self):
""" """
@ -555,9 +555,9 @@ class CableTestCase(TestCase):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
cable.clean() cable.clean()
def test_cable_cannot_terminate_to_a_cloud_circuittermination(self): def test_cable_cannot_terminate_to_a_provider_network_circuittermination(self):
""" """
Neither side of a cable can be terminated to a CircuitTermination which is attached to a Cloud Neither side of a cable can be terminated to a CircuitTermination which is attached to a ProviderNetwork
""" """
cable = Cable(termination_a=self.interface3, termination_b=self.circuittermination3) cable = Cable(termination_a=self.interface3, termination_b=self.circuittermination3)
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):

View File

@ -1,8 +1,8 @@
from collections import OrderedDict from collections import OrderedDict
from circuits.filters import CircuitFilterSet, CloudFilterSet, ProviderFilterSet from circuits.filters import CircuitFilterSet, ProviderFilterSet, ProviderNetworkFilterSet
from circuits.models import Circuit, Cloud, Provider from circuits.models import Circuit, ProviderNetwork, Provider
from circuits.tables import CircuitTable, CloudTable, ProviderTable from circuits.tables import CircuitTable, ProviderNetworkTable, ProviderTable
from dcim.filters import ( from dcim.filters import (
CableFilterSet, DeviceFilterSet, DeviceTypeFilterSet, PowerFeedFilterSet, RackFilterSet, LocationFilterSet, CableFilterSet, DeviceFilterSet, DeviceTypeFilterSet, PowerFeedFilterSet, RackFilterSet, LocationFilterSet,
SiteFilterSet, VirtualChassisFilterSet, SiteFilterSet, VirtualChassisFilterSet,
@ -45,11 +45,11 @@ SEARCH_TYPES = OrderedDict((
'table': CircuitTable, 'table': CircuitTable,
'url': 'circuits:circuit_list', 'url': 'circuits:circuit_list',
}), }),
('cloud', { ('providernetwork', {
'queryset': Cloud.objects.prefetch_related('provider'), 'queryset': ProviderNetwork.objects.prefetch_related('provider'),
'filterset': CloudFilterSet, 'filterset': ProviderNetworkFilterSet,
'table': CloudTable, 'table': ProviderNetworkTable,
'url': 'circuits:cloud_list', 'url': 'circuits:providernetwork_list',
}), }),
# DCIM # DCIM
('site', { ('site', {

View File

@ -26,19 +26,19 @@
<p class="form-control-static">{{ form.term_side.value }}</p> <p class="form-control-static">{{ form.term_side.value }}</p>
</div> </div>
</div> </div>
{% with cloud_tab_active=form.initial.cloud %} {% with providernetwork_tab_active=form.initial.provider_network %}
<ul class="nav nav-tabs" role="tablist"> <ul class="nav nav-tabs" role="tablist">
<li role="presentation"{% if not cloud_tab_active %} class="active"{% endif %}><a href="#site" role="tab" data-toggle="tab">Site</a></li> <li role="presentation"{% if not providernetwork_tab_active %} class="active"{% endif %}><a href="#site" role="tab" data-toggle="tab">Site</a></li>
<li role="presentation"{% if cloud_tab_active %} class="active"{% endif %}><a href="#cloud" role="tab" data-toggle="tab">Cloud</a></li> <li role="presentation"{% if providernetwork_tab_active %} class="active"{% endif %}><a href="#providernetwork" role="tab" data-toggle="tab">Provider Network</a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane{% if not cloud_tab_active %} active{% endif %}" id="site"> <div class="tab-pane{% if not providernetwork_tab_active %} active{% endif %}" id="site">
{% render_field form.region %} {% render_field form.region %}
{% render_field form.site_group %} {% render_field form.site_group %}
{% render_field form.site %} {% render_field form.site %}
</div> </div>
<div class="tab-pane{% if cloud_tab_active %} active{% endif %}" id="cloud"> <div class="tab-pane{% if providernetwork_tab_active %} active{% endif %}" id="providernetwork">
{% render_field form.cloud %} {% render_field form.provider_network %}
</div> </div>
</div> </div>
{% endwith %} {% endwith %}

View File

@ -85,9 +85,9 @@
</tr> </tr>
{% else %} {% else %}
<tr> <tr>
<td>Cloud</td> <td>Provider Network</td>
<td> <td>
<a href="{{ termination.cloud.get_absolute_url }}">{{ termination.cloud }}</a> <a href="{{ termination.provider_network.get_absolute_url }}">{{ termination.provider_network }}</a>
</td> </td>
</tr> </tr>
{% endif %} {% endif %}

View File

@ -4,8 +4,8 @@
{% load plugins %} {% load plugins %}
{% block breadcrumbs %} {% block breadcrumbs %}
<li><a href="{% url 'circuits:cloud_list' %}">Clouds</a></li> <li><a href="{% url 'circuits:providernetwork_list' %}">Provider Networks</a></li>
<li><a href="{% url 'circuits:cloud_list' %}?provider_id={{ object.provider_id }}">{{ object.provider }}</a></li> <li><a href="{% url 'circuits:providernetwork_list' %}?provider_id={{ object.provider_id }}">{{ object.provider }}</a></li>
<li>{{ object }}</li> <li>{{ object }}</li>
{% endblock %} {% endblock %}
@ -14,7 +14,7 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<strong>Cloud</strong> <strong>Provider Network</strong>
</div> </div>
<table class="table table-hover panel-body attr-table"> <table class="table table-hover panel-body attr-table">
<tr> <tr>
@ -46,7 +46,7 @@
</div> </div>
</div> </div>
{% include 'inc/custom_fields_panel.html' %} {% include 'inc/custom_fields_panel.html' %}
{% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='circuits:cloud_list' %} {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='circuits:providernetwork_list' %}
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col-md-8"> <div class="col-md-8">

View File

@ -465,14 +465,14 @@
</div> </div>
{% endif %} {% endif %}
<a href="{% url 'circuits:provider_list' %}">Providers</a> <a href="{% url 'circuits:provider_list' %}">Providers</a>
<li{% if not perms.circuits.view_cloud %} class="disabled"{% endif %}> <li{% if not perms.circuits.view_providernetwork %} class="disabled"{% endif %}>
{% if perms.circuits.add_cloud %} {% if perms.circuits.add_providernetwork %}
<div class="buttons pull-right"> <div class="buttons pull-right">
<a href="{% url 'circuits:cloud_add' %}" class="btn btn-xs btn-success" title="Add"><i class="mdi mdi-plus-thick"></i></a> <a href="{% url 'circuits:providernetwork_add' %}" class="btn btn-xs btn-success" title="Add"><i class="mdi mdi-plus-thick"></i></a>
<a href="{% url 'circuits:cloud_import' %}" class="btn btn-xs btn-info" title="Import"><i class="mdi mdi-database-import-outline"></i></a> <a href="{% url 'circuits:providernetwork_import' %}" class="btn btn-xs btn-info" title="Import"><i class="mdi mdi-database-import-outline"></i></a>
</div> </div>
{% endif %} {% endif %}
<a href="{% url 'circuits:cloud_list' %}">Clouds</a> <a href="{% url 'circuits:providernetwork_list' %}">Provider Networks</a>
</li> </li>
</ul> </ul>
</li> </li>