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

CRAYSAT-1917: Fix jinja2 rendering of boot_sets data in sat bootprep #280

Merged
merged 4 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.32.10] - 2024-11-04

### Fixed
- Fix jinja2 rendering of `boot_sets` data in `sat bootprep`.

## [3.32.9] - 2024-10-29

### Fixed
Expand Down
32 changes: 19 additions & 13 deletions sat/cli/bootprep/input/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,25 @@ def wrapper(self, *args, **kwargs):
# Default to no additional context if not set
context = getattr(self, 'jinja_context', {})

try:
return self.jinja_env.from_string(unrendered_result).render(context)
except SecurityError as err:
raise error_cls(f'Jinja2 template {unrendered_result} for value '
f'{func.__name__} tried to access unsafe attributes.') from err
except TemplateError as err:
raise error_cls(f'Failed to render Jinja2 template {unrendered_result} '
f'for value {func.__name__}: {err}') from err
def render_object(obj):
"""Render an object with the given context."""
if isinstance(obj, str):
try:
return self.jinja_env.from_string(obj).render(context)
except SecurityError as err:
raise error_cls(f'Jinja2 template {obj} for value '
f'{func.__name__} tried to access unsafe attributes.') from err
except TemplateError as err:
raise error_cls(f'Failed to render Jinja2 template {obj} '
f'for value {func.__name__}: {err}') from err
elif isinstance(obj, dict):
return {key: render_object(value) for key, value in obj.items()}
elif isinstance(obj, list):
return [render_object(item) for item in obj]
else:
return obj

return render_object(unrendered_result)

return wrapper

Expand Down Expand Up @@ -242,11 +253,6 @@ def name(self):
# items that inherit from BaseInputItem.
return self.data['name']

@property
def boot_set(self):
"""Return the full boot_sets dictionary."""
return self.data.get('bos_parameters', {}).get('boot_sets', {})

def __str__(self):
# Since the name can be rendered, and when unrendered, it does not need
# to be unique, just refer to this item by its index in the instance.
Expand Down
7 changes: 1 addition & 6 deletions sat/cli/bootprep/input/session_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def configuration(self):
return self.data['configuration']

@property
@jinja_rendered
def boot_sets(self):
"""dict: the boot sets specified for the session template"""
# the 'bos_parameters' property is required, and 'boot_sets' is required within that
Expand Down Expand Up @@ -186,12 +187,6 @@ def get_create_item_data(self):
boot_set_api_data.update(boot_set_data)
api_data['boot_sets'][boot_set_name] = boot_set_api_data

# Fetch full boot sets
boot_sets = self.boot_set
# Render the rootfs_provider_passthrough using Jinja2
rendered_rootfs = self.jinja_env.from_string(
boot_sets[boot_set_name]['rootfs_provider_passthrough']).render(self.data)
api_data['boot_sets'][boot_set_name]['rootfs_provider_passthrough'] = rendered_rootfs
return api_data

def get_image_record_by_id(self, ims_image_id):
Expand Down
20 changes: 19 additions & 1 deletion tests/cli/bootprep/input/test_base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# MIT License
#
# (C) Copyright 2022-2023 Hewlett Packard Enterprise Development LP
# (C) Copyright 2022-2024 Hewlett Packard Enterprise Development LP
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
Expand All @@ -26,6 +26,7 @@
"""

import unittest
from jinja2 import Template

from sat.cli.bootprep.input.base import BaseInputItem
from sat.constants import MISSING_VALUE
Expand Down Expand Up @@ -57,6 +58,12 @@ def get_create_item_data(self):

def create(self, payload):
return

def render_jinja_template(self, template_str):
"""Render a Jinja template with provided data."""
template = Template(template_str)
return template.render(**self.data)

return SomeTestItem


Expand Down Expand Up @@ -84,3 +91,14 @@ def test_missing_report_attrs_are_missing(self):
report_row = item_cls(data).report_row()
self.assertEqual(len(report_row), len(row_headings))
self.assertEqual(report_row[-1], MISSING_VALUE)

def test_jinja_template_rendering(self):
"""Test Jinja template rendering with data from the input item."""
item_cls = create_input_item_cls(['name', 'type'])
data = {'name': 'foo', 'type': 'configuration'}
item = item_cls(data)

template_str = "name: {{name}} and type: {{type}}"
rendered_output = item.render_jinja_template(template_str)
expected_output = "name: foo and type: configuration"
self.assertEqual(rendered_output, expected_output)
Loading