Skip to content

Commit

Permalink
Use new governance API throughout our infra (#5698)
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyashton authored Oct 4, 2023
1 parent 23e8a4f commit e73cf2f
Show file tree
Hide file tree
Showing 28 changed files with 799 additions and 544 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ package-lock.json
include/ccf/version.h
python/version.py
src/host/config_schema.h
src/node/gov/api_schema.h
**/compatibility_report.json
.venv_ccf_sandbox/
workspace/*
Expand Down
4 changes: 2 additions & 2 deletions .snpcc_canary
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
___ ___ ___
(. =) Y (0 0) (* *) Y
O \ (.) \- | -/ /
/-xXx--//-----x=x--/-xXx--/---x---->
O \ o | /
/-xXx--//-----x=x--/-xXx--/---x---->>
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
[5.0.0-dev3]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.0-dev3

- Added a `consensus.max_uncommitted_tx_count` configuration option, which specifies the maximum number of transactions that can be pending on the primary. When that threshold is exceeded, a `503 Service Unavailable` is temporarily returned on all but the `/node/*` paths (#5692).
- A new versioned governance API is now available, with the `api-version=2023-06-01-preview` query parameter. This will fully replace the previous governance endpoints, which will be removed in a future release.

## [5.0.0-dev2]

Expand Down
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,14 @@ configure_file(
@ONLY
)

file(READ ${CCF_DIR}/src/node/gov/2023-06-01-preview.json
GOV_API_SCHEMA_2023_06_01_PREVIEW
)
configure_file(
${CCF_DIR}/src/node/gov/api_schema.h.in ${CCF_DIR}/src/node/gov/api_schema.h
@ONLY
)

option(BUILD_TESTS "Build tests" ON)
option(BUILD_UNIT_TESTS "Build unit tests" ON)
option(CLIENT_PROTOCOLS_TEST "Test client protocols (TLS, HTTP/2)" OFF)
Expand Down
3 changes: 3 additions & 0 deletions include/ccf/common_endpoint_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,8 @@ namespace ccf
const std::string& method_prefix_, ccfapp::AbstractNodeContext& context_);

void init_handlers() override;

protected:
virtual void api_endpoint(ccf::endpoints::ReadOnlyEndpointContext& ctx);
};
}
4 changes: 2 additions & 2 deletions scripts/ci-checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ endgroup
group "TypeScript, JavaScript, Markdown, TypeSpec, YAML and JSON format"
npm install --loglevel=error --no-save prettier @typespec/prettier-plugin-typespec 1>/dev/null
if [ $FIX -ne 0 ]; then
git ls-files | grep -e '\.ts$' -e '\.js$' -e '\.md$' -e '\.yaml$' -e '\.yml$' -e '\.json$' | grep -v -e 'tests/sandbox/' | xargs npx prettier --write
git ls-files | grep -e '\.ts$' -e '\.js$' -e '\.md$' -e '\.yaml$' -e '\.yml$' -e '\.json$' | grep -v -e 'tests/sandbox/' -e 'src/node/gov/.*\.json$' | xargs npx prettier --write
else
git ls-files | grep -e '\.ts$' -e '\.js$' -e '\.md$' -e '\.yaml$' -e '\.yml$' -e '\.json$' | grep -v -e 'tests/sandbox/' | xargs npx prettier --check
git ls-files | grep -e '\.ts$' -e '\.js$' -e '\.md$' -e '\.yaml$' -e '\.yml$' -e '\.json$' | grep -v -e 'tests/sandbox/' -e 'src/node/gov/.*\.json$' | xargs npx prettier --check
fi
endgroup

Expand Down
49 changes: 26 additions & 23 deletions src/endpoints/common_endpoint_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,29 +271,8 @@ namespace ccf
.set_openapi_description("Permitted SGX code identities")
.install();

auto openapi = [this](auto& ctx, nlohmann::json&&) {
nlohmann::json document;
const auto result = generate_openapi_document_v1(
ctx.tx,
openapi_info.title,
openapi_info.description,
openapi_info.document_version,
document);

if (result == ccf::ApiResult::OK)
{
return make_success(document);
}
else
{
return make_error(
HTTP_STATUS_INTERNAL_SERVER_ERROR,
ccf::errors::InternalError,
fmt::format("Error code: {}", ccf::api_result_to_str(result)));
}
};
make_read_only_endpoint(
"/api", HTTP_GET, json_read_only_adapter(openapi), no_auth_required)
auto openapi = [this](auto& ctx) { this->api_endpoint(ctx); };
make_read_only_endpoint("/api", HTTP_GET, openapi, no_auth_required)
.set_auto_schema<void, GetAPI::Out>()
.set_openapi_summary("OpenAPI schema")
.install();
Expand Down Expand Up @@ -353,4 +332,28 @@ namespace ccf
"ledger")
.install();
}

void CommonEndpointRegistry::api_endpoint(
ccf::endpoints::ReadOnlyEndpointContext& ctx)
{
nlohmann::json document;
const auto result = generate_openapi_document_v1(
ctx.tx,
openapi_info.title,
openapi_info.description,
openapi_info.document_version,
document);

if (result == ccf::ApiResult::OK)
{
ctx.rpc_ctx->set_response_json(document, HTTP_STATUS_OK);
}
else
{
ctx.rpc_ctx->set_error(
HTTP_STATUS_INTERNAL_SERVER_ERROR,
ccf::errors::InternalError,
fmt::format("Error code: {}", ccf::api_result_to_str(result)));
}
}
}
1 change: 1 addition & 0 deletions src/node/gov/2023-06-01-preview.json

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions src/node/gov/api_schema.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once

namespace ccf::gov::endpoints::schema
{
// clang-format off

// Suppress large string warnings.
// "string literal of length N exceeds maximum length 65536 that C++ compilers are required to support"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverlength-strings"

//
// @CMAKE_GENERATED_COMMENT@
//

static constexpr auto v2023_06_01_preview =
R"!!!(@GOV_API_SCHEMA_2023_06_01_PREVIEW@)!!!";

#pragma clang diagnostic pop

// clang-format on
}
98 changes: 54 additions & 44 deletions src/node/gov/api_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,57 @@ namespace ccf::gov::endpoints
static constexpr std::pair<ApiVersion, char const*> api_version_strings[] = {
{ApiVersion::preview_v1, "2023-06-01-preview"}};

std::optional<ApiVersion> get_api_version(
ccf::endpoints::CommandEndpointContext& ctx)
{
const auto param_name = "api-version";
const auto parsed_query =
http::parse_query(ctx.rpc_ctx->get_request_query());
const auto qit = parsed_query.find(param_name);
if (qit == parsed_query.end())
{
ctx.rpc_ctx->set_error(
HTTP_STATUS_BAD_REQUEST,
ccf::errors::MissingApiVersionParameter,
fmt::format(
"The api-version query parameter (?{}=) is required for all "
"requests.",
param_name));
return std::nullopt;
}

const auto it = std::find_if(
std::begin(api_version_strings),
std::end(api_version_strings),
[&qit](const auto& p) { return p.second == qit->second; });
if (it == std::end(api_version_strings))
{
auto message = fmt::format(
"Unsupported api-version '{}'. The supported api-versions are: ",
qit->second);
auto first = true;
for (const auto& p : api_version_strings)
{
if (first)
{
message += p.second;
first = false;
}
else
{
message += fmt::format(", {}", p.second);
}
}
ctx.rpc_ctx->set_error(
HTTP_STATUS_BAD_REQUEST,
ccf::errors::UnsupportedApiVersionValue,
std::move(message));
return std::nullopt;
}

return it->first;
}

// Extracts api-version from query parameter, and passes this to the given
// functor. Will return error responses for missing and unknown api-versions.
// This means handler functors can safely provide a default implementation
Expand All @@ -26,53 +77,12 @@ namespace ccf::gov::endpoints
auto api_version_adapter(Fn&& f)
{
return [f](auto& ctx) {
const auto param_name = "api-version";
const auto parsed_query =
http::parse_query(ctx.rpc_ctx->get_request_query());
const auto qit = parsed_query.find(param_name);
if (qit == parsed_query.end())
{
ctx.rpc_ctx->set_error(
HTTP_STATUS_BAD_REQUEST,
ccf::errors::MissingApiVersionParameter,
fmt::format(
"The api-version query parameter (?{}=) is required for all "
"requests.",
param_name));
return;
}

const auto it = std::find_if(
std::begin(api_version_strings),
std::end(api_version_strings),
[&qit](const auto& p) { return p.second == qit->second; });
if (it == std::end(api_version_strings))
const auto api_version = get_api_version(ctx);
if (api_version.has_value())
{
auto message = fmt::format(
"Unsupported api-version '{}'. The supported api-versions are: ",
qit->second);
auto first = true;
for (const auto& p : api_version_strings)
{
if (first)
{
message += p.second;
first = false;
}
else
{
message += fmt::format(", {}", p.second);
}
}
ctx.rpc_ctx->set_error(
HTTP_STATUS_BAD_REQUEST,
ccf::errors::UnsupportedApiVersionValue,
std::move(message));
return;
f(ctx, api_version.value());
}

const ApiVersion api_version = it->first;
f(ctx, api_version);
return;
};
}
Expand Down
26 changes: 26 additions & 0 deletions src/node/gov/gov_endpoint_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include "ccf/common_endpoint_registry.h"
#include "node/gov/api_schema.h"
#include "node/gov/api_version.h"
#include "node/gov/handlers/acks.h"
#include "node/gov/handlers/proposals.h"
Expand Down Expand Up @@ -48,5 +49,30 @@ namespace ccf
(rpc_ctx.get_request_verb() == HTTP_POST &&
rpc_ctx.get_request_path() == "/gov/members/proposals:create");
}

void api_endpoint(ccf::endpoints::ReadOnlyEndpointContext& ctx) override
{
using namespace ccf::gov::endpoints;
const auto api_version = get_api_version(ctx);
if (api_version.has_value())
{
switch (api_version.value())
{
case ApiVersion::preview_v1:
{
ctx.rpc_ctx->set_response_body(schema::v2023_06_01_preview);
ctx.rpc_ctx->set_response_header(
http::headers::CONTENT_TYPE,
http::headervalues::contenttype::JSON);
ctx.rpc_ctx->set_response_status(HTTP_STATUS_OK);
break;
}
}
}
else
{
CommonEndpointRegistry::api_endpoint(ctx);
}
}
};
}
2 changes: 1 addition & 1 deletion src/node/gov/handlers/proposals.h
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ namespace ccf::gov::endpoints
"/members/proposals/{proposalId}:withdraw",
HTTP_POST,
api_version_adapter(withdraw_proposal),
detail::active_member_sig_only_policies("withdraw"))
detail::active_member_sig_only_policies("withdrawal"))
.set_openapi_hidden(true)
.install();

Expand Down
Loading

0 comments on commit e73cf2f

Please sign in to comment.