From 59b6087ed61d3b66a7864dbf77a4a6f7cf0cbb44 Mon Sep 17 00:00:00 2001 From: Johnny Bieren Date: Tue, 3 Oct 2023 12:31:32 -0400 Subject: [PATCH] feat(RHTAPREL-392): add jinja2 and templating to the image As part of RHTAPREL-392, we need to create advisories. The easiest way to do this is from a template using jinja2, so this commit adds jinja2 and a template to the repo. Some ansible filters are not present in vanilla jinja2, so a module providing those is added too. Signed-off-by: Johnny Bieren --- Dockerfile | 5 ++++ requirements.txt | 2 ++ templates/advisory.yaml.jinja | 23 +++++++++++++++ utils/apply_template.py | 53 +++++++++++++++++++++++++++++++++++ utils/test_apply_template.py | 34 ++++++++++++++++++++++ 5 files changed, 117 insertions(+) create mode 100644 templates/advisory.yaml.jinja create mode 100755 utils/apply_template.py create mode 100644 utils/test_apply_template.py diff --git a/Dockerfile b/Dockerfile index 5541b835..776b73d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,16 +20,21 @@ RUN dnf -y --setopt=tsflags=nodocs install \ jq \ python39-devel \ diffutils \ + python39-pip \ python39-requests \ skopeo \ krb5-workstation \ && dnf clean all +RUN pip3 install Jinja2 \ + jinja2-ansible-filters + ADD data/certs/2015-IT-Root-CA.pem data/certs/2022-IT-Root-CA.pem /etc/pki/ca-trust/source/anchors/ RUN update-ca-trust COPY pyxis /home/pyxis COPY utils /home/utils +COPY templates /home/templates # Set HOME variable to something else than `/` to avoid 'permission denied' problems when writing files. ENV HOME=/tekton/home diff --git a/requirements.txt b/requirements.txt index 547de5c5..8dd779b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ pytest requests +Jinja2 +jinja2-ansible-filters diff --git a/templates/advisory.yaml.jinja b/templates/advisory.yaml.jinja new file mode 100644 index 00000000..e8c2faaf --- /dev/null +++ b/templates/advisory.yaml.jinja @@ -0,0 +1,23 @@ +apiVersion: rhtap.redhat.com/v1alpha1 +kind: Advisory +metadata: + name: {{ advisory_name }} +spec: + product_id: {{ advisory.spec.product_id }} + cpe: {{ advisory.spec.cpe }} + type: {{ advisory.spec.type }} +{%- if 'issues' in advisory.spec %} + issues: + {{ advisory.spec.issues | to_nice_yaml(indent=2) | indent(4) | trim }} +{%- endif %} + content: + {{ advisory.spec.content | to_nice_yaml(indent=2) | indent(4) | trim }} + synopsis: {{ advisory.spec.synopsis }} + topic: >- + {{ advisory.spec.topic | wordwrap(76) | indent(4) }} + description: >- + {{ advisory.spec.description | wordwrap(76) | indent(4) }} + solution: >- + {{ advisory.spec.solution | wordwrap(76) | indent(4) }} + references: + {{ advisory.spec.references | to_nice_yaml | indent(4) }} diff --git a/utils/apply_template.py b/utils/apply_template.py new file mode 100755 index 00000000..a6be144e --- /dev/null +++ b/utils/apply_template.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +import sys +from jinja2 import Template +from jinja2_ansible_filters import AnsibleCoreFiltersExtension +import argparse +import json +from typing import Any + + +def setup_argparser(args: Any) -> argparse.Namespace: # pragma: no cover + """Setup argument parser + + :return: Initialized argument parser + """ + + parser = argparse.ArgumentParser(description="Applies a template.") + + parser.add_argument( + "--data", + help="JSON string containing data to use in the template.", + required=True, + ) + parser.add_argument( + "--template", + help="Path to the template file to use.", + required=True, + ) + parser.add_argument( + "-o", + "--output", + help="The desired filename of the result.", + required=True, + ) + return parser.parse_args(args) + + +def main(): # pragma: no cover + """Main func""" + + args = setup_argparser(sys.argv[1:]) + + with open(args.template) as t: + template = Template(t.read(), extensions=[AnsibleCoreFiltersExtension]) + content = template.render(json.loads(args.data)) + + filename = args.output + with open(filename, mode="w", encoding="utf-8") as advisory: + advisory.write(content) + print(f"Wrote {filename}") + + +if __name__ == "__main__": # pragma: no cover + main() diff --git a/utils/test_apply_template.py b/utils/test_apply_template.py new file mode 100644 index 00000000..1d8e1e47 --- /dev/null +++ b/utils/test_apply_template.py @@ -0,0 +1,34 @@ +import os +import pytest +from unittest.mock import patch, MagicMock +from apply_template import setup_argparser, main + + +def test_setup_argparser_proper_args(): + args_in = ["--data", "{}", "--template", "somefile", "-o", "newfile"] + args_out = setup_argparser(args_in) + assert args_out.data == "{}" + assert args_out.template == "somefile" + assert args_out.output == "newfile" + + +def test_setup_argparser_improper_args(): + with pytest.raises(SystemExit): + setup_argparser([]) + + +@patch("apply_template.Template.render") +@patch("apply_template.setup_argparser") +def test_apply_template_advisory_template(mock_argparser: MagicMock, mock_render: MagicMock): + args = MagicMock() + args.template = "templates/advisory.yaml.jinja" + args.data = "{}" + args.output = "somefile" + mock_argparser.return_value = args + mock_render.return_value = "applied template file" + + # Act + main() + + assert os.path.exists("somefile") + os.remove("somefile")