ec2_snitch: Coroutinize the aws_api_call_once()

The method connects a socket, grabs in/out streams from it then writes
HTTP request and reads+parses the response. For that it uses class
variables for socket and streams, but there's no real need for that --
all three actually exists throughput the method "lifetime".

To fix it, coroutinizes the method. The same could be achieved my moving
the connected socket and streams into do_with() context, but coroutine
is better than that.

(indentation is left broken)

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
This commit is contained in:
Pavel Emelyanov
2025-10-28 19:24:24 +03:00
parent 5d89816fed
commit 7640ade04d
2 changed files with 20 additions and 23 deletions

View File

@@ -90,12 +90,11 @@ future<sstring> ec2_snitch::aws_api_call(sstring addr, uint16_t port, sstring cm
}
future<sstring> ec2_snitch::aws_api_call_once(sstring addr, uint16_t port, sstring cmd, std::optional<sstring> token) {
return connect(socket_address(inet_address{addr}, port))
.then([this, addr, cmd, token] (connected_socket fd) {
_sd = std::move(fd);
_in = _sd.input();
_out = _sd.output();
connected_socket fd = co_await connect(socket_address(inet_address{addr}, port));
auto in = fd.input();
auto out = fd.output();
{
if (token) {
_req = sstring("GET ") + cmd +
sstring(" HTTP/1.1\r\nHost: ") +addr +
@@ -108,14 +107,15 @@ future<sstring> ec2_snitch::aws_api_call_once(sstring addr, uint16_t port, sstri
sstring("\r\n\r\n");
}
return _out.write(_req.c_str()).then([this] {
return _out.flush();
});
}).then([this] {
co_await out.write(_req.c_str());
co_await out.flush();
}
{
_parser.init();
return _in.consume(_parser).then([this] {
co_await in.consume(_parser);
{
if (_parser.eof()) {
return make_exception_future<sstring>("Bad HTTP response");
co_await coroutine::return_exception(std::runtime_error("Bad HTTP response"));
}
// Read HTTP response header first
@@ -123,27 +123,27 @@ future<sstring> ec2_snitch::aws_api_call_once(sstring addr, uint16_t port, sstri
auto rc = _rsp->_status;
// Verify EC2 instance metadata access
if (rc == http::reply::status_type(403)) {
return make_exception_future<sstring>(std::runtime_error("Error: Unauthorized response received when trying to communicate with instance metadata service."));
co_await coroutine::return_exception(std::runtime_error("Error: Unauthorized response received when trying to communicate with instance metadata service."));
}
if (_rsp->_status != http::reply::status_type::ok) {
return make_exception_future<sstring>(std::runtime_error(format("Error: HTTP response status {}", _rsp->_status)));
co_await coroutine::return_exception(std::runtime_error(format("Error: HTTP response status {}", _rsp->_status)));
}
auto it = _rsp->_headers.find("Content-Length");
if (it == _rsp->_headers.end()) {
return make_exception_future<sstring>("Error: HTTP response does not contain: Content-Length\n");
co_await coroutine::return_exception(std::runtime_error("Error: HTTP response does not contain: Content-Length\n"));
}
auto content_len = std::stoi(it->second);
// Read HTTP response body
return _in.read_exactly(content_len).then([] (temporary_buffer<char> buf) {
temporary_buffer<char> buf = co_await in.read_exactly(content_len);
{
sstring res(buf.get(), buf.size());
return make_ready_future<sstring>(std::move(res));
});
});
});
co_return res;
}
}
}
}
future<sstring> ec2_snitch::read_property_file() {

View File

@@ -30,9 +30,6 @@ protected:
future<sstring> aws_api_call(sstring addr, uint16_t port, const sstring cmd, std::optional<sstring> token);
future<sstring> read_property_file();
private:
connected_socket _sd;
input_stream<char> _in;
output_stream<char> _out;
http_response_parser _parser;
sstring _req;
exponential_backoff_retry _ec2_api_retry = exponential_backoff_retry(std::chrono::seconds(5), std::chrono::seconds(2560));