]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/template.py
import 15.2.4
[ceph.git] / ceph / src / pybind / mgr / cephadm / template.py
1 import copy
2 from typing import Optional
3
4 from jinja2 import Environment, PackageLoader, select_autoescape, StrictUndefined
5 from jinja2 import exceptions as j2_exceptions
6
7
8 class TemplateError(Exception):
9 pass
10
11
12 class UndefinedError(TemplateError):
13 pass
14
15
16 class TemplateNotFoundError(TemplateError):
17 pass
18
19
20 class TemplateEngine:
21 def render(self, name: str, context: Optional[dict] = None) -> str:
22 raise NotImplementedError()
23
24
25 class Jinja2Engine(TemplateEngine):
26 def __init__(self):
27 self.env = Environment(
28 loader=PackageLoader('cephadm', 'templates'),
29 autoescape=select_autoescape(['html', 'xml']),
30 trim_blocks=True,
31 lstrip_blocks=True,
32 undefined=StrictUndefined
33 )
34
35 def render(self, name: str, context: Optional[dict] = None) -> str:
36 try:
37 template = self.env.get_template(name)
38 if context is None:
39 return template.render()
40 return template.render(context)
41 except j2_exceptions.UndefinedError as e:
42 raise UndefinedError(e.message)
43 except j2_exceptions.TemplateNotFound as e:
44 raise TemplateNotFoundError(e.message)
45
46
47 class TemplateMgr:
48 def __init__(self):
49 self.engine = Jinja2Engine()
50 self.base_context = {
51 'cephadm_managed': 'This file is generated by cephadm.'
52 }
53
54 def render(self, name: str, context: Optional[dict] = None, managed_context=True) -> str:
55 """Render a string from a template with context.
56
57 :param name: template name. e.g. services/nfs/ganesha.conf.j2
58 :type name: str
59 :param context: a dictionary that contains values to be used in the template, defaults
60 to None
61 :type context: Optional[dict], optional
62 :param managed_context: to inject default context like managed header or not, defaults
63 to True
64 :type managed_context: bool, optional
65 :return: the templated string
66 :rtype: str
67 """
68 ctx = {}
69 if managed_context:
70 ctx = copy.deepcopy(self.base_context)
71 if context is not None:
72 ctx = {**ctx, **context}
73 return self.engine.render(name, ctx)