Files
mayan-edms/fabfile/server_config.py

142 lines
5.1 KiB
Python

"""Fabric server config management fabfile.
If you need additional configuration, setup ~/.fabricrc file:
user = your_remote_server_username
To get specific command help type:
fab -d command_name
"""
# From http://fueledbylemons.com/blog/2011/04/09/server-configs-and-fabric/
import os
from fabric.api import env, task
from fabric.utils import puts
from fabric import colors
import fabric.network
import fabric.state
YAML_AVAILABLE = True
try:
import yaml
except ImportError:
YAML_AVAILABLE = False
JSON_AVAILABLE = True
try:
import simplejson as json
except ImportError:
try:
import json
except ImportError:
JSON_AVAILABLE = False
################################
# ENVIRONMENTS #
################################
def _load_config(**kwargs):
"""Find and parse server config file.
If `config` keyword argument wasn't set look for default
'server_config.yaml' or 'server_config.json' file.
"""
config, ext = os.path.splitext(kwargs.get('config',
'server_config.yaml' if os.path.exists('server_config.yaml') else 'server_config.json'))
if not os.path.exists(config + ext):
print colors.red('Error. "%s" file not found.' % (config + ext))
return {}
if YAML_AVAILABLE and ext == '.yaml':
loader = yaml
elif JSON_AVAILABLE and ext =='.json':
loader = json
else:
print colors.red('Parser package not available')
return {}
# Open file and deserialize settings.
with open(config + ext) as config_file:
return loader.load(config_file)
@task
def servers(*args, **kwargs):
"""Set destination servers or server groups by comma delimited list of names"""
# Load config
servers = _load_config(**kwargs)
# If no arguments were recieved, print a message with a list of available configs.
if not args:
print 'No server name given. Available configs:'
for key in servers:
print colors.green('\t%s' % key)
# Create `group` - a dictionary, containing copies of configs for selected servers. Server hosts
# are used as dictionary keys, which allows us to connect current command destination host with
# the correct config. This is important, because somewhere along the way fabric messes up the
# hosts order, so simple list index incrementation won't suffice.
env.group = {}
# For each given server name
for name in args:
# Recursive function call to retrieve all server records. If `name` is a group(e.g. `all`)
# - get it's members, iterate through them and create `group`
# record. Else, get fields from `name` server record.
# If requested server is not in the settings dictionary output error message and list all
# available servers.
_build_group(name, servers)
# Copy server hosts from `env.group` keys - this gives us a complete list of unique hosts to
# operate on. No host is added twice, so we can safely add overlaping groups. Each added host is
# guaranteed to have a config record in `env.group`.
env.hosts = env.group.keys()
def _build_group(name, servers):
"""Recursively walk through servers dictionary and search for all server records."""
# We're going to reference server a lot, so we'd better store it.
server = servers.get(name, None)
# If `name` exists in servers dictionary we
if server:
# check whether it's a group by looking for `members`
if isinstance(server, list):
if fabric.state.output['debug']:
puts("%s is a group, getting members" % name)
for item in server:
# and call this function for each of them.
_build_group(item, servers)
# When, finally, we dig through to the standalone server records, we retrieve
# configs and store them in `env.group`
else:
if fabric.state.output['debug']:
puts("%s is a server, filling up env.group" % name)
env.group[server['host']] = server
else:
print colors.red('Error. "%s" config not found. Run `fab servers` to list all available configs' % name)
def reduce_env(task):
"""
Copies server config settings from `env.group` dictionary to env variable.
This way, tasks have easier access to server-specific variables:
`env.owner` instead of `env.group[env.host]['owner']`
"""
def task_with_setup(*args, **kwargs):
# If `s:server` was run before the current command - then we should copy values to
# `env`. Otherwise, hosts were passed through command line with `fab -H host1,host2
# command` and we skip.
if env.get("group", None):
for key,val in env.group[env.host].items():
setattr(env, key, val)
if fabric.state.output['debug']:
puts("[env] %s : %s" % (key, val))
task(*args, **kwargs)
# Don't keep host connections open, disconnect from each host after each task.
# Function will be available in fabric 1.0 release.
# fabric.network.disconnect_all()
return task_with_setup