Added --backends --servers orchestrate management command options

This commit is contained in:
Marc Aymerich 2015-04-16 15:46:26 +00:00
parent 9903fffda3
commit 5d95e64965
5 changed files with 70 additions and 11 deletions

View File

@ -17,6 +17,7 @@ class Bind9MasterDomainBackend(ServiceController):
('domains.Domain', 'origin'),
)
ignore_fields = ['serial']
CONF_PATH = settings.DOMAINS_MASTERS_PATH
@classmethod
def is_main(cls, obj):
@ -27,6 +28,10 @@ class Bind9MasterDomainBackend(ServiceController):
def save(self, domain):
context = self.get_context(domain)
domain.refresh_serial()
self.update_zone(domain, context)
self.update_conf(context)
def update_zone(self, domain, context):
context['zone'] = ';; %(banner)s\n' % context
context['zone'] += domain.render_zone().replace("'", '"')
self.append(textwrap.dedent("""\
@ -37,7 +42,6 @@ class Bind9MasterDomainBackend(ServiceController):
mv %(zone_path)s.tmp %(zone_path)s
""") % context
)
self.update_conf(context)
def update_conf(self, context):
self.append(textwrap.dedent("""\
@ -88,7 +92,9 @@ class Bind9MasterDomainBackend(ServiceController):
return servers
def get_slaves(self, domain):
return self.get_servers(domain, Bind9SlaveDomainBackend)
return set(settings.DOMAINS_SLAVES).union(
set(self.get_servers(domain, Bind9SlaveDomainBackend))
)
def get_context(self, domain):
slaves = self.get_slaves(domain)
@ -99,7 +105,7 @@ class Bind9MasterDomainBackend(ServiceController):
'banner': self.get_banner(),
'slaves': '; '.join(slaves) or 'none',
'also_notify': '; '.join(slaves) + ';' if slaves else '',
'conf_path': settings.DOMAINS_MASTERS_PATH,
'conf_path': self.CONF_PATH,
}
context['conf'] = textwrap.dedent("""
zone "%(name)s" {
@ -118,6 +124,7 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
related_models = (
('domains.Domain', 'origin'),
)
CONF_PATH = settings.DOMAINS_SLAVES_PATH
def save(self, domain):
context = self.get_context(domain)
@ -132,7 +139,9 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
self.append('if [[ $UPDATED == 1 ]]; then { sleep 1 && service bind9 reload; } & fi')
def get_masters(self, domain):
return self.get_servers(domain, Bind9MasterDomainBackend)
return set(settings.DOMAINS_MASTERS).union(
set(self.get_servers(domain, Bind9MasterDomainBackend))
)
def get_context(self, domain):
context = {
@ -140,7 +149,7 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
'banner': self.get_banner(),
'subdomains': domain.subdomains.all(),
'masters': '; '.join(self.get_masters(domain)) or 'none',
'conf_path': settings.DOMAINS_SLAVES_PATH,
'conf_path': self.CONF_PATH,
}
context['conf'] = textwrap.dedent("""
zone "%(name)s" {

View File

@ -90,3 +90,15 @@ DOMAINS_FORBIDDEN = getattr(settings, 'DOMAINS_FORBIDDEN',
# '%(site_dir)s/forbidden_domains.list')
''
)
DOMAINS_MASTERS = getattr(settings, 'DOMAINS_MASTERS',
# Additional master server ip addresses other than autodiscovered by router.get_servers()
()
)
DOMAINS_SLAVES = getattr(settings, 'DOMAINS_SLAVES',
# Additional slave server ip addresses other than autodiscovered by router.get_servers()
()
)

View File

@ -1,9 +1,12 @@
import sys
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandError
from django.db.models.loading import get_model
from orchestra.contrib.orchestration import manager
from orchestra.contrib.orchestration import manager, Operation
from orchestra.contrib.orchestration.models import Server
from orchestra.contrib.orchestration.backends import ServiceBackend
from orchestra.utils.python import import_class
class Command(BaseCommand):
@ -18,13 +21,28 @@ class Command(BaseCommand):
help='Tells Django to NOT prompt the user for input of any kind.')
parser.add_argument('--action', action='store', dest='action',
default='save', help='Executes action. Defaults to "save".')
parser.add_argument('--servers', action='store', dest='servers',
default='save', help='Overrides route server resolution with the provided server.')
parser.add_argument('--backends', action='store', dest='backends',
default='save', help='Overrides backend.')
parser.add_argument('--listbackends', action='store_true', dest='list_backends', default=False,
help='List available baclends.')
parser.add_argument('--dry-run', action='store_true', dest='dry', default=False,
help='Only prints scrtipt.')
def handle(self, *args, **options):
list_backends = options.get('list_backends')
if list_backends:
for backend in ServiceBackend.get_backends():
print(str(backend).split("'")[1])
return
model = get_model(*options['model'].split('.'))
action = options.get('action')
interactive = options.get('interactive')
servers = options.get('servers', '').split(',')
backends = options.get('backends', '').split(',')
if (servers and not backends) or (not servers and backends):
raise CommandError("--backends and --servers go in tandem.")
dry = options.get('dry')
kwargs = {}
for comp in options.get('query', []):
@ -34,8 +52,23 @@ class Command(BaseCommand):
operations = []
operations = set()
route_cache = {}
for instance in model.objects.filter(**kwargs):
manager.collect(instance, action, operations=operations, route_cache=route_cache)
if servers:
server_objects = []
# Get and create missing Servers
for server in servers:
try:
server = Server.objects.get(address=server)
except Server.DoesNotExist:
server = Server.objects.create(name=server, address=server)
server_objects.append(server)
# Generate operations for the given backend
for instance in model.objects.filter(**kwargs):
for backend in backends:
backend = import_class(backend)
operations.add(Operation(backend, instance, action, servers=server_objects))
else:
for instance in model.objects.filter(**kwargs):
manager.collect(instance, action, operations=operations, route_cache=route_cache)
scripts, block = manager.generate(operations)
servers = []
# Print scripts
@ -64,7 +97,7 @@ class Command(BaseCommand):
if not dry:
logs = manager.execute(scripts, block=block)
for log in logs:
print(log.stdout)
sys.stderr.write(log.stderr)
print(log.stdout.encode('utf8', errors='replace'))
sys.stderr.write(log.stderr.encode('utf8', errors='replace'))
for log in logs:
print(log.backend, log.state)

View File

@ -120,6 +120,9 @@ def SSH(backend, log, server, cmds, async=False):
logger.debug(log.traceback)
log.save()
finally:
if log.state == log.STARTED:
log.state = log.ABORTED
log.save(update_fields=['state'])
if channel is not None:
channel.close()
if ssh is not None:

View File

@ -52,6 +52,7 @@ class BackendLog(models.Model):
FAILURE = 'FAILURE'
ERROR = 'ERROR'
REVOKED = 'REVOKED'
ABORTED = 'ABORTED'
# Special state for mocked backendlogs
EXCEPTION = 'EXCEPTION'
@ -62,6 +63,7 @@ class BackendLog(models.Model):
(SUCCESS, SUCCESS),
(FAILURE, FAILURE),
(ERROR, ERROR),
(ABORTED, ABORTED),
(REVOKED, REVOKED),
)