Esempio n. 1
0
def rating(request):
    urlparts = request.matchdict['params']
    if len(urlparts) != 2:
        return HTTPClientError()

    ampy = initAmpy(request)
    if ampy is None:
        print("Failed to start ampy while creating event rating modal")
        return None

    eventid = urlparts[0]
    streamid = urlparts[1]

    # TODO grab some descriptive information that we can display about
    # this modal

    evdeets = ampy.get_single_event(streamid, eventid)

    request.override_renderer = "../templates/modals/eventrating.pt"

    return {
        "title": "Provide Feedback on this Event",
        "evstreamlabel": "TODO",
        "description": evdeets['description'],
        "eventid": eventid,
        "streamid": streamid,
    }
Esempio n. 2
0
def update_user(request):
    # get the username that we are trying to update
    username = urllib.parse.unquote(request.matchdict["username"])

    # ensure that the person making the request is the same as the user to be
    # updated, or someone with permissions to make changes to any user
    global_permissions = has_permission("editusers", request.context, request)
    local_permissions = (username == authenticated_userid(request))

    if not global_permissions and not local_permissions:
        return HTTPForbidden()

    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    try:
        body = request.json_body
        longname = body["longname"]
        email = body["email"]
        roles = body["roles"] if global_permissions else None
        password = body["password"]
    except (ValueError, KeyError):
        return HTTPBadRequest(body=json.dumps({"error": "missing value"}))

    if ampy.update_user(username, longname, email, roles, password):
        return HTTPNoContent()
    return HTTPBadRequest()
Esempio n. 3
0
def display_member_modal(request, ampname, category):
    """ Generate the content for the mesh membership modification modal """
    # TODO make sure all templates are in sensible places
    request.override_renderer = "../templates/member.pt"

    ampy = initAmpy(request)
    if ampy is None:
        print("Error starting ampy during mesh membership request")
        return None

    ampname = urllib.parse.unquote(ampname)

    if category == "site":
        members = ampy.get_meshes(None, site=ampname)
        available = ampy.get_meshes(None)
    else:
        members = get_mesh_members(ampy, ampname)
        available = ampy.get_amp_sites() # XXX exclude members

    return {
        "title": "Modify mesh membership",
        "ampname": ampname,
        "urlname": escapeURIComponent(ampname),
        "category": category,
        "members": members,
        "available": available, # XXX exclude members
    }
Esempio n. 4
0
def modify_schedule(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    try:
        body = request.json_body
    except (ValueError, KeyError):
        return HTTPBadRequest(body=json.dumps({"error": "invalid body"}))

    if len(set(SCHEDULE_OPTIONS).intersection(body)) == 0:
        return HTTPBadRequest(body=json.dumps(
                    {"error": "No valid options to update"}))

    # if args is present then the test name also needs to be set to validate
    if "args" in body:
        if "test" not in body:
            return HTTPBadRequest(body=json.dumps(
                        {"error":"Missing test type"}))
        if not validate_args(body["test"], body["args"]):
            return HTTPBadRequest(body=json.dumps(
                        {"error": "Bad arguments %s" % body["args"]}))

    result = ampy.update_amp_test(request.matchdict["schedule_id"], body)

    if result is None:
        return HTTPInternalServerError()
    if result:
        return HTTPNoContent()
    return HTTPNotFound()
Esempio n. 5
0
def display_modify_modal(request, username):
    """ Generate the content for the modal modify site/mesh page """
    request.override_renderer = "../templates/user_modal.pt"

    ampy = initAmpy(request)
    if ampy is None:
        print("Error starting ampy during item request")
        return None

    user = ampy.get_user(urllib.parse.unquote(username))

    # Disable parts of the interface that the user isn't able to change.
    # Global admin permissions are checked in the backend too, though the
    # backend will currently allow a user to delete themselves or for admins
    # to remove their own roles.
    if has_permission("editusers", request.context, request) and \
            user["username"] != request.authenticated_userid:
        full_edit = True
    else:
        full_edit = False

    return {
        "title": "Modify user",
        "user": user,
        "full_edit": full_edit,
    }
Esempio n. 6
0
def update_item(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    try:
        body = request.json_body
        longname = body["longname"]
        description = body["description"]
        if request.matched_route.name == "onesite":
            location = body["location"]
        elif request.matched_route.name == "onemesh":
            public = body["public"]
            issource = body["issource"]
    except (ValueError, KeyError):
        return HTTPBadRequest(body=json.dumps({"error": "missing value"}))

    if request.matched_route.name == "onesite":
        if ampy.update_amp_site(
                urllib.parse.unquote(request.matchdict["name"]), longname,
                location, description):
            return HTTPNoContent()
    elif request.matched_route.name == "onemesh":
        if ampy.update_amp_mesh(
                urllib.parse.unquote(request.matchdict["mesh"]), longname,
                description, public, issource):
            return HTTPNoContent()

    return HTTPBadRequest()
Esempio n. 7
0
def display_add_modal(request, ampname):
    """ Generate the content for the modal schedule page """
    request.override_renderer = "../templates/schedule/modal.pt"

    ampy = initAmpy(request)
    if ampy is None:
        print("Error starting ampy during schedule request")
        return None

    # Try to determine site vs mesh without an explicit argument. If we are
    # displaying a modal without coming from a mesh or site page then something
    # has gone pretty wrong.
    if request.referer.split("/")[-3] == "sites":
        info = ampy.get_amp_site_info(ampname)
        category = "site"
    else:
        info = ampy.get_amp_mesh_info(ampname)
        category = "mesh"

    mesh_targets = ampy.get_meshes("destination")
    mesh_sources = ampy.get_meshes("source", site=ampname)
    single_targets = ampy.get_amp_sites()
    test_macros = get_test_macros()

    return {
        "title": "Schedule new test",
        "ampname": ampname,
        "category": category,
        "info": info,
        "mesh_sources": mesh_sources,
        "mesh_targets": mesh_targets,
        "single_targets": single_targets,
        "test_macros": test_macros,
    }
Esempio n. 8
0
def display_site_landing(request):
    """ Display a list of all the available sites """
    page_renderer = get_renderer("../templates/site_landing.pt")
    body = page_renderer.implementation().macros['body']

    SCRIPTS = getCommonScripts() + [
        "modals/modal.js",
        "modals/iteminfo_modal.js",
    ]

    ampy = initAmpy(request)
    if ampy is None:
        print("Error starting ampy during item request")
        return None

    # get all sites that are in a source mesh, or that have a test scheduled
    # with them as the sources
    sources = ampy.get_amp_sources()
    sourcenames = [x["ampname"] for x in sources]
    sources.extend([x for x in ampy.get_amp_site_endpoints()
            if x["ampname"] not in sourcenames])
    sources.sort(key=lambda x: (x["longname"], x["ampname"]))

    # get all sites that are in a destination mesh, or are not in a mesh
    destinations = ampy.get_amp_destinations()
    destinations.extend(ampy.get_amp_meshless_sites())
    destinations.sort(key=lambda x: (x["longname"], x["ampname"]))

    # exclude any sources from the destinations list
    sourcenames = [x["ampname"] for x in sources]
    destinations = [x for x in destinations if x["ampname"] not in sourcenames]

    banopts = getBannerOptions(request)

    # TODO can this be done automatically when generating the lists?
    for source in sources:
        source["urlname"] = escapeURIComponent(source["ampname"])
    for destination in destinations:
        destination["urlname"] = escapeURIComponent(destination["ampname"])

    return {
        "title": "AMP Measurement Sites",
        "body": body,
        "scripts": SCRIPTS,
        "styles": ["bootstrap.min.css"],
        "sources": sources,
        "destinations": destinations,
        "gtag": getGATrackingID(request),
        "show_dash": banopts['showdash'],
        "show_matrix": banopts['showmatrix'],
        "can_edit": has_permission("editconfig", request.context, request),
        "show_config": has_permission("viewconfig", request.context, request),
        "show_users": has_permission("editusers", request.context, request),
        "logged_in": authenticated_userid(request),
        "bannertitle": banopts['title'],
    }
Esempio n. 9
0
def remove_member(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    if ampy.delete_amp_mesh_member(
            urllib.parse.unquote(request.matchdict["mesh"]),
            urllib.parse.unquote(request.matchdict["name"])):
        return HTTPNoContent()
    return HTTPNotFound()
Esempio n. 10
0
def get_single_schedule(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    item = ampy.get_amp_schedule_by_id(request.matchdict["schedule_id"])

    if item is None:
        return HTTPInternalServerError()
    if len(item) == 0:
        return HTTPNotFound()
    return HTTPOk(body=json.dumps(item))
Esempio n. 11
0
def display_modify_modal(request, ampname, schedule_id):
    """ Generate the content for the modal modify schedule page """
    request.override_renderer = "../templates/schedule/modal.pt"

    ampy = initAmpy(request)
    if ampy is None:
        print("Error starting ampy during schedule request")
        return None

    # Try to determine site vs mesh without an explicit argument. If we are
    # displaying a modal without coming from a mesh or site page then something
    # has gone pretty wrong.
    # XXX using the referer is not the best way to do this! we have to unquote
    # twice because everything gets encoded twice to beat WSGI
    current = urllib.parse.unquote(
        urllib.parse.unquote(request.referer.split("/")[-1]))
    if request.referer.split("/")[-3] == "sites":
        if ampname == current:
            # viewing a local site schedule
            info = ampy.get_amp_site_info(ampname)
            category = "site"
            inherited = False
        else:
            # viewing a schedule inherited from a mesh
            info = ampy.get_amp_mesh_info(ampname)
            category = "mesh"
            inherited = True
    else:
        # viewing a mesh schedule from the mesh itself
        info = ampy.get_amp_mesh_info(ampname)
        category = "mesh"
        inherited = False

    mesh_targets = ampy.get_meshes("destination")
    single_targets = ampy.get_amp_sites()
    sched = ampy.get_amp_source_schedule(ampname, schedule_id)[0]
    # dump as json to escape backslashes and quotes
    sched["args"] = json.dumps(sched["args"])
    test_macros = get_test_macros()

    return {
        "title": "Modify scheduled test",
        "ampname": ampname,
        "info": info,
        "inherited": inherited,
        "category": category,
        "mesh_targets": mesh_targets,
        "single_targets": single_targets,
        "schedule": sched,
        "test_macros": test_macros,
        "mesh_sources": [],
    }
Esempio n. 12
0
def delete_user(request):
    # TODO forcibly logout and revoke credentials of user if they are logged in
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    result = ampy.delete_user(urllib.parse.unquote(request.matchdict["username"]))

    if result is None:
        return HTTPInternalServerError()
    if result:
        return HTTPNoContent()
    return HTTPNotFound()
Esempio n. 13
0
def check_login(request, username, password):
    if username is None or password is None or len(password) == 0:
        return False

    ampy = initAmpy(request)
    if ampy is None:
        print("Failed to start ampy for checking login details")
        return False

    user = ampy.get_user(username)
    if user and user["enabled"]:
        return check_password(password, user["password"])
    return False
Esempio n. 14
0
def delete_schedule(request):
    """ Delete the specified schedule test item """
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    result = ampy.delete_amp_test(request.matchdict["schedule_id"])

    if result is None:
        return HTTPInternalServerError()
    if result:
        return HTTPNoContent()
    return HTTPNotFound()
Esempio n. 15
0
def groupfinder(username, request):
    if username is None:
        return None

    ampy = initAmpy(request)
    if ampy is None:
        print("Failed to start ampy for checking user group details")
        return None

    user = ampy.get_user(username)
    if user:
        return ["g:%s" % g for g in user.get("roles", [])]
    return None
Esempio n. 16
0
def get_flagged_mesh_tests(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    mesh = urllib.parse.unquote(request.matchdict["mesh"])
    tests = ampy.get_flagged_mesh_tests(mesh)

    if tests is None:
        return HTTPInternalServerError()
    if tests is False:
        return HTTPNotFound()

    return HTTPOk(body=json.dumps({"tests": tests}))
Esempio n. 17
0
def delete_endpoint(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    result = ampy.delete_amp_test_endpoints(request.matchdict["schedule_id"],
            urllib.parse.unquote(request.matchdict["name"]),
            urllib.parse.unquote(request.matchdict["destination"]))

    if result is None:
        return HTTPInternalServerError()
    if result:
        return HTTPNoContent()
    return HTTPNotFound()
Esempio n. 18
0
def schedule_status(request):
    """ Get the enabled status of the specified schedule test item """
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    status = ampy.is_amp_test_enabled(request.matchdict["schedule_id"])
    if status is None:
        response = HTTPNotFound()
    else:
        if status:
            response = HTTPOk(body=json.dumps({"status": "enabled"}))
        else:
            response = HTTPOk(body=json.dumps({"status": "disabled"}))
    return response
Esempio n. 19
0
def get_destinations(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    item = ampy.get_amp_schedule_by_id(request.matchdict["schedule_id"])

    if item is None:
        return HTTPInternalServerError()
    if len(item) == 0:
        return HTTPNotFound()

    sites = item["dest_site"] if "dest_site" in item else []
    meshes = item["dest_mesh"] if "dest_mesh" in item else []
    return HTTPOk(body=json.dumps({"dest_sites": sites, "dest_meshes": meshes}))
Esempio n. 20
0
def get_all_items(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    if request.matched_route.name == "allsites":
        items = ampy.get_amp_sites()
        label = "sites"
    elif request.matched_route.name == "allmeshes":
        items = ampy.get_meshes(None)
        label = "meshes"

    if items is None:
        return HTTPInternalServerError()
    return HTTPOk(body=json.dumps({label: items}))
Esempio n. 21
0
def api(request):
    """ Determine which API a request is being made against and fetch data """
    urlparts = request.matchdict['params']

    # Dictionary of possible internal API methods we support
    apidict = {
        #'_tracemap': tracemap,
    }

    ampyapidict = {
        '_view': viewapi.graph,
        '_legend': viewapi.legend,
        '_createview': viewapi.create,
        '_destinations': viewapi.destinations,
        '_event': eventapi.event,
        '_matrix': matrixapi.matrix,
        '_matrix_axis': matrixapi.matrix_axis,
        '_matrix_mesh': matrixapi.matrix_mesh,
        '_tooltip': tooltipapi.tooltip,
        '_validatetab': viewapi.validatetab,
    }

    # /api/_* are private APIs
    # /api/* is the public APIs that looks similar to the old one
    if len(urlparts) > 0:
        interface = urlparts[0]
        if interface.startswith("_"):
            if interface in ampyapidict:

                ampy = initAmpy(request)
                if ampy is None:
                    print("Failed to start ampy!")
                    return None

                result = ampyapidict[interface](ampy, request)

                # Allow responses for certain API calls to be cached for 2 mins
                if request.registry.settings['prevent_http_cache'] is not True:
                    if interface in ['_view']:
                        request.response.cache_expires = 120

                return result
            elif interface in apidict:
                return apidict[interface](request)
            else:
                return {"error": "Unsupported API method"}
    return public(request)
Esempio n. 22
0
def delete_item(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    if request.matched_route.name == "onesite":
        result = ampy.delete_amp_site(
            urllib.parse.unquote(request.matchdict["name"]))
    elif request.matched_route.name == "onemesh":
        result = ampy.delete_amp_mesh(
            urllib.parse.unquote(request.matchdict["mesh"]))

    if result is None:
        return HTTPInternalServerError()
    if result:
        return HTTPNoContent()
    return HTTPNotFound()
Esempio n. 23
0
def create_user(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    try:
        body = request.json_body
        username = body["username"]
        longname = body["longname"]
        email = body["email"]
        roles = body["roles"]
        password = body["password"]
    except (ValueError, KeyError):
        return HTTPBadRequest(body=json.dumps({"error": "missing value"}))

    if ampy.add_user(username, longname, email, roles, password):
        return HTTPNoContent()
    return HTTPBadRequest()
Esempio n. 24
0
def create_item(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    try:
        body = request.json_body
        ampname = body["ampname"]
        longname = body["longname"]
        description = body["description"]
        if request.matched_route.name == "allsites":
            location = body["location"]
        elif request.matched_route.name == "allmeshes":
            public = body["public"]
            issource = body["issource"]
    except (ValueError, KeyError):
        return HTTPBadRequest(body=json.dumps({"error": "missing value"}))

    if re.search("[^.:/a-zA-Z0-9_-]", ampname) is not None:
        return HTTPBadRequest(
            body=json.dumps({"error": "bad characters in ampname"}))

    if request.matched_route.name == "allsites":
        result = ampy.add_amp_site(ampname, longname, location, description)
        url = request.route_url("onesite", name=escapeURIComponent(ampname))
        label = "site"
    elif request.matched_route.name == "allmeshes":
        result = ampy.add_amp_mesh(ampname, longname, description, public,
                                   issource)
        url = request.route_url("onemesh", mesh=escapeURIComponent(ampname))
        label = "mesh"
    else:
        return HTTPBadRequest()

    if result:
        return HTTPCreated(headers=[("Location", url)],
                           body=json.dumps(
                               {label: {
                                   "ampname": ampname,
                                   "url": url,
                               }}))

    return HTTPBadRequest()
Esempio n. 25
0
def flag_mesh_tests(request):
    # XXX is it a good idea to be doing more than one operation at once here?
    # should the calling mesh info modal make a request per change?
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    mesh = urllib.parse.unquote(request.matchdict["mesh"])

    try:
        body = request.json_body
        tests = body["tests"]
    except (ValueError, KeyError):
        return HTTPBadRequest(body=json.dumps({"error": "missing tests"}))

    current = ampy.get_flagged_mesh_tests(mesh)

    # return error before we do any modifications
    for test in tests:
        if test not in [
                "latency", "tput", "hops", "http", "youtube", "external", "sip"
        ]:
            return HTTPBadRequest(body=json.dumps({"error": "unknown test"}))

    # add new tests that aren't currently enabled
    for test in tests:
        if test not in current:
            result = ampy.flag_mesh_test(mesh, test)
            if result is None:
                return HTTPInternalServerError()
            if result is False:
                return HTTPNotFound()

    # remove old tests that should no longer be enabled
    for test in current:
        if test not in tests:
            result = ampy.unflag_mesh_test(mesh, test)
            if result is None:
                return HTTPInternalServerError()
            if result is False:
                return HTTPNotFound()

    return HTTPNoContent()
Esempio n. 26
0
def add_endpoint(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    try:
        body = request.json_body
        destination = body["destination"]
    except (ValueError, KeyError):
        return HTTPBadRequest(body=json.dumps({"error": "missing destination"}))

    result = ampy.add_amp_test_endpoints(request.matchdict["schedule_id"],
            urllib.parse.unquote(request.matchdict["name"]), destination)

    if result is None:
        return HTTPInternalServerError()
    if result:
        return HTTPNoContent()
    return HTTPBadRequest()
Esempio n. 27
0
def matrix(request):
    page_renderer = get_renderer("../templates/matrix.pt")
    body = page_renderer.implementation().macros['body']

    SCRIPTS = getCommonScripts() + [
        "lib/jquery.sparkline.min.js",
        "pages/matrix.js",
        "matrix/basematrix.js",
        "matrix/latencymatrix.js",
        "matrix/lossmatrix.js",
        "matrix/hopmatrix.js",
        "matrix/throughputmatrix.js",
        "matrix/httpmatrix.js",
        "matrix/youtubematrix.js",
        "matrix/sipmatrix.js",
    ]

    ampy = initAmpy(request)
    if ampy is None:
        print("Error starting ampy during matrix request")
        return None

    src = ampy.get_meshes("source", public=True)

    banopts = getBannerOptions(request)

    return {
        "title": "AMP Measurements",
        "page": "matrix",
        "body": body,
        "scripts": SCRIPTS,
        "styles": ['bootstrap.min.css'],
        "logged_in": authenticated_userid(request),
        "show_config": has_permission("viewconfig", request.context, request),
        "show_users": has_permission("editusers", request.context, request),
        "gtag": getGATrackingID(request),
        "show_dash": banopts['showdash'],
        "show_matrix": banopts['showmatrix'],
        "bannertitle": banopts['title'],
        "srcMeshes": src,
        "tabs": _create_tabs(request),
    }
Esempio n. 28
0
def get_item(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    if request.matched_route.name == "onesite":
        item = ampy.get_amp_site_info(
            urllib.parse.unquote(request.matchdict["name"]))
        label = "site"
    elif request.matched_route.name == "onemesh":
        item = ampy.get_amp_mesh_info(
            urllib.parse.unquote(request.matchdict["mesh"]))
        label = "mesh"

    if item is None:
        return HTTPInternalServerError()
    if "unknown" in item and item["unknown"] is True:
        return HTTPNotFound()

    return HTTPOk(body=json.dumps({label: item}))
Esempio n. 29
0
def get_members(request):
    ampy = initAmpy(request)
    if ampy is None:
        return HTTPInternalServerError()

    if request.matched_route.name == "sitemeshes":
        members = ampy.get_meshes(None,
                                  site=urllib.parse.unquote(
                                      request.matchdict["name"]))
    elif request.matched_route.name == "meshsites":
        # TODO using this function is not ideal, could be done better in ampy
        members = get_mesh_members(
            ampy, urllib.parse.unquote(request.matchdict["mesh"]))

    # TODO deal with not existing vs zero mesh membership
    if members is None:
        return HTTPInternalServerError()
    if members is False:
        return HTTPNotFound()

    return HTTPOk(body=json.dumps({"membership": members}))
Esempio n. 30
0
def eventview(request):
    start = None
    end = None

    # extract the stream id etc from the request so we can rebuild it
    urlparts = request.matchdict["params"]
    if len(urlparts) < 2:
        raise exception_response(404)

    basestyle = urlparts[0]
    stream = int(urlparts[1])
    if len(urlparts) > 2:
        start = urlparts[2]
    if len(urlparts) > 3:
        end = urlparts[3]

    collection = graphStyleToCollection(basestyle)
    graphstyle = collectionToGraphStyle(basestyle)

    ampy = initAmpy(request)
    if ampy is None:
        print("Failed to start ampy for generating event view")
        return None

    # convert it into a view id, creating it if required
    view_id = ampy.get_event_view(collection, stream)
    if view_id is None:
        print("Failed to generate view for event on stream %d" % (stream))
        return None

    # call the normal graphing function with the view id
    params = (graphstyle, str(view_id))
    if start:
        params += (start,)
        if end:
            params += (end,)
    newurl = request.route_url("view", params=params)

    # send an HTTP 301 and browsers should remember the new location
    return HTTPMovedPermanently(location=newurl)