17 template <
typename Input>
21 template <
typename Input>
25 return [cb = std::move(cb), node_context](
29 if (config ==
nullptr || node_operation ==
nullptr)
32 HTTP_STATUS_BAD_REQUEST,
33 ccf::errors::InvalidNodeState,
34 "Unable to open self-healing-open subsystems");
37 if (!config->get().node_config.recover.self_healing_open.has_value())
40 HTTP_STATUS_BAD_REQUEST,
41 ccf::errors::InvalidNodeState,
42 "This node cannot do self-healing-open");
45 auto in = params.get<Input>();
51 args.
rpc_ctx->get_session_context()->caller_cert);
55 args.
tx, info.quote_info, cert_der, measurement);
58 const auto [code, message] = quote_verification_error(verify_result);
60 "Self-healing-open message from {} has an invalid quote: {} ({})",
61 info.identity.intrinsic_id,
64 return make_error(code, ccf::errors::InvalidQuote, message);
68 "Self-healing-open message from intrinsic id {} has a valid quote",
69 info.identity.intrinsic_id);
74 Tables::SELF_HEALING_OPEN_NODES);
75 auto existing_node_info =
76 node_info_handle->get(info.identity.intrinsic_id);
78 if (existing_node_info.has_value())
81 if (existing_node_info->cert_der != cert_der)
83 auto message = fmt::format(
84 "Self-healing-open message from intrinsic id {} is invalid: "
85 "certificate has changed",
86 info.identity.intrinsic_id);
89 HTTP_STATUS_BAD_REQUEST, ccf::errors::NodeAlreadyExists, message);
96 .identity = info.identity,
98 .service_identity = info.service_identity};
99 node_info_handle->put(info.identity.intrinsic_id, src_info);
104 auto ret = cb(args, in);
115 node_operation->self_healing_open().advance(args.
tx,
false);
117 catch (
const std::logic_error& e)
119 LOG_FAIL_FMT(
"Self-healing-open failed to advance state: {}", e.what());
121 HTTP_STATUS_INTERNAL_SERVER_ERROR,
122 ccf::errors::InternalError,
124 "Failed to advance self-healing-open state: {}", e.what()));
131 static void init_self_healing_open_handlers(
135 auto self_healing_open_gossip =
140 "Self-healing-open: receive gossip from {}",
141 in.info.identity.intrinsic_id);
144 auto chosen_replica = args.tx.template ro<self_healing_open::ChosenNode>(
145 Tables::SELF_HEALING_OPEN_CHOSEN_NODE);
146 if (chosen_replica->get().has_value())
149 .
status = HTTP_STATUS_INTERNAL_SERVER_ERROR,
150 .code = ccf::errors::InternalError,
152 "This node has already voted for {}",
153 chosen_replica->get().value())};
156 auto gossip_handle = args.tx.template rw<self_healing_open::Gossips>(
157 Tables::SELF_HEALING_OPEN_GOSSIPS);
158 if (gossip_handle->get(in.info.identity.intrinsic_id).has_value())
161 "Node {} already gossiped, skipping", in.info.identity.intrinsic_id);
164 gossip_handle->put(in.info.identity.intrinsic_id, in.txid);
169 "/self_healing_open/gossip",
171 json_adapter(wrap_self_healing_open<self_healing_open::GossipRequest>(
172 self_healing_open_gossip, node_context)),
178 auto self_healing_open_vote =
179 [](
auto& args, self_healing_open::TaggedWithNodeInfo in)
180 -> std::optional<ErrorDetails> {
182 "Self-healing-open: receive vote from {}",
183 in.info.identity.intrinsic_id);
186 .template rw<self_healing_open::Votes>(Tables::SELF_HEALING_OPEN_VOTES)
187 ->insert(in.info.identity.intrinsic_id);
193 "/self_healing_open/vote",
196 wrap_self_healing_open<self_healing_open::TaggedWithNodeInfo>(
197 self_healing_open_vote, node_context)),
203 auto self_healing_open_iamopen =
204 [](
auto& args, self_healing_open::TaggedWithNodeInfo in)
205 -> std::optional<ErrorDetails> {
207 "Self-healing-open: receive IAmOpen from {}",
208 in.info.identity.intrinsic_id);
210 .template rw<self_healing_open::SMState>(
211 Tables::SELF_HEALING_OPEN_SM_STATE)
214 .template rw<self_healing_open::ChosenNode>(
215 Tables::SELF_HEALING_OPEN_CHOSEN_NODE)
216 ->put(in.info.identity.intrinsic_id);
221 "/self_healing_open/iamopen",
224 wrap_self_healing_open<self_healing_open::TaggedWithNodeInfo>(
225 self_healing_open_iamopen, node_context)),
231 auto self_healing_open_timeout =
232 [&](
auto& args,
const nlohmann::json& params) {
234 auto config = node_context.
get_subsystem<NodeConfigurationSubsystem>();
235 auto node_operation =
237 if (config ==
nullptr || node_operation ==
nullptr)
240 HTTP_STATUS_BAD_REQUEST,
241 ccf::errors::InvalidNodeState,
242 "Unable to open self-healing-open subsystems");
245 if (!config->get().node_config.recover.self_healing_open.has_value())
248 HTTP_STATUS_BAD_REQUEST,
249 ccf::errors::InvalidNodeState,
250 "This node cannot do self-healing-open");
256 auto primary_id = node_operation->get_primary();
257 if (!primary_id.has_value())
259 LOG_FAIL_FMT(
"self-healing-open timeout: primary unknown");
261 HTTP_STATUS_INTERNAL_SERVER_ERROR,
262 ccf::errors::InternalError,
263 "Primary is unknown");
265 const auto& sig_auth_ident =
266 args.template get_caller<ccf::NodeCertAuthnIdentity>();
267 if (primary_id.value() != sig_auth_ident.node_id)
270 "self-healing-open timeout: request does not originate from "
273 HTTP_STATUS_INTERNAL_SERVER_ERROR,
274 ccf::errors::InternalError,
275 "Request does not originate from primary.");
280 node_operation->self_healing_open().advance(args.tx,
true);
282 catch (
const std::logic_error& e)
285 "Self-healing-open gossip failed to advance state: {}", e.what());
287 HTTP_STATUS_INTERNAL_SERVER_ERROR,
288 ccf::errors::InternalError,
290 "Failed to advance self-healing-open state: {}", e.what()));
292 return make_success(
"Self-healing-open timeout processed successfully");
296 "/self_healing_open/timeout",
299 {std::make_shared<NodeCertAuthnPolicy>()})
Definition node_operation_interface.h:24
Definition node_configuration_subsystem.h:13
Definition endpoint_registry.h:117
virtual Endpoint make_endpoint(const std::string &method, RESTVerb verb, const EndpointFunction &f, const AuthnPolicies &ap)
Definition endpoint_registry.cpp:204
M::Handle * rw(M &m)
Definition tx.h:211
#define LOG_INFO_FMT
Definition internal_logger.h:15
#define LOG_TRACE_FMT
Definition internal_logger.h:13
#define LOG_FAIL_FMT
Definition internal_logger.h:16
std::vector< uint8_t > public_key_der_from_cert(const std::vector< uint8_t > &der)
Definition verifier.cpp:43
std::variant< ErrorDetails, RedirectDetails, AlreadyPopulatedResponse, nlohmann::json > JsonAdapterResponse
Definition json_handler.h:62
Definition file_serving_handlers.h:10
std::function< std::optional< ErrorDetails >(endpoints::EndpointContext &args, Input &in)> SelfHealingOpenHandler
Definition self_healing_open_handlers.h:19
jsonhandler::JsonAdapterResponse make_success()
Definition json_handler.cpp:108
std::function< jsonhandler::JsonAdapterResponse(endpoints::EndpointContext &ctx, nlohmann::json &¶ms)> HandlerJsonParamsAndForward
Definition json_handler.h:85
QuoteVerificationResult
Definition quote.h:18
endpoints::EndpointFunction json_adapter(const HandlerJsonParamsAndForward &f)
Definition json_handler.cpp:142
jsonhandler::JsonAdapterResponse make_error(ccf::http_status status, const std::string &code, const std::string &msg)
Definition json_handler.cpp:124
Definition node_context.h:12
std::shared_ptr< T > get_subsystem(const std::string &name) const
Definition node_context.h:37
Definition odata_error.h:58
http_status status
Definition odata_error.h:59
std::shared_ptr< ccf::RpcContext > rpc_ctx
Definition endpoint_context.h:31
Definition endpoint_context.h:55
ccf::kv::Tx & tx
Definition endpoint_context.h:61
Endpoint & set_openapi_hidden(bool hidden)
Definition endpoint.cpp:10
void install()
Definition endpoint.cpp:135
Endpoint & set_forwarding_required(ForwardingRequired fr)
Definition endpoint.cpp:74
Definition self_healing_open_impl.h:32
Definition self_healing_open.h:30
ccf::QuoteInfo quote_info
Definition self_healing_open.h:31
Definition self_healing_open_impl.h:14