Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ Change status from Design to Design Instance #84

Merged
merged 8 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions nautobot_design_builder/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
"""Plugin declaration for design_builder."""
from importlib import metadata

from django.conf import settings
from django.utils.functional import classproperty
from nautobot.extras.plugins import PluginConfig

# Metadata is inherited from Nautobot. If not including Nautobot in the environment, this should be added
try:
from importlib import metadata
except ImportError:
# Python version < 3.8
import importlib_metadata as metadata

__version__ = metadata.version(__name__)


Expand All @@ -30,7 +25,7 @@ class DesignBuilderConfig(PluginConfig):

def ready(self):
super().ready()
from . import signals # noqa: F401
from . import signals # noqa:F401 pylint:disable=import-outside-toplevel,unused-import,cyclic-import

# pylint: disable=no-self-argument
@classproperty
Expand Down
18 changes: 12 additions & 6 deletions nautobot_design_builder/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Serializers for design builder."""
from django.contrib.contenttypes.models import ContentType
from drf_spectacular.utils import extend_schema_field
from nautobot.apps.api import NautobotModelSerializer, TaggedModelSerializerMixin
from nautobot.apps.api import NautobotModelSerializer, TaggedModelSerializerMixin, StatusModelSerializerMixin
from nautobot.core.api import ContentTypeField
from nautobot.extras.api.nested_serializers import NestedJobResultSerializer
from nautobot.extras.api.nested_serializers import NestedJobResultSerializer, NestedStatusSerializer
from nautobot.utilities.api import get_serializer_for_model
from rest_framework.fields import SerializerMethodField, DictField
from rest_framework.relations import HyperlinkedIdentityField
Expand Down Expand Up @@ -33,11 +33,12 @@ class Meta:
]


class DesignInstanceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
class DesignInstanceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin, StatusModelSerializerMixin):
"""Serializer for the design instance model."""

url = HyperlinkedIdentityField(view_name="plugins-api:nautobot_design_builder-api:design-detail")
design = NestedDesignSerializer()
live_state = NestedStatusSerializer()

class Meta:
"""Serializer options for the design model."""
Expand All @@ -51,6 +52,8 @@ class Meta:
"owner",
"first_implemented",
"last_implemented",
"status",
"live_state",
]


Expand Down Expand Up @@ -84,6 +87,9 @@ class Meta:

@extend_schema_field(DictField())
def get_design_object(self, obj):
serializer = get_serializer_for_model(obj.design_object, prefix="Nested")
context = {"request": self.context["request"]}
return serializer(obj.design_object, context=context).data
"""Get design object serialized."""
if obj.design_object:
serializer = get_serializer_for_model(obj.design_object, prefix="Nested")
context = {"request": self.context["request"]}
return serializer(obj.design_object, context=context).data
return None
4 changes: 2 additions & 2 deletions nautobot_design_builder/api/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""UI Views for design builder."""
from nautobot.extras.api.views import NautobotModelViewSet
from nautobot.extras.api.views import NautobotModelViewSet, StatusViewSetMixin

from nautobot_design_builder.api.serializers import (
DesignSerializer,
Expand All @@ -24,7 +24,7 @@ class DesignAPIViewSet(NautobotModelViewSet):
filterset_class = DesignFilterSet


class DesignInstanceAPIViewSet(NautobotModelViewSet):
class DesignInstanceAPIViewSet(NautobotModelViewSet, StatusViewSetMixin):
"""API views for the design instance model."""

queryset = DesignInstance.objects.all()
Expand Down
20 changes: 16 additions & 4 deletions nautobot_design_builder/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@
from nautobot.utilities.choices import ChoiceSet


class DesignStatusChoices(ChoiceSet):
"""Status choices for Designs."""
class DesignInstanceStatusChoices(ChoiceSet):
"""Status choices for Designs Instances."""

PENDING = "Pending"
ACTIVE = "Active"
DISABLED = "Disabled"
DECOMMISSIONED = "Decommissioned"

CHOICES = (
(PENDING, PENDING),
(ACTIVE, ACTIVE),
(DISABLED, DISABLED),
(DECOMMISSIONED, DECOMMISSIONED),
)


class DesignInstanceLiveStateChoices(ChoiceSet):
"""Status choices for Live State Designs Instance."""

DEPLOYED = "Deployed"
PENDING = "Pending"
ROLLBACKED = "Rollbacked"

CHOICES = (
(DEPLOYED, DEPLOYED),
(PENDING, PENDING),
(ROLLBACKED, ROLLBACKED),
)
2 changes: 2 additions & 0 deletions nautobot_design_builder/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ def _load_instance(self):
elif self.action != "create":
raise errors.DesignImplementationError(f"Unknown database action {self.action}", self.model_class)
self._initial_state = {}
if not self.instance:
self.created = True
self.instance = self.model_class()

def _update_fields(self): # pylint: disable=too-many-branches
Expand Down
12 changes: 10 additions & 2 deletions nautobot_design_builder/design_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import traceback
from abc import ABC, abstractmethod
from os import path
import yaml
from datetime import datetime
import yaml
from django.db import transaction
from django.contrib.contenttypes.models import ContentType

from jinja2 import TemplateError

from nautobot.extras.models import Status
from nautobot.extras.jobs import Job, StringVar


Expand All @@ -18,6 +20,7 @@
from nautobot_design_builder.design import Builder
from nautobot_design_builder.context import Context
from nautobot_design_builder import models
from nautobot_design_builder import choices

from .util import nautobot_version

Expand Down Expand Up @@ -54,6 +57,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def design_model(self):
"""Get the related Job."""
return models.Design.objects.for_design_job(self.job_result.job_model)

def post_implementation(self, context: Context, builder: Builder):
Expand Down Expand Up @@ -161,11 +165,16 @@ def _setup_journal(self, instance_name: str, design_owner: str):
instance.last_implemented = datetime.now()
except models.DesignInstance.DoesNotExist:
self.log_info(message=f'Implementing new design "{instance_name}".')
content_type = ContentType.objects.get_for_model(models.DesignInstance)
instance = models.DesignInstance(
name=instance_name,
owner=design_owner,
design=self.design_model(),
last_implemented=datetime.now(),
status=Status.objects.get(content_types=content_type, name=choices.DesignInstanceStatusChoices.ACTIVE),
live_state=Status.objects.get(
content_types=content_type, name=choices.DesignInstanceLiveStateChoices.PENDING
),
)
instance.validated_save()

Expand All @@ -179,7 +188,6 @@ def _setup_journal(self, instance_name: str, design_owner: str):
@transaction.atomic
def run(self, **kwargs): # pylint: disable=arguments-differ,too-many-branches
"""Render the design and implement it with a Builder object."""

if nautobot_version < "2.0.0":
commit = kwargs["commit"]
data = kwargs["data"]
Expand Down
12 changes: 9 additions & 3 deletions nautobot_design_builder/filters.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
"""Filters for the design builder app."""
from nautobot.apps.filters import NautobotFilterSet, NaturalKeyOrPKMultipleChoiceFilter
from nautobot.apps.filters import NautobotFilterSet, NaturalKeyOrPKMultipleChoiceFilter, StatusModelFilterSetMixin
from nautobot.extras.models import Job, JobResult
from nautobot.utilities.filters import SearchFilter
from nautobot.extras.filters.mixins import StatusFilter

from nautobot_design_builder.models import Design, DesignInstance, Journal, JournalEntry


class DesignFilterSet(NautobotFilterSet):
"""Filter set for the design model."""

q = SearchFilter(filter_predicates={})

job = NaturalKeyOrPKMultipleChoiceFilter(
Expand All @@ -22,9 +24,11 @@ class Meta:
fields = ["id", "job"]


class DesignInstanceFilterSet(NautobotFilterSet):
class DesignInstanceFilterSet(NautobotFilterSet, StatusModelFilterSetMixin):
"""Filter set for the design instance model."""

q = SearchFilter(filter_predicates={})
live_state = StatusFilter()

design = NaturalKeyOrPKMultipleChoiceFilter(
queryset=Design.objects.all(),
Expand All @@ -35,11 +39,12 @@ class Meta:
"""Meta attributes for filter."""

model = DesignInstance
fields = ["id", "design", "name", "owner", "first_implemented", "last_implemented"]
fields = ["id", "design", "name", "owner", "first_implemented", "last_implemented", "status", "live_state"]


class JournalFilterSet(NautobotFilterSet):
"""Filter set for the journal model."""

q = SearchFilter(filter_predicates={})

design_instance = NaturalKeyOrPKMultipleChoiceFilter(
Expand All @@ -61,6 +66,7 @@ class Meta:

class JournalEntryFilterSet(NautobotFilterSet):
"""Filter set for the journal entrymodel."""

q = SearchFilter(filter_predicates={})

journal = NaturalKeyOrPKMultipleChoiceFilter(
Expand Down
50 changes: 50 additions & 0 deletions nautobot_design_builder/migrations/0002_statuses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Generated by Django 3.2.23 on 2023-12-11 08:24

from django.db import migrations, models
import django.db.models.deletion
import nautobot.extras.models.statuses


class Migration(migrations.Migration):
dependencies = [
("extras", "0058_jobresult_add_time_status_idxs"),
("nautobot_design_builder", "0001_initial"),
]

operations = [
migrations.RemoveField(
model_name="design",
name="status",
),
migrations.AddField(
model_name="designinstance",
name="live_state",
field=nautobot.extras.models.statuses.StatusField(
null=True, on_delete=django.db.models.deletion.PROTECT, to="extras.status"
),
),
migrations.AddField(
model_name="designinstance",
name="status",
field=nautobot.extras.models.statuses.StatusField(
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="nautobot_design_builder_designinstance_related",
to="extras.status",
),
),
migrations.AlterField(
model_name="designinstance",
name="first_implemented",
field=models.DateTimeField(auto_now_add=True, null=True),
),
migrations.AlterField(
model_name="journalentry",
name="journal",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="entries",
to="nautobot_design_builder.journal",
),
),
]
Loading
Loading