2 ###############################################################################
3 # Copyright (c) 2016 Ericsson AB and others.
4 # peter.barabas@ericsson.com
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ###############################################################################
27 class Templater(object):
28 def __init__(self, base_file, template_file, output_file):
29 self.template_file = template_file
30 self.output_file = output_file
31 self.base = self.load_yaml(base_file)
33 def is_url(self, filespec):
34 regex = re.compile('^([^/:]+)://')
35 return re.search(regex, filespec)
37 def load_template(self, filespec):
39 if(self.is_url(filespec)):
40 response = urllib2.urlopen(filespec)
41 return response.read()
43 with io.open(filespec) as f:
45 except Exception as error:
46 err('Error opening template file: %s' % error)
48 def load_yaml(self, filespec):
50 if(self.is_url(filespec)):
51 response = urllib2.urlopen(filespec)
52 return yaml.load(response)
54 with io.open(filespec) as f:
56 except Exception as error:
57 err('Error opening YAML file: %s' % error)
59 def save_yaml(self, filename, content):
61 with io.open(filename, 'w') as yaml_file:
62 yaml_file.write(content)
63 except Exception as error:
64 err('Error writing YAML file: %s' % error)
66 def get_indent(self, line):
67 return len(line) - len(line.lstrip(' '))
69 def format_fragment(self, fragment, indent):
73 for line in fragment.splitlines():
74 # Skip indenting the first line as it is already indented
79 line = ' ' * indent + line + '\n'
83 return result.rstrip('\n')
85 def format_substitution(self, string):
86 if isinstance(string, basestring):
89 return yaml.dump(string, default_flow_style=False)
91 def parse_interface_tag(self, tag):
92 # Remove 'interface(' prefix, trailing ')' and split arguments
93 args = tag[len('interface('):].rstrip(')').split(',')
95 if len(args) == 1 and not args[0]:
96 err('No arguments for interface().')
97 elif len(args) == 2 and (not args[0] or not args[1]):
98 err('Empty argument for interface().')
100 err('Too many arguments for interface().')
104 def get_interface_from_network(self, interfaces, network):
105 nics = self.base[interfaces]
107 if network in nics[nic]:
110 err('Network not found: %s' % network)
112 def get_role_interfaces(self, role):
113 nodes = self.base['nodes']
115 if role in node['role']:
116 return node['interfaces']
118 err('Role not found: %s' % role)
120 def lookup_interface(self, args):
121 nodes = self.base['nodes']
124 interfaces = nodes[0]['interfaces']
126 interfaces = self.get_role_interfaces(args[1])
128 return self.get_interface_from_network(interfaces, args[0])
130 def parse_include_tag(self, tag):
131 # Remove 'include(' prefix and trailing ')'
132 filename = tag[len('include('):].rstrip(')')
135 err('No argument for include().')
139 def include_file(self, filename):
140 fragment = self.load_yaml(filename)
141 return yaml.dump(fragment, default_flow_style=False)
143 def parse_tag(self, tag, indent):
146 if 'interface(' in tag:
147 args = self.parse_interface_tag(tag)
148 fragment = self.lookup_interface(args)
149 elif 'include(' in tag:
150 filename = self.parse_include_tag(tag)
151 fragment = self.include_file(filename)
153 path = tag.split(DELIMITER)
157 fragment = fragment.get(i)
159 err('Error: key "%s" does not exist in base YAML file' % i)
161 fragment = self.format_substitution(fragment)
163 return self.format_fragment(fragment, indent)
168 regex = re.compile(re.escape(TAG_START) + r'([a-z].+)' + re.escape(TAG_END),
170 for line in self.load_template(self.template_file):
171 indent = self.get_indent(line)
172 result += re.sub(regex,
173 lambda match: self.parse_tag(match.group(1), indent),
176 self.save_yaml(self.output_file, result)
179 def parse_arguments():
180 description = '''Process 'template_file' using 'base_file' as source for
181 template variable substitution and write the results to 'output_file'.'''
183 parser = ArgParser(prog='python %s' % __file__,
184 description=description)
185 parser.add_argument('base_file',
186 help='Base YAML file or URL')
187 parser.add_argument('template_file',
188 help='Template file or URL')
189 parser.add_argument('output_file',
190 help='Output filename')
192 args = parser.parse_args()
193 return(args.base_file, args.template_file, args.output_file)
197 base_file, template_file, output_file = parse_arguments()
199 templater = Templater(base_file, template_file, output_file)
203 if __name__ == '__main__':