Add a copy of the nginx builder module
This commit is contained in:
parent
ee9e06b1ee
commit
261e9d9fbb
14 changed files with 1237 additions and 0 deletions
206
sysadmin/nginx/config/builder/baseplugins.py
Normal file
206
sysadmin/nginx/config/builder/baseplugins.py
Normal file
|
@ -0,0 +1,206 @@
|
|||
import re
|
||||
import six
|
||||
|
||||
from abc import ABCMeta, abstractproperty
|
||||
|
||||
from ..api import Block, Location
|
||||
from .exceptions import ConfigBuilderException
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class Navigable(object):
|
||||
""" Indicates that a class is navigable.
|
||||
|
||||
This means that it references some type of nginx config machinery,
|
||||
and that this is traversable.
|
||||
|
||||
"""
|
||||
_config_builder = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
""" Creates a new Navigable class
|
||||
|
||||
:param nginx.builder.ConfigBuilder config_builder: internal ConfigBuilder used to create nginx config objs
|
||||
"""
|
||||
# This can sometimes be added by direct access,
|
||||
# in the case of plugins
|
||||
self._config_builder = kwargs.get('config_builder', None)
|
||||
self._parent = kwargs.get('parent', None)
|
||||
|
||||
def chobj(self, obj):
|
||||
""" Changes the current working object to the one provided.
|
||||
|
||||
:param nginx.config.Block obj: object that we're scoping to
|
||||
"""
|
||||
self.config_builder._cwo = obj
|
||||
|
||||
@property
|
||||
def current_obj(self):
|
||||
""" Returns the current working object.
|
||||
|
||||
:returns nginx.config.Block: object that we're currently scoped to
|
||||
"""
|
||||
return self.config_builder._cwo
|
||||
|
||||
@property
|
||||
def config_builder(self):
|
||||
""" Internal config builder.
|
||||
|
||||
:returns nginx.builder.ConfigBuilder: the internal ConfigBuilder for manipulating the nginx config
|
||||
"""
|
||||
return self._config_builder
|
||||
|
||||
def up(self):
|
||||
""" Traverse up the config hierarchy """
|
||||
self.chobj(self.current_obj.parent)
|
||||
|
||||
def add_child(self, child):
|
||||
""" Adds a child to the config object
|
||||
|
||||
:param nginx.config.Builder child: child to insert into config tree
|
||||
"""
|
||||
name = re.split(r'\s+', self.current_obj.name)[0]
|
||||
if self.valid_cfg_parents and name not in self.valid_cfg_parents:
|
||||
raise ConfigBuilderException(
|
||||
'{parent} is not a valid parent for this plugin. Call this off of one of these: {valid_parents}'.format(
|
||||
parent=name if name else 'top',
|
||||
valid_parents=self.valid_cfg_parents
|
||||
), plugin=self._get_name()
|
||||
)
|
||||
|
||||
self.current_obj.sections.add(child)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.config_builder, attr)
|
||||
|
||||
@abstractproperty
|
||||
def valid_cfg_parents(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self._parent
|
||||
|
||||
def _get_name(self):
|
||||
return getattr(self, 'name', self.current_obj.name)
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class Plugin(Navigable):
|
||||
""" Plugin base class. All plugins must inherit from this
|
||||
|
||||
Defines a few properties that must be defined:
|
||||
|
||||
name - name of the plugin. must be unique per config builder
|
||||
exported_methods - dict of method names -> callables. method names don't need to match
|
||||
callables. exported method names must be unique
|
||||
"""
|
||||
|
||||
@abstractproperty
|
||||
def name(self):
|
||||
return ''
|
||||
|
||||
@abstractproperty
|
||||
def exported_methods(self):
|
||||
return {}
|
||||
|
||||
@property
|
||||
def http(self):
|
||||
return self.config_builder._http
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class Endable(Navigable):
|
||||
""" Role that adds an `end` convenience method to close scoped blocks (location, server, et al) """
|
||||
|
||||
def end(self):
|
||||
self.up()
|
||||
return self.config_builder
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class Routable(Navigable):
|
||||
""" A thing that can have routes attached to it.
|
||||
|
||||
In nginx, routes can either be attached to server blocks or other routes
|
||||
|
||||
"""
|
||||
|
||||
def add_route(self, path, *args, **kwargs):
|
||||
loc = Location(path, *args, **kwargs)
|
||||
self.add_child(loc)
|
||||
self.chobj(loc)
|
||||
|
||||
return RouteWrapper(self.current_obj, self.config_builder)
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class Wrapper(object):
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.config_builder, attr)
|
||||
|
||||
|
||||
class RouteWrapper(Routable, Wrapper, Endable):
|
||||
""" This needs to wrap routes emitted by this interface since we can nest routes in nginx configs.
|
||||
|
||||
This also enables users to use the returned routes/servers as a context manager, so that we can
|
||||
sugar-coat syntax even more than we already do
|
||||
|
||||
"""
|
||||
valid_cfg_parents = ('server', 'location')
|
||||
|
||||
def __init__(self, wrapped, config_builder):
|
||||
super(RouteWrapper, self).__init__(
|
||||
parent=wrapped,
|
||||
config_builder=config_builder
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, typ, val, tb):
|
||||
self.end()
|
||||
|
||||
|
||||
class RoutePlugin(Plugin, Routable, Endable):
|
||||
""" A plugin that creates routes
|
||||
|
||||
Routes can be nested infinitely.
|
||||
|
||||
Must be called off of either a server or a location block
|
||||
"""
|
||||
name = 'route'
|
||||
valid_cfg_parents = ('location', 'server')
|
||||
|
||||
@property
|
||||
def exported_methods(self):
|
||||
return {
|
||||
'add_route': self.add_route,
|
||||
}
|
||||
|
||||
|
||||
class ServerPlugin(Plugin, Routable, Endable):
|
||||
""" A plugin that creates server blocks
|
||||
|
||||
Must only be called off of an http block
|
||||
"""
|
||||
name = 'server'
|
||||
valid_cfg_parents = ('http',)
|
||||
|
||||
# XXX: add more server options
|
||||
def add_server(self, hostname='_', **kwargs):
|
||||
server = Block('server', server_name=hostname, **kwargs)
|
||||
self.add_child(server)
|
||||
self.chobj(server)
|
||||
|
||||
return RouteWrapper(self.current_obj, self.config_builder)
|
||||
|
||||
@property
|
||||
def exported_methods(self):
|
||||
return {
|
||||
'add_server': self.add_server,
|
||||
'end': self.end
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue