Skip to content

Commit

Permalink
implement plan_result and deploy_result
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffkala committed Sep 15, 2023
1 parent f88b8c3 commit 0352cf8
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 84 deletions.
8 changes: 6 additions & 2 deletions nautobot_golden_config/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,13 @@ class ConfigPlanFilterSet(NautobotFilterSet):
to_field_name="name",
label="Feature Name",
)
job_result_id = django_filters.ModelMultipleChoiceFilter(
plan_result_id = django_filters.ModelMultipleChoiceFilter(
queryset=JobResult.objects.filter(config_plan__isnull=False).distinct(),
label="JobResult ID",
label="Plan JobResult ID",
)
deploy_result_id = django_filters.ModelMultipleChoiceFilter(
queryset=JobResult.objects.filter(config_plan__isnull=False).distinct(),
label="Deploy JobResult ID",
)
change_control_id = django_filters.CharFilter(
field_name="change_control_id",
Expand Down
11 changes: 9 additions & 2 deletions nautobot_golden_config/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,10 +552,17 @@ class ConfigPlanFilterForm(NautobotFilterForm):
to_field_name="name",
)
change_control_id = forms.CharField(required=False, label="Change Control ID")
job_result_id = utilities_forms.DynamicModelMultipleChoiceField(
plan_result_id = utilities_forms.DynamicModelMultipleChoiceField(
queryset=JobResult.objects.all(),
query_params={"nautobot_golden_config_config_plan_null": True},
label="Job Result",
label="Plan Result",
required=False,
display_field="id",
)
deploy_result_id = utilities_forms.DynamicModelMultipleChoiceField(
queryset=JobResult.objects.all(),
query_params={"nautobot_golden_config_config_plan_null": True},
label="Deploy Result",
required=False,
display_field="id",
)
Expand Down
4 changes: 2 additions & 2 deletions nautobot_golden_config/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ def _generate_config_plan_from_feature(self):
change_control_id=self._change_control_id,
change_control_url=self._change_control_url,
status=self._status,
job_result=self.job_result,
plan_result=self.job_result,
)
config_plan.feature.set(features)
config_plan.validated_save()
Expand All @@ -325,7 +325,7 @@ def _generate_config_plan_from_manual(self):
change_control_id=self._change_control_id,
change_control_url=self._change_control_url,
status=self._status,
job_result=self.job_result,
plan_result=self.job_result,
)
self.log_success(obj=config_plan, message=f"Config plan created for {device} with manual commands.")

Expand Down
22 changes: 0 additions & 22 deletions nautobot_golden_config/migrations/0027_auto_20230912_1731.py

This file was deleted.

40 changes: 40 additions & 0 deletions nautobot_golden_config/migrations/0027_auto_20230915_1635.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 3.2.20 on 2023-09-15 16:35

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
("extras", "0058_jobresult_add_time_status_idxs"),
("nautobot_golden_config", "0026_configplan"),
]

operations = [
migrations.AlterModelOptions(
name="remediationsetting",
options={"ordering": ("platform", "remediation_type")},
),
migrations.RenameField(
model_name="configplan",
old_name="job_result",
new_name="plan_result",
),
migrations.AddField(
model_name="configplan",
name="deploy_result",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="config_plan_deploy_result",
to="extras.jobresult",
),
),
migrations.AlterField(
model_name="configplan",
name="change_control_id",
field=models.CharField(blank=True, default="", max_length=50),
preserve_default=False,
),
]
13 changes: 11 additions & 2 deletions nautobot_golden_config/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from nautobot.utilities.utils import serialize_object, serialize_object_v2
from netutils.config.compliance import feature_compliance
from netutils.lib_mapper import HIERCONFIG_LIB_MAPPER_REVERSE

from nautobot_golden_config.choices import ComplianceRuleConfigTypeChoice, ConfigPlanTypeChoice, RemediationTypeChoice
from nautobot_golden_config.utilities.constant import ENABLE_SOTAGG, PLUGIN_CFG
from nautobot_golden_config.utilities.utils import get_platform
Expand Down Expand Up @@ -865,11 +866,19 @@ class ConfigPlan(PrimaryModel): # pylint: disable=too-many-ancestors
related_name="config_plan",
blank=True,
)
job_result = models.ForeignKey(
plan_result = models.ForeignKey(
to="extras.JobResult",
on_delete=models.CASCADE,
related_name="config_plan",
verbose_name="Job Result",
verbose_name="Plan Result",
)
deploy_result = models.ForeignKey(
to="extras.JobResult",
on_delete=models.CASCADE,
related_name="config_plan_deploy_result",
verbose_name="Deploy Result",
blank=True,
null=True,
)
change_control_id = models.CharField(
max_length=50,
Expand Down
7 changes: 5 additions & 2 deletions nautobot_golden_config/nornir_plays/config_deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
InventoryPluginRegister.register("nautobot-inventory", NautobotORMInventory)


def run_deployment(task: Task, logger: NornirLogger, commit: bool, config_plan_qs) -> Result:
def run_deployment(task: Task, logger: NornirLogger, commit: bool, config_plan_qs, deploy_job_result) -> Result:
"""Deploy configurations to device."""
obj = task.host.data["obj"]
plans_to_deploy = config_plan_qs.filter(device=obj)
plans_to_deploy.update(deploy_result=deploy_job_result.job_result)
consolidated_config_set = "\n".join(plans_to_deploy.values_list("config_set", flat=True))
logger.log_debug(f"Consolidated config set: {consolidated_config_set}")
# TODO: We should add post-processing rendering here
Expand Down Expand Up @@ -67,7 +68,8 @@ def config_deployment(job_result, data, commit):
now = datetime.now()
logger = NornirLogger(__name__, job_result, data.get("debug"))
logger.log_debug("Starting config deployment")

logger.log_debug(f"{dir(job_result)}")
logger.log_debug(f"{type(job_result)}")
config_plan_qs = data["config_plan"]
if config_plan_qs.filter(status__slug="not-approved").exists():
logger.log_failure(
Expand Down Expand Up @@ -99,6 +101,7 @@ def config_deployment(job_result, data, commit):
logger=logger,
commit=commit,
config_plan_qs=config_plan_qs,
deploy_job_result=job_result,
)
except Exception as err:
logger.log_failure(obj=None, message=f"Failed to initialize Nornir: {err}")
Expand Down
35 changes: 18 additions & 17 deletions nautobot_golden_config/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,11 @@
from django.utils.html import format_html
from django_tables2 import Column, LinkColumn, TemplateColumn
from django_tables2.utils import A

from nautobot.extras.tables import StatusTableMixin
from nautobot.utilities.tables import (
BaseTable,
ToggleColumn,
TagColumn,
)
from nautobot_golden_config import models
from nautobot_golden_config.utilities.constant import (
ENABLE_BACKUP,
ENABLE_COMPLIANCE,
ENABLE_INTENDED,
CONFIG_FEATURES,
)
from nautobot.utilities.tables import BaseTable, TagColumn, ToggleColumn

from nautobot_golden_config import models
from nautobot_golden_config.utilities.constant import CONFIG_FEATURES, ENABLE_BACKUP, ENABLE_COMPLIANCE, ENABLE_INTENDED

ALL_ACTIONS = """
{% if backup == True %}
Expand Down Expand Up @@ -496,8 +486,17 @@ class ConfigPlanTable(StatusTableMixin, BaseTable):

pk = ToggleColumn()
device = LinkColumn("plugins:nautobot_golden_config:configplan", args=[A("pk")])
job_result = TemplateColumn(
template_code="""<a href="{% url 'extras:jobresult' pk=record.job_result.pk %}" <i class="mdi mdi-clipboard-text-play-outline"></i></a> """
plan_result = TemplateColumn(
template_code="""<a href="{% url 'extras:jobresult' pk=record.plan_result.pk %}" <i class="mdi mdi-clipboard-text-play-outline"></i></a> """
)
deploy_result = TemplateColumn(
template_code="""
{% if record.deploy_result %}
<a href="{% url 'extras:jobresult' pk=record.deploy_result.pk %}" <i class="mdi mdi-clipboard-text-play-outline"></i></a>
{% else %}
&mdash;
{% endif %}
"""
)
config_set = TemplateColumn(template_code=CONFIG_SET_BUTTON, verbose_name="Config Set", orderable=False)
tags = TagColumn(url_name="plugins:nautobot_golden_config:configplan_list")
Expand All @@ -514,7 +513,8 @@ class Meta(BaseTable.Meta):
"feature",
"change_control_id",
"change_control_url",
"job_result",
"plan_result",
"deploy_result",
"config_set",
"status",
"tags",
Expand All @@ -527,7 +527,8 @@ class Meta(BaseTable.Meta):
"feature",
"change_control_id",
"change_control_url",
"job_result",
"plan_result",
"deploy_result",
"config_set",
"status",
)
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@

function configPlanCount(jobResultId) {
return new Promise(function(resolve, reject) {
var configPlanApi = `/api/plugins/golden-config/config-plan/?job_result_id=${jobResultId}`;
var configPlanApi = `/api/plugins/golden-config/config-plan/?plan_result_id=${jobResultId}`;
$.ajax({
url: configPlanApi,
type: "GET",
Expand Down Expand Up @@ -108,7 +108,7 @@
}

var jobClass = "plugins/nautobot_golden_config.jobs/GenerateConfigPlans";
var redirectUrlTemplate = "/plugins/golden-config/config-plan/?job_result_id={jobData.result.id}";
var redirectUrlTemplate = "/plugins/golden-config/config-plan/?play_result_id={jobData.result.id}";
var changeControlUrlInput = document.getElementById("id_change_control_url");
var startJobButton = document.getElementById("startJob");
var form = document.querySelector("form");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,17 @@
<td><a href="{{ object.change_control_url }}">{{ object.change_control_url|placeholder }}</a></td>
</tr>
<tr>
<td>Job Result</td>
<td><a href="{{ object.job_result.get_absolute_url }}">{{ object.job_result.status|placeholder }}</a></td>
<td>Plan Result</td>
<td><a href="{{ object.plan_result.get_absolute_url }}">{{ object.plan_result.status|title }}</a></td>
</tr>
<tr>
<td>Deploy Result</td>
{% if object.deploy_result %}
<td><a href="{{ object.deploy_result.get_absolute_url }}">{{ object.deploy_result.status|title }}</a>
{% else %}
<td>{{ object.deploy_result|placeholder }}</td>
{% endif %}
</td>
</tr>
<tr>
<td>Status</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ <h3 class="modal-title">{{ modal_title }}</h3>
<td><div id="jobStatus" style="display:none;"></div></td>
</tr>
<tr>
<td>Job Results: </td>
<td>Plan Results: </td>
<td><div id="jobResults" style="display:none;"></div></td>
</tr>
<tr>
Expand Down
3 changes: 2 additions & 1 deletion nautobot_golden_config/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from nautobot.extras.models import DynamicGroup, GitRepository, GraphQLQuery, Status
from nautobot.utilities.testing import APITestCase, APIViewTestCases
from rest_framework import status

from nautobot_golden_config.choices import RemediationTypeChoice
from nautobot_golden_config.models import ConfigPlan, GoldenConfigSetting, RemediationSetting

Expand Down Expand Up @@ -376,7 +377,7 @@ def setUpTestData(cls):
change_control_id=f"Test Change Control ID {cont}",
change_control_url=f"https://{cont}.example.com/",
status=not_approved_status,
job_result_id=job_result_ids[cont - 1],
plan_result_id=job_result_ids[cont - 1],
)
plan.feature.add(features[cont - 1])
plan.validated_save()
Expand Down
17 changes: 9 additions & 8 deletions nautobot_golden_config/tests/test_filters.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
"""Unit tests for nautobot_golden_config models."""

from unittest import skip
from django.test import TestCase

from django.test import TestCase
from nautobot.dcim.models import Device, Platform
from nautobot.extras.models import Status, Tag
from nautobot.utilities.testing import FilterTestCases

from nautobot_golden_config import filters, models

from .conftest import create_feature_rule_json, create_device_data, create_feature_rule_cli, create_job_result
from .conftest import create_device_data, create_feature_rule_cli, create_feature_rule_json, create_job_result


class ConfigComplianceModelTestCase(TestCase):
Expand Down Expand Up @@ -335,7 +336,7 @@ def setUp(self):
config_set="intended test",
change_control_id="12345",
status=self.status2,
job_result_id=self.job_result1.id,
plan_result_id=self.job_result1.id,
)
self.config_plan1.tags.add(self.tag1)
self.config_plan1.feature.add(self.feature1)
Expand All @@ -347,7 +348,7 @@ def setUp(self):
config_set="missing test",
change_control_id="23456",
status=self.status1,
job_result_id=self.job_result1.id,
plan_result_id=self.job_result1.id,
)
self.config_plan2.tags.add(self.tag2)
self.config_plan2.feature.add(self.feature2)
Expand All @@ -359,7 +360,7 @@ def setUp(self):
config_set="remediation test",
change_control_id="34567",
status=self.status2,
job_result_id=self.job_result2.id,
plan_result_id=self.job_result2.id,
)
self.config_plan3.tags.add(self.tag2)
self.config_plan3.feature.set([self.feature1, self.feature3])
Expand All @@ -371,7 +372,7 @@ def setUp(self):
config_set="manual test",
change_control_id="45678",
status=self.status1,
job_result_id=self.job_result1.id,
plan_result_id=self.job_result1.id,
)
self.config_plan4.tags.add(self.tag1)
self.config_plan4.validated_save()
Expand Down Expand Up @@ -465,9 +466,9 @@ def test_filter_tag(self):

def test_job_result_id(self):
"""Test filtering by Job Result ID."""
params = {"job_result_id": [self.job_result1.pk]}
params = {"plan_result_id": [self.job_result1.pk]}
filterset = self.filterset(params, self.queryset)
self.assertEqual(filterset.qs.count(), 3)
self.assertQuerysetEqualAndNotEmpty(
filterset.qs, self.queryset.filter(job_result_id=self.job_result1.id).distinct()
filterset.qs, self.queryset.filter(plan_result_id=self.job_result1.id).distinct()
)
Loading

0 comments on commit 0352cf8

Please sign in to comment.