Switch the API to use a Unix Domain Socket

This drops support for the TCP port and switches to using a socket at
/var/run/weldr/api.socket

Also add the start of some docs for lorax-composer.

--host and --port argument have been removed.

--group sets the group name to use for access to the socket and its
parent directory. Defaults to 'weldr'

--socket sets the full path to the socket to create. Defaults to
'/var/run/weldr/api.socket'
This commit is contained in:
Brian C. Lane 2017-12-20 14:31:17 -08:00
parent 916a001d73
commit 377f5e4124
3 changed files with 77 additions and 6 deletions

View File

@ -14,6 +14,7 @@ Contents:
intro
lorax
livemedia-creator
lorax-composer
product-images
modules

37
docs/lorax-composer.rst Normal file
View File

@ -0,0 +1,37 @@
lorax-composer
==============
:Authors:
Brian C. Lane <bcl@redhat.com>
lorax-composer is an API server that is compatible with the Weldr project's
bdcs-api REST protocol. More information on Weldr can be found [on the Weldr
blog](https://www.weldr.io).
The server runs as root, and communication with it is via a unix domain socket
(``/run/weldr/api.socket`` by default). The directory and socket are owned by
root:weldr so that any user in the weldr group can use the API to control
lorax-composer.
When starting the server it will check for the correct permissions and
ownership of pre-existing directory, or it will create a new one if none exist.
The socket path and group owner's name can be changed from the cmdline by
passing it the ``--socket`` and ``--group`` arguments.
Logs
----
Logs are stored under ``/var/log/lorax-composer/`` and includes all console
messages as well as extra debugging info and API requests.
Quickstart
----------
1. Create a ``weldr`` group by running ``groupadd weldr``
2. Remove any pre-existing socket directory with ``rm -rf /run/weldr/``
A new directory with correct permissions will be created the first time the server runs.
3. Either start it via systemd with ``systemctl start lorax-composer`` or
run it directly with ``lorax-composer /path/to/recipes/``
The ``/path/to/recipes/`` is where the recipe's git repo will be created, and all
the recipes created with the ``/api/v0/recipes/new`` route will be stored.

View File

@ -25,9 +25,11 @@ server_log = logging.getLogger("server")
yum_log = logging.getLogger("yum")
import argparse
import grp
import os
import sys
from threading import Lock
from gevent import socket
from gevent.wsgi import WSGIServer
from pylorax import vernum
@ -44,10 +46,10 @@ def get_parser():
parser = argparse.ArgumentParser(description="Lorax Composer API Server",
fromfile_prefix_chars="@")
parser.add_argument("--host", default="127.0.0.1", metavar="HOST",
help="Host or IP to bind to (127.0.0.1)")
parser.add_argument("--port", default=4000, metavar="PORT",
help="Port to bind to (4000)")
parser.add_argument("--socket", default="/run/weldr/api.socket", metavar="SOCKET",
help="Path to the socket file to listen on")
parser.add_argument("--group", default="weldr", metavar="GROUP",
help="Group to set ownership of the socket to")
parser.add_argument("--log", dest="logfile", default="/var/log/lorax-composer/composer.log", metavar="LOG",
help="Path to logfile (/var/log/lorax-composer/composer.log)")
parser.add_argument("--mockfiles", default="/var/tmp/bdcs-mockfiles/", metavar="MOCKFILES",
@ -129,6 +131,29 @@ if __name__ == '__main__':
setup_logging(opts.logfile)
log.debug("opts=%s", opts)
# Check to make sure the group exists and get its gid
try:
gid = grp.getgrnam(opts.group).gr_gid
except KeyError:
log.error("Missing group '%s'", opts.group)
sys.exit(1)
# Check the socket path to make sure it exists, and that ownership and permissions are correct.
socket_dir = os.path.dirname(opts.socket)
if not os.path.exists(socket_dir):
# Create the directory and set permissions and ownership
os.makedirs(socket_dir, 0o750)
os.chown(socket_dir, 0, gid)
sockdir_stat = os.stat(socket_dir)
if sockdir_stat.st_mode & 0o007 != 0:
log.error("Incorrect permissions on %s, no 'other' permissions are allowed.")
sys.exit(1)
if sockdir_stat.st_gid != gid or sockdir_stat.st_uid != 0:
log.error("%s should be owned by root:%s", socket_dir, opts.group)
sys.exit(1)
if not os.path.isdir(opts.RECIPES):
log.warn("Creating empty recipe directory at %s", opts.RECIPES)
os.makedirs(opts.RECIPES)
@ -149,8 +174,16 @@ if __name__ == '__main__':
# Import example recipes
commit_recipe_directory(server.config["GITLOCK"].repo, "master", opts.RECIPES)
log.info("Starting %s on %s:%d with recipes from %s", VERSION, opts.host, opts.port, opts.RECIPES)
# Setup the Unix Domain Socket, remove old one, set ownership and permissions
if os.path.exists(opts.socket):
os.unlink(opts.socket)
listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
listener.bind(opts.socket)
os.chmod(opts.socket, 0o660)
os.chown(opts.socket, 0, gid)
listener.listen(1)
http_server = WSGIServer((opts.host, opts.port), server, log=LogWrapper(server_log))
log.info("Starting %s on %s with recipes from %s", VERSION, opts.socket, opts.RECIPES)
http_server = WSGIServer(listener, server, log=LogWrapper(server_log))
# The server writes directly to a file object, so point to our log directory
http_server.serve_forever()