mostly there, no ui yet.
This commit is contained in:
parent
dc8f42fc96
commit
c89d534b10
|
@ -1,11 +1,56 @@
|
|||
import json
|
||||
import os
|
||||
import pystache
|
||||
import subprocess
|
||||
from pystache.context import KeyNotFoundError
|
||||
|
||||
#def process_template(in_f, out_f):
|
||||
class CornfigException(Exception):
|
||||
pass
|
||||
|
||||
def install_cornfig(config_path, template_root):
|
||||
config = read_config(config_path)
|
||||
for in_file, out_file in template_paths(template_root):
|
||||
print render_template(in_file, config)
|
||||
|
||||
def build_tree(templates, config):
|
||||
res = {}
|
||||
for in_file, out_file in templates:
|
||||
res[out_file] = render_template(in_file, config)
|
||||
return res
|
||||
|
||||
def render_template(template, config):
|
||||
if is_executable(template):
|
||||
return render_executable(template, config)
|
||||
else:
|
||||
return render_moustache(open(template).read(), config)
|
||||
|
||||
def is_executable(path):
|
||||
return os.path.isfile(path) and os.access(path, os.X_OK)
|
||||
|
||||
def render_moustache(text, config):
|
||||
r = pystache.Renderer(missing_tags = 'strict')
|
||||
return r.render(text, config)
|
||||
|
||||
def render_executable(path, config):
|
||||
try:
|
||||
return subprocess.check_output([path], env=flatten(config))
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise CornfigException("config script failed: %s\n\nwith output:\n\n%s" % (path, e.output))
|
||||
|
||||
def read_config(path):
|
||||
return json.loads(open(path).read())
|
||||
|
||||
def flatten(d, prefix='', res=None):
|
||||
res = res or {}
|
||||
for k, v in d.items():
|
||||
key = (prefix + '.' + k) if len(prefix) > 0 else k
|
||||
if isinstance(v, str):
|
||||
res[key] = v
|
||||
elif isinstance(v, dict):
|
||||
res = dict(res.items() + flatten(v, key, res).items())
|
||||
else:
|
||||
raise CornfigException("expected only strings and hashes in config.")
|
||||
return res
|
||||
|
||||
# given a root directory, return a list of tuples
|
||||
# containing input and output paths
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
import json
|
||||
import os
|
||||
import tempfile
|
||||
from nose.tools import *
|
||||
from cornfig.cornfig import *
|
||||
import os
|
||||
|
||||
TEMPLATES = os.path.join(os.path.dirname(__file__), 'templates')
|
||||
TEMPLATE_PATHS = ["/etc/keystone/keystone.conf"]
|
||||
TEMPLATE_PATHS = [
|
||||
"/etc/glance/script.conf",
|
||||
"/etc/keystone/keystone.conf"
|
||||
]
|
||||
|
||||
CONFIG = {
|
||||
"x": "foo",
|
||||
"database": {
|
||||
"url": "sqlite:///blah"
|
||||
}
|
||||
}
|
||||
|
||||
def setup():
|
||||
pass
|
||||
|
@ -11,15 +23,57 @@ def setup():
|
|||
def teardown():
|
||||
pass
|
||||
|
||||
def test_template_paths():
|
||||
expected = map(lambda p: (os.path.join(TEMPLATES, p[1:]), p), TEMPLATE_PATHS)
|
||||
assert template_paths(TEMPLATES) == expected
|
||||
def template(relpath):
|
||||
return os.path.join(TEMPLATES, relpath[1:])
|
||||
|
||||
@raises(Exception)
|
||||
def test_build_tree():
|
||||
print flatten(CONFIG)
|
||||
assert_equals( build_tree(template_paths(TEMPLATES), CONFIG),
|
||||
{
|
||||
"/etc/keystone/keystone.conf": "[foo]\ndatabase = sqlite:///blah\n",
|
||||
"/etc/glance/script.conf": "foo\n"
|
||||
})
|
||||
|
||||
def test_flatten():
|
||||
assert_equals( flatten({"x": {"a": "b", "c": "d"}, "y": "z"}), {"x.a": "b", "x.c": "d", "y": "z"} )
|
||||
|
||||
def test_render_template():
|
||||
# execute executable files, moustache non-executables
|
||||
assert render_template(template("/etc/glance/script.conf"), {"x": "abc"}) == "abc\n"
|
||||
assert_raises(CornfigException, render_template, template("/etc/glance/script.conf"), {})
|
||||
|
||||
def test_render_moustache():
|
||||
assert_equals( render_moustache("ab{{x.a}}cd", {"x": {"a": "123"}}), "ab123cd" )
|
||||
|
||||
@raises(KeyNotFoundError)
|
||||
def test_render_moustache_bad_key():
|
||||
render_moustache("{{badkey}}", {})
|
||||
|
||||
def test_render_executable():
|
||||
params = {"x": "foo"}
|
||||
assert render_executable(template("/etc/glance/script.conf"), params) == "foo\n"
|
||||
|
||||
@raises(CornfigException)
|
||||
def test_render_executable_failure():
|
||||
render_executable(template("/etc/glance/script.conf"), {})
|
||||
|
||||
def test_template_paths():
|
||||
expected = map(lambda p: (template(p), p), TEMPLATE_PATHS)
|
||||
assert_equals( template_paths(TEMPLATES), expected)
|
||||
|
||||
def test_read_config():
|
||||
with tempfile.NamedTemporaryFile() as t:
|
||||
d = {"a": {"b": ["c", "d"] } }
|
||||
t.write(json.dumps(d))
|
||||
t.flush()
|
||||
assert_equals( read_config(t.name), d )
|
||||
|
||||
@raises(ValueError)
|
||||
def test_read_config_bad_json():
|
||||
with tempfile.TemporaryFile() as t:
|
||||
with tempfile.NamedTemporaryFile() as t:
|
||||
t.write("{{{{")
|
||||
read_config(t.path)
|
||||
t.flush()
|
||||
read_config(t.name)
|
||||
|
||||
@raises(Exception)
|
||||
def test_read_config_no_file():
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
set -u
|
||||
echo $x
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
adf
|
||||
asdf
|
||||
[foo]
|
||||
database = {{database.url}}
|
||||
|
|
Loading…
Reference in New Issue