Example #1
0
 def get_slaves(self, domain):
     ips = []
     masters_ips = self.get_masters_ips(domain)
     records = domain.get_records()
     # Slaves from NS
     for record in records.by_type(Record.NS):
         hostname = record.value.rstrip('.')
         # First try with a DNS query, a more reliable source
         try:
             addr = socket.gethostbyname(hostname)
         except socket.gaierror:
             # check if hostname is declared
             try:
                 domain = Domain.objects.get(name=hostname)
             except Domain.DoesNotExist:
                 continue
             else:
                 # default to domain A record address
                 addr = records.by_type(Record.A)[0].value
         if addr not in masters_ips:
             ips.append(addr)
     # Slaves from internal networks
     if not settings.DOMAINS_MASTERS:
         for server in self.get_servers(domain, Bind9SlaveDomainController):
             ips.append(server)
     return OrderedSet(sorted(ips))
Example #2
0
 def get_pending_operations(cls):
     # Check if an error poped up before OperationsMiddleware.process_request()
     if hasattr(cls.thread_locals, 'request'):
         request = cls.thread_locals.request
         if not hasattr(request, 'pending_operations'):
             request.pending_operations = OrderedSet()
         return request.pending_operations
     return set()
Example #3
0
 def get_php_init_vars(self, merge=settings.WEBAPPS_MERGE_PHP_WEBAPPS):
     """ Prepares PHP options for inclusion on php.ini """
     init_vars = OrderedDict()
     options = self.get_options(merge=merge)
     php_version_number = float(self.get_php_version_number())
     timeout = None
     for name, value in options.items():
         if name == 'timeout':
             timeout = value
         else:
             opt = AppOption.get(name)
             # Filter non-deprecated PHP options
             if opt.group == opt.PHP and (opt.deprecated
                                          or 999) > php_version_number:
                 init_vars[name] = value
     # Disable functions
     if self.PHP_DISABLED_FUNCTIONS:
         enable_functions = init_vars.pop('enable_functions', None)
         enable_functions = OrderedSet(
             enable_functions.split(',') if enable_functions else ())
         disable_functions = init_vars.pop('disable_functions', None)
         disable_functions = OrderedSet(
             disable_functions.split(',') if disable_functions else ())
         if disable_functions or enable_functions or self.is_fpm:
             # FPM: Defining 'disable_functions' or 'disable_classes' will not overwrite previously
             #      defined php.ini values, but will append the new value
             for function in self.PHP_DISABLED_FUNCTIONS:
                 if function not in enable_functions:
                     disable_functions.add(function)
             init_vars['disable_functions'] = ','.join(disable_functions)
     # Process timeout
     if timeout:
         timeout = max(settings.WEBAPPS_PYTHON_DEFAULT_TIMEOUT,
                       int(timeout))
         # Give a little slack here
         timeout = str(timeout - 2)
         init_vars['max_execution_time'] = timeout
     # Custom error log
     if self.PHP_ERROR_LOG_PATH and 'error_log' not in init_vars:
         context = self.get_directive_context()
         error_log_path = os.path.normpath(self.PHP_ERROR_LOG_PATH %
                                           context)
         init_vars['error_log'] = error_log_path
     # Auto update max_post_size
     if 'upload_max_filesize' in init_vars:
         upload_max_filesize = init_vars['upload_max_filesize']
         post_max_size = init_vars.get('post_max_size', '0')
         upload_max_filesize_value = eval(
             upload_max_filesize.replace('M', '*1024'))
         post_max_size_value = eval(post_max_size.replace('M', '*1024'))
         init_vars['post_max_size'] = post_max_size
         if upload_max_filesize_value > post_max_size_value:
             init_vars['post_max_size'] = upload_max_filesize
     return init_vars
Example #4
0
 def get_php_init_vars(self, merge=settings.WEBAPPS_MERGE_PHP_WEBAPPS):
     """ Prepares PHP options for inclusion on php.ini """
     init_vars = OrderedDict()
     options = self.get_options(merge=merge)
     php_version_number = float(self.get_php_version_number())
     timeout = None
     for name, value in options.items():
         if name == 'timeout':
             timeout = value
         else:
             opt = AppOption.get(name)
             # Filter non-deprecated PHP options
             if opt.group == opt.PHP and (opt.deprecated or 999) > php_version_number:
                 init_vars[name] = value
     # Disable functions
     if self.PHP_DISABLED_FUNCTIONS:
         enable_functions = init_vars.pop('enable_functions', None)
         enable_functions = OrderedSet(enable_functions.split(',') if enable_functions else ())
         disable_functions = init_vars.pop('disable_functions', None)
         disable_functions = OrderedSet(disable_functions.split(',') if disable_functions else ())
         if disable_functions or enable_functions or self.is_fpm:
             # FPM: Defining 'disable_functions' or 'disable_classes' will not overwrite previously
             #      defined php.ini values, but will append the new value
             for function in self.PHP_DISABLED_FUNCTIONS:
                 if function not in enable_functions:
                     disable_functions.add(function)
             init_vars['disable_functions'] = ','.join(disable_functions)
     # Process timeout
     if timeout:
         timeout = max(settings.WEBAPPS_PYTHON_DEFAULT_TIMEOUT, int(timeout))
         # Give a little slack here
         timeout = str(timeout-2)
         init_vars['max_execution_time'] = timeout
     # Custom error log
     if self.PHP_ERROR_LOG_PATH and 'error_log' not in init_vars:
         context = self.get_directive_context()
         error_log_path = os.path.normpath(self.PHP_ERROR_LOG_PATH % context)
         init_vars['error_log'] = error_log_path
     # Auto update max_post_size
     if 'upload_max_filesize' in init_vars:
         upload_max_filesize = init_vars['upload_max_filesize']
         post_max_size = init_vars.get('post_max_size', '0')
         upload_max_filesize_value = eval(upload_max_filesize.replace('M', '*1024'))
         post_max_size_value = eval(post_max_size.replace('M', '*1024'))
         init_vars['post_max_size'] = post_max_size
         if upload_max_filesize_value > post_max_size_value:
             init_vars['post_max_size'] = upload_max_filesize
     return init_vars
Example #5
0
 def handle(self, *args, **options):
     list_backends = options.get('list_backends')
     if list_backends:
         for backend in ServiceBackend.get_backends():
             self.stdout.write(str(backend).split("'")[1])
         return
     model = apps.get_model(*options['model'].split('.'))
     action = options.get('action')
     interactive = options.get('interactive')
     servers = options.get('servers')
     backends = options.get('backends')
     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', []):
         comps = iter(comp.split('='))
         for arg in comps:
             kwargs[arg] = next(comps).strip().rstrip(',')
     operations = OrderedSet()
     route_cache = {}
     queryset = model.objects.filter(**kwargs).order_by('id')
     if servers:
         servers = servers.split(',')
         backends = backends.split(',')
         server_objects = []
         # Get and create missing Servers
         for server in servers:
             try:
                 server = Server.objects.get(address=server)
             except Server.DoesNotExist:
                 server = Server(name=server, address=server)
                 server.full_clean()
                 server.save()
             server_objects.append(server)
         # Generate operations for the given backend
         for instance in queryset:
             for backend in backends:
                 backend = import_class(backend)
                 operations.add(Operation(backend, instance, action, servers=server_objects))
     else:
         for instance in queryset:
             manager.collect(instance, action, operations=operations, route_cache=route_cache)
     scripts, block = manager.generate(operations)
     servers = []
     # Print scripts
     for key, value in scripts.items():
         server, __ = key
         backend, operations = value
         servers.append(server.name)
         self.stdout.write('# Execute on %s' % server.name)
         for method, commands in backend.scripts:
             script = '\n'.join(commands)
             self.stdout.write(script)
     if interactive:
         context = {
             'servers': ', '.join(servers),
         }
         msg = ("\n\nAre your sure to execute the previous scripts on %(servers)s (yes/no)? " % context)
         confirm = input(msg)
         while 1:
             if confirm not in ('yes', 'no'):
                 confirm = input('Please enter either "yes" or "no": ')
                 continue
             if confirm == 'no':
                 return
             break
     if not dry:
         logs = manager.execute(scripts, block=block)
         for log in logs:
             self.stdout.write(log.stdout)
             self.stderr.write(log.stderr)
         for log in logs:
             self.stdout.write(' '.join((log.backend, log.state)))
Example #6
0
 def get_masters_ips(self, domain):
     ips = list(settings.DOMAINS_MASTERS)
     if not ips:
         ips += self.get_servers(domain, Bind9MasterDomainController)
     return OrderedSet(sorted(ips))
Example #7
0
def collect(instance, action, **kwargs):
    """ collect operations """
    operations = kwargs.get('operations', OrderedSet())
    route_cache = kwargs.get('route_cache', {})
    for backend_cls in ServiceBackend.get_backends():
        # Check if there exists a related instance to be executed for this backend and action
        instances = []
        if action in backend_cls.actions:
            if backend_cls.is_main(instance):
                instances = [(instance, action)]
            else:
                for candidate in backend_cls.get_related(instance):
                    if candidate.__class__.__name__ == 'ManyRelatedManager':
                        if 'pk_set' in kwargs:
                            # m2m_changed signal
                            candidates = kwargs['model'].objects.filter(
                                pk__in=kwargs['pk_set'])
                        else:
                            candidates = candidate.all()
                    else:
                        candidates = [candidate]
                    for candidate in candidates:
                        # Check if a delete for candidate is in operations
                        delete_mock = Operation(backend_cls, candidate,
                                                Operation.DELETE)
                        if delete_mock not in operations:
                            # related objects with backend.model trigger save()
                            instances.append((candidate, Operation.SAVE))
        for selected, iaction in instances:
            # Maintain consistent state of operations based on save/delete behaviour
            # Prevent creating a deleted selected by deleting existing saves
            if iaction == Operation.DELETE:
                save_mock = Operation(backend_cls, selected, Operation.SAVE)
                try:
                    operations.remove(save_mock)
                except KeyError:
                    pass
            else:
                update_fields = kwargs.get('update_fields', None)
                if update_fields is not None:
                    # TODO remove this, django does not execute post_save if update_fields=[]...
                    # Maybe open a ticket at Djangoproject ?
                    # INITIAL INTENTION: "update_fields=[]" is a convention for explicitly executing backend
                    # i.e. account.disable()
                    if update_fields != []:
                        execute = False
                        for field in update_fields:
                            if field not in backend_cls.ignore_fields:
                                execute = True
                                break
                        if not execute:
                            continue
            operation = Operation(backend_cls, selected, iaction)
            # Only schedule operations if the router has execution routes
            routes = router.objects.get_for_operation(operation,
                                                      cache=route_cache)
            if routes:
                logger.debug("Operation %s collected for execution" %
                             operation)
                operation.routes = routes
                if iaction != Operation.DELETE:
                    # usually we expect to be using last object state,
                    # except when we are deleting it
                    operations.discard(operation)
                elif iaction == Operation.DELETE:
                    operation.preload_context()
                operations.add(operation)
    return operations
Example #8
0
 def __enter__(self):
     cls = type(self)
     self.old_pending_operations = cls.thread_locals.pending_operations
     cls.thread_locals.pending_operations = OrderedSet()
     self.old_route_cache = cls.thread_locals.route_cache
     cls.thread_locals.route_cache = {}
Example #9
0
 def handle(self, *args, **options):
     list_backends = options.get('list_backends')
     if list_backends:
         for backend in ServiceBackend.get_backends():
             self.stdout.write(str(backend).split("'")[1])
         return
     model = apps.get_model(*options['model'].split('.'))
     action = options.get('action')
     interactive = options.get('interactive')
     servers = options.get('servers')
     backends = options.get('backends')
     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', []):
         comps = iter(comp.split('='))
         for arg in comps:
             kwargs[arg] = next(comps).strip().rstrip(',')
     operations = OrderedSet()
     route_cache = {}
     queryset = model.objects.filter(**kwargs).order_by('id')
     if servers:
         servers = servers.split(',')
         backends = backends.split(',')
         routes = []
         # Get and create missing Servers
         for server in servers:
             try:
                 server = Server.objects.get(address=server)
             except Server.DoesNotExist:
                 server = Server(name=server, address=server)
                 server.full_clean()
                 server.save()
             routes.append(AttrDict(
                 host=server,
                 async=False,
                 action_is_async=lambda self: False,
             ))
         # Generate operations for the given backend
         for instance in queryset:
             for backend in backends:
                 backend = import_class(backend)
                 operations.add(Operation(backend, instance, action, routes=routes))
     else:
         for instance in queryset:
             manager.collect(instance, action, operations=operations, route_cache=route_cache)
     scripts, serialize = manager.generate(operations)
     servers = []
     # Print scripts
     for key, value in scripts.items():
         route, __, __ = key
         backend, operations = value
         servers.append(str(route.host))
         self.stdout.write('# Execute %s on %s' % (backend.get_name(), route.host))
         for method, commands in backend.scripts:
             script = '\n'.join(commands)
             self.stdout.write(script)
     if interactive:
         context = {
             'servers': ', '.join(servers),
         }
         if not confirm("\n\nAre your sure to execute the previous scripts on %(servers)s (yes/no)? " % context):
             return
     if not dry:
         logs = manager.execute(scripts, serialize=serialize, async=True)
         running = list(logs)
         stdout = 0
         stderr = 0
         while running:
             for log in running:
                 cstdout = len(log.stdout)
                 cstderr = len(log.stderr)
                 if cstdout > stdout:
                     self.stdout.write(log.stdout[stdout:])
                     stdout = cstdout
                 if cstderr > stderr:
                     self.stderr.write(log.stderr[stderr:])
                     stderr = cstderr
                 if log.has_finished:
                     running.remove(log)
                 time.sleep(0.05)
         for log in logs:
             self.stdout.write(' '.join((log.backend, log.state)))
Example #10
0
    def collect_operations(self, **options):
        model = options.get('model')
        backends = options.get('backends') or set()
        if backends:
            backends = set(backends.split(','))
        servers = options.get('servers') or set()
        if servers:
            servers = set([
                Server.objects.get(Q(address=server) | Q(name=server))
                for server in servers.split(',')
            ])
        action = options.get('action')
        if not model:
            models = set()
            if servers:
                for server in servers:
                    if backends:
                        routes = server.routes.filter(backend__in=backends)
                    else:
                        routes = server.routes.all()
            elif backends:
                routes = Route.objects.filter(backend__in=backends)
            else:
                raise CommandError("Model or --servers or --backends?")
            for route in routes.filter(is_active=True):
                model = route.backend_class.model_class()
                models.add(model)
            querysets = [model.objects.order_by('id') for model in models]
        else:
            kwargs = {}
            for comp in options.get('query', []):
                comps = iter(comp.split('='))
                for arg in comps:
                    kwargs[arg] = next(comps).strip().rstrip(',')
            model = apps.get_model(*model.split('.'))
            queryset = model.objects.filter(**kwargs).order_by('id')
            querysets = [queryset]

        operations = OrderedSet()
        route_cache = {}
        for queryset in querysets:
            for instance in queryset:
                manager.collect(instance,
                                action,
                                operations=operations,
                                route_cache=route_cache)
        if backends:
            result = []
            for operation in operations:
                if operation.backend in backends:
                    result.append(operation)
            operations = result
        if servers:
            routes = []
            result = []
            for operation in operations:
                routes = [
                    route for route in operation.routes
                    if route.host in servers
                ]
                operation.routes = routes
                if routes:
                    result.append(operation)
            operations = result
        return operations
Example #11
0
def orchestrate(modeladmin, request, queryset):
    operations = set()
    action = Operation.SAVE
    operations = OrderedSet()
    if queryset.model is Route:
        for route in queryset:
            routes = [route]
            backend = route.backend_class
            if action not in backend.actions:
                continue
            for instance in backend.model_class().objects.all():
                if route.matches(instance):
                    operations.add(Operation(backend, instance, action, routes=routes))
    elif queryset.model is Server:
        models = set()
        for server in queryset:
            routes = server.routes.all()
            for route in routes.filter(is_active=True):
                model = route.backend_class.model_class()
                models.add(model)
        querysets = [model.objects.order_by('id') for model in models]
        
        route_cache = {}
        for model in models:
            for instance in model.objects.all():
                manager.collect(instance, action, operations=operations, route_cache=route_cache)
            routes = []
        result = []
        for operation in operations:
            routes = [route for route in operation.routes if route.host in queryset]
            operation.routes = routes
            if routes:
                result.append(operation)
        operations = result
    if not operations:
        messages.warning(request, _("No related operations."))
        return
    
    if request.POST.get('post') == 'generic_confirmation':
        logs = Operation.execute(operations)
        message_user(request, logs)
        for obj in queryset:
            modeladmin.log_change(request, obj, 'Orchestrated')
        return
    
    opts = modeladmin.model._meta
    display_objects = {}
    for operation in operations:
        try:
            display_objects[operation.backend].append(operation)
        except KeyError:
            display_objects[operation.backend] = [operation]
    context = {
        'title': _("Are you sure to execute the following operations?"),
        'action_name': _('Orchestrate'),
        'action_value': 'orchestrate',
        'display_objects': display_objects,
        'queryset': queryset,
        'opts': opts,
        'app_label': opts.app_label,
        'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
        'obj': get_object_from_url(modeladmin, request),
    }
    return render(request, 'admin/orchestration/orchestrate.html', context)