Skip to content

Models

nautobot_golden_config.models

Django Models for tracking the configuration compliance per feature and device.

ComplianceFeature

Bases: PrimaryModel

ComplianceFeature details.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
)
class ComplianceFeature(PrimaryModel):  # pylint: disable=too-many-ancestors
    """ComplianceFeature details."""

    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    description = models.CharField(max_length=200, blank=True)

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

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (self.name, self.slug, self.description)

    class Meta:
        """Meta information for ComplianceFeature model."""

        ordering = ("slug",)

    def __str__(self):
        """Return a sane string representation of the instance."""
        return self.slug

    def get_absolute_url(self):
        """Absolute url for the ComplianceFeature instance."""
        return reverse("plugins:nautobot_golden_config:compliancefeature", args=[self.pk])

Meta

Meta information for ComplianceFeature model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Meta information for ComplianceFeature model."""

    ordering = ("slug",)

__str__()

Return a sane string representation of the instance.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """Return a sane string representation of the instance."""
    return self.slug

get_absolute_url()

Absolute url for the ComplianceFeature instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Absolute url for the ComplianceFeature instance."""
    return reverse("plugins:nautobot_golden_config:compliancefeature", args=[self.pk])

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (self.name, self.slug, self.description)

ComplianceRule

Bases: PrimaryModel

ComplianceRule details.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
)
class ComplianceRule(PrimaryModel):  # pylint: disable=too-many-ancestors
    """ComplianceRule details."""

    feature = models.ForeignKey(to="ComplianceFeature", on_delete=models.CASCADE, blank=False, related_name="feature")

    platform = models.ForeignKey(
        to="dcim.Platform",
        on_delete=models.CASCADE,
        related_name="compliance_rules",
        null=False,
        blank=False,
    )
    description = models.CharField(
        max_length=200,
        blank=True,
    )
    config_ordered = models.BooleanField(
        null=False,
        blank=False,
        verbose_name="Configured Ordered",
        help_text="Whether or not the configuration order matters, such as in ACLs.",
    )

    config_remediation = models.BooleanField(
        default=False,
        verbose_name="Config Remediation",
        help_text="Whether or not the config remediation is executed for this compliance rule.",
    )

    match_config = models.TextField(
        null=True,
        blank=True,
        verbose_name="Config to Match",
        help_text="The config to match that is matched based on the parent most configuration. E.g.: For CLI `router bgp` or `ntp`. For JSON this is a top level key name.",
    )
    config_type = models.CharField(
        max_length=20,
        default=ComplianceRuleConfigTypeChoice.TYPE_CLI,
        choices=ComplianceRuleConfigTypeChoice,
        help_text="Whether the configuration is in CLI or JSON/structured format.",
    )

    custom_compliance = models.BooleanField(
        default=False, help_text="Whether this Compliance Rule is proceeded as custom."
    )

    csv_headers = [
        "platform",
        "feature",
        "description",
        "config_ordered",
        "match_config",
        "config_type",
        "custom_compliance",
        "config_remediation",
    ]

    @property
    def remediation_setting(self):
        """Returns remediation settings for a particular platform."""
        return RemediationSetting.objects.filter(platform=self.platform).first()

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (
            self.platform.slug,
            self.feature.name,
            self.description,
            self.config_ordered,
            self.match_config,
            self.config_type,
            self.custom_compliance,
            self.config_remediation,
        )

    class Meta:
        """Meta information for ComplianceRule model."""

        ordering = ("platform", "feature__name")
        unique_together = (
            "feature",
            "platform",
        )

    def __str__(self):
        """Return a sane string representation of the instance."""
        return f"{self.platform} - {self.feature.name}"

    def get_absolute_url(self):
        """Absolute url for the ComplianceRule instance."""
        return reverse("plugins:nautobot_golden_config:compliancerule", args=[self.pk])

    def clean(self):
        """Verify that if cli, then match_config is set."""
        if self.config_type == ComplianceRuleConfigTypeChoice.TYPE_CLI and not self.match_config:
            raise ValidationError("CLI configuration set, but no configuration set to match.")

remediation_setting property

Returns remediation settings for a particular platform.

Meta

Meta information for ComplianceRule model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Meta information for ComplianceRule model."""

    ordering = ("platform", "feature__name")
    unique_together = (
        "feature",
        "platform",
    )

__str__()

Return a sane string representation of the instance.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """Return a sane string representation of the instance."""
    return f"{self.platform} - {self.feature.name}"

clean()

Verify that if cli, then match_config is set.

Source code in nautobot_golden_config/models.py
def clean(self):
    """Verify that if cli, then match_config is set."""
    if self.config_type == ComplianceRuleConfigTypeChoice.TYPE_CLI and not self.match_config:
        raise ValidationError("CLI configuration set, but no configuration set to match.")

get_absolute_url()

Absolute url for the ComplianceRule instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Absolute url for the ComplianceRule instance."""
    return reverse("plugins:nautobot_golden_config:compliancerule", args=[self.pk])

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (
        self.platform.slug,
        self.feature.name,
        self.description,
        self.config_ordered,
        self.match_config,
        self.config_type,
        self.custom_compliance,
        self.config_remediation,
    )

ConfigCompliance

Bases: PrimaryModel

Configuration compliance details.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_links",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
)
class ConfigCompliance(PrimaryModel):  # pylint: disable=too-many-ancestors
    """Configuration compliance details."""

    device = models.ForeignKey(to="dcim.Device", on_delete=models.CASCADE, help_text="The device", blank=False)
    rule = models.ForeignKey(to="ComplianceRule", on_delete=models.CASCADE, blank=False, related_name="rule")
    compliance = models.BooleanField(null=True, blank=True)
    actual = models.JSONField(blank=True, help_text="Actual Configuration for feature")
    intended = models.JSONField(blank=True, help_text="Intended Configuration for feature")
    # these three are config snippets exposed for the ConfigDeployment.
    remediation = models.JSONField(blank=True, null=True, help_text="Remediation Configuration for the device")
    missing = models.JSONField(blank=True, help_text="Configuration that should be on the device.")
    extra = models.JSONField(blank=True, help_text="Configuration that should not be on the device.")
    ordered = models.BooleanField(default=True)
    # Used for django-pivot, both compliance and compliance_int should be set.
    compliance_int = models.IntegerField(null=True, blank=True)

    csv_headers = ["Device Name", "Feature", "Compliance"]

    def get_absolute_url(self):
        """Return absolute URL for instance."""
        return reverse("plugins:nautobot_golden_config:configcompliance", args=[self.pk])

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (self.device.name, self.rule.feature.name, self.compliance)

    def to_objectchange(
        self, action, *, related_object=None, object_data_extra=None, object_data_exclude=None
    ):  # pylint: disable=arguments-differ
        """Remove actual and intended configuration from changelog."""
        if not object_data_exclude:
            object_data_exclude = ["actual", "intended"]
        return ObjectChange(
            changed_object=self,
            object_repr=str(self),
            action=action,
            object_data=serialize_object(self, extra=object_data_extra, exclude=object_data_exclude),
            object_data_v2=serialize_object_v2(self),
            related_object=related_object,
        )

    class Meta:
        """Set unique together fields for model."""

        ordering = ["device", "rule"]
        unique_together = ("device", "rule")

    def __str__(self):
        """String representation of a the compliance."""
        return f"{self.device} -> {self.rule} -> {self.compliance}"

    def compliance_on_save(self):
        """The actual configuration compliance happens here, but the details for actual compliance job would be found in FUNC_MAPPER."""
        if self.rule.custom_compliance:
            if not FUNC_MAPPER.get("custom"):
                raise ValidationError(
                    "Custom type provided, but no `get_custom_compliance` config set, please contact system admin."
                )
            compliance_details = FUNC_MAPPER["custom"](obj=self)
            _verify_get_custom_compliance_data(compliance_details)
        else:
            compliance_details = FUNC_MAPPER[self.rule.config_type](obj=self)

        self.compliance = compliance_details["compliance"]
        self.compliance_int = compliance_details["compliance_int"]
        self.ordered = compliance_details["ordered"]
        self.missing = compliance_details["missing"]
        self.extra = compliance_details["extra"]

    def remediation_on_save(self):
        """The actual remediation happens here, before saving the object."""
        if self.compliance:
            self.remediation = None
            return

        if not self.rule.config_remediation:
            self.remediation = None
            return

        if not self.rule.remediation_setting:
            self.remediation = None
            return

        remediation_config = FUNC_MAPPER[self.rule.remediation_setting.remediation_type](obj=self)
        self.remediation = remediation_config

    def save(self, *args, **kwargs):
        """The actual configuration compliance happens here, but the details for actual compliance job would be found in FUNC_MAPPER."""
        self.compliance_on_save()
        self.remediation_on_save()

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

Meta

Set unique together fields for model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Set unique together fields for model."""

    ordering = ["device", "rule"]
    unique_together = ("device", "rule")

__str__()

String representation of a the compliance.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """String representation of a the compliance."""
    return f"{self.device} -> {self.rule} -> {self.compliance}"

compliance_on_save()

The actual configuration compliance happens here, but the details for actual compliance job would be found in FUNC_MAPPER.

Source code in nautobot_golden_config/models.py
def compliance_on_save(self):
    """The actual configuration compliance happens here, but the details for actual compliance job would be found in FUNC_MAPPER."""
    if self.rule.custom_compliance:
        if not FUNC_MAPPER.get("custom"):
            raise ValidationError(
                "Custom type provided, but no `get_custom_compliance` config set, please contact system admin."
            )
        compliance_details = FUNC_MAPPER["custom"](obj=self)
        _verify_get_custom_compliance_data(compliance_details)
    else:
        compliance_details = FUNC_MAPPER[self.rule.config_type](obj=self)

    self.compliance = compliance_details["compliance"]
    self.compliance_int = compliance_details["compliance_int"]
    self.ordered = compliance_details["ordered"]
    self.missing = compliance_details["missing"]
    self.extra = compliance_details["extra"]

get_absolute_url()

Return absolute URL for instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Return absolute URL for instance."""
    return reverse("plugins:nautobot_golden_config:configcompliance", args=[self.pk])

remediation_on_save()

The actual remediation happens here, before saving the object.

Source code in nautobot_golden_config/models.py
def remediation_on_save(self):
    """The actual remediation happens here, before saving the object."""
    if self.compliance:
        self.remediation = None
        return

    if not self.rule.config_remediation:
        self.remediation = None
        return

    if not self.rule.remediation_setting:
        self.remediation = None
        return

    remediation_config = FUNC_MAPPER[self.rule.remediation_setting.remediation_type](obj=self)
    self.remediation = remediation_config

save(*args, **kwargs)

The actual configuration compliance happens here, but the details for actual compliance job would be found in FUNC_MAPPER.

Source code in nautobot_golden_config/models.py
def save(self, *args, **kwargs):
    """The actual configuration compliance happens here, but the details for actual compliance job would be found in FUNC_MAPPER."""
    self.compliance_on_save()
    self.remediation_on_save()

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

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (self.device.name, self.rule.feature.name, self.compliance)

to_objectchange(action, *, related_object=None, object_data_extra=None, object_data_exclude=None)

Remove actual and intended configuration from changelog.

Source code in nautobot_golden_config/models.py
def to_objectchange(
    self, action, *, related_object=None, object_data_extra=None, object_data_exclude=None
):  # pylint: disable=arguments-differ
    """Remove actual and intended configuration from changelog."""
    if not object_data_exclude:
        object_data_exclude = ["actual", "intended"]
    return ObjectChange(
        changed_object=self,
        object_repr=str(self),
        action=action,
        object_data=serialize_object(self, extra=object_data_extra, exclude=object_data_exclude),
        object_data_v2=serialize_object_v2(self),
        related_object=related_object,
    )

ConfigPlan

Bases: PrimaryModel

ConfigPlan for Golden Configuration Plan Model definition.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_links",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
    "statuses",
)
class ConfigPlan(PrimaryModel):  # pylint: disable=too-many-ancestors
    """ConfigPlan for Golden Configuration Plan Model definition."""

    plan_type = models.CharField(max_length=20, choices=ConfigPlanTypeChoice, verbose_name="Plan Type")
    device = models.ForeignKey(
        to="dcim.Device",
        on_delete=models.CASCADE,
        related_name="config_plan",
    )
    config_set = models.TextField(help_text="Configuration set to be applied to device.")
    feature = models.ManyToManyField(
        to=ComplianceFeature,
        related_name="config_plan",
        blank=True,
    )
    plan_result = models.ForeignKey(
        to="extras.JobResult",
        on_delete=models.CASCADE,
        related_name="config_plan",
        verbose_name="Plan Result",
    )
    deploy_result = models.ForeignKey(
        to="extras.JobResult",
        on_delete=models.PROTECT,
        related_name="config_plan_deploy_result",
        verbose_name="Deploy Result",
        blank=True,
        null=True,
    )
    change_control_id = models.CharField(
        max_length=50,
        blank=True,
        verbose_name="Change Control ID",
        help_text="Change Control ID for this configuration plan.",
    )
    change_control_url = models.URLField(blank=True, verbose_name="Change Control URL")
    status = StatusField(blank=True, null=True, on_delete=models.PROTECT)

    class Meta:
        """Meta information for ConfigPlan model."""

        ordering = ("-created", "device")

    def __str__(self):
        """Return a simple string if model is called."""
        return f"{self.device.name}-{self.plan_type}-{self.created}"

    def get_absolute_url(self):
        """Return absolute URL for instance."""
        return reverse("plugins:nautobot_golden_config:configplan", args=[self.pk])

Meta

Meta information for ConfigPlan model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Meta information for ConfigPlan model."""

    ordering = ("-created", "device")

__str__()

Return a simple string if model is called.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """Return a simple string if model is called."""
    return f"{self.device.name}-{self.plan_type}-{self.created}"

get_absolute_url()

Return absolute URL for instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Return absolute URL for instance."""
    return reverse("plugins:nautobot_golden_config:configplan", args=[self.pk])

ConfigRemove

Bases: PrimaryModel

ConfigRemove for Regex Line Removals from Backup Configuration Model definition.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_links",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
)
class ConfigRemove(PrimaryModel):  # pylint: disable=too-many-ancestors
    """ConfigRemove for Regex Line Removals from Backup Configuration Model definition."""

    name = models.CharField(max_length=255, null=False, blank=False)
    platform = models.ForeignKey(
        to="dcim.Platform",
        on_delete=models.CASCADE,
        related_name="backup_line_remove",
        null=False,
        blank=False,
    )
    description = models.CharField(
        max_length=200,
        blank=True,
    )
    regex = models.CharField(
        max_length=200,
        verbose_name="Regex Pattern",
        help_text="Regex pattern used to remove a line from the backup configuration.",
    )

    clone_fields = ["platform", "description", "regex"]
    csv_headers = ["name", "platform", "description", "regex"]

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (self.name, self.platform.slug, self.regex)

    class Meta:
        """Meta information for ConfigRemove model."""

        ordering = ("platform", "name")
        unique_together = ("name", "platform")

    def __str__(self):
        """Return a simple string if model is called."""
        return self.name

    def get_absolute_url(self):
        """Return absolute URL for instance."""
        return reverse("plugins:nautobot_golden_config:configremove", args=[self.pk])

Meta

Meta information for ConfigRemove model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Meta information for ConfigRemove model."""

    ordering = ("platform", "name")
    unique_together = ("name", "platform")

__str__()

Return a simple string if model is called.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """Return a simple string if model is called."""
    return self.name

get_absolute_url()

Return absolute URL for instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Return absolute URL for instance."""
    return reverse("plugins:nautobot_golden_config:configremove", args=[self.pk])

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (self.name, self.platform.slug, self.regex)

ConfigReplace

Bases: PrimaryModel

ConfigReplace for Regex Line Replacements from Backup Configuration Model definition.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_links",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
)
class ConfigReplace(PrimaryModel):  # pylint: disable=too-many-ancestors
    """ConfigReplace for Regex Line Replacements from Backup Configuration Model definition."""

    name = models.CharField(max_length=255, null=False, blank=False)
    platform = models.ForeignKey(
        to="dcim.Platform",
        on_delete=models.CASCADE,
        related_name="backup_line_replace",
        null=False,
        blank=False,
    )
    description = models.CharField(
        max_length=200,
        blank=True,
    )
    regex = models.CharField(
        max_length=200,
        verbose_name="Regex Pattern to Substitute",
        help_text="Regex pattern that will be found and replaced with 'replaced text'.",
    )
    replace = models.CharField(
        max_length=200,
        verbose_name="Replaced Text",
        help_text="Text that will be inserted in place of Regex pattern match.",
    )

    clone_fields = ["platform", "description", "regex", "replace"]
    csv_headers = ["name", "platform", "description", "regex", "replace"]

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (self.name, self.platform.slug, self.description, self.regex, self.replace)

    class Meta:
        """Meta information for ConfigReplace model."""

        ordering = ("platform", "name")
        unique_together = ("name", "platform")

    def get_absolute_url(self):
        """Return absolute URL for instance."""
        return reverse("plugins:nautobot_golden_config:configreplace", args=[self.pk])

    def __str__(self):
        """Return a simple string if model is called."""
        return self.name

Meta

Meta information for ConfigReplace model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Meta information for ConfigReplace model."""

    ordering = ("platform", "name")
    unique_together = ("name", "platform")

__str__()

Return a simple string if model is called.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """Return a simple string if model is called."""
    return self.name

get_absolute_url()

Return absolute URL for instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Return absolute URL for instance."""
    return reverse("plugins:nautobot_golden_config:configreplace", args=[self.pk])

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (self.name, self.platform.slug, self.description, self.regex, self.replace)

GoldenConfig

Bases: PrimaryModel

Configuration Management Model.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_links",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
)
class GoldenConfig(PrimaryModel):  # pylint: disable=too-many-ancestors
    """Configuration Management Model."""

    device = models.ForeignKey(
        to="dcim.Device",
        on_delete=models.CASCADE,
        help_text="device",
        blank=False,
    )
    backup_config = models.TextField(blank=True, help_text="Full backup config for device.")
    backup_last_attempt_date = models.DateTimeField(null=True)
    backup_last_success_date = models.DateTimeField(null=True)

    intended_config = models.TextField(blank=True, help_text="Intended config for the device.")
    intended_last_attempt_date = models.DateTimeField(null=True)
    intended_last_success_date = models.DateTimeField(null=True)

    compliance_config = models.TextField(blank=True, help_text="Full config diff for device.")
    compliance_last_attempt_date = models.DateTimeField(null=True)
    compliance_last_success_date = models.DateTimeField(null=True)

    csv_headers = [
        "Device Name",
        "backup attempt",
        "backup successful",
        "intended attempt",
        "intended successful",
        "compliance attempt",
        "compliance successful",
    ]

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (
            self.device,
            self.backup_last_attempt_date,
            self.backup_last_success_date,
            self.intended_last_attempt_date,
            self.intended_last_success_date,
            self.compliance_last_attempt_date,
            self.compliance_last_success_date,
        )

    def to_objectchange(
        self, action, *, related_object=None, object_data_extra=None, object_data_exclude=None
    ):  # pylint: disable=arguments-differ
        """Remove actual and intended configuration from changelog."""
        if not object_data_exclude:
            object_data_exclude = ["backup_config", "intended_config", "compliance_config"]
        return ObjectChange(
            changed_object=self,
            object_repr=str(self),
            action=action,
            object_data=serialize_object(self, extra=object_data_extra, exclude=object_data_exclude),
            object_data_v2=serialize_object_v2(self),
            related_object=related_object,
        )

    class Meta:
        """Set unique together fields for model."""

        ordering = ["device"]

    def __str__(self):
        """String representation of a the compliance."""
        return f"{self.device}"

Meta

Set unique together fields for model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Set unique together fields for model."""

    ordering = ["device"]

__str__()

String representation of a the compliance.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """String representation of a the compliance."""
    return f"{self.device}"

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (
        self.device,
        self.backup_last_attempt_date,
        self.backup_last_success_date,
        self.intended_last_attempt_date,
        self.intended_last_success_date,
        self.compliance_last_attempt_date,
        self.compliance_last_success_date,
    )

to_objectchange(action, *, related_object=None, object_data_extra=None, object_data_exclude=None)

Remove actual and intended configuration from changelog.

Source code in nautobot_golden_config/models.py
def to_objectchange(
    self, action, *, related_object=None, object_data_extra=None, object_data_exclude=None
):  # pylint: disable=arguments-differ
    """Remove actual and intended configuration from changelog."""
    if not object_data_exclude:
        object_data_exclude = ["backup_config", "intended_config", "compliance_config"]
    return ObjectChange(
        changed_object=self,
        object_repr=str(self),
        action=action,
        object_data=serialize_object(self, extra=object_data_extra, exclude=object_data_exclude),
        object_data_v2=serialize_object_v2(self),
        related_object=related_object,
    )

GoldenConfigSetting

Bases: PrimaryModel

GoldenConfigSetting Model definition. This provides global configs instead of via configs.py.

Source code in nautobot_golden_config/models.py
@extras_features(
    "graphql",
)
class GoldenConfigSetting(PrimaryModel):  # pylint: disable=too-many-ancestors
    """GoldenConfigSetting Model definition. This provides global configs instead of via configs.py."""

    name = models.CharField(max_length=100, unique=True, blank=False)
    slug = models.SlugField(max_length=100, unique=True, blank=False)
    weight = models.PositiveSmallIntegerField(default=1000, blank=False)
    description = models.CharField(
        max_length=200,
        blank=True,
    )
    backup_repository = models.ForeignKey(
        to="extras.GitRepository",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="backup_repository",
        limit_choices_to={"provided_contents__contains": "nautobot_golden_config.backupconfigs"},
    )
    backup_path_template = models.CharField(
        max_length=255,
        null=False,
        blank=True,
        verbose_name="Backup Path in Jinja Template Form",
        help_text="The Jinja path representation of where the backup file will be found. The variable `obj` is available as the device instance object of a given device, as is the case for all Jinja templates. e.g. `{{obj.site.slug}}/{{obj.name}}.cfg`",
    )
    intended_repository = models.ForeignKey(
        to="extras.GitRepository",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="intended_repository",
        limit_choices_to={"provided_contents__contains": "nautobot_golden_config.intendedconfigs"},
    )
    intended_path_template = models.CharField(
        max_length=255,
        null=False,
        blank=True,
        verbose_name="Intended Path in Jinja Template Form",
        help_text="The Jinja path representation of where the generated file will be places. e.g. `{{obj.site.slug}}/{{obj.name}}.cfg`",
    )
    jinja_repository = models.ForeignKey(
        to="extras.GitRepository",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="jinja_template",
        limit_choices_to={"provided_contents__contains": "nautobot_golden_config.jinjatemplate"},
    )
    jinja_path_template = models.CharField(
        max_length=255,
        null=False,
        blank=True,
        verbose_name="Template Path in Jinja Template Form",
        help_text="The Jinja path representation of where the Jinja template can be found. e.g. `{{obj.platform.slug}}.j2`",
    )
    backup_test_connectivity = models.BooleanField(
        null=False,
        default=True,
        verbose_name="Backup Test",
        help_text="Whether or not to pretest the connectivity of the device by verifying there is a resolvable IP that can connect to port 22.",
    )
    sot_agg_query = models.ForeignKey(
        to="extras.GraphQLQuery",
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name="sot_aggregation",
    )
    dynamic_group = models.OneToOneField(
        to="extras.DynamicGroup",
        on_delete=models.PROTECT,
        related_name="golden_config_setting",
    )

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

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (
            self.name,
            self.slug,
            self.weight,
            self.description,
        )

    def get_absolute_url(self):
        """Return absolute URL for instance."""
        return reverse("plugins:nautobot_golden_config:goldenconfigsetting", args=[self.pk])

    def __str__(self):
        """Return a simple string if model is called."""
        return f"Golden Config Setting - {self.name}"

    @property
    def scope(self):
        """Returns filter from DynamicGroup."""
        if self.dynamic_group:
            return self.dynamic_group.filter
        return {}

    @scope.setter
    def scope(self, value):
        """Create DynamicGroup based on original scope JSON data."""
        if hasattr(self, "dynamic_group"):
            self.dynamic_group.filter = value
            self.dynamic_group.validated_save()
        else:
            name = f"GoldenConfigSetting {self.name} scope"
            content_type = ContentType.objects.get(app_label="dcim", model="device")
            dynamic_group = DynamicGroup.objects.create(
                name=name,
                slug=slugify(name),
                filter=value,
                content_type=content_type,
                description="Automatically generated for nautobot_golden_config GoldenConfigSetting.",
            )
            self.dynamic_group = dynamic_group
            self.validated_save()

    class Meta:
        """Set unique fields for model.

        Provide ordering used in tables and get_device_to_settings_map.
        Sorting on weight is performed from the highest weight value to the lowest weight value.
        This is to ensure only one plugin settings could be applied per single device based on priority and name.
        """

        verbose_name = "Golden Config Setting"
        ordering = ["-weight", "name"]  # Refer to weight comment in class docstring.

    def clean(self):
        """Validate the scope and GraphQL query."""
        super().clean()

        if ENABLE_SOTAGG and not self.sot_agg_query:
            raise ValidationError("A GraphQL query must be defined when `ENABLE_SOTAGG` is True")

        if self.sot_agg_query:
            LOGGER.debug("GraphQL - test  query start with: `%s`", GRAPHQL_STR_START)
            if not str(self.sot_agg_query.query.lstrip()).startswith(GRAPHQL_STR_START):
                raise ValidationError(f"The GraphQL query must start with exactly `{GRAPHQL_STR_START}`")

    def get_queryset(self):
        """Generate a Device QuerySet from the filter."""
        return self.dynamic_group.members

    def device_count(self):
        """Return the number of devices in the group."""
        return self.dynamic_group.count

    def get_url_to_filtered_device_list(self):
        """Get url to all devices that are matching the filter."""
        return self.dynamic_group.get_group_members_url()

scope property writable

Returns filter from DynamicGroup.

Meta

Set unique fields for model.

Provide ordering used in tables and get_device_to_settings_map. Sorting on weight is performed from the highest weight value to the lowest weight value. This is to ensure only one plugin settings could be applied per single device based on priority and name.

Source code in nautobot_golden_config/models.py
class Meta:
    """Set unique fields for model.

    Provide ordering used in tables and get_device_to_settings_map.
    Sorting on weight is performed from the highest weight value to the lowest weight value.
    This is to ensure only one plugin settings could be applied per single device based on priority and name.
    """

    verbose_name = "Golden Config Setting"
    ordering = ["-weight", "name"]  # Refer to weight comment in class docstring.

__str__()

Return a simple string if model is called.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """Return a simple string if model is called."""
    return f"Golden Config Setting - {self.name}"

clean()

Validate the scope and GraphQL query.

Source code in nautobot_golden_config/models.py
def clean(self):
    """Validate the scope and GraphQL query."""
    super().clean()

    if ENABLE_SOTAGG and not self.sot_agg_query:
        raise ValidationError("A GraphQL query must be defined when `ENABLE_SOTAGG` is True")

    if self.sot_agg_query:
        LOGGER.debug("GraphQL - test  query start with: `%s`", GRAPHQL_STR_START)
        if not str(self.sot_agg_query.query.lstrip()).startswith(GRAPHQL_STR_START):
            raise ValidationError(f"The GraphQL query must start with exactly `{GRAPHQL_STR_START}`")

device_count()

Return the number of devices in the group.

Source code in nautobot_golden_config/models.py
def device_count(self):
    """Return the number of devices in the group."""
    return self.dynamic_group.count

get_absolute_url()

Return absolute URL for instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Return absolute URL for instance."""
    return reverse("plugins:nautobot_golden_config:goldenconfigsetting", args=[self.pk])

get_queryset()

Generate a Device QuerySet from the filter.

Source code in nautobot_golden_config/models.py
def get_queryset(self):
    """Generate a Device QuerySet from the filter."""
    return self.dynamic_group.members

get_url_to_filtered_device_list()

Get url to all devices that are matching the filter.

Source code in nautobot_golden_config/models.py
def get_url_to_filtered_device_list(self):
    """Get url to all devices that are matching the filter."""
    return self.dynamic_group.get_group_members_url()

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (
        self.name,
        self.slug,
        self.weight,
        self.description,
    )

RemediationSetting

Bases: PrimaryModel

RemediationSetting details.

Source code in nautobot_golden_config/models.py
@extras_features(
    "custom_fields",
    "custom_links",
    "custom_validators",
    "export_templates",
    "graphql",
    "relationships",
    "webhooks",
)
class RemediationSetting(PrimaryModel):  # pylint: disable=too-many-ancestors
    """RemediationSetting details."""

    # Remediation points to the platform
    platform = models.OneToOneField(
        to="dcim.Platform",
        on_delete=models.CASCADE,
        related_name="remediation_settings",
    )

    remediation_type = models.CharField(
        max_length=50,
        default=RemediationTypeChoice.TYPE_HIERCONFIG,
        choices=RemediationTypeChoice,
        help_text="Whether the remediation setting is type HierConfig or custom.",
    )

    # takes options.json.
    remediation_options = models.JSONField(
        blank=True,
        default=dict,
        help_text="Remediation Configuration for the device",
    )

    csv_headers = [
        "platform",
        "remediation_type",
    ]

    class Meta:
        """Meta information for RemediationSettings model."""

        ordering = ("platform", "remediation_type")

    def to_csv(self):
        """Indicates model fields to return as csv."""
        return (
            self.platform,
            self.remediation_type,
        )

    def __str__(self):
        """Return a sane string representation of the instance."""
        return str(self.platform.slug)

    def get_absolute_url(self):
        """Absolute url for the RemediationRule instance."""
        return reverse("plugins:nautobot_golden_config:remediationsetting", args=[self.pk])

Meta

Meta information for RemediationSettings model.

Source code in nautobot_golden_config/models.py
class Meta:
    """Meta information for RemediationSettings model."""

    ordering = ("platform", "remediation_type")

__str__()

Return a sane string representation of the instance.

Source code in nautobot_golden_config/models.py
def __str__(self):
    """Return a sane string representation of the instance."""
    return str(self.platform.slug)

get_absolute_url()

Absolute url for the RemediationRule instance.

Source code in nautobot_golden_config/models.py
def get_absolute_url(self):
    """Absolute url for the RemediationRule instance."""
    return reverse("plugins:nautobot_golden_config:remediationsetting", args=[self.pk])

to_csv()

Indicates model fields to return as csv.

Source code in nautobot_golden_config/models.py
def to_csv(self):
    """Indicates model fields to return as csv."""
    return (
        self.platform,
        self.remediation_type,
    )