|
|
|
@ -39,8 +39,8 @@ def Expand(config, imports=None, env=None, validate_schema=False):
|
|
|
|
|
to their values
|
|
|
|
|
validate_schema: True to run schema validation; False otherwise
|
|
|
|
|
Returns:
|
|
|
|
|
YAML containing the expanded configuration and its layout, in the following
|
|
|
|
|
format:
|
|
|
|
|
YAML containing the expanded configuration and its layout,
|
|
|
|
|
in the following format:
|
|
|
|
|
|
|
|
|
|
config:
|
|
|
|
|
...
|
|
|
|
@ -67,12 +67,12 @@ def _Expand(config, imports=None, env=None, validate_schema=False):
|
|
|
|
|
try:
|
|
|
|
|
yaml_config = yaml.safe_load(config)
|
|
|
|
|
except yaml.scanner.ScannerError as e:
|
|
|
|
|
# Here we know that YAML parser could not parse the template we've given it.
|
|
|
|
|
# YAML raises a ScannerError that specifies which file had the problem, as
|
|
|
|
|
# well as line and column, but since we're giving it the template from
|
|
|
|
|
# string, error message contains <string>, which is not very helpful on the
|
|
|
|
|
# user end, so replace it with word "template" and make it obvious that YAML
|
|
|
|
|
# contains a syntactic error.
|
|
|
|
|
# Here we know that YAML parser could not parse the template
|
|
|
|
|
# we've given it. YAML raises a ScannerError that specifies which file
|
|
|
|
|
# had the problem, as well as line and column, but since we're giving
|
|
|
|
|
# it the template from string, error message contains <string>, which
|
|
|
|
|
# is not very helpful on the user end, so replace it with word
|
|
|
|
|
# "template" and make it obvious that YAML contains a syntactic error.
|
|
|
|
|
msg = str(e).replace('"<string>"', 'template')
|
|
|
|
|
raise Exception('Error parsing YAML: %s' % msg)
|
|
|
|
|
|
|
|
|
@ -81,12 +81,12 @@ def _Expand(config, imports=None, env=None, validate_schema=False):
|
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
# If the configuration does not have ':' in it, the yaml_config will be a
|
|
|
|
|
# string. If this is the case just return the str. The code below it assumes
|
|
|
|
|
# yaml_config is a map for common cases.
|
|
|
|
|
# string. If this is the case just return the str. The code below it
|
|
|
|
|
# assumes yaml_config is a map for common cases.
|
|
|
|
|
if type(yaml_config) is str:
|
|
|
|
|
return yaml_config
|
|
|
|
|
|
|
|
|
|
if not yaml_config.has_key('resources') or yaml_config['resources'] is None:
|
|
|
|
|
if 'resources' not in yaml_config or yaml_config['resources'] is None:
|
|
|
|
|
yaml_config['resources'] = []
|
|
|
|
|
|
|
|
|
|
config = {'resources': []}
|
|
|
|
@ -125,11 +125,11 @@ def _ProcessResource(resource, imports, env, validate_schema=False):
|
|
|
|
|
ExpansionError: if there is any error occurred during expansion
|
|
|
|
|
"""
|
|
|
|
|
# A resource has to have to a name.
|
|
|
|
|
if not resource.has_key('name'):
|
|
|
|
|
if 'name' not in resource:
|
|
|
|
|
raise ExpansionError(resource, 'Resource does not have a name.')
|
|
|
|
|
|
|
|
|
|
# A resource has to have a type.
|
|
|
|
|
if not resource.has_key('type'):
|
|
|
|
|
if 'type' not in resource:
|
|
|
|
|
raise ExpansionError(resource, 'Resource does not have type defined.')
|
|
|
|
|
|
|
|
|
|
config = {'resources': []}
|
|
|
|
@ -139,19 +139,23 @@ def _ProcessResource(resource, imports, env, validate_schema=False):
|
|
|
|
|
|
|
|
|
|
if resource['type'] in imports:
|
|
|
|
|
# A template resource, which contains sub-resources.
|
|
|
|
|
expanded_template = ExpandTemplate(resource, imports, env, validate_schema)
|
|
|
|
|
expanded_template = ExpandTemplate(resource, imports,
|
|
|
|
|
env, validate_schema)
|
|
|
|
|
|
|
|
|
|
if expanded_template['resources']:
|
|
|
|
|
_ValidateUniqueNames(expanded_template['resources'], resource['type'])
|
|
|
|
|
_ValidateUniqueNames(expanded_template['resources'],
|
|
|
|
|
resource['type'])
|
|
|
|
|
|
|
|
|
|
# Process all sub-resources of this template.
|
|
|
|
|
for resource_to_process in expanded_template['resources']:
|
|
|
|
|
processed_resource = _ProcessResource(resource_to_process, imports, env,
|
|
|
|
|
processed_resource = _ProcessResource(resource_to_process,
|
|
|
|
|
imports, env,
|
|
|
|
|
validate_schema)
|
|
|
|
|
|
|
|
|
|
# Append all sub-resources to the config resources, and the resulting
|
|
|
|
|
# layout of sub-resources.
|
|
|
|
|
config['resources'].extend(processed_resource['config']['resources'])
|
|
|
|
|
# Append all sub-resources to the config resources,
|
|
|
|
|
# and the resulting layout of sub-resources.
|
|
|
|
|
config['resources'].extend(processed_resource['config']
|
|
|
|
|
['resources'])
|
|
|
|
|
|
|
|
|
|
# Lazy-initialize resources key here because it is not set for
|
|
|
|
|
# non-template layouts.
|
|
|
|
@ -178,8 +182,8 @@ def _ValidateUniqueNames(template_resources, template_name='config'):
|
|
|
|
|
if resource['name'] in names:
|
|
|
|
|
raise ExpansionError(
|
|
|
|
|
resource,
|
|
|
|
|
'Resource name \'%s\' is not unique in %s.' % (resource['name'],
|
|
|
|
|
template_name))
|
|
|
|
|
'Resource name \'%s\' is not unique in %s.'
|
|
|
|
|
% (resource['name'], template_name))
|
|
|
|
|
names.add(resource['name'])
|
|
|
|
|
# If this resource doesn't have a name, we will report that error later
|
|
|
|
|
|
|
|
|
@ -210,8 +214,9 @@ def ExpandTemplate(resource, imports, env, validate_schema=False):
|
|
|
|
|
source_file,
|
|
|
|
|
'Unable to find source file %s in imports.' % (source_file))
|
|
|
|
|
|
|
|
|
|
# source_file could be a short version of the template (say github short name)
|
|
|
|
|
# so we need to potentially map this into the fully resolvable name.
|
|
|
|
|
# source_file could be a short version of the template
|
|
|
|
|
# say github short name) so we need to potentially map this into
|
|
|
|
|
# the fully resolvable name.
|
|
|
|
|
if 'path' in imports[source_file] and imports[source_file]['path']:
|
|
|
|
|
path = imports[source_file]['path']
|
|
|
|
|
|
|
|
|
@ -260,12 +265,16 @@ def ExpandJinja(file_name, source_template, resource, imports):
|
|
|
|
|
"""Render the jinja template using jinja libraries.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
file_name: string, the file name.
|
|
|
|
|
source_template: string, the content of jinja file to be render
|
|
|
|
|
resource: resource object, the resource that contains parameters to the
|
|
|
|
|
file_name:
|
|
|
|
|
string, the file name.
|
|
|
|
|
source_template:
|
|
|
|
|
string, the content of jinja file to be render
|
|
|
|
|
resource:
|
|
|
|
|
resource object, the resource that contains parameters to the
|
|
|
|
|
jinja file
|
|
|
|
|
imports: map from string to map {name, path}, the map of imported files names
|
|
|
|
|
fully resolved path and contents
|
|
|
|
|
imports:
|
|
|
|
|
map from string to map {name, path}, the map of imported
|
|
|
|
|
files names fully resolved path and contents
|
|
|
|
|
Returns:
|
|
|
|
|
The final expanded template
|
|
|
|
|
Raises:
|
|
|
|
@ -277,8 +286,8 @@ def ExpandJinja(file_name, source_template, resource, imports):
|
|
|
|
|
|
|
|
|
|
template = env.from_string(source_template)
|
|
|
|
|
|
|
|
|
|
if (resource.has_key('properties') or resource.has_key('env') or
|
|
|
|
|
resource.has_key('imports')):
|
|
|
|
|
if ('properties' in resource or 'env' in resource or
|
|
|
|
|
'imports' in resource):
|
|
|
|
|
return template.render(resource)
|
|
|
|
|
else:
|
|
|
|
|
return template.render()
|
|
|
|
@ -322,17 +331,17 @@ class PythonEvaluationContext(object):
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, params):
|
|
|
|
|
if params.has_key('properties'):
|
|
|
|
|
if 'properties' in params:
|
|
|
|
|
self.properties = params['properties']
|
|
|
|
|
else:
|
|
|
|
|
self.properties = None
|
|
|
|
|
|
|
|
|
|
if params.has_key('imports'):
|
|
|
|
|
if 'imports' in params:
|
|
|
|
|
self.imports = params['imports']
|
|
|
|
|
else:
|
|
|
|
|
self.imports = None
|
|
|
|
|
|
|
|
|
|
if params.has_key('env'):
|
|
|
|
|
if 'env' in params:
|
|
|
|
|
self.env = params['env']
|
|
|
|
|
else:
|
|
|
|
|
self.env = None
|
|
|
|
@ -361,7 +370,8 @@ def main():
|
|
|
|
|
imports = {}
|
|
|
|
|
while idx < len(sys.argv):
|
|
|
|
|
if idx + 1 == len(sys.argv):
|
|
|
|
|
print >>sys.stderr, 'Invalid import definition at argv pos %d' % idx
|
|
|
|
|
print >>sys.stderr, 'Invalid import definition at argv pos %d' \
|
|
|
|
|
% idx
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
name = sys.argv[idx]
|
|
|
|
|
path = sys.argv[idx + 1]
|
|
|
|
|