Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Added basic template/configuration hierarchy and simple PostgreSQL
project.
  • Loading branch information
praiskup committed May 10, 2015
0 parents commit bebb1e8
Show file tree
Hide file tree
Showing 27 changed files with 536 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.py[oc]
17 changes: 17 additions & 0 deletions bin/dg
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/python

from distgen.generator import Generator


def main():
generator = Generator()
generator.load_project("projects/postgresql")
generator.render(
"postgresql.yaml",
"docker.tpl",
"rhel-7-x86_64.yaml"
)


if __name__ == "__main__":
main()
15 changes: 15 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
default:
commands:
pkginstall:
pkgs:
- postgresql-server
pkgreinstall:
pkgs:
- glibc-common

distros:
fedora:
20:
pkginstall:
rhel:

Empty file added config/fedora-20-x86_64.yaml
Empty file.
1 change: 1 addition & 0 deletions config/fedora-21-i686.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extends: "lib/fedora.yaml"
6 changes: 6 additions & 0 deletions config/fedora-21-x86_64.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extends: "fedora-21-i686.yaml"

dirs:
libdir: /usr/lib64

arch: x86_64
6 changes: 6 additions & 0 deletions config/lib/fedora.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extends: lib/rpmsystems.yaml

distribution: fedora

docker:
from: fedora
13 changes: 13 additions & 0 deletions config/lib/general.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
dirs:
sysconfdir: /etc
bindir: /usr/bin
libexecdir: /usr/libexec
libdir: /usr/lib

distribution: unknown
distversion: unknown
arch: i686

docker:
registry: index.docker.io
from: unset
6 changes: 6 additions & 0 deletions config/lib/rhel.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extends: lib/rpmsystems.yaml

distribution: rhel

docker:
registry: registry.access.redhat.com
5 changes: 5 additions & 0 deletions config/lib/rpmsystems.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extends: lib/general.yaml

package_installer:
name: yum
version: unknown
10 changes: 10 additions & 0 deletions config/rhel-7-x86_64.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extends: "lib/rhel.yaml"

distversion: 7
arch: x86_64

dirs:
libdir: /usr/lib64

docker:
from: rhel7
8 changes: 8 additions & 0 deletions dg.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh

proj_cli_dir="$(dirname "$(readlink -f "$0")")"

export PYTHONPATH="$proj_cli_dir/distgen:${PYTHONPATH+:$PYTHONPATH}"
export PATH="$proj_cli_dir/bin:${PATH+:$PATH}"

dg "$@"
Empty file added distgen/__init__.py
Empty file.
46 changes: 46 additions & 0 deletions distgen/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import sys
import copy
from pathmanager import PathManager

def die(msg):
# TODO: use logging
print msg
sys.exit(2)


def merge_yaml(origin, override):
"""
Merge simple yaml node recursively. If the node is non-dict, return itself,
otherwise recurse down for each item.
"""
if isinstance(origin, dict) and isinstance(override, dict):
for k, v in override.iteritems():
if k in origin:
origin[k] = merge_yaml(origin[k], override[k])
else:
origin[k] = copy.deepcopy(override[k])
return origin

return copy.deepcopy(override)


def __recursive_load(pm, stack, filename):
if filename in stack:
die("already parsed " + filename)

stack.append(filename)
main_file = pm.get_file(filename)

import yaml
yaml_data = yaml.load(open(main_file))

if yaml_data and "extends" in yaml_data:
subdata = __recursive_load(pm, stack, yaml_data["extends"])
yaml_data = merge_yaml(subdata, yaml_data)

return yaml_data


def load_config(path, config_file, context=None):
yaml_data = __recursive_load(PathManager(path), [], config_file)
return yaml_data
82 changes: 82 additions & 0 deletions distgen/generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import os
import imp
from jinja2 import Environment, FileSystemLoader
from pathmanager import PathManager
from config import load_config


class Generator(object):
project = None

pm_cfg = None
pm_tpl = None
pm_spc = None


def __init__(self):
self.pm_cfg = PathManager(["config"], envvar="DG_CONFIGDIR")

self.pm_tpl = PathManager(['templates'], envvar="DG_TPLDIR")

self.pm_spc = PathManager([])


def _load_class_from_file(self, filename, classname):
mod_name, file_ext = os.path.splitext(os.path.split(filename)[-1])
if file_ext.lower() == '.py':
py_mod = imp.load_source(mod_name, filename)
elif file_ext.lower() == '.pyc':
py_mod = imp.load_compiled(mod_name, filename)

if hasattr(py_mod, classname):
return getattr(py_mod, classname)()
else:
return None


def load_project(self, project):
project_file = project + "/project.py"
self.project = self._load_class_from_file(project_file, "Project")
self.project.directory = project
self.project.tplgen = Environment(
loader=FileSystemLoader(self.pm_tpl.get_path()),
)

self.project.initialize()


def render(self, specfile, template, config, output=None):
config_path = [self.project.directory] + self.pm_cfg.get_path()
sysconfig = load_config(config_path, config)

init_data = self.project.inst_init(specfile, template, sysconfig)

# NOTE: This is soo ugly, sorry for that, in future we need to modify
# PyYAML to let us specify callbacks, somehow. But for now, import
# yaml right here to be able to add the constructors/representers
# "locally".
import yaml

def _eval_node(loader, node):
return str(eval(str(loader.construct_scalar(node)), {
'init': init_data,
'config': sysconfig,
'dirs': sysconfig['dirs']
}))

yaml.add_constructor(u'!eval', _eval_node)

spec = yaml.load(
open(self.pm_spc.get_file(specfile, [self.project.directory]))
)

self.project.inst_finish(specfile, template, spec)

tpl = self.project.tplgen.get_template(template)
print tpl.render(
config=sysconfig,
dirs=sysconfig["dirs"],
container={'name': 'docker'},
spec=spec,
project=self.project,
)
30 changes: 30 additions & 0 deletions distgen/pathmanager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import os


class PathManager(object):
envvar = None

def __init__(self, path, envvar=None):
self.path = path
self.envvar = envvar


def get_file(self, relative, prefered_path=None):
path = self.path
if prefered_path:
path = prefered_path + path

if self.envvar:
env_path = os.environ[self.envvar].split(':')
path = env_path + path

for i in path:
config_file = i + "/" + relative
if os.path.isfile(config_file):
return config_file

return None


def get_path(self):
return self.path
48 changes: 48 additions & 0 deletions distgen/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class AbstractProject():
tplgen = None

maintainer = "unknown <[email protected]>"

"""
Initially, I was thinking about "task_root" as the main task, which could
have dependencies (children), etc. However, we'll see whether this is
necessary in future. Most probably we'll be fine with simple generator and
we let the dependency resolution upon make or some other cool tool.
"""
task_root = None

def __init__(self):
# self.ctx = ctx
# self.config = self.ctx.system_config
# # Just a shortcut to dirs.
# self.dirs = ctx.system_config["dirs"]
# self.task_root = TaskTemplate(ctx)
pass


def inst_init(self, spec, template):
"""
Returns dict with data to be used in specification file.
"""
return {}


def inst_finish(self, spec, template, data):
""" edit data (parsed specification) """
pass


def prebuild(self):
"""
This be defined in inheritting Project
"""
pass


def build(self):
self.prebuild()
self.task_root.perform()


def initialize(self):
pass
8 changes: 8 additions & 0 deletions projects/postgresql/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
distro=fedora
distrover=20

instantiate = cat

root.tar: out
tar -cf $@ out

47 changes: 47 additions & 0 deletions projects/postgresql/postgresql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
maintainer: Pavel Raiskup <[email protected]>

expose: [5432]

parts:
# envvars:
# data:
# - name: ahoj
# value: asdf
pkginstall:
data:
- type: "pkg"
action: "install"
packages: [ postgresql-server ]

# Reinstall glibc-common to fix locale issues (rhbz#1129697)
- type: "pkg"
action: "reinstall"
packages: ["glibc-common"]

volumes:
data:
- path: /var/lib/pgsql/data
- path: /var/run/postgresql

addfiles:
data:
- type: files
dest: !eval "\"/usr/bin\""
files:
- "./scripts/rh-cont-pg-initdb"
- "./scripts/rh-cont-pg-entry"
- "./scripts/rh-cont-pg-exec"
- "./scripts/rh-cont-pg-execpre"
- type: files
dest: "/etc/systemd/system/"
files: ["./data/postgresql-container.service"]

commands:
data:
- type: shell
action: "mkdir -p \"$PGDATA\""
- type: shell
action: "touch \"$PGDATA\"/.container_internal"

footer:
user: postgres
10 changes: 10 additions & 0 deletions projects/postgresql/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/python

from distgen.project import AbstractProject

class Project(AbstractProject):

maintainer = "Pavel Raiskup <[email protected]>"

def inst_init(self, spec, template, sysconf):
return {}
2 changes: 2 additions & 0 deletions templates/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
parts/
docker/
Loading

0 comments on commit bebb1e8

Please sign in to comment.