Compare commits
No commits in common. "3cb8bacb31e250d7d228335c92bf138727c91a6f" and "444cca48de6c5b366f941d492eceed901d5f048f" have entirely different histories.
3cb8bacb31
...
444cca48de
21
checkdb.py
21
checkdb.py
|
@ -3,11 +3,28 @@
|
|||
import ZODB
|
||||
import ZODB.FileStorage
|
||||
|
||||
# def main():
|
||||
# storage = ZODB.FileStorage.FileStorage("pupper.db")
|
||||
# db = ZODB.DB(storage)
|
||||
# for k, v in db.open().root.nodes.items():
|
||||
# print(k, v.name, ":", v, "\n\t", v.body, "\n")
|
||||
|
||||
# def main():
|
||||
# storage = ZODB.FileStorage.FileStorage("pupper.db")
|
||||
# db = ZODB.DB(storage)
|
||||
# for k, v in db.open().root.nodes["foo2"].classes.items():
|
||||
# # print(k, v.name, ":", v, "\n\t", v.body, "\n")
|
||||
# print(v.conf)
|
||||
|
||||
|
||||
def main():
|
||||
storage = ZODB.FileStorage.FileStorage("pupper.db")
|
||||
db = ZODB.DB(storage)
|
||||
for k, v in db.open().root.nodes.items():
|
||||
print(k, v.name, ":", v, "\n\t", v.body, "\n")
|
||||
with db.transaction() as c:
|
||||
del c.root.nodes["puppettest5.scc.net.davepedu.com"].classes["base2"]
|
||||
# for k, v in db.open().root.nodes["foo2"].classes.items():
|
||||
# # print(k, v.name, ":", v, "\n\t", v.body, "\n")
|
||||
# print(v.conf
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -7,6 +7,7 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|||
from nodepupper.common import pwhash
|
||||
import math
|
||||
from urllib.parse import urlparse
|
||||
import yaml
|
||||
|
||||
|
||||
APPROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))
|
||||
|
@ -58,7 +59,7 @@ class AppWeb(object):
|
|||
"""
|
||||
with self.nodes.db.transaction() as c:
|
||||
ret = {
|
||||
"classes": c.root.classes,
|
||||
"classnames": c.root.classes.keys(),
|
||||
# "all_albums": [],
|
||||
"path": cherrypy.request.path_info,
|
||||
"auth": True or auth()
|
||||
|
@ -67,7 +68,6 @@ class AppWeb(object):
|
|||
|
||||
@cherrypy.expose
|
||||
def node_edit(self, node=None, op=None, body=None, fqdn=None):
|
||||
print(op, body, fqdn)
|
||||
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)
|
||||
|
@ -85,6 +85,20 @@ class AppWeb(object):
|
|||
yield self.render("nodes.html", nodes=c.root.nodes.values())
|
||||
# raise cherrypy.HTTPRedirect('feed', 302)
|
||||
|
||||
@cherrypy.expose
|
||||
def puppet(self, fqdn):
|
||||
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()},
|
||||
"parameters": {}}
|
||||
|
||||
for name, attachment in node.classes.items():
|
||||
print(name)
|
||||
|
||||
yield "---\n"
|
||||
yield yaml.dump(doc, default_flow_style=False)
|
||||
|
||||
@cherrypy.expose
|
||||
def login(self):
|
||||
"""
|
||||
|
@ -122,6 +136,13 @@ class NodesWeb(object):
|
|||
with self.nodes.db.transaction() as c:
|
||||
yield self.render("node.html", node=c.root.nodes[node])
|
||||
|
||||
@cherrypy.expose
|
||||
def op(self, node, op, clsname, config):
|
||||
with self.nodes.db.transaction() as c:
|
||||
# TODO validate yaml
|
||||
c.root.nodes[node].classes[clsname] = NClassAttachment(c.root.classes[clsname], config)
|
||||
raise cherrypy.HTTPRedirect("/node/{}".format(node), 302)
|
||||
|
||||
|
||||
@cherrypy.popargs("cls")
|
||||
class ClassWeb(object):
|
||||
|
@ -131,7 +152,7 @@ class ClassWeb(object):
|
|||
self.render = root.render
|
||||
|
||||
@cherrypy.expose
|
||||
def index(self, cls):
|
||||
def index(self, cls=None):
|
||||
# with self.nodes.db.transaction() as c:
|
||||
yield self.render("classes.html")
|
||||
|
||||
|
@ -140,6 +161,14 @@ class ClassWeb(object):
|
|||
# with self.nodes.db.transaction() as c:
|
||||
yield self.render("classes.html")
|
||||
|
||||
@cherrypy.expose
|
||||
def add(self, op, name):
|
||||
with self.nodes.db.transaction() as c:
|
||||
if op == "Create":
|
||||
if name not in c.root.classes:
|
||||
c.root.classes[name] = NClass(name)
|
||||
raise cherrypy.HTTPRedirect("/classes/{}".format(name), 302)
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
|
|
@ -15,7 +15,6 @@ def pmap():
|
|||
|
||||
|
||||
class NObject(persistent.Persistent):
|
||||
|
||||
def __init__(self, fqdn, body):
|
||||
self.fqdn = fqdn
|
||||
self.parents = plist()
|
||||
|
@ -24,13 +23,11 @@ class NObject(persistent.Persistent):
|
|||
|
||||
|
||||
class NClass(persistent.Persistent):
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
|
||||
class NClassAttachment(persistent.Persistent):
|
||||
|
||||
def __init__(self, cls, conf):
|
||||
self.cls = cls
|
||||
self.conf = conf
|
||||
|
@ -45,101 +42,4 @@ class NodeOps(object):
|
|||
if "nodes" not in c.root():
|
||||
c.root.nodes = BTrees.OOBTree.BTree()
|
||||
if "classes" not in c.root():
|
||||
c.root.classes = persistent.list.PersistentList()
|
||||
|
||||
# def add_photoset(self, photoset):
|
||||
# """
|
||||
# Commit a populated photoset object to the library. The paths in the photoset's file list entries will be updated
|
||||
# as the file is moved to the library path.
|
||||
# """
|
||||
|
||||
# # Create target directory
|
||||
# path = os.path.join(self.path, self.get_datedir_path(photoset.date))
|
||||
# os.makedirs(path, exist_ok=True)
|
||||
|
||||
# moves = [] # Track files moved. If the sql transaction files, we'll undo these
|
||||
|
||||
# for file in photoset.files:
|
||||
# dest = os.path.join(path, os.path.basename(file.path))
|
||||
|
||||
# # Check if the name is already in use, rename new file if needed
|
||||
# dupe_rename = 1
|
||||
# while os.path.exists(dest):
|
||||
# fname = os.path.basename(file.path).split(".")
|
||||
# fname[-2] += "_{}".format(dupe_rename)
|
||||
# dest = os.path.join(path, '.'.join(fname))
|
||||
# dupe_rename += 1
|
||||
# os.rename(file.path, dest)
|
||||
# moves.append((file.path, dest))
|
||||
# file.path = dest.lstrip(self.path)
|
||||
|
||||
# s = self.session()
|
||||
# s.add(photoset)
|
||||
# try:
|
||||
# s.commit()
|
||||
# except IntegrityError:
|
||||
# # Commit failed, undo the moves
|
||||
# for move in moves:
|
||||
# os.rename(move[1], move[0])
|
||||
# raise
|
||||
|
||||
# def get_datedir_path(self, date):
|
||||
# """
|
||||
# Return a path like 2018/3/31 given a datetime object representing the same date
|
||||
# """
|
||||
# return os.path.join(str(date.year), str(date.month), str(date.day))
|
||||
|
||||
# def make_thumb(self, photo, style):
|
||||
# """
|
||||
# Create a thumbnail of the given photo, scaled/cropped to the given named style
|
||||
# :return: local path to thumbnail file or None if creation failed or was blocked
|
||||
# """
|
||||
# # style tuples: max x, max y, rotate ok)
|
||||
# # rotate ok means x and y maxes can be swapped if it fits the image's aspect ratio better
|
||||
# styles = {"tiny": (80, 80, False),
|
||||
# "small": (100, 100, False),
|
||||
# "feed": (250, 250, False),
|
||||
# "preview": (1024, 768, True),
|
||||
# "big": (2048, 1536, True)}
|
||||
# dest = os.path.join(self.cache_path, "thumbs", style, "{}.jpg".format(photo.uuid))
|
||||
# if os.path.exists(dest):
|
||||
# return os.path.abspath(dest)
|
||||
# if photo.width is None: # todo better detection of images that PIL can't open
|
||||
# return None
|
||||
# if photo.uuid not in self._failed_thumbs_cache[style]:
|
||||
# thumb_width, thumb_height, flip_ok = styles[style]
|
||||
# i_width = photo.width
|
||||
# i_height = photo.height
|
||||
# im_is_rotated = photo.orientation % 2 != 0 or i_height > i_width
|
||||
|
||||
# if im_is_rotated and flip_ok:
|
||||
# thumb_width, thumb_height = thumb_height, thumb_width
|
||||
|
||||
# thumb_width = min(thumb_width, i_width if i_width > 0 else 999999999) # TODO do we even have photo.width if PIL can't read the image?
|
||||
# thumb_height = min(thumb_height, i_height if i_height > 0 else 999999999) # TODO this seems bad
|
||||
|
||||
# p = Process(target=self.gen_thumb, args=(os.path.join(self.path, photo.path), dest, thumb_width, thumb_height, photo.orientation))
|
||||
# p.start()
|
||||
# p.join()
|
||||
# if p.exitcode != 0:
|
||||
# self._failed_thumbs_cache[style][photo.uuid] = True # dont retry failed generations
|
||||
# return None
|
||||
# return os.path.abspath(dest)
|
||||
# return None
|
||||
|
||||
# @staticmethod
|
||||
# def gen_thumb(src_img, dest_img, width, height, rotation):
|
||||
# try:
|
||||
# start = time()
|
||||
# # TODO lock around the dir creation
|
||||
# os.makedirs(os.path.split(dest_img)[0], exist_ok=True)
|
||||
# image = Image.open(src_img)
|
||||
# image = image.rotate(90 * rotation, expand=True)
|
||||
# thumb = ImageOps.fit(image, (width, height), Image.ANTIALIAS)
|
||||
# thumb.save(dest_img, 'JPEG')
|
||||
# print("Generated {} in {}s".format(dest_img, round(time() - start, 4)))
|
||||
# except:
|
||||
# traceback.print_exc()
|
||||
# if os.path.exists(dest_img):
|
||||
# os.unlink(dest_img)
|
||||
# sys.exit(1)
|
||||
c.root.classes = BTrees.OOBTree.BTree()
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
{% extends "page.html" %}
|
||||
{% block title %}All classes{% endblock %}
|
||||
{% block subtitle %}<a href="/node_edit">Add</a>{% endblock %}
|
||||
{% block subtitle %}{% endblock %}
|
||||
{% block buttons %}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="classes-all">
|
||||
{% for node in classes %}
|
||||
{% for cls in classnames %}
|
||||
<div class="class">
|
||||
<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>
|
||||
<h2>{{ cls }}</h2>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="class-add">
|
||||
<form action="/classes/add" method="post" class="pure-form pure-form-stacked">
|
||||
<fieldset>
|
||||
<fieldset class="pure-group pure-u-1">
|
||||
<input name="name" type="text" class="pure-input-1" placeholder="Name" value="" />
|
||||
</fieldset>
|
||||
<div class="pure-u-1">
|
||||
<input type="submit" name="op" class="pure-button pure-button-primary" value="Create" />
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -27,12 +27,26 @@
|
|||
<div class="node-classes">
|
||||
<h2>Classes</h2>
|
||||
<div class="class-list">
|
||||
{% for class in node.classes %}
|
||||
{% for name, class in node.classes.items() %}
|
||||
<div class="class">
|
||||
{{ class.cls.name }}
|
||||
</div>
|
||||
<div class="class-conf">
|
||||
<pre>{{ class.conf }}</pre>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="node-add-class">
|
||||
<form action="/node/{{ node.fqdn }}/op" method="post" class="pure-form pure-form-stacked">
|
||||
<select name="clsname">
|
||||
{% for cls in classnames %}
|
||||
<option value="{{ cls }}">{{ cls }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<textarea name="config" cols="30" rows="10" placeholder="Yaml config"></textarea>
|
||||
<input type="submit" name="op" class="pure-button pure-button-primary" value="Attach"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue