1""" 2Functions for working with Mako templates 3""" 4 5try: 6 from mako.lookup import ( 7 TemplateCollection, 8 TemplateLookup, 9 ) # pylint: disable=import-error,3rd-party-module-not-gated 10 11 HAS_MAKO = True 12except ImportError: 13 HAS_MAKO = False 14 15if HAS_MAKO: 16 import os 17 18 import urllib.parse 19 import salt.fileclient 20 import salt.utils.url 21 22 class SaltMakoTemplateLookup(TemplateCollection): 23 """ 24 Look up Mako template files using file:// or salt:// URLs with <%include/> 25 or <%namespace/>. 26 27 (1) Look up mako template files on local file system via files://... URL. 28 Make sure mako template file is present locally on minion beforehand. 29 30 Examples: 31 <%include file="file:///etc/salt/lib/templates/sls-parts.mako"/> 32 <%namespace file="file:///etc/salt/lib/templates/utils.mako" import="helper"/> 33 34 (2) Look up mako template files on Salt master via salt://... URL. 35 If URL is a relative path (without an URL scheme) then assume it's relative 36 to the directory of the salt file that's doing the lookup. If URL is an absolute 37 path then it's treated as if it has been prefixed with salt://. 38 39 Examples:: 40 <%include file="templates/sls-parts.mako"/> 41 <%include file="salt://lib/templates/sls-parts.mako"/> 42 <%include file="/lib/templates/sls-parts.mako"/> ##-- treated as salt:// 43 44 <%namespace file="templates/utils.mako"/> 45 <%namespace file="salt://lib/templates/utils.mako" import="helper"/> 46 <%namespace file="/lib/templates/utils.mako" import="helper"/> ##-- treated as salt:// 47 48 """ 49 50 def __init__(self, opts, saltenv="base", pillar_rend=False): 51 self.opts = opts 52 self.saltenv = saltenv 53 self._file_client = None 54 self.pillar_rend = pillar_rend 55 self.lookup = TemplateLookup(directories="/") 56 self.cache = {} 57 58 def file_client(self): 59 """ 60 Setup and return file_client 61 """ 62 if not self._file_client: 63 self._file_client = salt.fileclient.get_file_client( 64 self.opts, self.pillar_rend 65 ) 66 return self._file_client 67 68 def adjust_uri(self, uri, filename): 69 scheme = urllib.parse.urlparse(uri).scheme 70 if scheme in ("salt", "file"): 71 return uri 72 elif scheme: 73 raise ValueError("Unsupported URL scheme({}) in {}".format(scheme, uri)) 74 return self.lookup.adjust_uri(uri, filename) 75 76 def get_template(self, uri, relativeto=None): 77 if uri.startswith("file://"): 78 proto = "file://" 79 searchpath = "/" 80 salt_uri = uri 81 else: 82 proto = "salt://" 83 if self.opts["file_client"] == "local": 84 searchpath = self.opts["file_roots"][self.saltenv] 85 else: 86 searchpath = [ 87 os.path.join(self.opts["cachedir"], "files", self.saltenv) 88 ] 89 salt_uri = uri if uri.startswith(proto) else salt.utils.url.create(uri) 90 self.cache_file(salt_uri) 91 92 self.lookup = TemplateLookup(directories=searchpath) 93 return self.lookup.get_template(salt_uri[len(proto) :]) 94 95 def cache_file(self, fpath): 96 if fpath not in self.cache: 97 self.cache[fpath] = self.file_client().get_file( 98 fpath, "", True, self.saltenv 99 ) 100