Added --backends --servers orchestrate management command options
This commit is contained in:
parent
9903fffda3
commit
5d95e64965
|
@ -17,6 +17,7 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
('domains.Domain', 'origin'),
|
('domains.Domain', 'origin'),
|
||||||
)
|
)
|
||||||
ignore_fields = ['serial']
|
ignore_fields = ['serial']
|
||||||
|
CONF_PATH = settings.DOMAINS_MASTERS_PATH
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_main(cls, obj):
|
def is_main(cls, obj):
|
||||||
|
@ -27,6 +28,10 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
def save(self, domain):
|
def save(self, domain):
|
||||||
context = self.get_context(domain)
|
context = self.get_context(domain)
|
||||||
domain.refresh_serial()
|
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'] = ';; %(banner)s\n' % context
|
||||||
context['zone'] += domain.render_zone().replace("'", '"')
|
context['zone'] += domain.render_zone().replace("'", '"')
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
|
@ -37,7 +42,6 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
mv %(zone_path)s.tmp %(zone_path)s
|
mv %(zone_path)s.tmp %(zone_path)s
|
||||||
""") % context
|
""") % context
|
||||||
)
|
)
|
||||||
self.update_conf(context)
|
|
||||||
|
|
||||||
def update_conf(self, context):
|
def update_conf(self, context):
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
|
@ -88,7 +92,9 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
return servers
|
return servers
|
||||||
|
|
||||||
def get_slaves(self, domain):
|
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):
|
def get_context(self, domain):
|
||||||
slaves = self.get_slaves(domain)
|
slaves = self.get_slaves(domain)
|
||||||
|
@ -99,7 +105,7 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
'banner': self.get_banner(),
|
'banner': self.get_banner(),
|
||||||
'slaves': '; '.join(slaves) or 'none',
|
'slaves': '; '.join(slaves) or 'none',
|
||||||
'also_notify': '; '.join(slaves) + ';' if slaves else '',
|
'also_notify': '; '.join(slaves) + ';' if slaves else '',
|
||||||
'conf_path': settings.DOMAINS_MASTERS_PATH,
|
'conf_path': self.CONF_PATH,
|
||||||
}
|
}
|
||||||
context['conf'] = textwrap.dedent("""
|
context['conf'] = textwrap.dedent("""
|
||||||
zone "%(name)s" {
|
zone "%(name)s" {
|
||||||
|
@ -118,6 +124,7 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
||||||
related_models = (
|
related_models = (
|
||||||
('domains.Domain', 'origin'),
|
('domains.Domain', 'origin'),
|
||||||
)
|
)
|
||||||
|
CONF_PATH = settings.DOMAINS_SLAVES_PATH
|
||||||
|
|
||||||
def save(self, domain):
|
def save(self, domain):
|
||||||
context = self.get_context(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')
|
self.append('if [[ $UPDATED == 1 ]]; then { sleep 1 && service bind9 reload; } & fi')
|
||||||
|
|
||||||
def get_masters(self, domain):
|
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):
|
def get_context(self, domain):
|
||||||
context = {
|
context = {
|
||||||
|
@ -140,7 +149,7 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
||||||
'banner': self.get_banner(),
|
'banner': self.get_banner(),
|
||||||
'subdomains': domain.subdomains.all(),
|
'subdomains': domain.subdomains.all(),
|
||||||
'masters': '; '.join(self.get_masters(domain)) or 'none',
|
'masters': '; '.join(self.get_masters(domain)) or 'none',
|
||||||
'conf_path': settings.DOMAINS_SLAVES_PATH,
|
'conf_path': self.CONF_PATH,
|
||||||
}
|
}
|
||||||
context['conf'] = textwrap.dedent("""
|
context['conf'] = textwrap.dedent("""
|
||||||
zone "%(name)s" {
|
zone "%(name)s" {
|
||||||
|
|
|
@ -90,3 +90,15 @@ DOMAINS_FORBIDDEN = getattr(settings, 'DOMAINS_FORBIDDEN',
|
||||||
# '%(site_dir)s/forbidden_domains.list')
|
# '%(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()
|
||||||
|
()
|
||||||
|
)
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import sys
|
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 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):
|
class Command(BaseCommand):
|
||||||
|
@ -18,13 +21,28 @@ class Command(BaseCommand):
|
||||||
help='Tells Django to NOT prompt the user for input of any kind.')
|
help='Tells Django to NOT prompt the user for input of any kind.')
|
||||||
parser.add_argument('--action', action='store', dest='action',
|
parser.add_argument('--action', action='store', dest='action',
|
||||||
default='save', help='Executes action. Defaults to "save".')
|
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,
|
parser.add_argument('--dry-run', action='store_true', dest='dry', default=False,
|
||||||
help='Only prints scrtipt.')
|
help='Only prints scrtipt.')
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
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('.'))
|
model = get_model(*options['model'].split('.'))
|
||||||
action = options.get('action')
|
action = options.get('action')
|
||||||
interactive = options.get('interactive')
|
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')
|
dry = options.get('dry')
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
for comp in options.get('query', []):
|
for comp in options.get('query', []):
|
||||||
|
@ -34,6 +52,21 @@ class Command(BaseCommand):
|
||||||
operations = []
|
operations = []
|
||||||
operations = set()
|
operations = set()
|
||||||
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):
|
for instance in model.objects.filter(**kwargs):
|
||||||
manager.collect(instance, action, operations=operations, route_cache=route_cache)
|
manager.collect(instance, action, operations=operations, route_cache=route_cache)
|
||||||
scripts, block = manager.generate(operations)
|
scripts, block = manager.generate(operations)
|
||||||
|
@ -64,7 +97,7 @@ class Command(BaseCommand):
|
||||||
if not dry:
|
if not dry:
|
||||||
logs = manager.execute(scripts, block=block)
|
logs = manager.execute(scripts, block=block)
|
||||||
for log in logs:
|
for log in logs:
|
||||||
print(log.stdout)
|
print(log.stdout.encode('utf8', errors='replace'))
|
||||||
sys.stderr.write(log.stderr)
|
sys.stderr.write(log.stderr.encode('utf8', errors='replace'))
|
||||||
for log in logs:
|
for log in logs:
|
||||||
print(log.backend, log.state)
|
print(log.backend, log.state)
|
||||||
|
|
|
@ -120,6 +120,9 @@ def SSH(backend, log, server, cmds, async=False):
|
||||||
logger.debug(log.traceback)
|
logger.debug(log.traceback)
|
||||||
log.save()
|
log.save()
|
||||||
finally:
|
finally:
|
||||||
|
if log.state == log.STARTED:
|
||||||
|
log.state = log.ABORTED
|
||||||
|
log.save(update_fields=['state'])
|
||||||
if channel is not None:
|
if channel is not None:
|
||||||
channel.close()
|
channel.close()
|
||||||
if ssh is not None:
|
if ssh is not None:
|
||||||
|
|
|
@ -52,6 +52,7 @@ class BackendLog(models.Model):
|
||||||
FAILURE = 'FAILURE'
|
FAILURE = 'FAILURE'
|
||||||
ERROR = 'ERROR'
|
ERROR = 'ERROR'
|
||||||
REVOKED = 'REVOKED'
|
REVOKED = 'REVOKED'
|
||||||
|
ABORTED = 'ABORTED'
|
||||||
# Special state for mocked backendlogs
|
# Special state for mocked backendlogs
|
||||||
EXCEPTION = 'EXCEPTION'
|
EXCEPTION = 'EXCEPTION'
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ class BackendLog(models.Model):
|
||||||
(SUCCESS, SUCCESS),
|
(SUCCESS, SUCCESS),
|
||||||
(FAILURE, FAILURE),
|
(FAILURE, FAILURE),
|
||||||
(ERROR, ERROR),
|
(ERROR, ERROR),
|
||||||
|
(ABORTED, ABORTED),
|
||||||
(REVOKED, REVOKED),
|
(REVOKED, REVOKED),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue