diff --git a/checkdb.py b/checkdb.py index e69257a..06b29c8 100755 --- a/checkdb.py +++ b/checkdb.py @@ -17,17 +17,20 @@ import ZODB.FileStorage # print(v.conf) -# def main(): -# storage = ZODB.FileStorage.FileStorage("pupper.db") -# db = ZODB.DB(storage) -# with db.transaction() as c: -# del c.root.nodes["puppettest5.scc.net.davepedu.com"].classes["base2"] - def main(): storage = ZODB.FileStorage.FileStorage("pupper.db") db = ZODB.DB(storage) with db.transaction() as c: - print(c.root.nodes["puppettest5.scc.net.davepedu.com"].parents) + for host in ("scc", "root", "puppettest5.scc.net.davepedu.com"): + if "foo2" in c.root.nodes[host].classes: + del c.root.nodes[host].classes["foo2"] + # del c.root.nodes["scc"].classes["foo2"] + +# def main(): +# storage = ZODB.FileStorage.FileStorage("pupper.db") +# db = ZODB.DB(storage) +# with db.transaction() as c: +# print(c.root.nodes["puppettest5.scc.net.davepedu.com"].parents) if __name__ == "__main__": diff --git a/nodepupper/daemon.py b/nodepupper/daemon.py index 2437aed..81f40fe 100644 --- a/nodepupper/daemon.py +++ b/nodepupper/daemon.py @@ -1,7 +1,6 @@ import os import cherrypy import logging -from datetime import datetime, timedelta from nodepupper.nodeops import NodeOps, NObject, NClass, NClassAttachment from jinja2 import Environment, FileSystemLoader, select_autoescape from nodepupper.common import pwhash @@ -35,6 +34,7 @@ def slugify(words): return ''.join(letter for letter in '-'.join(words.lower().split()) if ('a' <= letter <= 'z') or ('0' <= letter <= '9') or letter == '-') + def recurse_params(node): params = yaml.load(node.body) for item in node.parents: @@ -43,6 +43,16 @@ def recurse_params(node): params[k] = v return params + +def recurse_classes(node): + classes = {c.cls: c.conf for _, c in node.classes.items()} + for item in node.parents: + for cls, conf in recurse_classes(item).items(): + if cls not in classes: + classes[cls] = conf + return classes + + class AppWeb(object): def __init__(self, nodedb, template_dir): self.nodes = nodedb @@ -75,12 +85,17 @@ class AppWeb(object): return ret @cherrypy.expose - def node_edit(self, node=None, op=None, body=None, fqdn=None): + def node_edit(self, node=None, op=None, body=None, fqdn=None, parent=None): if op in ("Edit", "Create") and body and fqdn: with self.nodes.db.transaction() as c: obj = c.root.nodes[fqdn] if fqdn in c.root.nodes else NObject(fqdn, body) obj.body = body + obj.parents.clear() + parent = parent or [] + for name in [parent] if isinstance(parent, str) else parent: + obj.parents.append(c.root.nodes[name]) c.root.nodes[fqdn] = obj + raise cherrypy.HTTPRedirect("node/{}".format(fqdn), 302) with self.nodes.db.transaction() as c: yield self.render("node_edit.html", node=c.root.nodes.get(node, None)) @@ -94,12 +109,14 @@ class AppWeb(object): # raise cherrypy.HTTPRedirect('feed', 302) @cherrypy.expose - def puppet(self, fqdn): + def puppet(self, fqdn, preview=False): with self.nodes.db.transaction() as c: node = c.root.nodes[fqdn] doc = {"environment": "production", - "classes": {k: yaml.load(v.conf) or {} for k, v in node.classes.items()}, + "classes": {cls.name: yaml.load(conf) or {} for cls, conf in recurse_classes(node).items()}, "parameters": recurse_params(node)} + if preview: + yield "" yield "---\n" yield yaml.dump(doc, default_flow_style=False) @@ -131,7 +148,7 @@ class AppWeb(object): @cherrypy.popargs("node") class NodesWeb(object): def __init__(self, root): - self.root = root + # self.base = root self.nodes = root.nodes self.render = root.render diff --git a/nodepupper/nodeops.py b/nodepupper/nodeops.py index b8be1f0..8f901fe 100644 --- a/nodepupper/nodeops.py +++ b/nodepupper/nodeops.py @@ -21,6 +21,9 @@ class NObject(persistent.Persistent): self.classes = pmap() self.body = body + def parent_names(self): + return [n.fqdn for n in self.parents] + class NClass(persistent.Persistent): def __init__(self, name): diff --git a/templates/node.html b/templates/node.html index 1ab9bd1..60d0881 100644 --- a/templates/node.html +++ b/templates/node.html @@ -8,7 +8,9 @@ <input type="submit" class="secondary-button pure-button" name="op" value="Make all private" /> <input type="submit" class="secondary-button pure-button" name="op" value="Delete tag" /> </form>--> - <a href="//node/{{ node.fqdn }}/attach"><button class="secondary-button pure-button">Attach class</button></a> + <a href="/node_edit?node={{ node.fqdn }}"><button class="secondary-button pure-button">Edit</button></a> + <a href="/node/{{ node.fqdn }}/attach"><button class="secondary-button pure-button">Attach class</button></a> + <a href="/puppet?preview=true&fqdn={{ node.fqdn }}"><button class="secondary-button pure-button">Render</button></a> {% endblock %} {% block body %} @@ -24,7 +26,7 @@ <div class="node-parents"> <h2>Parents</h2> {% for item in node.parents %} - {{ item.fqdn }} <br /> + <a href="/node/{{ item.fqdn }}">{{ item.fqdn }}</a><br /> {% endfor %} </div> <div class="node-classes"> @@ -37,6 +39,7 @@ <div class="class-conf"> <pre>{{ class.conf }}</pre> </div> + <hr/> {% endfor %} </div> <div class="node-add-class"> diff --git a/templates/node_edit.html b/templates/node_edit.html index e613d89..e0548e7 100644 --- a/templates/node_edit.html +++ b/templates/node_edit.html @@ -20,6 +20,14 @@ <label for="offset">Offset (minutes)</label> <input id="offset" class="pure-u-1-2" type="text" name="offset" value="xxx" /> </div> --> + <div class="pure-u-1"> + <label for="parent">Parents</label> + <select multiple name="parent"> + {% for item in nodenames %}{% if item != node.fqdn %} + <option value="{{ item }}"{% if node and item in node.parent_names() %} selected="selected"{% endif %}>{{ item }}</option> + {% endif %}{% endfor %} + </select> + </div> <div class="pure-u-1"> <input type="submit" class="pure-button pure-button-primary" name="op" value="{% if node %}Edit{% else %}Create{% endif %}" /> </div> diff --git a/templates/nodes.html b/templates/nodes.html index 1c4ff29..5215479 100644 --- a/templates/nodes.html +++ b/templates/nodes.html @@ -6,17 +6,13 @@ {% block body %} <div class="nodes-all"> - {% for node in nodes %} - <div class="node"> - <h2>{{ node.fqdn }}</h2> - <p> - <a href="/node/{{ node.fqdn }}">view</a> <a href="/node_edit?node={{ node.fqdn }}">edit</a> - </p> - <pre> -{{ node.body }} - </pre> - </div> + <ul> + {% for node in nodes|sort(attribute="fqdn") %} + <li> + <a href="/node/{{ node.fqdn }}">{{ node.fqdn }}</a> + </li> {% endfor %} + </ul> </div> {% endblock %}