Add support for getting tenant and cluster metadata in fdbcli in a JSON format
This commit is contained in:
parent
98c3813431
commit
367e59dc33
|
@ -153,16 +153,39 @@ ACTOR Future<bool> metaclusterListCommand(Reference<IDatabase> db, std::vector<S
|
|||
|
||||
// metacluster get command
|
||||
ACTOR Future<bool> metaclusterGetCommand(Reference<IDatabase> db, std::vector<StringRef> tokens) {
|
||||
if (tokens.size() > 3) {
|
||||
fmt::print("Usage: metacluster get <NAME>\n\n");
|
||||
if (tokens.size() > 4 || (tokens.size() == 4 && tokens[3] != "JSON"_sr)) {
|
||||
fmt::print("Usage: metacluster get <NAME> [JSON]\n\n");
|
||||
fmt::print("Prints metadata associated with the given data cluster.\n");
|
||||
fmt::print("If JSON is specified, then the output will be in JSON format.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
DataClusterMetadata metadata = wait(MetaclusterAPI::getCluster(db, tokens[2]));
|
||||
printf(" connection string: %s\n", metadata.connectionString.toString().c_str());
|
||||
printf(" tenant group capacity: %d\n", metadata.entry.capacity.numTenantGroups);
|
||||
printf(" allocated tenant groups: %d\n", metadata.entry.allocated.numTenantGroups);
|
||||
state bool useJson = tokens.size() == 4;
|
||||
|
||||
try {
|
||||
DataClusterMetadata metadata = wait(MetaclusterAPI::getCluster(db, tokens[2]));
|
||||
|
||||
if (useJson) {
|
||||
json_spirit::mObject obj;
|
||||
obj["type"] = "success";
|
||||
obj["cluster"] = metadata.toJson();
|
||||
printf("%s\n", json_spirit::write_string(json_spirit::mValue(obj), json_spirit::pretty_print).c_str());
|
||||
} else {
|
||||
printf(" connection string: %s\n", metadata.connectionString.toString().c_str());
|
||||
printf(" tenant group capacity: %d\n", metadata.entry.capacity.numTenantGroups);
|
||||
printf(" allocated tenant groups: %d\n", metadata.entry.allocated.numTenantGroups);
|
||||
}
|
||||
} catch (Error& e) {
|
||||
if (useJson) {
|
||||
json_spirit::mObject obj;
|
||||
obj["type"] = "error";
|
||||
obj["error"] = e.what();
|
||||
printf("%s\n", json_spirit::write_string(json_spirit::mValue(obj), json_spirit::pretty_print).c_str());
|
||||
return false;
|
||||
} else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -253,8 +276,8 @@ std::vector<const char*> metaclusterHintGenerator(std::vector<StringRef> const&
|
|||
} else if (tokencmp(tokens[1], "list") && tokens.size() < 5) {
|
||||
static std::vector<const char*> opts = { "[BEGIN]", "[END]", "[LIMIT]" };
|
||||
return std::vector<const char*>(opts.begin() + tokens.size() - 2, opts.end());
|
||||
} else if (tokencmp(tokens[1], "get") && tokens.size() < 3) {
|
||||
static std::vector<const char*> opts = { "<NAME>" };
|
||||
} else if (tokencmp(tokens[1], "get") && tokens.size() < 4) {
|
||||
static std::vector<const char*> opts = { "<NAME>", "[JSON]" };
|
||||
return std::vector<const char*>(opts.begin() + tokens.size() - 2, opts.end());
|
||||
} else if (tokencmp(tokens[1], "configure")) {
|
||||
static std::vector<const char*> opts = {
|
||||
|
|
|
@ -253,11 +253,12 @@ CommandFactory listTenantsFactory(
|
|||
|
||||
// gettenant command
|
||||
ACTOR Future<bool> getTenantCommandActor(Reference<IDatabase> db, std::vector<StringRef> tokens) {
|
||||
if (tokens.size() != 2) {
|
||||
if (tokens.size() < 2 || tokens.size() > 3 || (tokens.size() == 3 && tokens[2] != "JSON"_sr)) {
|
||||
printUsage(tokens[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
state bool useJson = tokens.size() == 3;
|
||||
state Key tenantNameKey = tenantMapSpecialKeyRange.begin.withSuffix(tokens[1]);
|
||||
state Reference<ITransaction> tr = db->createTransaction();
|
||||
|
||||
|
@ -272,35 +273,65 @@ ACTOR Future<bool> getTenantCommandActor(Reference<IDatabase> db, std::vector<St
|
|||
|
||||
json_spirit::mValue jsonObject;
|
||||
json_spirit::read_string(tenant.get().toString(), jsonObject);
|
||||
JSONDoc doc(jsonObject);
|
||||
|
||||
int64_t id;
|
||||
std::string prefix;
|
||||
std::string tenantGroup;
|
||||
doc.get("id", id);
|
||||
doc.get("prefix", prefix);
|
||||
bool hasTenantGroup = doc.tryGet("tenant_group", tenantGroup);
|
||||
if (useJson) {
|
||||
json_spirit::mObject resultObj;
|
||||
resultObj["tenant"] = jsonObject;
|
||||
resultObj["type"] = "success";
|
||||
printf("%s\n",
|
||||
json_spirit::write_string(json_spirit::mValue(resultObj), json_spirit::pretty_print).c_str());
|
||||
} else {
|
||||
|
||||
printf(" id: %" PRId64 "\n", id);
|
||||
printf(" prefix: %s\n", printable(prefix).c_str());
|
||||
if (hasTenantGroup) {
|
||||
printf(" tenant group: %s\n", printable(tenantGroup).c_str());
|
||||
JSONDoc doc(jsonObject);
|
||||
|
||||
int64_t id;
|
||||
std::string prefix;
|
||||
std::string tenantGroup;
|
||||
doc.get("id", id);
|
||||
doc.get("prefix", prefix);
|
||||
bool hasTenantGroup = doc.tryGet("tenant_group", tenantGroup);
|
||||
|
||||
printf(" id: %" PRId64 "\n", id);
|
||||
printf(" prefix: %s\n", printable(prefix).c_str());
|
||||
if (hasTenantGroup) {
|
||||
printf(" tenant group: %s\n", printable(tenantGroup).c_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (Error& e) {
|
||||
state Error err(e);
|
||||
if (e.code() == error_code_special_keys_api_failure) {
|
||||
std::string errorMsgStr = wait(getSpecialKeysFailureErrorMessage(tr));
|
||||
fprintf(stderr, "ERROR: %s\n", errorMsgStr.c_str());
|
||||
try {
|
||||
wait(safeThreadFutureToFuture(tr->onError(e)));
|
||||
} catch (Error& finalErr) {
|
||||
state std::string errorStr;
|
||||
if (finalErr.code() == error_code_special_keys_api_failure) {
|
||||
std::string str = wait(getSpecialKeysFailureErrorMessage(tr));
|
||||
errorStr = str;
|
||||
} else if (useJson) {
|
||||
errorStr = finalErr.what();
|
||||
} else {
|
||||
throw finalErr;
|
||||
}
|
||||
|
||||
if (useJson) {
|
||||
json_spirit::mObject resultObj;
|
||||
resultObj["type"] = "error";
|
||||
resultObj["error"] = errorStr;
|
||||
printf(
|
||||
"%s\n",
|
||||
json_spirit::write_string(json_spirit::mValue(resultObj), json_spirit::pretty_print).c_str());
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: %s\n", errorStr.c_str());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
wait(safeThreadFutureToFuture(tr->onError(err)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CommandFactory getTenantFactory("gettenant",
|
||||
CommandHelp("gettenant <TENANT_NAME>",
|
||||
"prints the metadata for a tenant",
|
||||
"Prints the metadata for a tenant."));
|
||||
CommandFactory getTenantFactory(
|
||||
"gettenant",
|
||||
CommandHelp("gettenant <TENANT_NAME> [JSON]",
|
||||
"prints the metadata for a tenant",
|
||||
"Prints the metadata for a tenant. If JSON is specified, then the output will be in JSON format."));
|
||||
} // namespace fdb_cli
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
FDB_DEFINE_BOOLEAN_PARAM(AddNewTenants);
|
||||
FDB_DEFINE_BOOLEAN_PARAM(RemoveMissingTenants);
|
||||
|
||||
json_spirit::mObject ClusterUsage::toJson() {
|
||||
json_spirit::mObject ClusterUsage::toJson() const {
|
||||
json_spirit::mObject obj;
|
||||
obj["num_tenant_groups"] = numTenantGroups;
|
||||
return obj;
|
||||
|
|
|
@ -37,7 +37,7 @@ struct ClusterUsage {
|
|||
ClusterUsage() = default;
|
||||
ClusterUsage(int numTenantGroups) : numTenantGroups(numTenantGroups) {}
|
||||
|
||||
json_spirit::mObject toJson();
|
||||
json_spirit::mObject toJson() const;
|
||||
|
||||
bool operator==(const ClusterUsage& other) const noexcept { return numTenantGroups == other.numTenantGroups; }
|
||||
bool operator!=(const ClusterUsage& other) const noexcept { return !(*this == other); }
|
||||
|
@ -72,7 +72,7 @@ struct DataClusterEntry {
|
|||
return id == other.id && capacity == other.capacity;
|
||||
}
|
||||
|
||||
Value encode() { return ObjectWriter::toValue(*this, IncludeVersion(ProtocolVersion::withMetacluster())); }
|
||||
Value encode() const { return ObjectWriter::toValue(*this, IncludeVersion(ProtocolVersion::withMetacluster())); }
|
||||
static DataClusterEntry decode(ValueRef const& value) {
|
||||
DataClusterEntry entry;
|
||||
ObjectReader reader(value.begin(), IncludeVersion());
|
||||
|
@ -80,6 +80,13 @@ struct DataClusterEntry {
|
|||
return entry;
|
||||
}
|
||||
|
||||
json_spirit::mObject toJson() const {
|
||||
json_spirit::mObject obj;
|
||||
obj["capacity"] = capacity.toJson();
|
||||
obj["allocated"] = allocated.toJson();
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <class Ar>
|
||||
void serialize(Ar& ar) {
|
||||
serializer(ar, id, capacity, allocated);
|
||||
|
|
|
@ -68,6 +68,12 @@ struct DataClusterMetadata {
|
|||
return metadata;
|
||||
}
|
||||
|
||||
json_spirit::mValue toJson() const {
|
||||
json_spirit::mObject obj = entry.toJson();
|
||||
obj["connection_string"] = connectionString.toString();
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <class Ar>
|
||||
void serialize(Ar& ar) {
|
||||
serializer(ar, connectionString, entry);
|
||||
|
|
Loading…
Reference in New Issue