Skip to content

Commit

Permalink
Fix transaction (#124)
Browse files Browse the repository at this point in the history
* fix: Fixed filter lookup from new metadata class

The transaction was mistakenly removed in a previous change and
design errors were no longer rolling back the database. This
fix corrects that error.
  • Loading branch information
abates authored Mar 27, 2024
1 parent 60206ce commit a1450ff
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 10 deletions.
34 changes: 24 additions & 10 deletions nautobot_design_builder/design_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self, *args, **kwargs):
self.designs = {}
# TODO: Remove this when we no longer support Nautobot 1.x
self.rendered = None
self.rendered_design = None
self.failed = False
self.report = None

Expand Down Expand Up @@ -119,21 +120,14 @@ def render_design(self, context, design_file):
context (Context object): a tree of variables that can include templates for values
design_file (str): Filename of the design file to render.
"""
self.rendered_design = design_file
self.rendered = self.render(context, design_file)
# Save the rendered result for later examination from
# the job result/additional data tab.
output_file = path.basename(design_file)
# this should remove the .j2
output_file, _ = path.splitext(output_file)
if not output_file.endswith(".yaml") and not output_file.endswith(".yml"):
output_file = f"{output_file}.yaml"
self.save_design_file(output_file, self.rendered)

design = yaml.safe_load(self.rendered)
self.designs[design_file] = design

# no need to save the rendered content if yaml loaded
# it okay
self.rendered_design = None
self.rendered = None
return design

Expand All @@ -160,8 +154,28 @@ def implement_design(self, context, design_file, commit):
design = self.render_design(context, design_file)
self.environment.implement_design(design, commit)

def run(self, **kwargs): # pylint: disable=arguments-differ,too-many-branches
def run(self, **kwargs): # pylint: disable=arguments-differ
"""Render the design and implement it within a build Environment object."""
try:
return self._run_in_transaction(**kwargs)
finally:
if self.rendered:
self.save_design_file(self.rendered_design, self.rendered)
for design_file, design in self.designs.items():
output_file = path.basename(design_file)
# this should remove the .j2
output_file, _ = path.splitext(output_file)
if not output_file.endswith(".yaml") and not output_file.endswith(".yml"):
output_file = f"{output_file}.yaml"
self.save_design_file(output_file, yaml.safe_dump(design))

@transaction.atomic
def _run_in_transaction(self, **kwargs): # pylint: disable=too-many-branches
"""Render the design and implement it within a build Environment object.
This version of `run` is wrapped in a transaction and will roll back database changes
on error. In general, this method should only be called by the `run` method.
"""
self.log_info(message=f"Building {getattr(self.Meta, 'name')}")
extensions = getattr(self.Meta, "extensions", [])
self.environment = Environment(job_result=self.job_result, extensions=extensions)
Expand Down
1 change: 1 addition & 0 deletions nautobot_design_builder/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def get_mocked_job(self, design_class: Type[DesignJob]):
if nautobot_version < "2.0.0":
job.request = mock.Mock()
else:
# TODO: Remove this when we no longer support Nautobot 1.x
job.job_result.data = {}
old_run = job.run

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
manufacturers:
name: "Test Manufacturer 1"
name: "Test Manufacturer"
8 changes: 8 additions & 0 deletions nautobot_design_builder/tests/designs/test_designs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ class Meta: # pylint: disable=too-few-public-methods
design_file = "templates/simple_design.yaml.j2"


class SimpleDesign3(DesignJob):
"""Simple design job with extra manufacturer."""

class Meta: # pylint: disable=too-few-public-methods
name = "Simple Design 3"
design_file = "templates/simple_design_3.yaml.j2"


class SimpleDesignReport(DesignJob):
"""Simple design job that includes a post-implementation report."""

Expand Down
13 changes: 13 additions & 0 deletions nautobot_design_builder/tests/test_design_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ def test_simple_design_commit(self, environment: Mock):
)
environment.return_value.roll_back.assert_not_called()

def test_simple_design_rollback(self):
job1 = self.get_mocked_job(test_designs.SimpleDesign)
job1.run(data={}, commit=True)
self.assertFalse(job1.failed)
self.assertEqual(1, Manufacturer.objects.all().count())
job2 = self.get_mocked_job(test_designs.SimpleDesign3)
if nautobot_version < "2":
job2.run(data={}, commit=True)
else:
self.assertRaises(DesignValidationError, job2.run, data={}, commit=True)
self.assertTrue(job2.failed)
self.assertEqual(1, Manufacturer.objects.all().count())

def test_simple_design_report(self):
job = self.get_mocked_job(test_designs.SimpleDesignReport)
job.run(data={}, commit=True)
Expand Down

0 comments on commit a1450ff

Please sign in to comment.