Example #1
0
    def render_form(back, **kwargs):
        save_error = kwargs.get('save_error')
        if api:
            if form.errors:
                return JsonResponse(form.errors.get_json_data(), status=400)
            if save_error:
                return JsonResponse({'error': save_error[0]}, status=500)

        if not server_form_list and back:
            for l_tmp in back.server_set.all():
                server_form_list.append(ServerForm(instance=l_tmp))
        if not header_form_list and back:
            for h_tmp in back.headers.all():
                header_form_list.append(HeaderForm(instance=h_tmp))
        if not httpchk_header_form_list and back:
            for k, v in back.http_health_check_headers.items():
                httpchk_header_form_list.append(
                    HttpHealthCheckHeaderForm({
                        'check_header_name': k,
                        'check_header_value': v
                    }))
        return render(
            request, 'apps/backend_edit.html', {
                'form': form,
                'servers': server_form_list,
                'server_form': ServerForm(),
                'headers': header_form_list,
                'header_form': HeaderForm(),
                'http_health_check_headers': httpchk_header_form_list,
                'http_health_check_headers_form': HttpHealthCheckHeaderForm(),
                **kwargs
            })
Example #2
0
def backend_clone(request, object_id):
    """ Backend view used to clone a Backend object
    N.B: Do not totally clone the object and save-it in MongoDB 
        because some attributes are unique constraints
 
    :param request: Django request object
    :param object_id: MongoDB object_id of a Backend object
    """
    if not object_id:
        return HttpResponseRedirect('/apps/backend/')
    """ Retrieve object from id in MongoDB """
    try:
        backend = Backend.objects.get(pk=object_id)
    except ObjectDoesNotExist:
        return HttpResponseForbidden("Injection detected")

    server_form_list = []
    header_form_list = []
    httpchk_header_form_list = []

    for l_tmp in backend.server_set.all():
        l_tmp.pk = None
        server_form_list.append(ServerForm(instance=l_tmp))
    for h_tmp in backend.headers.all():
        h_tmp.pk = None
        header_form_list.append(HeaderForm(instance=h_tmp))
    for k, v in backend.http_health_check_headers.items():
        httpchk_header_form_list.append(
            HttpHealthCheckHeaderForm({
                'check_header_name': k,
                'check_header_value': v
            }))

    backend.pk = None
    backend.name = 'Copy of {}'.format(backend.name)
    form = BackendForm(None, instance=backend, error_class=DivErrorList)

    return render(
        request, 'apps/backend_edit.html', {
            'form': form,
            'servers': server_form_list,
            'server_form': ServerForm(),
            'headers': header_form_list,
            'header_form': HeaderForm(),
            'http_health_check_headers': httpchk_header_form_list,
            'http_health_check_headers_form': HttpHealthCheckHeaderForm(),
            'cloned': True
        })
Example #3
0
    def render_form(back, **kwargs):
        save_error = kwargs.get('save_error')
        if api:
            if len(api_errors) > 0 or form.errors:
                api_errors.append(form.errors.as_json())
                return JsonResponse({"errors": api_errors}, status=400)

            if save_error:
                return JsonResponse({'error': save_error[0]}, status=500)

        available_sockets = get_darwin_sockets()

        if not server_form_list and back:
            for l_tmp in back.server_set.all():
                server_form_list.append(ServerForm(instance=l_tmp))

        if not header_form_list and back:
            for h_tmp in back.headers.all():
                header_form_list.append(HeaderForm(instance=h_tmp))

        if not httpchk_header_form_list and back:
            for k, v in back.http_health_check_headers.items():
                httpchk_header_form_list.append(
                    HttpHealthCheckHeaderForm({
                        'check_header_name': k,
                        'check_header_value': v
                    }))

        return render(
            request, 'apps/backend_edit.html', {
                'form': form,
                'servers': server_form_list,
                'net_server_form': ServerForm(mode='net'),
                'unix_server_form': ServerForm(mode='unix'),
                'headers': header_form_list,
                'header_form': HeaderForm(),
                'sockets_choice': available_sockets,
                'http_health_check_headers': httpchk_header_form_list,
                'http_health_check_headers_form': HttpHealthCheckHeaderForm(),
                **kwargs
            })
Example #4
0
def backend_edit(request, object_id=None, api=False):
    backend = None
    server_form_list = []
    header_form_list = []
    httpchk_header_form_list = []
    api_errors = []

    if object_id:
        try:
            backend = Backend.objects.get(pk=object_id)
        except ObjectDoesNotExist:
            if api:
                return JsonResponse({'error': _("Object does not exist.")},
                                    status=404)
            return HttpResponseForbidden("Injection detected")
    """ Create form with object if exists, and request.POST (or JSON) if exists """
    if hasattr(request, "JSON") and api:
        form = BackendForm(request.JSON or None,
                           instance=backend,
                           error_class=DivErrorList)
    else:
        form = BackendForm(request.POST or None,
                           instance=backend,
                           error_class=DivErrorList)

    def render_form(back, **kwargs):
        save_error = kwargs.get('save_error')
        if api:
            if len(api_errors) > 0 or form.errors:
                api_errors.append(form.errors.as_json())
                return JsonResponse({"errors": api_errors}, status=400)

            if save_error:
                return JsonResponse({'error': save_error[0]}, status=500)

        available_sockets = get_darwin_sockets()

        if not server_form_list and back:
            for l_tmp in back.server_set.all():
                server_form_list.append(ServerForm(instance=l_tmp))

        if not header_form_list and back:
            for h_tmp in back.headers.all():
                header_form_list.append(HeaderForm(instance=h_tmp))

        if not httpchk_header_form_list and back:
            for k, v in back.http_health_check_headers.items():
                httpchk_header_form_list.append(
                    HttpHealthCheckHeaderForm({
                        'check_header_name': k,
                        'check_header_value': v
                    }))

        return render(
            request, 'apps/backend_edit.html', {
                'form': form,
                'servers': server_form_list,
                'net_server_form': ServerForm(mode='net'),
                'unix_server_form': ServerForm(mode='unix'),
                'headers': header_form_list,
                'header_form': HeaderForm(),
                'sockets_choice': available_sockets,
                'http_health_check_headers': httpchk_header_form_list,
                'http_health_check_headers_form': HttpHealthCheckHeaderForm(),
                **kwargs
            })

    if request.method in ("POST", "PUT"):
        """ Handle JSON formatted listeners """
        try:
            if api:
                server_ids = request.JSON.get('servers', [])
                assert isinstance(server_ids,
                                  list), "Servers field must be a list."
            else:
                server_ids = json_loads(request.POST.get('servers', "[]"))
        except Exception as e:
            return render_form(backend,
                               save_error=[
                                   "Error in Servers field : {}".format(e),
                                   str.join('', format_exception(*exc_info()))
                               ])
        header_objs = []
        httpchk_headers_dict = {}
        if form.data.get('mode') == "http":
            """ Handle JSON formatted request headers """
            try:
                if api:
                    header_ids = request.JSON.get('headers', [])
                    assert isinstance(header_ids,
                                      list), "Headers field must be a list."
                else:
                    header_ids = json_loads(request.POST.get('headers', "[]"))
            except Exception as e:
                return render_form(
                    backend,
                    save_error=[
                        "Error in Request-headers field : {}".format(e),
                        str.join('', format_exception(*exc_info()))
                    ])
            """ Handle JSON formatted request Http-health-check-headers """
            try:
                if api:
                    httpchk_header_ids = request.JSON.get(
                        'http_health_check_headers', [])
                    assert isinstance(
                        httpchk_header_ids,
                        list), "Health check headers field must be a list."
                else:
                    httpchk_header_ids = json_loads(
                        request.POST.get('http_health_check_headers', "[]"))
            except Exception as e:
                return render_form(
                    backend,
                    save_error=[
                        "Error in Http-health-check-headers field : {}".format(
                            e),
                        str.join('', format_exception(*exc_info()))
                    ])
            """ For each Health check header in list """
            for header in httpchk_header_ids:
                httpchkform = HttpHealthCheckHeaderForm(
                    header, error_class=DivErrorList)
                if not httpchkform.is_valid():
                    if api:
                        api_errors.append({
                            "health_check":
                            httpchkform.errors.get_json_data()
                        })
                    else:
                        form.add_error('enable_http_health_check',
                                       httpchkform.errors.as_ul())
                    continue

                # Save forms in case we re-print the page
                httpchk_header_form_list.append(httpchkform)
                httpchk_headers_dict[header.get(
                    'check_header_name')] = header.get('check_header_value')
            """ For each header in list """
            for header in header_ids:
                """ If id is given, retrieve object from mongo """
                try:
                    instance_h = Header.objects.get(
                        pk=header['id']) if header.get('id') else None
                except ObjectDoesNotExist:
                    form.add_error(
                        None,
                        "Request-header with id {} not found. Injection detected ?"
                    )
                    continue
                """ And instantiate form with the object, or None """
                header_f = HeaderForm(header, instance=instance_h)
                if not header_f.is_valid():
                    if api:
                        api_errors.append(
                            {"headers": header_f.errors.get_json_data()})
                    else:
                        form.add_error('headers', header_f.errors.as_ul())
                    continue

                # Save forms in case we re-print the page
                header_form_list.append(header_f)
                # And save objects list, to save them later, when Frontend will be saved
                header_objs.append(header_f.save(commit=False))

        server_objs = []
        """ For each listener in list """
        for server in server_ids:
            """ If id is given, retrieve object from mongo """
            try:
                instance_s = Server.objects.get(
                    pk=server['id']) if server['id'] else None
            except ObjectDoesNotExist:
                form.add_error(
                    None, "Server with id {} not found.".format(server['id']))
                continue
            """ And instantiate form with the object, or None """
            server_f = ServerForm(server, instance=instance_s)
            if not server_f.is_valid():
                if api:
                    api_errors.append(
                        {'server': server_f.errors.get_json_data()})
                else:
                    form.add_error(None, server_f.errors.as_ul())

                continue

            server_form_list.append(server_f)
            server_obj = server_f.save(commit=False)
            server_objs.append(server_obj)

        # If errors has been added in form
        if not form.is_valid():
            logger.error("Form errors: {}".format(form.errors.as_json()))
            return render_form(backend)

        # Save the form to get an id if there is not already one
        backend = form.save(commit=False)
        backend.configuration = ""
        backend.http_health_check_headers = httpchk_headers_dict

        # At least one server is required if Frontend enabled
        if not server_objs and backend.enabled:
            form.add_error(
                None, "At least one server is required if backend is enabled.")
            return render_form(backend)
        """ Generate the non-yet saved object conf """
        try:
            logger.debug("Generating conf of backend '{}'".format(
                backend.name))
            backend.configuration = backend.generate_conf(
                header_list=header_objs, server_list=server_objs)
            """ Save the conf on disk, and test-it with haproxy -c """
            logger.debug("Writing/Testing conf of backend '{}'".format(
                backend.name))
            backend.test_conf()
        except ServiceError as e:
            logger.exception(e)
            return render_form(backend, save_error=[str(e), e.traceback])

        except Exception as e:
            logger.exception(e)
            return render_form(backend,
                               save_error=[
                                   "No referenced error",
                                   str.join('', format_exception(*exc_info()))
                               ])
        """ If the conf is OK, save the Backend object """
        # Is that object already in db or not
        first_save = not backend.id
        try:
            logger.debug("Saving backend")
            backend.save()
            logger.debug("Backend '{}' (id={}) saved in MongoDB.".format(
                backend.name, backend.id))
            """ And all the listeners created earlier """
            for s in server_objs:
                s.backend = backend
                logger.debug("Saving server {}".format(str(s)))
                s.save()
            """ Delete listeners deleted in form """
            for s in backend.server_set.exclude(
                    pk__in=[l.id for l in server_objs]):
                s.delete()
                logger.info("Deleting server {}".format(s))
            """ If mode is HTTP """
            if backend.mode == "http":
                """ Remove request-headers removed """
                for header in backend.headers.all():
                    if header not in header_objs:
                        backend.headers.remove(header)
                """ Associate added request-headers """
                for header in header_objs:
                    new_object = not header.id
                    header.save()
                    if new_object:
                        backend.headers.add(header)
                    logger.debug(
                        "HTTP Headers {} associated to Frontend {}".format(
                            header, backend))
            """ if the Backend is updated and its name was changed """
            if not first_save and "name" in form.changed_data:
                logger.info(
                    "Backend name changed, looking for associated frontends..."
                )
                workflow_list = backend.workflow_set.all()
                for workflow in workflow_list:
                    logger.info(
                        "reloading frontend '{}' haproxy configuration".format(
                            workflow.frontend))
                    workflow.frontend.reload_conf()

            # Re-generate config AFTER save, to get ID
            backend.configuration = backend.generate_conf()
            """ asynchronous API request to save conf on node """
            # Save conf first, to raise if there is an error
            backend.save_conf()
            logger.debug("Write conf of backend '{}' asked on cluster".format(
                backend.name))
            """ Reload HAProxy service - After rsyslog to prevent logging crash """
            api_res = Cluster.api_request(
                "services.haproxy.haproxy.reload_service")
            if not api_res.get('status'):
                raise ServiceReloadError("on cluster\n API request error.",
                                         "haproxy",
                                         traceback=api_res.get('message'))
            for node in Node.objects.all():
                backend.status[node.name] = "WAITING"

            backend.save()

        except (VultureSystemError, ServiceError) as e:
            """ Error saving configuration file """
            """ The object has been saved, delete-it if needed """
            if first_save:
                for server in backend.server_set.all():
                    server.delete()

                backend.delete()

            logger.exception(e)
            return render_form(backend, save_error=[str(e), e.traceback])

        except Exception as e:
            """ If we arrive here, the object has not been saved """
            logger.exception(e)
            return render_form(
                backend,
                save_error=[
                    "Failed to save object in database :\n{}".format(e),
                    str.join('', format_exception(*exc_info()))
                ])

        if api:
            return build_response(backend.id, "applications.backend.api",
                                  COMMAND_LIST)
        return HttpResponseRedirect('/apps/backend/')

    return render_form(backend)