void Launcher::servicesFromXML(const anna::xml::Node* servicesNode, bool eventOperation) throw(anna::RuntimeException) {
- //<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>
+
+ CommandLine& cl(anna::CommandLine::instantiate());
+ bool allLogsDisabled = cl.exists("disableLogs");
+
+ //<!ATTLIST stack id CDATA #REQUIRED dictionary CDATA #REQUIRED>
const anna::xml::Attribute *id, *dictionary;
// <!ATTLIST node originRealm CDATA #REQUIRED applicationId CDATA #REQUIRED originHost CDATA #IMPLIED cer CDATA #IMPLIED dwr CDATA #IMPLIED allowedInactivityTime CDATA #IMPLIED tcpConnectDelay CDATA #IMPLIED answersTimeout CDATA #IMPLIED ceaTimeout CDATA #IMPLIED watchdogPeriod CDATA #IMPLIED entity CDATA #IMPLIED entityServerSessions CDATA #IMPLIED diameterServer CDATA #IMPLIED diameterServerSessions CDATA #IMPLIED balance (yes | no) #IMPLIED sessionBasedModelsClientSocketSelection (SessionIdLowPart | SessionIdHighPart | SessionIdOptionalPart | RoundRobin) #IMPLIED retries CDATA #IMPLIED log CDATA #IMPLIED splitLog (yes | no) #IMPLIED detailedLog (yes | no) #IMPLIED dumpLog (yes | no) #IMPLIED burstLog (yes | no) #IMPLIED>
*answersTimeout, *ceaTimeout, *watchdogPeriod, *entity, *entityServerSessions,
*diameterServer, *diameterServerSessions, *balance, *sessionBasedModelsClientSocketSelection,
*retries, *log, *splitLog, *detailedLog, *dumpLog, *burstLog;
-
// Never clear services content from here (append new data from xml). At the moment no node removing is implemented in this process
// Stacks
anna::diameter::comm::ApplicationMessageOamModule & appMsgOamModule = anna::diameter::comm::ApplicationMessageOamModule::instantiate();
appMsgOamModule.enableCounters(); // this special module is disabled by default (the only)
static int scope_id = 3;
- bool id_0_registered = false;
unsigned int id_value;
std::string codecEngineName;
dictionary = (*it)->getAttribute("dictionary");
id_value = id->getIntegerValue();
+ if (stackEngine.getDictionary(id_value)) { // Ignore (but don't fail) dictionary load with same stack id already registered
+ LOGWARNING(anna::Logger::warning(anna::functions::asString("Ignore dictionary load for stack id already registered: %llu", id_value), ANNA_FILE_LOCATION));
+ continue;
+ }
+
try {
d = stackEngine.createDictionary(id_value, dictionary->getValue());
LOGDEBUG(anna::Logger::debug(anna::functions::asString("Created dictionary (%p) for stack id %llu", d, id_value), ANNA_FILE_LOCATION));
throw ex;
}
- if (id_value == 0) {
- id_0_registered = true;
- bpd = d;
- }
+ bpd = d; // base protocol dictionary in case of monostack. If multistack, will be calculated later
// Create codec engine and register it in the codec engine manager:
codecEngineName = anna::functions::asString("CodecEngineForStackId_%llu", id_value);
// Basic checking for multistack:
bool multistack = (stackEngine.stack_size() > 1);
if (multistack) {
- if(!id_0_registered)
+ bpd = stackEngine.getDictionary(0);
+ if(!bpd)
throw anna::RuntimeException("In multistack applications is mandatory register a stack id = 0 using a dictionary which contains the needed elements to build base protocol messages (CER/A, DWR/A, DPR/A, STR/A, etc.)", ANNA_FILE_LOCATION);
}
- else { // monostack
- if (!bpd)
- bpd = ce->getDictionary(); // in mono-stack applications, we understand the existing stack as the used
- // for base protocol, regardless if it is registered with stack id 0 or not
- }
// REALMS:
for(anna::xml::Node::const_child_iterator it = servicesNode->child_begin(); it != servicesNode->child_end(); it++) {
}
// Logs:
- std::string realm = commEngine->getRealm();
- std::string s_log = realm + ".launcher.log"; if (log) s_log = log->getValue();
- bool b_splitLog = (splitLog ? (splitLog->getValue() == "yes") : false);
- bool b_detailedLog = (detailedLog ? (detailedLog->getValue() == "yes") : false);
- bool b_dumpLog = (dumpLog ? (dumpLog->getValue() == "yes") : false);
- std::string s_burstLog = realm + ".launcher.burst"; if (burstLog) s_burstLog = burstLog->getValue();
- a_workingNode->setLogs(s_log, b_splitLog, b_detailedLog, b_dumpLog, s_burstLog);
+ if (!allLogsDisabled) {
+ std::string realm = commEngine->getRealm();
+ std::string s_log = realm + ".launcher.log"; if (log) s_log = log->getValue();
+ bool b_splitLog = (splitLog ? (splitLog->getValue() == "yes") : false);
+ bool b_detailedLog = (detailedLog ? (detailedLog->getValue() == "yes") : false);
+ bool b_dumpLog = (dumpLog ? (dumpLog->getValue() == "yes") : false);
+ std::string s_burstLog = realm + ".launcher.burst"; if (burstLog) s_burstLog = burstLog->getValue();
+ a_workingNode->setLogs(s_log, b_splitLog, b_detailedLog, b_dumpLog, s_burstLog);
+ }
// Lazy initialization for comm engine:
result += "\n to load new nodes once the ADML is started, regardless if command";
result += "\n line '--services' parameter was used or not. Those services which";
result += "\n are not correctly loaded will be ignored to keep the process alive.";
+ result += "\n If you need to load services as deltas, you must firstly load the";
+ result += "\n diameter base dictionary with stack id 0, because all the realms";
+ result += "\n will use this dictionary to encode/decode base protocol messages";
+ result += "\n managed by the communication engine.";
result += "\n";
result += "\ndiameterServerSessions|<integer> Updates the maximum number of accepted connections to diameter";
result += "\n server socket.";
result += "\n This operation applies over all the registered realm nodes";
result += "\n except if one specific working node has been set.";
result += "\nforceCountersRecord Forces dump to file the current counters of the process.";
+ result += "\nshow-oam Dumps current counters of the process. This is also done at";
+ result += "\n process context dump.";
+ result += "\nshow-stats Dumps statistics of the process. This is also done at process";
+ result += "\n context dump.";
result += "\n";
result += "\n<visibility action>[|<address>:<port>][|socket id]";
result += "\n";
result += "\n";
result += "\n delay|<msecs> Blocking step until the time lapse expires. Useful to give ";
result += "\n some cadence control and time schedule for a specific case.";
+ result += "\n A value of 0 could be used as a dummy step.";
result += "\n wait<fe/fc>|<condition> Blocking step until condition is fulfilled. The message could";
result += "\n received from entity (waitfe) or from client (waitfc).";
result += "\n";
result += "\n";
result += "\n Provide 0 in order to stop the timer triggering.";
result += "\n";
- result += "\n There timer manager resolution currently harcoded allows a maximum of ";
+ result += "\n The timer manager resolution currently harcoded allows a maximum of ";
result += anna::functions::asString(1000/a_admlMinResolution); result += " events";
result += "\n per second. To reach greater rates ADML will join synchronously the needed number of";
result += "\n new time-triggered test cases per a single event, writting a warning-level trace to";
result += "\n advice about the risk of burst sendings and recommend launching multiple instances";
result += "\n to achieve such load with a lower rate per instance.";
result += "\n";
+ result += "\n test|next[|<sync-amount>] Forces the execution of the next test case(s) without waiting for test manager tick.";
+ result += "\n Provide an integer value for 'sync-amount' to send a burst synchronous amount of the";
+ result += "\n next programmed test cases (1 by default). This event works regardless the timer tick";
+ result += "\n function, but it is normally used with the test manager tick stopped.";
+ result += "\n";
result += "\n test|ip-limit[|amount] In-progress limit of test cases. No new test cases will be launched over this value";
result += "\n (test Manager tick work will be ignored). Zero-value is equivalent to stop the clock.";
result += "\n tick, -1 is used to specify 'no limit' which is the default. If missing amount, the";
return;
}
+ // OAM & statistics:
+ if(operation == "show-oam") {
+ anna::xml::Node root("root");
+ response_content = anna::xml::Compiler().apply(oamAsXML(&root));
+ return;
+ }
+ if(operation == "show-stats") {
+ anna::xml::Node root("root");
+ response_content = anna::xml::Compiler().apply(statsAsXML(&root));
+ return;
+ }
+
///////////////////////////////////////////////////////////////////
// Tokenize operation
Tokenizer params;
}
catch(anna::RuntimeException &ex) {
ex.trace();
- response_content = anna::functions::asString("Loaded services from file '%s' with some problems (ignored ones)", servicesFile.c_str());
+ response_content = anna::functions::asString("Loaded services from file '%s' with errors", servicesFile.c_str());
return;
}
response_content = anna::functions::asString("Loaded services from file '%s'", servicesFile.c_str());
} else if((opType == "test")) {
// test|<id>|<command>[|parameters] Add a new step to the test case ...
// test|ttps|<amount> Starts/resume the provided number of time ticks per second (ttps). The ADML starts ...
+ // test|next[|<sync-amount>] Forces the execution of the next test case(s) without waiting for test manager tick ...
// test|ip-limit[|amount] In-progress limit of test cases. No new test cases will be launched over this value ...
// test|repeats|<amount> Restarts the whole programmed test list when finished the amount number of times ...
// test|report[|[yes]|no] Every time a test case is finished a report file in xml format will be created under ...
opt_response_content += "unable to configure the test rate provided";
}
}
+ else if (param1 == "next") {
+ if (numParams > 2)
+ throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+
+ int sync_amount = ((param2 != "") ? atoi(param2.c_str()) : 1);
+
+ if (sync_amount < 1)
+ throw anna::RuntimeException("The parameter 'sync-amount' must be a positive integer value", ANNA_FILE_LOCATION);
+
+ bool success = testManager.execTestCases(sync_amount);
+
+ opt_response_content = (success ? "" : "not completely " /* completed cycle and no repeats, rare case */);
+ opt_response_content += "processed ";
+ opt_response_content += anna::functions::asString(sync_amount);
+ opt_response_content += ((sync_amount > 1) ? " test cases synchronously" : " test case");
+ }
else if(param1 == "ip-limit") {
if (numParams > 2)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
if (numParams > 3)
throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
if(param3 == "") throw anna::RuntimeException("Missing milliseconds for 'delay' command in test id operation", ANNA_FILE_LOCATION);
- anna::Millisecond delay = checkTimeMeasure("Test case delay step", param3);
+ anna::Millisecond delay = ((param3 == "0" /* special case */) ? (anna::Millisecond)0 : checkTimeMeasure("Test case delay step", param3));
testManager.getTestCase(id)->addDelay(delay); // creates / reuses
}
else if ((param2 == "waitfe")||(param2 == "waitfc")) {
it->second->asXML(result);
}
+ // OAM & statistics:
+ oamAsXML(result);
+ statsAsXML(result);
+
+ // Testing: could be heavy if test case reports are enabled
+ TestManager::instantiate().asXML(result);
+
+ return result;
+}
+
+anna::xml::Node* Launcher::oamAsXML(anna::xml::Node* parent) const
+throw() {
+ anna::xml::Node* result = parent->createChild("Oam");
+
// OAM:
anna::diameter::comm::OamModule::instantiate().asXML(result);
anna::diameter::comm::ApplicationMessageOamModule::instantiate().asXML(result);
anna::diameter::codec::OamModule::instantiate().asXML(result);
+
+ return result;
+}
+
+anna::xml::Node* Launcher::statsAsXML(anna::xml::Node* parent) const
+throw() {
+ anna::xml::Node* result = parent->createChild("Statistics");
+
// Statistics:
anna::statistics::Engine::instantiate().asXML(result);
- // Testing: could be heavy if test case reports are enabled
- TestManager::instantiate().asXML(result);
-
return result;
}