Skip to content

Commit

Permalink
[#7867] docdb: Fix redirection logic in master-path-handlers to respe…
Browse files Browse the repository at this point in the history
…ct broadcast addresses.

Summary: Conditionally use broadcast addresses when redirecting http requests in master. As is already done for public vs private addresses for making rpcs, we change the URL redirection logic to respect the use_private_ip flag and the node zoning when forwarding HTTP requests.

Test Plan:
Local testing with yugabyted.

Tested the redirect logic by using a non-leader master to access the UI.
Tested the logic when server_broadcast_addresses is empty - it still redirects using a private address instead.
Testing the logic when the leader is down - it shows the expected error message (Not found (yb/master/master-path-handlers.cc:205): Unable to locate leader master to redirect this request: /)

Reviewers: sanketh, skedia

Reviewed By: skedia

Subscribers: ybase, bogdan

Differential Revision: https://phabricator.dev.yugabyte.com/D16780
  • Loading branch information
druzac committed May 10, 2022
1 parent 41bbd03 commit e99e294
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 37 deletions.
82 changes: 45 additions & 37 deletions src/yb/master/master-path-handlers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,58 +157,66 @@ void MasterPathHandlers::ZoneTabletCounts::operator+=(const ZoneTabletCounts& ot
}

// Retrieve the specified URL response from the leader master
void MasterPathHandlers::RedirectToLeader(const Webserver::WebRequest& req,
Webserver::WebResponse* resp) {
std::stringstream *output = &resp->output;
vector<ServerEntryPB> masters;
Status s = master_->ListMasters(&masters);
if (!s.ok()) {
s = s.CloneAndPrepend("Unable to list masters during web request handling");
void MasterPathHandlers::RedirectToLeader(
const Webserver::WebRequest& req, Webserver::WebResponse* resp) {
std::stringstream* output = &resp->output;
auto redirect_result = GetLeaderAddress(req);
if (!redirect_result) {
auto s = redirect_result.status();
LOG(WARNING) << s.ToString();
*output << "<h2>" << s.ToString() << "</h2>\n";
return;
}

string redirect;
for (const ServerEntryPB& master : masters) {
if (master.has_error()) {
continue;
}

if (master.role() == PeerRole::LEADER) {
// URI already starts with a /, so none is needed between $1 and $2.
if (master.registration().http_addresses().size() > 0) {
redirect = Substitute(
"http://$0$1$2",
HostPortPBToString(master.registration().http_addresses(0)),
req.redirect_uri,
req.query_string.empty() ? "?raw" : "?" + req.query_string + "&raw");
}
break;
}
}

if (redirect.empty()) {
string error = "Unable to locate leader master to redirect this request: " + redirect;
LOG(WARNING) << error;
*output << error << "<br>";
return;
}

std::string redirect = *redirect_result;
EasyCurl curl;
faststring buf;
s = curl.FetchURL(redirect, &buf, kCurlTimeoutSec);
auto s = curl.FetchURL(redirect, &buf, kCurlTimeoutSec);
if (!s.ok()) {
LOG(WARNING) << "Error retrieving leader master URL: " << redirect
<< ", error :" << s.ToString();
*output << "Error retrieving leader master URL: <a href=\"" << redirect
<< "\">" + redirect + "</a><br> Error: " << s.ToString() << ".<br>";
return;
}

*output << buf.ToString();
}

Result<std::string> MasterPathHandlers::GetLeaderAddress(const Webserver::WebRequest& req) {
vector<ServerEntryPB> masters;
Status s = master_->ListMasters(&masters);
if (!s.ok()) {
s = s.CloneAndPrepend("Unable to list masters during web request handling");
return s;
}
ServerRegistrationPB local_reg;
s = master_->GetMasterRegistration(&local_reg);
if (!s.ok()) {
s = s.CloneAndPrepend("Unable to get local registration during web request handling");
return s;
}
const auto leader = std::find_if(masters.begin(), masters.end(), [](const auto& master) {
return !master.has_error() && master.role() == PeerRole::LEADER;
});
if (leader == masters.end() || leader->registration().http_addresses().empty()) {
return STATUS(
NotFound, "Unable to locate leader master to redirect this request: " + req.redirect_uri);
}
auto& reg = leader->registration();
auto http_broadcast_addresses = reg.broadcast_addresses();
for (HostPortPB& host_port : http_broadcast_addresses) {
host_port.set_port(reg.http_addresses(0).port());
}
return Substitute(
"http://$0$1$2",
HostPortPBToString(DesiredHostPort(
http_broadcast_addresses,
reg.http_addresses(),
reg.cloud_info(),
local_reg.cloud_info())),
req.redirect_uri,
req.query_string.empty() ? "?raw" : "?" + req.query_string + "&raw");
}

void MasterPathHandlers::CallIfLeaderOrPrintRedirect(
const Webserver::WebRequest& req, Webserver::WebResponse* resp,
const Webserver::PathHandlerCallback& callback) {
Expand Down Expand Up @@ -1546,7 +1554,7 @@ void MasterPathHandlers::HandleGetUnderReplicationStatus(const Webserver::WebReq

void MasterPathHandlers::RootHandler(const Webserver::WebRequest& req,
Webserver::WebResponse* resp) {
std::stringstream *output = &resp->output;
std::stringstream* output = &resp->output;
// First check if we are the master leader. If not, make a curl call to the master leader and
// return that as the UI payload.
SCOPED_LEADER_SHARED_LOCK(l, master_->catalog_manager_impl());
Expand Down
1 change: 1 addition & 0 deletions src/yb/master/master-path-handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ class MasterPathHandlers {
void CallIfLeaderOrPrintRedirect(const Webserver::WebRequest& req, Webserver::WebResponse* resp,
const Webserver::PathHandlerCallback& callback);
void RedirectToLeader(const Webserver::WebRequest& req, Webserver::WebResponse* resp);
Result<std::string> GetLeaderAddress(const Webserver::WebRequest& req);
void RootHandler(const Webserver::WebRequest& req,
Webserver::WebResponse* resp);
void HandleTabletServers(const Webserver::WebRequest& req,
Expand Down

0 comments on commit e99e294

Please sign in to comment.