示例#1
0
class Cluster(PrimaryModel):
    """
    A cluster of VirtualMachines. Each Cluster may optionally be associated with one or more Devices.
    """
    name = models.CharField(max_length=100, unique=True)
    type = models.ForeignKey(to=ClusterType,
                             on_delete=models.PROTECT,
                             related_name='clusters')
    group = models.ForeignKey(to=ClusterGroup,
                              on_delete=models.PROTECT,
                              related_name='clusters',
                              blank=True,
                              null=True)
    tenant = models.ForeignKey(to='tenancy.Tenant',
                               on_delete=models.PROTECT,
                               related_name='clusters',
                               blank=True,
                               null=True)
    site = models.ForeignKey(to='dcim.Site',
                             on_delete=models.PROTECT,
                             related_name='clusters',
                             blank=True,
                             null=True)
    comments = models.TextField(blank=True)
    vlan_groups = GenericRelation(to='ipam.VLANGroup',
                                  content_type_field='scope_type',
                                  object_id_field='scope_id',
                                  related_query_name='cluster')

    objects = RestrictedQuerySet.as_manager()

    clone_fields = [
        'type',
        'group',
        'tenant',
        'site',
    ]

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('virtualization:cluster', args=[self.pk])

    def clean(self):
        super().clean()

        # If the Cluster is assigned to a Site, verify that all host Devices belong to that Site.
        if self.pk and self.site:
            nonsite_devices = Device.objects.filter(cluster=self).exclude(
                site=self.site).count()
            if nonsite_devices:
                raise ValidationError({
                    'site':
                    "{} devices are assigned as hosts for this cluster but are not in site {}"
                    .format(nonsite_devices, self.site)
                })
示例#2
0
文件: models.py 项目: zhyh329/netbox
class SecretRole(OrganizationalModel):
    """
    A SecretRole represents an arbitrary functional classification of Secrets. For example, a user might define roles
    such as "Login Credentials" or "SNMP Communities."
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    description = models.CharField(
        max_length=200,
        blank=True,
    )

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'description']

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('secrets:secretrole', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.description,
        )
示例#3
0
文件: devices.py 项目: xcdr/netbox
class DeviceRole(OrganizationalModel):
    """
    Devices are organized by functional role; for example, "Core Switch" or "File Server". Each DeviceRole is assigned a
    color to be used when displaying rack elevations. The vm_role field determines whether the role is applicable to
    virtual machines as well.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    color = ColorField(default=ColorChoices.COLOR_GREY)
    vm_role = models.BooleanField(
        default=True,
        verbose_name='VM Role',
        help_text='Virtual machines may be assigned to this role')
    description = models.CharField(
        max_length=200,
        blank=True,
    )

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('dcim:devicerole', args=[self.pk])
示例#4
0
class Manufacturer(ChangeLoggedModel):
    """
    A Manufacturer represents a company which produces hardware devices; for example, Juniper or Dell.
    """
    name = models.CharField(max_length=50, unique=True, verbose_name="Имя")
    slug = models.SlugField(unique=True)
    description = models.CharField(max_length=200,
                                   blank=True,
                                   verbose_name="Описание")

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'description']

    class Meta:
        ordering = ['name']
        verbose_name = "Производитель"

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return "{}?manufacturer={}".format(reverse('dcim:devicetype_list'),
                                           self.slug)

    def to_csv(self):
        return (self.name, self.slug, self.description)
示例#5
0
文件: models.py 项目: nkeulen/netbox
class Tenant(PrimaryModel):
    """
    A Tenant represents an organization served by the NetBox owner. This is typically a customer or an internal
    department.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    group = models.ForeignKey(to='tenancy.TenantGroup',
                              on_delete=models.SET_NULL,
                              related_name='tenants',
                              blank=True,
                              null=True)
    description = models.CharField(max_length=200, blank=True)
    comments = models.TextField(blank=True)

    objects = RestrictedQuerySet.as_manager()

    clone_fields = [
        'group',
        'description',
    ]

    class Meta:
        ordering = ['group', 'name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('tenancy:tenant', args=[self.pk])
示例#6
0
class Tag(ChangeLoggedModel, TagBase):
    color = ColorField(
        default=ColorChoices.COLOR_GREY
    )
    description = models.CharField(
        max_length=200,
        blank=True,
    )

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'color', 'description']

    class Meta:
        ordering = ['name']

    def get_absolute_url(self):
        return reverse('extras:tag', args=[self.pk])

    def slugify(self, tag, i=None):
        # Allow Unicode in Tag slugs (avoids empty slugs for Tags with all-Unicode names)
        slug = slugify(tag, allow_unicode=True)
        if i is not None:
            slug += "_%d" % i
        return slug

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.color,
            self.description
        )
示例#7
0
class ObjectPermission(models.Model):
    """
    A mapping of view, add, change, and/or delete permission for users and/or groups to an arbitrary set of objects
    identified by ORM query parameters.
    """
    name = models.CharField(
        max_length=100
    )
    description = models.CharField(
        max_length=200,
        blank=True
    )
    enabled = models.BooleanField(
        default=True
    )
    object_types = models.ManyToManyField(
        to=ContentType,
        limit_choices_to=Q(
            ~Q(app_label__in=['admin', 'auth', 'contenttypes', 'sessions', 'taggit', 'users']) |
            Q(app_label='auth', model__in=['group', 'user']) |
            Q(app_label='users', model__in=['objectpermission', 'token'])
        ),
        related_name='object_permissions'
    )
    groups = models.ManyToManyField(
        to=Group,
        blank=True,
        related_name='object_permissions'
    )
    users = models.ManyToManyField(
        to=User,
        blank=True,
        related_name='object_permissions'
    )
    actions = ArrayField(
        base_field=models.CharField(max_length=30),
        help_text="The list of actions granted by this permission"
    )
    constraints = models.JSONField(
        blank=True,
        null=True,
        help_text="Queryset filter matching the applicable objects of the selected type(s)"
    )

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ['name']
        verbose_name = "permission"

    def __str__(self):
        return self.name

    def list_constraints(self):
        """
        Return all constraint sets as a list (even if only a single set is defined).
        """
        if type(self.constraints) is not list:
            return [self.constraints]
        return self.constraints
示例#8
0
class PowerPanel(PrimaryModel):
    """
    A distribution point for electrical power; e.g. a data center RPP.
    """
    site = models.ForeignKey(to='Site', on_delete=models.PROTECT)
    location = models.ForeignKey(to='dcim.Location',
                                 on_delete=models.PROTECT,
                                 blank=True,
                                 null=True)
    name = models.CharField(max_length=100)

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ['site', 'name']
        unique_together = ['site', 'name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('dcim:powerpanel', args=[self.pk])

    def clean(self):
        super().clean()

        # Location must belong to assigned Site
        if self.location and self.location.site != self.site:
            raise ValidationError(
                f"Location {self.location} ({self.location.site}) is in a different site than {self.site}"
            )
示例#9
0
文件: models.py 项目: mpalmer/netbox
class JournalEntry(ChangeLoggedModel):
    """
    A historical remark concerning an object; collectively, these form an object's journal. The journal is used to
    preserve historical context around an object, and complements NetBox's built-in change logging. For example, you
    might record a new journal entry when a device undergoes maintenance, or when a prefix is expanded.
    """
    assigned_object_type = models.ForeignKey(to=ContentType,
                                             on_delete=models.CASCADE)
    assigned_object_id = models.PositiveIntegerField()
    assigned_object = GenericForeignKey(ct_field='assigned_object_type',
                                        fk_field='assigned_object_id')
    created = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(to=User,
                                   on_delete=models.SET_NULL,
                                   blank=True,
                                   null=True)
    kind = models.CharField(max_length=30,
                            choices=JournalEntryKindChoices,
                            default=JournalEntryKindChoices.KIND_INFO)
    comments = models.TextField()

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ('-created', )
        verbose_name_plural = 'journal entries'

    def __str__(self):
        return f"{date_format(self.created)} - {time_format(self.created)} ({self.get_kind_display()})"

    def get_absolute_url(self):
        return reverse('extras:journalentry', args=[self.pk])

    def get_kind_class(self):
        return JournalEntryKindChoices.CSS_CLASSES.get(self.kind)
示例#10
0
class CircuitTermination(PathEndpoint, CableTermination):
    circuit = models.ForeignKey(to='circuits.Circuit',
                                on_delete=models.CASCADE,
                                related_name='terminations')
    term_side = models.CharField(max_length=1,
                                 choices=CircuitTerminationSideChoices,
                                 verbose_name='Termination')
    site = models.ForeignKey(to='dcim.Site',
                             on_delete=models.PROTECT,
                             related_name='circuit_terminations')
    port_speed = models.PositiveIntegerField(verbose_name='Port speed (Kbps)',
                                             blank=True,
                                             null=True)
    upstream_speed = models.PositiveIntegerField(
        blank=True,
        null=True,
        verbose_name='Upstream speed (Kbps)',
        help_text='Upstream speed, if different from port speed')
    xconnect_id = models.CharField(max_length=50,
                                   blank=True,
                                   verbose_name='Cross-connect ID')
    pp_info = models.CharField(max_length=100,
                               blank=True,
                               verbose_name='Patch panel/port(s)')
    description = models.CharField(max_length=200, blank=True)

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ['circuit', 'term_side']
        unique_together = ['circuit', 'term_side']

    def __str__(self):
        return 'Side {}'.format(self.get_term_side_display())

    def to_objectchange(self, action):
        # Annotate the parent Circuit
        try:
            related_object = self.circuit
        except Circuit.DoesNotExist:
            # Parent circuit has been deleted
            related_object = None

        return ObjectChange(changed_object=self,
                            object_repr=str(self),
                            action=action,
                            related_object=related_object,
                            object_data=serialize_object(self))

    @property
    def parent(self):
        return self.circuit

    def get_peer_termination(self):
        peer_side = 'Z' if self.term_side == 'A' else 'A'
        try:
            return CircuitTermination.objects.prefetch_related('site').get(
                circuit=self.circuit, term_side=peer_side)
        except CircuitTermination.DoesNotExist:
            return None
示例#11
0
class ClusterType(ChangeLoggedModel):
    """
    A type of Cluster.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    description = models.CharField(max_length=200, blank=True)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'description']

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return "{}?type={}".format(reverse('virtualization:cluster_list'),
                                   self.slug)

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.description,
        )
示例#12
0
class BGPBase(ChangeLoggedModel):
    """
    """
    site = models.ForeignKey(to='dcim.Site',
                             on_delete=models.PROTECT,
                             related_name="%(class)s_related",
                             blank=True,
                             null=True)
    tenant = models.ForeignKey(to='tenancy.Tenant',
                               on_delete=models.PROTECT,
                               blank=True,
                               null=True)
    status = models.CharField(max_length=50,
                              choices=ASNStatusChoices,
                              default=ASNStatusChoices.STATUS_ACTIVE)
    role = models.ForeignKey(to='ipam.Role',
                             on_delete=models.SET_NULL,
                             blank=True,
                             null=True)
    description = models.CharField(max_length=200, blank=True)
    tags = TaggableManager(through=TaggedItem)

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        abstract = True
示例#13
0
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(max_length=100)
    provider = models.ForeignKey(to='circuits.Provider',
                                 on_delete=models.PROTECT,
                                 related_name='networks')
    description = models.CharField(max_length=200, blank=True)
    comments = models.TextField(blank=True)

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ('provider', 'name')
        constraints = (models.UniqueConstraint(
            fields=('provider', 'name'),
            name='circuits_providernetwork_provider_name'), )
        unique_together = ('provider', 'name')

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('circuits:providernetwork', args=[self.pk])
示例#14
0
文件: vrfs.py 项目: zhyh329/netbox
class RouteTarget(PrimaryModel):
    """
    A BGP extended community used to control the redistribution of routes among VRFs, as defined in RFC 4364.
    """
    name = models.CharField(
        max_length=
        VRF_RD_MAX_LENGTH,  # Same format options as VRF RD (RFC 4360 section 4)
        unique=True,
        help_text='Route target value (formatted in accordance with RFC 4360)')
    description = models.CharField(max_length=200, blank=True)
    tenant = models.ForeignKey(to='tenancy.Tenant',
                               on_delete=models.PROTECT,
                               related_name='route_targets',
                               blank=True,
                               null=True)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'description', 'tenant']

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('ipam:routetarget', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.description,
            self.tenant.name if self.tenant else None,
        )
示例#15
0
class CircuitType(ChangeLoggedModel):
    """
    Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
    "Long Haul," "Metro," or "Out-of-Band".
    """
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(unique=True)
    description = models.CharField(
        max_length=200,
        blank=True,
    )

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'description']

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return "{}?type={}".format(reverse('circuits:circuit_list'), self.slug)

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.description,
        )
示例#16
0
class Config(models.Model):

    device = models.ForeignKey(
        to='dcim.Device',
        on_delete=models.PROTECT,
    )
    files = models.FileField(upload_to='configs', blank=True, null=True)

    #date = models.TimeField(null=True)
    config_date = models.DateTimeField(null=True)

    session = models.CharField(max_length=100, null=True)

    config_type = models.CharField(max_length=100,
                                   null=True,
                                   choices=ConfigurationChoices)
    objects = RestrictedQuerySet.as_manager()

    def get_absolute_url(self):
        return reverse('dcim:config', kwargs={'pk': self.pk})

    csv_headers = ['device', 'files', 'date', 'session']

    class Meta:
        verbose_name = "Configuration Files Historie"

        ordering = []
示例#17
0
文件: ip.py 项目: zhyh329/netbox
class Role(OrganizationalModel):
    """
    A Role represents the functional role of a Prefix or VLAN; for example, "Customer," "Infrastructure," or
    "Management."
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    weight = models.PositiveSmallIntegerField(default=1000)
    description = models.CharField(
        max_length=200,
        blank=True,
    )

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'weight', 'description']

    class Meta:
        ordering = ['weight', 'name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('ipam:role', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.weight,
            self.description,
        )
示例#18
0
class ClusterGroup(OrganizationalModel):
    """
    An organizational group of Clusters.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    description = models.CharField(max_length=200, blank=True)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'description']

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('virtualization:clustergroup', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.description,
        )
示例#19
0
文件: ip.py 项目: zhyh329/netbox
class RIR(OrganizationalModel):
    """
    A Regional Internet Registry (RIR) is responsible for the allocation of a large portion of the global IP address
    space. This can be an organization like ARIN or RIPE, or a governing standard such as RFC 1918.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    is_private = models.BooleanField(
        default=False,
        verbose_name='Private',
        help_text='IP space managed by this RIR is considered private')
    description = models.CharField(max_length=200, blank=True)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'is_private', 'description']

    class Meta:
        ordering = ['name']
        verbose_name = 'RIR'
        verbose_name_plural = 'RIRs'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('ipam:rir', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.is_private,
            self.description,
        )
示例#20
0
class RackRole(OrganizationalModel):
    """
    Racks can be organized by functional role, similar to Devices.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    color = ColorField(default=ColorChoices.COLOR_GREY)
    description = models.CharField(
        max_length=200,
        blank=True,
    )

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'color', 'description']

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('dcim:rackrole', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.color,
            self.description,
        )
示例#21
0
class CircuitType(OrganizationalModel):
    """
    Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
    "Long Haul," "Metro," or "Out-of-Band".
    """
    name = models.CharField(
        max_length=100,
        unique=True
    )
    slug = models.SlugField(
        max_length=100,
        unique=True
    )
    description = models.CharField(
        max_length=200,
        blank=True,
    )

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('circuits:circuittype', args=[self.pk])
示例#22
0
class Provider(ChangeLoggedModel, CustomFieldModel):
    """
    Each Circuit belongs to a Provider. This is usually a telecommunications company or similar organization. This model
    stores information pertinent to the user's relationship with the Provider.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    asn = ASNField(blank=True,
                   null=True,
                   verbose_name='ASN',
                   help_text='32-bit autonomous system number')
    account = models.CharField(max_length=30,
                               blank=True,
                               verbose_name='Account number')
    portal_url = models.URLField(blank=True, verbose_name='Portal URL')
    noc_contact = models.TextField(blank=True, verbose_name='NOC contact')
    admin_contact = models.TextField(blank=True, verbose_name='Admin contact')
    comments = models.TextField(blank=True)
    tags = TaggableManager(through=TaggedItem)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = [
        'name',
        'slug',
        'asn',
        'account',
        'portal_url',
        'noc_contact',
        'admin_contact',
        'comments',
    ]
    clone_fields = [
        'asn',
        'account',
        'portal_url',
        'noc_contact',
        'admin_contact',
    ]

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('circuits:provider', args=[self.slug])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.asn,
            self.account,
            self.portal_url,
            self.noc_contact,
            self.admin_contact,
            self.comments,
        )
示例#23
0
文件: models.py 项目: fdomain/netbox
class ImageAttachment(BigIDModel):
    """
    An uploaded image which is associated with an object.
    """
    content_type = models.ForeignKey(to=ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    parent = GenericForeignKey(ct_field='content_type', fk_field='object_id')
    image = models.ImageField(upload_to=image_upload,
                              height_field='image_height',
                              width_field='image_width')
    image_height = models.PositiveSmallIntegerField()
    image_width = models.PositiveSmallIntegerField()
    name = models.CharField(max_length=50, blank=True)
    created = models.DateTimeField(auto_now_add=True)

    objects = RestrictedQuerySet.as_manager()

    clone_fields = ('content_type', 'object_id')

    class Meta:
        ordering = ('name', 'pk')  # name may be non-unique

    def __str__(self):
        if self.name:
            return self.name
        filename = self.image.name.rsplit('/', 1)[-1]
        return filename.split('_', 2)[2]

    def delete(self, *args, **kwargs):

        _name = self.image.name

        super().delete(*args, **kwargs)

        # Delete file from disk
        self.image.delete(save=False)

        # Deleting the file erases its name. We restore the image's filename here in case we still need to reference it
        # before the request finishes. (For example, to display a message indicating the ImageAttachment was deleted.)
        self.image.name = _name

    @property
    def size(self):
        """
        Wrapper around `image.size` to suppress an OSError in case the file is inaccessible. Also opportunistically
        catch other exceptions that we know other storage back-ends to throw.
        """
        expected_exceptions = [OSError]

        try:
            from botocore.exceptions import ClientError
            expected_exceptions.append(ClientError)
        except ImportError:
            pass

        try:
            return self.image.size
        except tuple(expected_exceptions):
            return None
示例#24
0
class ChangeLoggedModel(ChangeLoggingMixin, CustomValidationMixin, BigIDModel):
    """
    Base model for all objects which support change logging.
    """
    objects = RestrictedQuerySet.as_manager()

    class Meta:
        abstract = True
示例#25
0
class RackReservation(PrimaryModel):
    """
    One or more reserved units within a Rack.
    """
    rack = models.ForeignKey(to='dcim.Rack',
                             on_delete=models.CASCADE,
                             related_name='reservations')
    units = ArrayField(base_field=models.PositiveSmallIntegerField())
    tenant = models.ForeignKey(to='tenancy.Tenant',
                               on_delete=models.PROTECT,
                               related_name='rackreservations',
                               blank=True,
                               null=True)
    user = models.ForeignKey(to=User, on_delete=models.PROTECT)
    description = models.CharField(max_length=200)

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ['created', 'pk']

    def __str__(self):
        return "Reservation for rack {}".format(self.rack)

    def get_absolute_url(self):
        return reverse('dcim:rackreservation', args=[self.pk])

    def clean(self):
        super().clean()

        if hasattr(self, 'rack') and self.units:

            # Validate that all specified units exist in the Rack.
            invalid_units = [u for u in self.units if u not in self.rack.units]
            if invalid_units:
                raise ValidationError({
                    'units':
                    "Invalid unit(s) for {}U rack: {}".format(
                        self.rack.u_height,
                        ', '.join([str(u) for u in invalid_units]),
                    ),
                })

            # Check that none of the units has already been reserved for this Rack.
            reserved_units = []
            for resv in self.rack.reservations.exclude(pk=self.pk):
                reserved_units += resv.units
            conflicting_units = [u for u in self.units if u in reserved_units]
            if conflicting_units:
                raise ValidationError({
                    'units':
                    'The following units have already been reserved: {}'.
                    format(', '.join([str(u) for u in conflicting_units]), )
                })

    @property
    def unit_list(self):
        return array_to_string(self.units)
示例#26
0
文件: models.py 项目: wbdosx/netbox
class ExportTemplate(models.Model):
    content_type = models.ForeignKey(
        to=ContentType,
        on_delete=models.CASCADE,
        limit_choices_to=FeatureQuery('export_templates'))
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=200, blank=True)
    template_code = models.TextField(
        help_text=
        'The list of objects being exported is passed as a context variable named <code>queryset</code>.'
    )
    mime_type = models.CharField(
        max_length=50,
        blank=True,
        verbose_name='MIME type',
        help_text='Defaults to <code>text/plain</code>')
    file_extension = models.CharField(
        max_length=15,
        blank=True,
        help_text='Extension to append to the rendered filename')

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        ordering = ['content_type', 'name']
        unique_together = [['content_type', 'name']]

    def __str__(self):
        return '{}: {}'.format(self.content_type, self.name)

    def render(self, queryset):
        """
        Render the contents of the template.
        """
        context = {'queryset': queryset}
        output = render_jinja2(self.template_code, context)

        # Replace CRLF-style line terminators
        output = output.replace('\r\n', '\n')

        return output

    def render_to_response(self, queryset):
        """
        Render the template to an HTTP response, delivered as a named file attachment
        """
        output = self.render(queryset)
        mime_type = 'text/plain' if not self.mime_type else self.mime_type

        # Build the response
        response = HttpResponse(output, content_type=mime_type)
        filename = 'netbox_{}{}'.format(
            queryset.model._meta.verbose_name_plural,
            '.{}'.format(self.file_extension) if self.file_extension else '')
        response['Content-Disposition'] = 'attachment; filename="{}"'.format(
            filename)

        return response
示例#27
0
class VirtualChassis(ChangeLoggedModel, CustomFieldModel):
    """
    A collection of Devices which operate with a shared control plane (e.g. a switch stack).
    """
    master = models.OneToOneField(to='Device',
                                  on_delete=models.PROTECT,
                                  related_name='vc_master_for',
                                  blank=True,
                                  null=True)
    name = models.CharField(max_length=64)
    domain = models.CharField(max_length=30, blank=True)
    tags = TaggableManager(through=TaggedItem)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'domain', 'master']

    class Meta:
        ordering = ['name']
        verbose_name_plural = 'virtual chassis'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('dcim:virtualchassis', kwargs={'pk': self.pk})

    def clean(self):
        super().clean()

        # Verify that the selected master device has been assigned to this VirtualChassis. (Skip when creating a new
        # VirtualChassis.)
        if self.pk and self.master and self.master not in self.members.all():
            raise ValidationError({
                'master':
                f"The selected master ({self.master}) is not assigned to this virtual chassis."
            })

    def delete(self, *args, **kwargs):

        # Check for LAG interfaces split across member chassis
        interfaces = Interface.objects.filter(
            device__in=self.members.all(),
            lag__isnull=False).exclude(lag__device=F('device'))
        if interfaces:
            raise ProtectedError(
                f"Unable to delete virtual chassis {self}. There are member interfaces which form a cross-chassis LAG",
                interfaces)

        return super().delete(*args, **kwargs)

    def to_csv(self):
        return (
            self.name,
            self.domain,
            self.master.name if self.master else None,
        )
示例#28
0
文件: models.py 项目: toondv/netbox
class VLANGroup(ChangeLoggedModel):
    """
    A VLAN group is an arbitrary collection of VLANs within which VLAN IDs and names must be unique.
    """
    name = models.CharField(
        max_length=50
    )
    slug = models.SlugField()
    site = models.ForeignKey(
        to='dcim.Site',
        on_delete=models.PROTECT,
        related_name='vlan_groups',
        blank=True,
        null=True
    )
    description = models.CharField(
        max_length=200,
        blank=True
    )

    objects = RestrictedQuerySet.as_manager()

    csv_headers = ['name', 'slug', 'site', 'description']

    class Meta:
        ordering = ('site', 'name', 'pk')  # (site, name) may be non-unique
        unique_together = [
            ['site', 'name'],
            ['site', 'slug'],
        ]
        verbose_name = 'VLAN group'
        verbose_name_plural = 'VLAN groups'

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('ipam:vlangroup_vlans', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.site.name if self.site else None,
            self.description,
        )

    def get_next_available_vid(self):
        """
        Return the first available VLAN ID (1-4094) in the group.
        """
        vlan_ids = VLAN.objects.filter(group=self).values_list('vid', flat=True)
        for i in range(1, 4095):
            if i not in vlan_ids:
                return i
        return None
示例#29
0
class Platform(OrganizationalModel):
    """
    Platform refers to the software or firmware running on a Device. For example, "Cisco IOS-XR" or "Juniper Junos".
    NetBox uses Platforms to determine how to interact with devices when pulling inventory data or other information by
    specifying a NAPALM driver.
    """
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    manufacturer = models.ForeignKey(
        to='dcim.Manufacturer',
        on_delete=models.PROTECT,
        related_name='platforms',
        blank=True,
        null=True,
        help_text=
        'Optionally limit this platform to devices of a certain manufacturer')
    napalm_driver = models.CharField(
        max_length=50,
        blank=True,
        verbose_name='NAPALM driver',
        help_text=
        'The name of the NAPALM driver to use when interacting with devices')
    napalm_args = models.JSONField(
        blank=True,
        null=True,
        verbose_name='NAPALM arguments',
        help_text=
        'Additional arguments to pass when initiating the NAPALM driver (JSON format)'
    )
    description = models.CharField(max_length=200, blank=True)

    objects = RestrictedQuerySet.as_manager()

    csv_headers = [
        'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args',
        'description'
    ]

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('dcim:platform', args=[self.pk])

    def to_csv(self):
        return (
            self.name,
            self.slug,
            self.manufacturer.name if self.manufacturer else None,
            self.napalm_driver,
            self.napalm_args,
            self.description,
        )
示例#30
0
class ComponentModel(models.Model):
    """
    An abstract model inherited by any model which has a parent Device.
    """
    device = models.ForeignKey(
        to='dcim.Device',
        on_delete=models.CASCADE,
        related_name='%(class)ss'
    )
    name = models.CharField(
        max_length=64
    )
    _name = NaturalOrderingField(
        target_field='name',
        max_length=100,
        blank=True
    )
    label = models.CharField(
        max_length=64,
        blank=True,
        help_text="Physical label"
    )
    description = models.CharField(
        max_length=200,
        blank=True
    )

    objects = RestrictedQuerySet.as_manager()

    class Meta:
        abstract = True

    def __str__(self):
        if self.label:
            return f"{self.name} ({self.label})"
        return self.name

    def to_objectchange(self, action):
        # Annotate the parent Device
        try:
            device = self.device
        except ObjectDoesNotExist:
            # The parent Device has already been deleted
            device = None
        return ObjectChange(
            changed_object=self,
            object_repr=str(self),
            action=action,
            related_object=device,
            object_data=serialize_object(self)
        )

    @property
    def parent(self):
        return getattr(self, 'device', None)