add file support

Signed-off-by: Nico Schottelius <nico@wurzel.schottelius.org>
This commit is contained in:
Nico Schottelius 2016-11-27 17:11:34 +01:00
parent 4207124c52
commit 9afb57412d
2 changed files with 62 additions and 26 deletions

View file

@ -20,11 +20,14 @@
# #
# #
import ipaddress
import logging import logging
import re import re
import socket import socket
import http.server import http.server
import os
import socketserver import socketserver
import shutil
import multiprocessing import multiprocessing
@ -37,10 +40,11 @@ class Trigger():
"""cdist trigger handling""" """cdist trigger handling"""
# Arguments that are only trigger specific # Arguments that are only trigger specific
triggers_args = [ "http_port", "ipv6", "directory", "content" ] triggers_args = [ "http_port", "ipv6", "directory", "source" ]
def __init__(self, http_port=None, dry_run=False, ipv6=False, def __init__(self, http_port=None, dry_run=False, ipv6=False,
directory=None, content=None, cdistargs=None): directory=None, source=None, cdistargs=None):
self.log = logging.getLogger("trigger") self.log = logging.getLogger("trigger")
self.dry_run = dry_run self.dry_run = dry_run
self.http_port = int(http_port) self.http_port = int(http_port)
@ -48,7 +52,7 @@ class Trigger():
self.args = cdistargs self.args = cdistargs
self.directory = directory self.directory = directory
self.content = content self.source = source
log.debug("IPv6: %s", self.ipv6) log.debug("IPv6: %s", self.ipv6)
@ -59,7 +63,7 @@ class Trigger():
httpdcls = HTTPServerV6 httpdcls = HTTPServerV6
else: else:
httpdcls = HTTPServerV4 httpdcls = HTTPServerV4
httpd = httpdcls(self.args, server_address, TriggerHttp) httpd = httpdcls(self.args, self.directory, self.source, server_address, TriggerHttp)
log.debug("Starting server at port %d", self.http_port) log.debug("Starting server at port %d", self.http_port)
if self.dry_run: if self.dry_run:
@ -86,44 +90,73 @@ class Trigger():
t.run() t.run()
class TriggerHttp(http.server.BaseHTTPRequestHandler): class TriggerHttp(http.server.BaseHTTPRequestHandler):
actions = { "cdist": [ "config", "install" ],
"file": [ "present", "absent" ]
}
def do_HEAD(self):
self.dispatch_request()
def do_POST(self):
self.dispatch_request()
def do_GET(self): def do_GET(self):
self.dispatch_request()
def dispatch_request(self):
host = self.client_address[0] host = self.client_address[0]
code = 200 code = 200
mode = None
self.cdistargs = self.server.cdistargs self.cdistargs = self.server.cdistargs
m = re.match("^/(?P<subsystem>cdist|file)/(?P<action>create|delete|config|install)/", "/cdist/install/") # FIXME: generate regexp based on self.actions
m = re.match("^/(?P<subsystem>cdist|file)/(?P<action>present|absent|config|install)/", self.path)
if m: if m:
subsystem = m.group('subsystem') subsystem = m.group('subsystem')
action = m.group('action') action = m.group('action')
log.debug("Calling {} -> {}".format(subsystem, action)) handler = getattr(self, "handler_" + subsystem)
if not action in self.actions[subsystem]:
code = 404
else: else:
code = 404 code = 404
if mode: if code == 200:
log.debug("Running cdist for %s in mode %s", host, mode) log.debug("Calling {} -> {}".format(subsystem, action))
if self.server.dry_run: handler(action, host)
log.info("Dry run, skipping cdist execution")
else:
self.run_cdist(mode, host)
log.debug("cdist run finished")
else:
log.info("Unsupported mode in path %s, ignoring", self.path)
self.send_response(code) self.send_response(code)
self.end_headers() self.end_headers()
def do_HEAD(self): def handler_file(self, action, host):
self.do_GET() if not self.server.directory or not self.server.source:
log.info("Cannot server file request: directory or source not setup")
return
def do_POST(self): try:
self.do_GET() ipaddress.ip_address(host)
except ValueError:
log.error("Host is not a valid IP address - aborting")
return
def run_cdist(self, mode, host): dst = os.path.join(self.server.directory, host)
cname = mode.title()
module = getattr(cdist, mode) if action == "present":
shutil.copyfile(self.server.source, dst)
if action == "absent":
if os.path.exists(dst):
os.remove(dst)
def handler_cdist(self, action, host):
log.debug("Running cdist for %s in mode %s", host, mode)
if self.server.dry_run:
log.info("Dry run, skipping cdist execution")
return
cname = action.title()
module = getattr(cdist, action)
theclass = getattr(module, cname) theclass = getattr(module, cname)
if hasattr(self.cdistargs, 'out_path'): if hasattr(self.cdistargs, 'out_path'):
@ -145,9 +178,12 @@ class HTTPServerV6(socketserver.ForkingMixIn, http.server.HTTPServer):
""" """
address_family = socket.AF_INET6 address_family = socket.AF_INET6
def __init__(self, cdistargs, *args, **kwargs): def __init__(self, cdistargs, directory, source, *args, **kwargs):
self.cdistargs = cdistargs self.cdistargs = cdistargs
self.dry_run = cdistargs.dry_run self.dry_run = cdistargs.dry_run
self.directory = directory
self.source = source
http.server.HTTPServer.__init__(self, *args, **kwargs) http.server.HTTPServer.__init__(self, *args, **kwargs)
class HTTPServerV4(HTTPServerV6): class HTTPServerV4(HTTPServerV6):

View file

@ -197,8 +197,8 @@ def commandline():
help=('Where to create local files')) help=('Where to create local files'))
parser['trigger'].add_argument( parser['trigger'].add_argument(
'-C', '--content', action='store', required=False, '-S', '--source', action='store', required=False,
help=('What to store in created files')) help=('Which file to copy for creation'))
parser['trigger'].set_defaults(func=cdist.trigger.Trigger.commandline) parser['trigger'].set_defaults(func=cdist.trigger.Trigger.commandline)