Add a script to generate PaaS manifest with environment variables

`./scripts/generate_manifest.py` takes a path to a PaaS manifest file
and a list of variable files and prints a single CloudFoundry manifest.

The generated manifest replaces all `inherit` keys by loading the data
from parent manifests. This allows us to pipe the script output directly
to CF CLI, without saving it to disk, which minimises the risk of it
being accidentally included in the deployment artefact. The combined
manifest might differ from the results produced by CF CLI itself, so
the original manifest shouldn't normally be used on its own.

After combining the manifests the script will load and parse all listed
variable files and add them to the manifest's `env` by merging the files
together in the order they were listed (so in case of any key conflicts
the latest file overwrites previous values), upper-casing keys and
processing any list or dictionary values with `json.dumps`, so that they
can be set as environment variables.

This gives us a full list of environment variables that were previously
parsed from the CloudFoundry user services data.
This commit is contained in:
Alexey Bezhan
2018-01-03 16:27:44 +00:00
parent d1da39c388
commit da1a7ceb0d

62
scripts/generate_manifest.py Executable file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import json
import yaml
def merge_dicts(a, b):
if not (isinstance(a, dict) and isinstance(b, dict)):
raise ValueError("Error merging variables: '{}' and '{}'".format(
type(a).__name__, type(b).__name__
))
result = a.copy()
for key, val in b.items():
if isinstance(result.get(key), dict):
result[key] = merge_dicts(a[key], b[key])
else:
result[key] = val
return result
def load_manifest(manifest_file):
with open(manifest_file) as f:
manifest = yaml.load(f)
if 'inherit' in manifest:
inherit_file = os.path.join(os.path.dirname(manifest_file), manifest.pop('inherit'))
manifest = merge_dicts(load_manifest(inherit_file), manifest)
return manifest
def load_variables(vars_files):
variables = {}
for vars_file in vars_files:
with open(vars_file) as f:
variables = merge_dicts(variables, json.load(f))
return {
k.upper(): json.dumps(v) if isinstance(v, (dict, list)) else v
for k, v in variables.items()
}
def paas_manifest(manifest_file, *vars_files):
"""Generate a PaaS manifest file from a Jinja2 template"""
manifest = load_manifest(manifest_file)
variables = load_variables(vars_files)
manifest['env'].update(variables)
return yaml.dump(manifest, default_flow_style=False, allow_unicode=True)
if __name__ == "__main__":
print(paas_manifest(*sys.argv[1:]))