//------------------------------------------------------------------------------
// @file: com_space_node.cc
// @author: Fabio Luchetti - CERN
//------------------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2018 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your token) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#include
#include
#include
#include "XrdOuc/XrdOucEnv.hh"
#include "common/StringTokenizer.hh"
#include "common/StringConversion.hh"
#include "common/SymKeys.hh"
#include "console/ConsoleMain.hh"
#include "console/commands/ICmdHelper.hh"
#include "mgm/tgc/Constants.hh"
#include "mgm/http/rest-api/Constants.hh"
void com_space_help();
//------------------------------------------------------------------------------
//! Class SpaceHelper
//------------------------------------------------------------------------------
class SpaceHelper : public ICmdHelper
{
public:
//----------------------------------------------------------------------------
//! Constructor
//!
//! @param opts global options
//----------------------------------------------------------------------------
SpaceHelper(const GlobalOptions& opts):
ICmdHelper(opts)
{
mIsAdmin = true;
}
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
~SpaceHelper() override = default;
//----------------------------------------------------------------------------
//! Parse command line input
//!
//! @param arg input
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool ParseCommand(const char* arg) override;
};
//------------------------------------------------------------------------------
// Parse command line input
//------------------------------------------------------------------------------
bool SpaceHelper::ParseCommand(const char* arg)
{
eos::console::SpaceProto* space = mReq.mutable_space();
eos::common::StringTokenizer tokenizer(arg);
tokenizer.GetLine();
std::string token;
if (!tokenizer.NextToken(token)) {
return false;
}
if (token == "ls") {
eos::console::SpaceProto_LsProto* ls = space->mutable_ls();
while (tokenizer.NextToken(token)) {
if (token == "-s") {
mIsSilent = true;
} else if (token == "-g") {
if (!tokenizer.NextToken(token) ||
!eos::common::StringTokenizer::IsUnsignedNumber(token)) {
std::cerr << "error: geodepth was not provided or it does not have "
<< "the correct value: geodepth should be a positive "
<< "integer" << std::endl;
return false;
}
try {
ls->set_outdepth(std::stoi(token));
} catch (const std::exception& e) {
std::cerr << "error: argument needs to be numeric" << std::endl;
return false;
}
} else if (token == "-m") {
ls->set_outformat(eos::console::SpaceProto_LsProto::MONITORING);
} else if (token == "-l") {
ls->set_outformat(eos::console::SpaceProto_LsProto::LISTING);
} else if (token == "--io") {
ls->set_outformat(eos::console::SpaceProto_LsProto::IO);
} else if (token == "--fsck") {
ls->set_outformat(eos::console::SpaceProto_LsProto::FSCK);
} else if ((token.find('-') != 0)) { // does not begin with "-"
ls->set_selection(token);
} else {
return false;
}
}
} else if (token == "tracker") {
eos::console::SpaceProto_TrackerProto* tracker = space->mutable_tracker();
tracker->set_mgmspace("default");
} else if (token == "inspector") {
eos::console::SpaceProto_InspectorProto* inspector = space->mutable_inspector();
inspector->set_mgmspace("default");
std::string options;
while (tokenizer.NextToken(token)) {
if ((token == "-s") || (token == "--space")) {
if (tokenizer.NextToken(token)) {
inspector->set_mgmspace(token);
} else {
std::cerr << "error: no space specified" << std::endl;
return false;
}
} else if (token == "-c" || token == "--current") {
options += "c";
} else if (token == "-l" || token == "--last") {
options += "l";
} else if (token == "-m") {
options += "m";
} else if (token == "-p") {
options += "p";
} else if (token == "-e") {
options += "e";
} else if (token == "-C" || token == "--cost") {
options += "C";
} else if (token == "-U" || token == "--usage") {
options += "U";
} else if (token == "-L" || token == "--layouts") {
options += "L";
} else if (token == "-B" || token == "--birth") {
options += "B";
} else if (token == "-A" || token == "--access") {
options += "A";
} else if (token == "-a" || token == "--all") {
options += "Z";
} else if (token == "-V" || token == "--vs") {
options += "V";
} else {
return false;
}
}
inspector->set_options(options);
} else if (token == "reset") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_ResetProto* reset = space->mutable_reset();
reset->set_mgmspace(token);
while (tokenizer.NextToken(token)) {
if (token == "--egroup") {
reset->set_option(eos::console::SpaceProto_ResetProto::EGROUP);
} else if (token == "--mapping") {
reset->set_option(eos::console::SpaceProto_ResetProto::MAPPING);
} else if (token == "--drain") {
reset->set_option(eos::console::SpaceProto_ResetProto::DRAIN);
} else if (token == "--scheduledrain") {
reset->set_option(eos::console::SpaceProto_ResetProto::SCHEDULEDRAIN);
} else if (token == "--schedulebalance") {
reset->set_option(eos::console::SpaceProto_ResetProto::SCHEDULEBALANCE);
} else if (token == "--ns") {
reset->set_option(eos::console::SpaceProto_ResetProto::NS);
} else if (token == "--nsfilesystemview") {
reset->set_option(eos::console::SpaceProto_ResetProto::NSFILESISTEMVIEW);
} else if (token == "--nsfilemap") {
reset->set_option(eos::console::SpaceProto_ResetProto::NSFILEMAP);
} else if (token == "--nsdirectorymap") {
reset->set_option(eos::console::SpaceProto_ResetProto::NSDIRECTORYMAP);
} else {
return false;
}
}
} else if (token == "define") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_DefineProto* define = space->mutable_define();
define->set_mgmspace(token);
if (!tokenizer.NextToken(token)) {
define->set_groupsize(0);
define->set_groupmod(24);
} else {
define->set_groupsize(std::stoi(token));
if (!tokenizer.NextToken(token)) {
define->set_groupmod(24);
} else {
define->set_groupmod(std::stoi(token));
}
}
} else if (token == "set") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_SetProto* set = space->mutable_set();
set->set_mgmspace(token);
if (!tokenizer.NextToken(token)) {
return false;
}
if (token == "on") {
set->set_state_switch(true);
} else if (token == "off") {
set->set_state_switch(false);
} else {
return false;
}
} else if (token == "rm") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_RmProto* rm = space->mutable_rm();
rm->set_mgmspace(token);
} else if (token == "status") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_StatusProto* status = space->mutable_status();
status->set_mgmspace(token);
if (tokenizer.NextToken(token)) {
if (token == "-m") {
status->set_outformat_m(true);
} else {
return false;
}
}
std::string contents =
eos::common::StringConversion::StringFromShellCmd("cat /var/eos/md/stacktrace 2> /dev/null");
} else if (token == "node-set") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_NodeSetProto* nodeset = space->mutable_nodeset();
nodeset->set_mgmspace(token);
if (!tokenizer.NextToken(token)) {
return false;
}
nodeset->set_nodeset_key(token);
if (!tokenizer.NextToken(token)) {
return false;
}
if (token.find('/') == 0) { // if begins with "/"
std::ifstream ifs(token, std::ios::in | std::ios::binary);
if (!ifs) {
std::cerr << "error: unable to read " << token << " - errno=" << errno << '\n';
return false;
}
std::string val = std::string((std::istreambuf_iterator(ifs)),
std::istreambuf_iterator());
if (val.length() > 512) {
std::cerr <<
"error: the file contents exceeds 0.5 kB - configure a file hosted on the MGM using file:\n";
return false;
}
// store the value b64 encoded
XrdOucString val64;
eos::common::SymKey::Base64Encode((char*) val.c_str(), val.length(), val64);
while (val64.replace("=", ":")) {}
nodeset->set_nodeset_value(std::string(("base64:" + val64).c_str()));
} else {
nodeset->set_nodeset_value(token);
}
} else if (token == "node-get") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_NodeGetProto* nodeget = space->mutable_nodeget();
nodeget->set_mgmspace(token);
if (!tokenizer.NextToken(token)) {
return false;
}
nodeget->set_nodeget_key(token);
} else if (token == "quota") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_QuotaProto* quota = space->mutable_quota();
quota->set_mgmspace(token);
if (!tokenizer.NextToken(token)) {
return false;
}
if (token == "on") {
quota->set_quota_switch(true);
} else if (token == "off") {
quota->set_quota_switch(false);
} else {
return false;
}
} else if (token == "config") {
if (!tokenizer.NextToken(token)) {
return false;
}
eos::console::SpaceProto_ConfigProto* config = space->mutable_config();
config->set_mgmspace_name(token);
if (!tokenizer.NextToken(token)) {
return false;
}
std::string::size_type pos = token.find('=');
// contains 1 and only 1 '='. It expects a token like =
if ((pos != std::string::npos) &&
(count(token.begin(), token.end(), '=') == 1)) {
config->set_mgmspace_key(token.substr(0, pos));
config->set_mgmspace_value(token.substr(pos + 1, token.length() - 1));
} else {
return false;
}
} else if (token == "groupbalancer") {
// Parsing eos space groupbalancer
auto groupbalancer = space->mutable_groupbalancer();
// subcmd
if (!tokenizer.NextToken(token)) {
return false;
}
if (token == "status") {
// spacename
if (!tokenizer.NextToken(token)) {
return false;
}
groupbalancer->set_mgmspace(token);
auto groupbalancer_status = groupbalancer->mutable_status();
// Now parse options
std::string options;
while (tokenizer.NextToken(token)) {
if (token == "--detail" || token == "-d") {
options += "d";
} else if (token == "-m") {
options += "m";
}
}
if (!options.empty()) {
groupbalancer_status->set_options(options);
}
return true;
}
return false;
} else if (token == "groupdrainer") {
auto groupdrainer = space->mutable_groupdrainer();
// subcmd
if (!tokenizer.NextToken(token)) {
return false;
}
if (token == "status") {
if (!tokenizer.NextToken(token)) {
return false;
}
groupdrainer->set_mgmspace(token);
auto status_cmd = groupdrainer->mutable_status();
if (tokenizer.NextToken(token)) {
if (token == "--detail" || token == "-d") {
status_cmd->set_outformat(
eos::console::SpaceProto::GroupDrainerStatusProto::DETAIL);
} else if (token == "-m") {
status_cmd->set_outformat(
eos::console::SpaceProto::GroupDrainerStatusProto::MONITORING);
}
}
return true;
} else if (token == "reset") {
if (!tokenizer.NextToken(token)) {
return false;
}
groupdrainer->set_mgmspace(token);
auto reset_cmd = groupdrainer->mutable_reset();
if (!tokenizer.NextToken(token)) {
return false;
}
if (token == "--failed") {
reset_cmd->set_option(eos::console::SpaceProto::GroupDrainerResetProto::FAILED);
} else if (token == "--all") {
reset_cmd->set_option(eos::console::SpaceProto::GroupDrainerResetProto::ALL);
}
}
} else { // no proper subcommand
return false;
}
return true;
}
//------------------------------------------------------------------------------
// Space command entry point
//------------------------------------------------------------------------------
int com_proto_space(char* arg)
{
if (wants_help(arg)) {
com_space_help();
global_retc = EINVAL;
return EINVAL;
}
SpaceHelper space(gGlobalOpts);
if (!space.ParseCommand(arg)) {
global_retc = EINVAL;
return EINVAL;
}
global_retc = space.Execute();
return global_retc;
}
//------------------------------------------------------------------------------
// Print help message
//------------------------------------------------------------------------------
void com_space_help()
{
std::ostringstream oss;
oss
<< " usage:\n"
<< "space ls [-s|-g ] [-m|-l|--io|--fsck] [] : list in all spaces or select only . is a substring match and can be a comma separated list\n"
<< "\t -s : silent mode\n"
<< "\t -m : monitoring key=value output format\n"
<< "\t -l : long output - list also file systems after each space\n"
<< "\t -g : geo output - aggregate space information along the instance geotree down to \n"
<< "\t --io : print IO statistics\n"
<< "\t --fsck : print filesystem check statistics\n"
<< std::endl
<< "space config space.nominalsize= : configure the nominal size for this space\n"
<< "space config space.balancer=on|off : enable/disable the space balancer [ default=off ]\n"
<< "space config space.balancer.threshold= : configure the used bytes deviation which triggers balancing [ default=20 (%%) ] \n"
<< "space config space.balancer.node.rate= : configure the nominal transfer bandwidth per running transfer on a node [ default=25 (MB/s) ]\n"
<< "space config space.balancer.node.ntx=<#> : configure the number of parallel balancing transfers per node [ default=2 (streams) ]\n"
<< "space config space.balancer.max-queue-jobs=<#> : configure the maximum number of queued jobs allowed in the balancer thread pool [ default=1000 (jobs) ]\n"
<< "space config space.balancer.max-thread-pool-size=<#> : configure the maximum number of threads to be used in the balancer thread pool [ default=100 (threads) ]\n"
<< "space config space.balancer.update.interval=<#> : configure the update interval of the balancing statistics used for spawning transfers [ default=60 (seconds) min=1 max=300]\n"
<< "space config space.converter=on|off : enable/disable the space converter [ default=off ]\n"
<< "space config space.converter.ntx=<#> : configure the number of parallel conversions per space [ default=2 (streams) ]\n"
<< "space config space.drainer.node.rate= : configure the nominal transfer bandwidth per running transfer on a node [ default=25 (MB/s) ]\n"
<< "space config space.drainer.node.ntx=<#> : configure the number of parallel draining transfers per node [ default=2 (streams) ]\n"
<< "space config space.drainer.node.nfs=<#> : configure the number of max draining filesystems per node (Valid only for central drain) [ default=5 ]\n"
<< "space config space.drainer.retries=<#> : configure the number of retry for the draining process (Valid only for central drain) [ default=1 ]\n"
<< "space config space.drainer.fs.ntx=<#> : configure the number of parallel draining transfers per fs (Valid only for central drain) [ default=5 ]\n"
<< "space config space.groupbalancer=on|off : enable/disable the group balancer [ default=off ]\n"
<< "space config space.groupbalancer.ntx= : configure the number of parallel group balancer jobs per 10s [ default=10 ]\n"
<< "space config space.groupbalancer.engine=[value] : configure the groupbalancer engine - std/minmax/freespace [ default=std ]\n"
<< "space config space.groupbalancer.min_threshold= : configure the groupbalancer min threshold(%), groups below this will be picked as targets [default=60]\n"
<< "space config space.groupbalancer.max_threshold= : configure the groupbalancer max threshold(%), groups above this will be picked as sources [default=95]\n"
<< "space config space.groupbalancer.min_file_size=<#K/M/G/T>: configure the min file size to move between groups [ default=1G ]\n"
<< "space config space.groupbalancer.max_file_size=<#K/M/G/T>: configure the max file size to move between groups [ default=16G ]\n"
<< "space config space.groupbalancer.file_attempts=<#> : configure the no of attempts to find a file within sizes [ default=50 ]\n"
<< "space config space.groupbalancer.threshold= : [Deprecated use <..>.min/max_threshold (see above)] configure the threshold when a group is balanced\n"
<< "space config space.groupbalancer.blocklist= : comma list eg. group1, group2 of groups blocklisted (only available for freespace engine)\n"
<< "space config space.geobalancer=on|off : enable/disable the geo balancer [ default=off ]\n"
<< "space config space.geobalancer.ntx= : configure the numebr of parallel geobalancer jobs [ default=0 ]\n"
<< "space config space.geobalancer.threshold= : configure the threshold when a geotag is balanced [ default=0 ] \n"
<< "space config space.groupdrainer=on|off : enable/disable the group drainer [ default=on ]\n"
<< "space config space.groupdrainer.threshold= : configure the threshold(%) for picking target groups\n"
<< "space config space.groupdrainer.group_refresh_interval : configure time in seconds for refreshing cached groups info [default=300]\n"
<< "space config space.groupdrainer.retry_interval : configure time in seconds for retrying failed drains [default=4*3600]\n"
<< "space config space.groupdrainer.retry_count : configure the amount of retries for failed drains [default=5]\n"
<< "space config space.groupdrainer.ntx : configure the max file transfer queue size [default=10000]\n"
<< "space config space.lru=on|off : enable/disable the LRU policy engine [ default=off ]\n"
<< "space config space.lru.interval= : configure the default lru scan interval\n"
<< "space config fs.max.ropen= : allow more than read streams per disk in the given space\n"
<< "space config fs.max.wopen= : allow more than write streams per disk in the given space\n"
<< "space config space.wfe=on|off|paused : enable/disable the Workflow Engine [ default=off ]\n"
<< "space config space.wfe.interval= : configure the default WFE scan interval\n"
<< "space config space.headroom= : configure the default disk headroom if not defined on a filesystem (see fs for details)\n"
<< "space config space.scaninterval= : configure the default scan interval if not defined on a filesystem (see fs for details)\n"
<< "space config space.scan_rain_interval= : configure the default rain scan interval if not defined on a filesystem (see fs for details)\n"
<< "space config space.scanrate= : configure the default scan rate if not defined on a filesystem (see fs for details)\n"
<< "space config space.scan_disk_interva= : time interval after which the disk scanner will run, default 4h\n"
<< "space config space.scan_ns_interval= : time interval after which the namespace scanner will run, default 3 days\n"
<< "space config space.scan_ns_rate=entry/sec : namespace scan rate in terms of number of stat requests per second done against the local disk\n"
<< "space config space.scheduler.type= : configure the default scheduler for space, eg. geo, roundrobin, weightedrandom etc\n"
<< "space config space.fsck_refresh_interval= : time interval after which fsck inconsistencies are refreshed\n"
<< "space config space.drainperiod= : configure the default drain period if not defined on a filesystem (see fs for details)\n"
<< "space config space.graceperiod= : configure the default grace period if not defined on a filesystem (see fs for details)\n"
<< "space config space.filearchivedgc=on|off : enable/disable the 'file archived' garbage collector [ default=off ]\n"
<< "space config space.tracker=on|off : enable/disable the space layout creation tracker [ default=off ]\n"
<< "space config space.inspector=on|off : enable/disable the file inspector [ default=off ]\n"
<< "space config space.inspector.interval= : time interval after which the inspector will run, default 4h\n"
<< "space config space.inspector.price.currency=[0-5] : currency printed by the cost evaluation ( 0=EOS, 1=CHF, 2=EUR, 3=USD, 4=AUD, 5=YEN )\n"
<< "space config space.inspector.price.disk.tbyear= : set the price of a tb year of data on disk without redundancy (default=20)\n"
<< "space config space.inspector.price.tape.tbyear= : set the price of a tb year of data on disk without redundancy (default=10)\n"
<< "space config space.geo.access.policy.write.exact=on|off : if 'on' use exact matching geo replica (if available), 'off' uses weighting [ for write case ]\n"
<< "space config space.geo.access.policy.read.exact=on|off : if 'on' use exact matching geo replica (if available), 'off' uses weighting [ for read case ]\n"
<< "space config fs.= : configure file system parameters for each filesystem in this space (see help of 'fs config' for details)\n"
<< "space config space.policy.[layout|nstripes|checksum|blockchecksum|blocksize|bw|schedule|iopriority]= \n"
<< " : configure default file layout creation settings as a space policy - a value='remove' deletes the space policy\n"
<< std::endl
<< "space config space.policy.recycle=on\n"
<< " : globally enforce using always a recycle bin\n"
<< std::endl
<< "REST API specific parameters:\n"
<< "space config default " << eos::mgm::rest::TAPE_REST_API_SWITCH_ON_OFF <<
"=on|off : enable/disable the tape REST API handler [ default=off ]\n"
<< "space config default " << eos::mgm::rest::TAPE_REST_API_STAGE_SWITCH_ON_OFF
<< "=on|off : enable/disable the tape REST API STAGE resource [ default=off ]\n"
<< std::endl
<< "Tape specific configuration parameters:\n"
<< "space config space." << eos::mgm::tgc::TGC_NAME_QRY_PERIOD_SECS
<< "=<#> : tape-aware GC query period in seconds [ default=" <<
eos::mgm::tgc::TGC_DEFAULT_QRY_PERIOD_SECS << " ]\n"
<< " => value must be > 0 and <= "
<< eos::mgm::tgc::TGC_MAX_QRY_PERIOD_SECS << "\n"
<< "space config space." <<
eos::mgm::tgc::TGC_NAME_FREE_BYTES_SCRIPT <<
"= : optional path to a script used to determine the number of free bytes in a given EOS space [ default='"
<< eos::mgm::tgc::TGC_DEFAULT_FREE_BYTES_SCRIPT << "' ]\n"
<< " => an empty or invalid path means the compile time default way of determining free space will be used\n"
<< "space config space." << eos::mgm::tgc::TGC_NAME_AVAIL_BYTES <<
"=<#> : configure the number of available bytes the space should have [ default="
<< eos::mgm::tgc::TGC_DEFAULT_AVAIL_BYTES << " ] \n"
<< "space config space." << eos::mgm::tgc::TGC_NAME_TOTAL_BYTES <<
"=<#> : configure the total number of bytes the space should have before the tape-aware GC kicks in [ default="
<< eos::mgm::tgc::TGC_DEFAULT_TOTAL_BYTES << " ] \n"
<< std::endl
<< "space define [ []] : define how many filesystems can end up in one scheduling group [ default=0 ]\n"
<< " => =0 means that no groups are built within a space, otherwise it should be the maximum number of nodes in a scheduling group\n"
<< " => maximum number of groups in the space, which should be at least equal to the maximum number of filesystems per node\n"
<< std::endl
<< "space inspector [--current|-c] [--last|-l] [-m] [-p] [-e] [-s|--space ] [--all|-a] [--cost|-C] [--usage|-U] [--birth|-B] [--access|-A] [--vs|-V] [--layouts|-L] : show namespace inspector output\n"
<< "\t -c : show current scan\n"
<< "\t -l : show last complete scan\n"
<< "\t -m : print last scan in monitoring format ( by default this enables --cost --usage --birth --access --layouts)\n"
<< "\t -A : combined with -m prints access time distributions\n"
<< "\t -V : combined with -m prints birth time vs access time distributions\n"
<< "\t -B : combined with -m prints birth time distributions\n"
<< "\t -C : combined with -m prints cost information (storage price per user/group)\n"
<< "\t -U : combined with -m prints usage information (stored bytes per user/group)\n"
<< "\t -L : combined with -m prints layout statistics\n"
<< "\t -a : combined with -m or -C or -U removes the restriction to show only the top 10 user ranking\n"
<< "\t -p : combined with -c or -l lists erroneous files\n"
<< "\t -e : combined with -c or -l exports erroneous files on the MGM into /var/log/eos/mgm/FileInspector..list\n"
<< "\t -s : select target space, by default \"default\" space is used\n"
<< std::endl
<< "space node-set : store the contents of into the node configuration variable visible to all FSTs\n"
<< " => if matches file: the file is loaded from the MGM and not from the client\n"
<< " => local files cannot exceed 512 bytes - MGM files can be arbitrary length\n"
<< " => the contents gets base64 encoded by default\n"
<< std::endl
<< "space node-get : get the value of and base64 decode before output\n"
<< " => if the value for is identical for all nodes in the referenced space, it is dumped only once, otherwise the value is dumped for each node separately\n"
<< std::endl
<< "space reset [--egroup|mapping|drain|scheduledrain|schedulebalance|ns|nsfilesystemview|nsfilemap|nsdirectorymap] : reset different space attributes\n"
<< "\t --egroup : clear cached egroup information\n"
<< "\t --mapping : clear all user/group uid/gid caches\n"
<< "\t --drain : reset draining\n"
<< "\t --scheduledrain : reset drain scheduling map\n"
<< "\t --schedulebalance : reset balance scheduling map\n"
<< "\t --ns : resize all namespace maps\n"
<< "\t --nsfilesystemview : resize namespace filesystem view\n"
<< "\t --nsfilemap : resize namespace file map\n"
<< "\t --nsdirectorymap : resize namespace directory map\n"
<< std::endl
<< "space status [-m] : print all defined variables for space\n"
<< std::endl
<< "space tracker : print all file replication tracking entries\n"
<< std::endl
<< "space set on|off : enable/disable all groups under that space\n"
<< " => value will enable all nodes, value won't affect nodes\n"
<< std::endl
<< "space rm : remove space\n"
<< std::endl
<< "space quota on|off : enable/disable quota\n"
<< std::endl
<< "space groupbalancer status [--detail(-d)|-m] : print groupbalancer status\n"
<< std::endl
<< "space groupdrainer status [--detail(-d)|-m] : print groupdrainer status\n"
<< "space groupdrainer reset <--failed|--all> : reset failed transfers/all caches\n"
<< std::endl;
std::cerr << oss.str();
}