Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

support heterogeneous version tests #6942

Merged
merged 3 commits into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 36 additions & 20 deletions programs/eosio-launcher/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ struct launcher_def {
bool skip_transaction_signatures = false;
string eosd_extra_args;
std::map<uint,string> specific_nodeos_args;
std::map<uint,string> specific_nodeos_installation_paths;
testnet_def network;
string gelf_endpoint;
vector <string> aliases;
Expand Down Expand Up @@ -488,8 +489,10 @@ launcher_def::set_options (bpo::options_description &cfg) {
("genesis,g",bpo::value<string>()->default_value("./genesis.json"),"set the path to genesis.json")
("skip-signature", bpo::bool_switch(&skip_transaction_signatures)->default_value(false), "nodeos does not require transaction signatures.")
("nodeos", bpo::value<string>(&eosd_extra_args), "forward nodeos command line argument(s) to each instance of nodeos, enclose arg(s) in quotes")
("specific-num", bpo::value<vector<uint>>()->composing(), "forward nodeos command line argument(s) (using \"--specific-nodeos\" flag) to this specific instance of nodeos. This parameter can be entered multiple times and requires a paired \"--specific-nodeos\" flag")
("specific-num", bpo::value<vector<uint>>()->composing(), "forward nodeos command line argument(s) (using \"--specific-nodeos\" flag) to this specific instance of nodeos. This parameter can be entered multiple times and requires a paired \"--specific-nodeos\" flag each time it is used")
("specific-nodeos", bpo::value<vector<string>>()->composing(), "forward nodeos command line argument(s) to its paired specific instance of nodeos(using \"--specific-num\"), enclose arg(s) in quotes")
("spcfc-inst-num", bpo::value<vector<uint>>()->composing(), "Specify a specific version installation path (using \"--spcfc-inst-nodeos\" flag) for launching this specific instance of nodeos. This parameter can be entered multiple times and requires a paired \"--spcfc-inst-nodeos\" flag each time it is used")
("spcfc-inst-nodeos", bpo::value<vector<string>>()->composing(), "Provide a specific version installation path to its paired specific instance of nodeos(using \"--spcfc-inst-num\")")
("delay,d",bpo::value<int>(&start_delay)->default_value(0),"seconds delay before starting each node after the first")
("boot",bpo::bool_switch(&boot)->default_value(false),"After deploying the nodes and generating a boot script, invoke it.")
("nogen",bpo::bool_switch(&nogen)->default_value(false),"launch nodes without writing new config files")
Expand All @@ -513,6 +516,28 @@ inline enum_type& operator|=(enum_type&lhs, const enum_type& rhs)
return lhs = static_cast<enum_type>(static_cast<T>(lhs) | static_cast<T>(rhs));
}

template <typename T>
void retrieve_paired_array_parameters (const variables_map &vmap, const std::string& num_selector, const std::string& paired_selector, std::map<uint,T>& selector_map) {
if (vmap.count(num_selector)) {
const auto specific_nums = vmap[num_selector].as<vector<uint>>();
const auto specific_args = vmap[paired_selector].as<vector<string>>();
if (specific_nums.size() != specific_args.size()) {
cerr << "ERROR: every " << num_selector << " argument must be paired with a " << paired_selector << " argument" << endl;
exit (-1);
}
const auto total_nodes = vmap["nodes"].as<size_t>();
for(uint i = 0; i < specific_nums.size(); ++i)
{
const auto& num = specific_nums[i];
if (num >= total_nodes) {
cerr << "\"--" << num_selector << "\" provided value= " << num << " is higher than \"--nodes\" provided value=" << total_nodes << endl;
exit (-1);
}
selector_map[num] = specific_args[i];
}
}
}

void
launcher_def::initialize (const variables_map &vmap) {
if (vmap.count("mode")) {
Expand Down Expand Up @@ -550,24 +575,8 @@ launcher_def::initialize (const variables_map &vmap) {
server_ident_file = vmap["servers"].as<string>();
}

if (vmap.count("specific-num")) {
const auto specific_nums = vmap["specific-num"].as<vector<uint>>();
const auto specific_args = vmap["specific-nodeos"].as<vector<string>>();
if (specific_nums.size() != specific_args.size()) {
cerr << "ERROR: every specific-num argument must be paired with a specific-nodeos argument" << endl;
exit (-1);
}
const auto total_nodes = vmap["nodes"].as<size_t>();
for(uint i = 0; i < specific_nums.size(); ++i)
{
const auto& num = specific_nums[i];
if (num >= total_nodes) {
cerr << "\"--specific-num\" provided value= " << num << " is higher than \"--nodes\" provided value=" << total_nodes << endl;
exit (-1);
}
specific_nodeos_args[num] = specific_args[i];
}
}
retrieve_paired_array_parameters(vmap, "specific-num", "specific-nodeos", specific_nodeos_args);
retrieve_paired_array_parameters(vmap, "spcfc-inst-num", "spcfc-inst-nodeos", specific_nodeos_installation_paths);

using namespace std::chrono;
system_clock::time_point now = system_clock::now();
Expand Down Expand Up @@ -1511,7 +1520,14 @@ launcher_def::launch (eosd_def &instance, string &gts) {
node_rt_info info;
info.remote = !host->is_local();

string eosdcmd = "programs/nodeos/nodeos ";
string install_path;
if (instance.name != "bios" && !specific_nodeos_installation_paths.empty()) {
const auto node_num = boost::lexical_cast<uint16_t,string>(instance.get_node_num());
if (specific_nodeos_installation_paths.count(node_num)) {
install_path = specific_nodeos_installation_paths[node_num] + "/";
}
}
string eosdcmd = install_path + "programs/nodeos/nodeos ";
if (skip_transaction_signatures) {
eosdcmd += "--skip-transaction-signatures ";
}
Expand Down
60 changes: 58 additions & 2 deletions tests/Cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def __init__(self, walletd=False, localCluster=True, host="localhost", port=8888

self.useBiosBootFile=False
self.filesToCleanup=[]
self.alternateVersionLabels=Cluster.__defaultAlternateVersionLabels()


def setChainStrategy(self, chainSyncStrategy=Utils.SyncReplayTag):
Expand All @@ -93,13 +94,43 @@ def setChainStrategy(self, chainSyncStrategy=Utils.SyncReplayTag):
def setWalletMgr(self, walletMgr):
self.walletMgr=walletMgr

@staticmethod
def __defaultAlternateVersionLabels():
"""Return a labels dictionary with just the "current" label to path set."""
labels={}
labels["current"]="./"
return labels

def setAlternateVersionLabels(self, file):
"""From the provided file return a dictionary of labels to paths."""
brianjohnson5972 marked this conversation as resolved.
Show resolved Hide resolved
Utils.Print("alternate file=%s" % (file))
self.alternateVersionLabels=Cluster.__defaultAlternateVersionLabels()
if file is None:
# only have "current"
return
if not os.path.exists(file):
Utils.errorExit("Alternate Version Labels file \"%s\" does not exist" % (file))
with open(file, 'r') as f:
content=f.read()
p=re.compile(r'^\s*(\w+)\s*=\s*([^\s](?:.*[^\s])?)\s*$', re.MULTILINE)
all=p.findall(content)
for match in all:
label=match[0]
path=match[1]
if label=="current":
Utils.Print("ERROR: cannot overwrite default label %s with path=%s" % (label, path))
continue
self.alternateVersionLabels[label]=path
if Utils.Debug: Utils.Print("Version label \"%s\" maps to \"%s\"" % (label, path))

# launch local nodes and set self.nodes
# pylint: disable=too-many-locals
# pylint: disable=too-many-return-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="net", delay=1, onlyBios=False, dontBootstrap=False,
totalProducers=None, extraNodeosArgs=None, useBiosBootFile=True, specificExtraNodeosArgs=None):
totalProducers=None, extraNodeosArgs=None, useBiosBootFile=True, specificExtraNodeosArgs=None, alternateVersionLabelsFile=None,
associatedNodeLabels=None):
"""Launch cluster.
pnodes: producer nodes count
totalNodes: producer + non-producer nodes count
Expand All @@ -115,8 +146,19 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="ne
A value of false uses manual bootstrapping in this script, which does not do things like stake votes for producers.
specificExtraNodeosArgs: dictionary of arguments to pass to a specific node (via --specific-num and
--specific-nodeos flags on launcher), example: { "5" : "--plugin eosio::test_control_api_plugin" }
alternateVersionLabelsFile: Supply an alternate version labels file to use with associatedNodeLabels.
associatedNodeLabels: Supply a dictionary of node numbers to use an alternate label for a specific node.
"""
assert(isinstance(topo, str))
if alternateVersionLabelsFile is not None:
assert(isinstance(alternateVersionLabelsFile, str))
elif associatedNodeLabels is not None:
associatedNodeLabels=None # need to supply alternateVersionLabelsFile to use labels

if associatedNodeLabels is not None:
assert(isinstance(associatedNodeLabels, dict))
Utils.Print("associatedNodeLabels size=%s" % (len(associatedNodeLabels)))
Utils.Print("alternateVersionLabelsFile=%s" % (alternateVersionLabelsFile))

if not self.localCluster:
Utils.Print("WARNING: Cluster not local, not launching %s." % (Utils.EosServerName))
Expand All @@ -136,6 +178,8 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="ne
assert(isinstance(totalProducers, (str,int)))
producerFlag="--producers %s" % (totalProducers)

self.setAlternateVersionLabels(alternateVersionLabelsFile)

tries = 30
while not Utils.arePortsAvailable(set(range(self.port, self.port+totalNodes+1))):
Utils.Print("ERROR: Another process is listening on nodeos default port. wait...")
Expand Down Expand Up @@ -181,6 +225,18 @@ def launch(self, pnodes=1, totalNodes=1, prodCount=1, topo="mesh", p2pPlugin="ne
cmdArr.append("--max-transaction-cpu-usage")
cmdArr.append(str(150000000))

if associatedNodeLabels is not None:
for nodeNum,label in associatedNodeLabels.items():
assert(isinstance(nodeNum, (str,int)))
assert(isinstance(label, str))
path=self.alternateVersionLabels.get(label)
if path is None:
Utils.errorExit("associatedNodeLabels passed in indicates label %s for node num %s, but it was not identified in %s" % (label, nodeNum, alternateVersionLabelsFile))
cmdArr.append("--spcfc-inst-num")
cmdArr.append(str(nodeNum))
cmdArr.append("--spcfc-inst-nodeos")
cmdArr.append(path)

# must be last cmdArr.append before subprocess.call, so that everything is on the command line
# before constructing the shape.json file for "bridge"
if topo=="bridge":
Expand Down Expand Up @@ -273,7 +329,7 @@ def getNodeNum(nodeName):
producerGroup2.append(nodeName)
Utils.Print("Group2 grouping producerIndex=%s, secondGroupStart=%s" % (producerIndex,secondGroupStart))
if group!=prodGroup:
errorExit("Node configuration not consistent with \"bridge\" topology. Node %s has producers that fall into both halves of the bridged network" % (nodeName))
Utils.errorExit("Node configuration not consistent with \"bridge\" topology. Node %s has producers that fall into both halves of the bridged network" % (nodeName))

for _,bridgeNode in bridgeNodes.items():
bridgeNode["peers"]=[]
Expand Down
2 changes: 2 additions & 0 deletions tests/TestHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ def parse_args(includeArgs, applicationSpecificArgs=AppArgs()):
parser.add_argument("--clean-run", help="Kill all nodeos and kleos instances", action='store_true')
if "--sanity-test" in includeArgs:
parser.add_argument("--sanity-test", help="Validates nodeos and kleos are in path and can be started up.", action='store_true')
if "--alternate-versions-labels-file" in includeArgs:
parser.add_argument("--alternate-versions-labels-file", type=str, help="Provide a file to define the labels that can be used in the test and the path to the version installation associated with that.")

for arg in applicationSpecificArgs.args:
parser.add_argument(arg.flag, type=arg.type, help=arg.help, choices=arg.choices, default=arg.default)
Expand Down