void qdra_config_link_route_delete_CT(qdr_core_t          *core,
                                      qdr_query_t         *query,
                                      qd_field_iterator_t *name,
                                      qd_field_iterator_t *identity)
{
    qdr_link_route_t *lr = 0;

    if (!name && !identity)
        query->status = QD_AMQP_BAD_REQUEST;
    else {
        if (identity)
            lr = qdr_link_route_config_find_by_identity_CT(core, identity);
        else if (name)
            lr = qdr_link_route_config_find_by_name_CT(core, name);

        if (lr) {
            qdr_route_del_link_route_CT(core, lr);
            query->status = QD_AMQP_NO_CONTENT;
        } else
            query->status = QD_AMQP_NOT_FOUND;
    }

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #2
0
void qdra_config_auto_link_get_next_CT(qdr_core_t *core, qdr_query_t *query)
{
    qdr_auto_link_t *al = 0;

    if (query->next_offset < DEQ_SIZE(core->auto_links)) {
        al = DEQ_HEAD(core->auto_links);
        for (int i = 0; i < query->next_offset && al; i++)
            al = DEQ_NEXT(al);
    }

    if (al) {
        //
        // Write the columns of the addr entity into the response body.
        //
        qdr_agent_write_config_auto_link_CT(query, al);

        //
        // Advance to the next object
        //
        qdr_manage_advance_config_auto_link_CT(query, al);
    } else
        query->more = false;

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #3
0
void qdra_conn_link_route_get_CT(qdr_core_t    *core,
                                     qd_iterator_t *name,
                                     qd_iterator_t *identity,
                                     qdr_query_t   *query,
                                     const char    *columns[])
{
    query->status = QD_AMQP_BAD_REQUEST;

    if (!name && !identity) {
        query->status.description = "No name or identity provided";
        goto exit;
    }

    qdr_connection_t *conn = _find_conn_CT(core, query->in_conn);
    qdr_link_route_t *lr = (conn) ? _find_link_route_CT(conn, name, identity) : NULL;

    if (!lr) {
        // Send back a 404
        query->status = QD_AMQP_NOT_FOUND;
        goto exit;
    }

    //
    // Write the columns of the linkRoute entity into the response body.
    //
    query->status = QD_AMQP_OK;
    _write_as_map_CT(query, lr);

exit:
    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #4
0
void qdra_address_get_CT(qdr_core_t          *core,
                         qd_field_iterator_t *name,
                         qd_field_iterator_t *identity,
                         qdr_query_t         *query,
                         const char          *qdr_address_columns[])
{
    qdr_address_t *addr = 0;

    if (identity) //If there is identity, ignore the name
        qd_hash_retrieve(core->addr_hash, identity, (void*) &addr);
    else if (name)
        qd_hash_retrieve(core->addr_hash, name, (void*) &addr);

    if (addr == 0) {
        // Send back a 404
        query->status = QD_AMQP_NOT_FOUND;
    }
    else {
        //
        // Write the columns of the address entity into the response body.
        //
        qdr_manage_write_address_map_CT(core, addr, query->body, qdr_address_columns);
        query->status = QD_AMQP_OK;
    }

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);

}
예제 #5
0
void qdra_config_auto_link_delete_CT(qdr_core_t          *core,
                                      qdr_query_t         *query,
                                      qd_field_iterator_t *name,
                                      qd_field_iterator_t *identity)
{
    qdr_auto_link_t *al = 0;

    if (!name && !identity) {
        query->status = QD_AMQP_BAD_REQUEST;
        query->status.description = "No name or identity provided";
        qd_log(core->agent_log, QD_LOG_ERROR, "Error performing DELETE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description);
    }
    else {
        if (identity)
            al = qdr_auto_link_config_find_by_identity_CT(core, identity);
        else if (name)
            al = qdr_auto_link_config_find_by_name_CT(core, name);

        if (al) {
            qdr_route_del_auto_link_CT(core, al);
            query->status = QD_AMQP_NO_CONTENT;
        } else
            query->status = QD_AMQP_NOT_FOUND;
    }

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #6
0
void qdra_link_get_next_CT(qdr_core_t *core, qdr_query_t *query)
{
    qdr_link_t *link = 0;

        if (query->next_offset < DEQ_SIZE(core->open_links)) {
            link = DEQ_HEAD(core->open_links);
            for (int i = 0; i < query->next_offset && link; i++)
                link = DEQ_NEXT(link);
        }

    if (link) {
        //
        // Write the columns of the link entity into the response body.
        //
        qdr_agent_write_link_CT(query, link);

        //
        // Advance to the next link
        //
        qdr_manage_advance_link_CT(query, link);
    } else
        query->more = false;

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
void qdra_config_link_route_get_next_CT(qdr_core_t *core, qdr_query_t *query)
{
    qdr_link_route_t *lr = 0;

    if (query->next_offset < DEQ_SIZE(core->link_routes)) {
        lr = DEQ_HEAD(core->link_routes);
        for (int i = 0; i < query->next_offset && lr; i++)
            lr = DEQ_NEXT(lr);
    }

    if (lr) {
        //
        // Write the columns of the addr entity into the response body.
        //
        qdr_agent_write_config_link_route_CT(query, lr);

        //
        // Advance to the next object
        //
        qdr_manage_advance_config_link_route_CT(query, lr);
    } else
        query->more = false;

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #8
0
void qdra_link_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset)
{
    //
    // Queries that get this far will always succeed.
    //
    query->status = QD_AMQP_OK;

    //
    // If the offset goes beyond the set of links, end the query now.
    //
    if (offset >= DEQ_SIZE(core->open_links)) {
        query->more = false;
        qdr_agent_enqueue_response_CT(core, query);
        return;
    }

    //
    // Run to the address at the offset.
    //
    qdr_link_t *link = DEQ_HEAD(core->open_links);
    for (int i = 0; i < offset && link; i++)
        link = DEQ_NEXT(link);
    assert(link);

    //
    // Write the columns of the link into the response body.
    //
    qdr_agent_write_link_CT(query, link);

    //
    // Advance to the next address
    //
    query->next_offset = offset;
    qdr_manage_advance_link_CT(query, link);

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #9
0
void qdra_config_auto_link_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset)
{
    //
    // Queries that get this far will always succeed.
    //
    query->status = QD_AMQP_OK;

    //
    // If the offset goes beyond the set of objects, end the query now.
    //
    if (offset >= DEQ_SIZE(core->auto_links)) {
        query->more = false;
        qdr_agent_enqueue_response_CT(core, query);
        return;
    }

    //
    // Run to the object at the offset.
    //
    qdr_auto_link_t *al = DEQ_HEAD(core->auto_links);
    for (int i = 0; i < offset && al; i++)
        al = DEQ_NEXT(al);
    assert(al);

    //
    // Write the columns of the object into the response body.
    //
    qdr_agent_write_config_auto_link_CT(query, al);

    //
    // Advance to the next auto_link
    //
    query->next_offset = offset;
    qdr_manage_advance_config_auto_link_CT(query, al);

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #10
0
void qdra_router_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset)
{
    //
    // Queries that get this far will always succeed.
    //
    query->status = QD_AMQP_OK;

    if (offset >= 1) {
        query->more = false;
        qdr_agent_enqueue_response_CT(core, query);
        return;
    }

    //
    // Write the columns of core into the response body.
    //
    qdr_agent_write_router_CT(query, core);

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #11
0
void qdra_link_update_CT(qdr_core_t              *core,
                             qd_field_iterator_t *name,
                             qd_field_iterator_t *identity,
                             qdr_query_t         *query,
                             qd_parsed_field_t   *in_body)

{
    // If the request was successful then the statusCode MUST contain 200 (OK) and the body of the message
    // MUST contain a map containing the actual attributes of the entity updated. These MAY differ from those
    // requested.
    // A map containing attributes that are not applicable for the entity being created, or invalid values for a
    // given attribute, MUST result in a failure response with a statusCode of 400 (Bad Request).
    if (qd_parse_is_map(in_body)) {
        // The absence of an attribute name implies that the entity should retain its existing value.
        // If the map contains a key-value pair where the value is null then the updated entity should have no value
        // for that attribute, removing any previous value.

        qd_parsed_field_t *admin_state = qd_parse_value_by_key(in_body, qdr_link_columns[QDR_LINK_ADMIN_STATE]);
        if (admin_state) { //admin state is the only field that can be updated via the update management request
            //qd_field_iterator_t *adm_state = qd_parse_raw(admin_state);

            if (identity) {
                qdr_link_t *link = qdr_link_find_by_identity(core, identity);
                // TODO - set the adm_state on the link
                qdra_link_update_set_status(core, query, link);
            }
            else if (name) {
                qdr_link_t *link = qdr_link_find_by_name(core, name);
                // TODO - set the adm_state on the link
                qdra_link_update_set_status(core, query, link);
            }
            else {
                qdra_link_set_bad_request(query);
            }
        }
        else
            qdra_link_set_bad_request(query);

    }
    else
        query->status = QD_AMQP_BAD_REQUEST;

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #12
0
void qdra_address_get_next_CT(qdr_core_t *core, qdr_query_t *query)
{
    qdr_address_t *addr = 0;

    //
    // Use the stored key to try to find the next entry in the table.
    //
    if (query->next_key) {
        qd_hash_retrieve(core->addr_hash, query->next_key->iterator, (void**) &addr);
        qdr_field_free(query->next_key);
        query->next_key = 0;
    }
    if (!addr) {
        //
        // If the address was removed in the time between this get and the previous one,
        // we need to use the saved offset, which is less efficient.
        //
        if (query->next_offset < DEQ_SIZE(core->addrs)) {
            addr = DEQ_HEAD(core->addrs);
            for (int i = 0; i < query->next_offset && addr; i++)
                addr = DEQ_NEXT(addr);
        }
    }

    if (addr) {
        //
        // Write the columns of the address entity into the response body.
        //
        qdr_manage_write_address_list_CT(core, query, addr);

        //
        // Advance to the next address
        //
        qdr_manage_advance_address_CT(query, addr);
    } else
        query->more = false;

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #13
0
void qdra_conn_link_route_get_first_CT(qdr_core_t *core, qdr_query_t *query, int offset)
{
    query->status = QD_AMQP_OK;

    qdr_connection_t *conn = _find_conn_CT(core, query->in_conn);
    if (!conn || offset >= DEQ_SIZE(conn->conn_link_routes)) {
        query->more = false;
    } else {
        // Find the lr at the offset.
        //
        qdr_link_route_t *lr = DEQ_HEAD(conn->conn_link_routes);
        for (int i = 0; i < offset && lr; i++)
            lr = DEQ_NEXT(lr);
        assert(lr);
        // write the lr into the response and advance to next
        _write_as_list_CT(query, lr);
        query->next_offset = offset + 1;
        query->more = DEQ_NEXT(lr) != NULL;
    }
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #14
0
void qdra_conn_link_route_get_next_CT(qdr_core_t *core, qdr_query_t *query)
{
    qdr_connection_t *conn = _find_conn_CT(core, query->in_conn);
    if (!conn || query->next_offset >= DEQ_SIZE(conn->conn_link_routes)) {
        query->more = false;
    } else {
        // find the lr at the offset
        //
        qdr_link_route_t *lr = DEQ_HEAD(conn->conn_link_routes);
        for (int i = 0; i < query->next_offset && lr; i++)
            lr = DEQ_NEXT(lr);

        if (lr) {
            // write response and advance to next
            _write_as_list_CT(query, lr);
            ++query->next_offset;
            query->more = DEQ_NEXT(lr) != NULL;
        } else
            query->more = false;
    }
    qdr_agent_enqueue_response_CT(core, query);
}
예제 #15
0
void qdra_config_auto_link_get_CT(qdr_core_t        *core,
                                qd_field_iterator_t *name,
                                qd_field_iterator_t *identity,
                                qdr_query_t         *query,
                                const char          *qdr_config_auto_link_columns[])
{
    qdr_auto_link_t *al = 0;

    if (!name && !identity) {
        query->status = QD_AMQP_BAD_REQUEST;
        query->status.description = "No name or identity provided";
        qd_log(core->agent_log, QD_LOG_ERROR, "Error performing READ of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description);
    }
    else {
        if (identity) //If there is identity, ignore the name
            al = qdr_auto_link_config_find_by_identity_CT(core, identity);
        else if (name)
            al = qdr_auto_link_config_find_by_name_CT(core, name);

        if (al == 0) {
            // Send back a 404
            query->status = QD_AMQP_NOT_FOUND;
        }
        else {
            //
            // Write the columns of the address entity into the response body.
            //
            qdr_manage_write_config_auto_link_map_CT(core, al, query->body, qdr_config_auto_link_columns);
            query->status = QD_AMQP_OK;
        }
    }

    //
    // Enqueue the response.
    //
    qdr_agent_enqueue_response_CT(core, query);

}
예제 #16
0
void qdra_conn_link_route_delete_CT(qdr_core_t    *core,
                                        qdr_query_t   *query,
                                        qd_iterator_t *name,
                                        qd_iterator_t *identity)
{
    query->status = QD_AMQP_BAD_REQUEST;

    if (!name && !identity) {
        query->status.description = "No name or identity provided";
        goto exit;
    }

    // find the associated connection, if it is not present then the entity has
    // automatically been deleted (not an error)
    //
    qdr_connection_t *conn = _find_conn_CT(core, query->in_conn);
    if (!conn) {
        query->status = QD_AMQP_NO_CONTENT;
        goto exit;
    }

    // find the targetted link route
    qdr_link_route_t *lr = _find_link_route_CT(conn, name, identity);
    if (!lr) {
        query->status = QD_AMQP_NOT_FOUND;
        goto exit;
    }

    qdr_route_del_conn_route_CT(core, lr);
    query->status = QD_AMQP_NO_CONTENT;

exit:
    if (query->status.status != QD_AMQP_NO_CONTENT.status) {
        qd_log(core->agent_log, QD_LOG_ERROR, "Error performing DELETE of %s: %s",
               CONN_LINK_ROUTE_TYPE, query->status.description);
    }
    qdr_agent_enqueue_response_CT(core, query);
}
void qdra_config_link_route_create_CT(qdr_core_t          *core,
                                      qd_field_iterator_t *name,
                                      qdr_query_t         *query,
                                      qd_parsed_field_t   *in_body)
{
    while (true) {
        //
        // Ensure there isn't a duplicate name and that the body is a map
        //
        qdr_link_route_t *lr = DEQ_HEAD(core->link_routes);
        while (lr) {
            if (name && lr->name && qd_field_iterator_equal(name, (const unsigned char*) lr->name))
                break;
            lr = DEQ_NEXT(lr);
        }

        if (!!lr) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = "Name conflicts with an existing entity";
            break;
        }

        if (!qd_parse_is_map(in_body)) {
            query->status = QD_AMQP_BAD_REQUEST;
            break;
        }

        //
        // Extract the fields from the request
        //
        qd_parsed_field_t *prefix_field     = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_PREFIX]);
        qd_parsed_field_t *distrib_field    = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_DISTRIBUTION]);
        qd_parsed_field_t *connection_field = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_CONNECTION]);
        qd_parsed_field_t *container_field  = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_CONTAINER_ID]);
        qd_parsed_field_t *dir_field        = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_DIR]);

        //
        // Prefix and dir fields are mandatory.  Fail if they're not both here.
        //
        if (!prefix_field || !dir_field) {
            query->status = QD_AMQP_BAD_REQUEST;
            break;
        }

        qd_direction_t dir;
        const char *error = qdra_link_route_direction_CT(dir_field, &dir);
        if (error) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = error;
            break;
        }

        qd_address_treatment_t trt;
        error = qdra_link_route_treatment_CT(distrib_field, &trt);
        if (error) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = error;
            break;
        }

        //
        // The request is good.  Create the entity.
        //
        bool               is_container = !!container_field;
        qd_parsed_field_t *in_use_conn  = is_container ? container_field : connection_field;

        lr = qdr_route_add_link_route_CT(core, name, prefix_field, in_use_conn, is_container, trt, dir);

        //
        // Compose the result map for the response.
        //
        if (query->body) {
            qd_compose_start_map(query->body);
            for (int col = 0; col < QDR_CONFIG_LINK_ROUTE_COLUMN_COUNT; col++)
                qdr_config_link_route_insert_column_CT(lr, col, query->body, true);
            qd_compose_end_map(query->body);
        }

        query->status = QD_AMQP_CREATED;
        break;
    }

    //
    // Enqueue the response if there is a body. If there is no body, this is a management
    // operation created internally by the configuration file parser.
    //
    if (query->body) {
        //
        // If there was an error in processing the create, insert a NULL value into the body.
        //
        if (query->status.status / 100 > 2)
            qd_compose_insert_null(query->body);
        qdr_agent_enqueue_response_CT(core, query);
    } else {
        if (query->status.status / 100 > 2)
            qd_log(core->log, QD_LOG_ERROR, "Error configuring linkRoute: %s", query->status.description);
        qdr_query_free(query);
    }
}
예제 #18
0
void qdra_config_auto_link_create_CT(qdr_core_t          *core,
                                      qd_field_iterator_t *name,
                                      qdr_query_t         *query,
                                      qd_parsed_field_t   *in_body)
{
    while (true) {
        //
        // Ensure there isn't a duplicate name and that the body is a map
        //
        qdr_auto_link_t *al = DEQ_HEAD(core->auto_links);
        while (al) {
            if (name && al->name && qd_field_iterator_equal(name, (const unsigned char*) al->name))
                break;
            al = DEQ_NEXT(al);
        }

        if (!!al) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = "Name conflicts with an existing entity";
            qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description);
            break;
        }

        if (!qd_parse_is_map(in_body)) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = "Body of request must be a map";
            qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description);
            break;
        }

        //
        // Extract the fields from the request
        //
        qd_parsed_field_t *addr_field       = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_ADDR]);
        qd_parsed_field_t *dir_field        = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_DIR]);
        qd_parsed_field_t *phase_field      = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_PHASE]);
        qd_parsed_field_t *connection_field = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_CONNECTION]);
        qd_parsed_field_t *container_field  = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_CONTAINER_ID]);

        //
        // Addr and dir fields are mandatory.  Fail if they're not both here.
        //
        if (!addr_field || !dir_field) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = "addr and dir fields are mandatory";
            qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description);
            break;
        }

        qd_direction_t dir;
        const char *error = qdra_auto_link_direction_CT(dir_field, &dir);
        if (error) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = error;
            qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description);
            break;
        }

        //
        // Use the specified phase if present.  Otherwise default based on the direction:
        // Phase 0 for outgoing links and phase 1 for incoming links.
        //
        int phase = phase_field ? qd_parse_as_int(phase_field) : (dir == QD_OUTGOING ? 0 : 1);

        //
        // Validate the phase
        //
        if (phase < 0 || phase > 9) {
            query->status = QD_AMQP_BAD_REQUEST;
            query->status.description = "autoLink phase must be between 0 and 9";
            qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description);
            break;
        }

        //
        // The request is good.  Create the entity.
        //
        bool               is_container = !!container_field;
        qd_parsed_field_t *in_use_conn  = is_container ? container_field : connection_field;

        al = qdr_route_add_auto_link_CT(core, name, addr_field, dir, phase, in_use_conn, is_container);

        //
        // Compose the result map for the response.
        //
        if (query->body) {
            qd_compose_start_map(query->body);
            for (int col = 0; col < QDR_CONFIG_AUTO_LINK_COLUMN_COUNT; col++)
                qdr_config_auto_link_insert_column_CT(al, col, query->body, true);
            qd_compose_end_map(query->body);
        }

        query->status = QD_AMQP_CREATED;
        break;
    }

    //
    // Enqueue the response if there is a body. If there is no body, this is a management
    // operation created internally by the configuration file parser.
    //
    if (query->body) {
        //
        // If there was an error in processing the create, insert a NULL value into the body.
        //
        if (query->status.status / 100 > 2)
            qd_compose_insert_null(query->body);
        qdr_agent_enqueue_response_CT(core, query);
    } else {
        if (query->status.status / 100 > 2)
            qd_log(core->log, QD_LOG_ERROR, "Error configuring linkRoute: %s", query->status.description);
        qdr_query_free(query);
    }
}
예제 #19
0
void qdra_conn_link_route_create_CT(qdr_core_t         *core,
                                    qd_iterator_t      *name,
                                    qdr_query_t        *query,
                                    qd_parsed_field_t  *in_body)
{
    char *pattern = NULL;

    query->status = QD_AMQP_BAD_REQUEST;

    // fail if creating via a configuration file
    if (query->in_conn == 0) {
        query->status.description = "Can only create via management CREATE";
        goto exit;
    }

    // find the associated connection
    qdr_connection_t *conn = _find_conn_CT(core, query->in_conn);
    if (!conn) {
        query->status.description = "Parent connection no longer exists";
        goto exit;
    }

    // fail if forbidden by policy
    if (!conn->policy_allow_dynamic_link_routes) {
        query->status = QD_AMQP_FORBIDDEN;
        goto exit;
    }

    if (!qd_parse_is_map(in_body)) {
        query->status.description = "Body of request must be a map";
        goto exit;
    }

    //
    // Extract the fields from the request
    //
    qd_parsed_field_t *pattern_field    = qd_parse_value_by_key(in_body, qdr_conn_link_route_columns[QDR_CONN_LINK_ROUTE_PATTERN]);
    qd_parsed_field_t *dir_field        = qd_parse_value_by_key(in_body, qdr_conn_link_route_columns[QDR_CONN_LINK_ROUTE_DIRECTION]);

    if (!pattern_field) {
        query->status.description = "Pattern field is required";
        goto exit;
    }

    const char *error = NULL;
    pattern = qdra_config_address_validate_pattern_CT(pattern_field, false, &error);
    if (!pattern) {
        query->status.description = error;
        goto exit;
    }

    qd_direction_t dir;
    error = qdra_link_route_direction_CT(dir_field, &dir);
    if (error) {
        query->status.description = error;
        goto exit;
    }

    qdr_link_route_t *lr = qdr_route_add_conn_route_CT(core, conn, name, pattern, dir);
    if (!lr) {
        query->status.description = "creation failed";
        goto exit;
    }

    query->status = QD_AMQP_CREATED;
    _write_as_map_CT(query, lr);

exit:
    free(pattern);
    if (query->status.status != QD_AMQP_CREATED.status) {
        qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s",
               CONN_LINK_ROUTE_TYPE, query->status.description);
        qd_compose_insert_null(query->body);  // no body map
    }
    qdr_agent_enqueue_response_CT(core, query);
}