X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FContainer%2FSALOME_ContainerManager.cxx;h=ffb6252f56a11688d73926559f33e589a6c8b5dc;hb=7e1d8de9f1daaf767b8d556843e07c6b5b3121a7;hp=6039bd28afa80d7a67c4111bbfa87b037fa84279;hpb=80844f7ad2a6f9bd1c91bf208d4a3c9faefa2ac8;p=modules%2Fkernel.git diff --git a/src/Container/SALOME_ContainerManager.cxx b/src/Container/SALOME_ContainerManager.cxx index 6039bd28a..ffb6252f5 100644 --- a/src/Container/SALOME_ContainerManager.cxx +++ b/src/Container/SALOME_ContainerManager.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -29,6 +29,7 @@ #include "SALOME_ModuleCatalog.hh" #include "Basics_Utils.hxx" #include "Basics_DirUtils.hxx" +#include "PythonCppUtils.hxx" #include #include #include @@ -39,6 +40,7 @@ #include "Utils_CorbaException.hxx" #include #include +#include #include #include CORBA_CLIENT_HEADER(SALOME_Session) @@ -277,6 +279,27 @@ void SALOME_ContainerManager::ShutdownContainers() } } +void SALOME_ContainerManager::SetOverrideEnvForContainers(const Engines::KeyValDict& env) +{ + this->_override_env.clear(); + auto sz = env.length(); + for(auto i = 0 ; i < sz ; ++i) + _override_env.emplace_back(env[i].key.in(), env[i].val.in()); +} + +Engines::KeyValDict *SALOME_ContainerManager::GetOverrideEnvForContainers() +{ + std::unique_ptr ret( new Engines::KeyValDict ); + auto sz = _override_env.size(); + ret->length(sz); + for(auto i = 0 ; i < sz ; ++i) + { + (*ret)[i].key = CORBA::string_dup( _override_env[i].first.c_str() ); + (*ret)[i].val = CORBA::string_dup( _override_env[i].second.c_str() ); + } + return ret.release(); +} + //============================================================================= //! Give a suitable Container given constraints /*! CORBA Method: @@ -437,6 +460,20 @@ Engines::Container_ptr SALOME_ContainerManager::GiveContainer(const Engines::Con if (!CORBA::is_nil(cont)) { INFOS("[GiveContainer] container " << containerNameInNS << " launched"); + std::ostringstream envInfo; + std::for_each( _override_env.begin(), _override_env.end(), [&envInfo](const std::pair& p) { envInfo << p.first << " = " << p.second << std::endl; } ); + INFOS("[GiveContainer] container " << containerNameInNS << " override " << envInfo.str()); + Engines::FieldsDict envCorba; + { + auto sz = _override_env.size(); + envCorba.length(sz); + for(auto i = 0 ; i < sz ; ++i) + { + envCorba[i].key = CORBA::string_dup( _override_env[i].first.c_str() ); + envCorba[i].value <<= CORBA::string_dup( _override_env[i].second.c_str() ); + } + } + cont->override_environment_python( envCorba ); return cont._retn(); } else @@ -567,13 +604,22 @@ SALOME_ContainerManager::LaunchContainer(const Engines::ContainerParameters& par MESSAGE("[GiveContainer] Try to launch a new container on " << resource_selected); // if a parallel container is launched in batch job, command is: "mpirun -np nbproc -machinefile nodesfile SALOME_MPIContainer" if( GetenvThreadSafe("LIBBATCH_NODEFILE") != NULL && params.isMPI ) + { command = BuildCommandToLaunchLocalContainer(params, machFile, container_exe, tmpFileName); + MESSAGE("[LaunchContainer] LIBBATCH_NODEFILE : \"" << command << "\""); + } // if a container is launched on localhost, command is "SALOME_Container" or "mpirun -np nbproc SALOME_MPIContainer" else if(hostname == Kernel_Utils::GetHostname()) + { command = BuildCommandToLaunchLocalContainer(params, machFile, container_exe, tmpFileName); + MESSAGE("[LaunchContainer] hostname local : \"" << command << "\""); + } // if a container is launched in remote mode, command is "ssh resource_selected SALOME_Container" or "ssh resource_selected mpirun -np nbproc SALOME_MPIContainer" else + { command = BuildCommandToLaunchRemoteContainer(resource_selected, params, container_exe); + MESSAGE("[LaunchContainer] remote : \"" << command << "\""); + } //redirect stdout and stderr in a file #ifdef WIN32 @@ -603,7 +649,8 @@ SALOME_ContainerManager::LaunchContainer(const Engines::ContainerParameters& par logFilename += ".log" ; command += " > " + logFilename + " 2>&1"; MakeTheCommandToBeLaunchedASync(command); - + + MESSAGE("[LaunchContainer] SYSTEM COMMAND that will be launched : \"" << command << "\""); // launch container with a system call status=SystemThreadSafe(command.c_str()); }//end of critical of section @@ -748,14 +795,18 @@ std::string SALOME_ContainerManager::BuildCommandToLaunchRemoteContainer(const std::string& resource_name, const Engines::ContainerParameters& params, const std::string& container_exe) const { std::string command,tmpFileName; + const ParserResourcesType resInfo(_resManager->GetResourceDefinition(resource_name)); + std::string wdir = params.workingdir.in(); if (!_isAppliSalomeDefined) - command = BuildTempFileToLaunchRemoteContainer(resource_name, params, tmpFileName); + { + MESSAGE("[BuildCommandToLaunchRemoteContainer] NO APPLI MODE : " << " Protocol :" << resInfo.Protocol << " hostname :" << resInfo.HostName << " username : " << resInfo.UserName << " appli : " << resInfo.AppliPath << " wdir : \"" << wdir << "\""); + command = getCommandToRunRemoteProcessNoAppli(resInfo.Protocol, resInfo.HostName, + resInfo.UserName, resInfo.AppliPath, + wdir); + } else { - const ParserResourcesType resInfo(_resManager->GetResourceDefinition(resource_name)); - - std::string wdir = params.workingdir.in(); - + MESSAGE("[BuildCommandToLaunchRemoteContainer] WITH APPLI MODE : " << " Protocol :" << resInfo.Protocol << " hostname :" << resInfo.HostName << " username : " << resInfo.UserName << " appli : " << resInfo.AppliPath << " wdir : \"" << wdir << "\""); // "ssh -l user machine distantPath/runRemote.sh hostNS portNS WORKINGDIR workingdir // SALOME_Container containerName -ORBInitRef NameService=IOR:01000..." // or @@ -764,123 +815,229 @@ SALOME_ContainerManager::BuildCommandToLaunchRemoteContainer(const std::string& command = getCommandToRunRemoteProcess(resInfo.Protocol, resInfo.HostName, resInfo.UserName, resInfo.AppliPath, wdir); - - if(params.isMPI) - { - int nbproc = params.nb_proc <= 0 ? 1 : params.nb_proc; - command += " mpirun -np "; - std::ostringstream o; - o << nbproc << " "; - command += o.str(); + } + if(params.isMPI) + { + int nbproc = params.nb_proc <= 0 ? 1 : params.nb_proc; + command += " mpirun -np "; + std::ostringstream o; + o << nbproc << " "; + command += o.str(); #ifdef LAM_MPI - command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace "; + command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace "; #elif defined(OPEN_MPI) - if( GetenvThreadSafe("OMPI_URI_FILE") == NULL ) - command += "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace"; - else{ - command += "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace -ompi-server file:"; - command += GetenvThreadSafeAsString("OMPI_URI_FILE"); - } + if( GetenvThreadSafe("OMPI_URI_FILE") == NULL ) + command += "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace"; + else{ + command += "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace -ompi-server file:"; + command += GetenvThreadSafeAsString("OMPI_URI_FILE"); + } #elif defined(MPICH) - command += "-nameserver " + Kernel_Utils::GetHostname(); + command += "-nameserver " + Kernel_Utils::GetHostname(); #endif - command += " SALOME_MPIContainer "; - } - else - command += " " +container_exe+ " "; + command += " SALOME_MPIContainer "; + } + else + command += " " +container_exe+ " "; - command += _NS->ContainerName(params); - if(!this->_isSSL) - { - command += " -"; - AddOmninamesParams(command); - } - MESSAGE("command =" << command); + command += _NS->ContainerName(params) + " "; + if(this->_isSSL) + { + Engines::EmbeddedNamingService_var ns = GetEmbeddedNamingService(); + CORBA::String_var iorNS = _orb->object_to_string(ns); + command += std::string(iorNS); + } + else //if(!this->_isSSL) + { + command += " -"; + AddOmninamesParams(command); } + MESSAGE("command =" << command); return command; } //============================================================================= -/*! - * builds the command to be launched. +//! Return a path to the directory with scripts templates +/*! + * \return the path pointed by SALOME_KERNEL_SCRIPTS_DIR environment variable, if it is defined, + * ${KERNEL_ROOT_DIR}/share/salome/resources/separator/kernel/ScriptsTemplate - otherwise */ //============================================================================= -std::string SALOME_ContainerManager::BuildCommandToLaunchLocalContainer(const Engines::ContainerParameters& params, const std::string& machinesFile, const std::string& container_exe, std::string& tmpFileName) const +std::string getScriptTemplateFilePath() +{ + auto parseScriptTemplateFilePath = []() -> std::string + { + std::string scriptTemplateFilePath = SALOME_ContainerManager::GetenvThreadSafeAsString("SALOME_KERNEL_SCRIPTS_DIR"); + if (!scriptTemplateFilePath.empty()) + { + return scriptTemplateFilePath; + } + else { + return SALOME_ContainerManager::GetenvThreadSafeAsString("KERNEL_ROOT_DIR") + + "/share/salome/resources/kernel/ScriptsTemplate"; + } + }; + + static const std::string scriptTemplateFilePath = parseScriptTemplateFilePath(); + return scriptTemplateFilePath; +} + +//============================================================================= +//! Return a command line constructed based on Python scripts templates +/*! + * \param theScriptName the name of Python script template + * \param theScriptParameters the queue of parameter values + * \return the command line constructed according to the given parameters + */ +//============================================================================= +std::string GetCommandFromTemplate(const std::string& theScriptName, + std::queue& theScriptParameters) { - tmpFileName = BuildTemporaryFileName(); std::string command; + AutoGIL agil; + // manage GIL - std::ostringstream o; + PyObject* mod(PyImport_ImportModule(theScriptName.c_str())); + if (!mod) + { + PyObject* sys = PyImport_ImportModule("sys"); + PyObject* sys_path = PyObject_GetAttrString(sys, "path"); + PyObject* folder_path = PyUnicode_FromString(getScriptTemplateFilePath().c_str()); + PyList_Append(sys_path, folder_path); - if (params.isMPI) + mod = PyImport_ImportModule(theScriptName.c_str()); + + Py_XDECREF(folder_path); + Py_XDECREF(sys_path); + Py_XDECREF(sys); + } + + if (mod) + { + PyObject* meth(PyObject_GetAttrString(mod, "command")); + if (!meth) { - int nbproc = params.nb_proc <= 0 ? 1 : params.nb_proc; + Py_XDECREF(mod); + } + else + { + int id = -1; + PyObject* tuple(PyTuple_New(theScriptParameters.size())); - o << "mpirun -np "; + auto insert_parameter = [&tuple, &theScriptParameters, &id]() + { + if (!theScriptParameters.empty()) + { + PyTuple_SetItem(tuple, ++id, PyUnicode_FromString(theScriptParameters.front().c_str())); + theScriptParameters.pop(); + } + }; + + while (!theScriptParameters.empty()) + { + insert_parameter(); + } + + PyObject *args(PyTuple_New(1)); + PyTuple_SetItem(args, 0, tuple); + + PyObject *res(PyObject_CallObject(meth, args)); + if (res) + { + command = PyUnicode_AsUTF8(res); + Py_XDECREF(res); + } - o << nbproc << " "; + Py_XDECREF(args); + Py_XDECREF(tuple); + Py_XDECREF(meth); + Py_XDECREF(mod); + } + } - if( GetenvThreadSafe("LIBBATCH_NODEFILE") != NULL ) - o << "-machinefile " << machinesFile << " "; + MESSAGE("Command from template is ... " << command << std::endl); + return command; +} +//============================================================================= +//============================================================================= +/*! + * builds the command to be launched. + */ +//============================================================================= +std::string SALOME_ContainerManager::BuildCommandToLaunchLocalContainer(const Engines::ContainerParameters& params, const std::string& machinesFile, const std::string& container_exe, std::string& tmpFileName) const +{ + // Prepare name of the script to be used + std::string script_name = "SALOME_CM_LOCAL_NO_MPI"; + if (params.isMPI) + { #ifdef LAM_MPI - o << "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace "; + script_name = "SALOME_CM_LOCAL_MPI_LAN"; #elif defined(OPEN_MPI) - if( GetenvThreadSafe("OMPI_URI_FILE") == NULL ) - o << "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace"; - else - { - o << "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace -ompi-server file:"; - o << GetenvThreadSafeAsString("OMPI_URI_FILE"); - } + script_name = "SALOME_CM_LOCAL_MPI_OPENMPI"; #elif defined(MPICH) - o << "-nameserver " + Kernel_Utils::GetHostname(); + script_name = "SALOME_CM_LOCAL_MPI_MPICH"; #endif + } + + // Prepare parameters to use in the Python script: + // 1. All parameters are strings. + // 2. For some booleans use "1" = True, "0" = False. + // 3. If a parameter is NULL, then its value is "NULL". - if (isPythonContainer(params.container_name)) - o << " pyMPI SALOME_ContainerPy.py "; - else - o << " SALOME_MPIContainer "; - } + std::queue script_parameters; + + // ===== Number of processes (key = "nb_proc") + script_parameters.push(params.isMPI ? std::to_string(params.nb_proc <= 0 ? 1 : params.nb_proc) : "NULL"); + + // ===== Working directory (key = "workdir") and temporary directory flag (key = "isTmpDir") + // A working directory is requested + std::string workdir = params.workingdir.in(); + std::string isTmpDir = std::to_string(0); + if (workdir == "$TEMPDIR") + { + // A new temporary directory is requested + isTmpDir = std::to_string(1); + workdir = Kernel_Utils::GetTmpDir(); + } + script_parameters.push(workdir); + script_parameters.push(isTmpDir); + + // ===== Server name (key = "name_server") + script_parameters.push(Kernel_Utils::GetHostname()); + // ===== Container (key = "container") + std::string container; + if (params.isMPI) + { + container = isPythonContainer(params.container_name) ? "pyMPI SALOME_ContainerPy.py" : "SALOME_MPIContainer"; + } else - { - std::string wdir=params.workingdir.in(); - if(wdir != "") - { - // a working directory is requested - if(wdir == "$TEMPDIR") - { - // a new temporary directory is requested - std::string dir = Kernel_Utils::GetTmpDir(); -#ifdef WIN32 - o << "cd /d " << dir << std::endl; -#else - o << "cd " << dir << ";"; -#endif + { + container = isPythonContainer(params.container_name) ? "SALOME_ContainerPy.py" : container_exe; + } + script_parameters.push(container); - } - else - { - // a permanent directory is requested use it or create it -#ifdef WIN32 - o << "mkdir " + wdir << std::endl; - o << "cd /D " + wdir << std::endl; -#else - o << "mkdir -p " << wdir << " && cd " << wdir + ";"; -#endif - } - } + // ===== Container name (key = "container_name") + script_parameters.push(_NS->ContainerName(params)); - if (isPythonContainer(params.container_name)) - o << "SALOME_ContainerPy.py "; - else - o << container_exe + " "; + // ===== LIBBATCH node file (key = "libbatch_nodefile") + script_parameters.push(std::to_string(GetenvThreadSafe("LIBBATCH_NODEFILE") != NULL ? 1 : 0)); - } + // ===== Machine file (key = "machine_file") + script_parameters.push(machinesFile.empty() ? "NULL" : machinesFile); + + // ===== OMPI uri file (key = "ompi_uri_file") + std::string ompi_uri_file = GetenvThreadSafeAsString("OMPI_URI_FILE"); + script_parameters.push(ompi_uri_file.empty() ? "NULL" : ompi_uri_file); + + std::string command_from_template = GetCommandFromTemplate(script_name, script_parameters); + + std::ostringstream o; + o << command_from_template << " "; - o << _NS->ContainerName(params) << " "; + //==================================================================================== */ if( this->_isSSL ) { @@ -894,6 +1051,7 @@ std::string SALOME_ContainerManager::BuildCommandToLaunchLocalContainer(const En AddOmninamesParams(o); } + tmpFileName = BuildTemporaryFileName(); std::ofstream command_file( tmpFileName.c_str() ); command_file << o.str(); command_file.close(); @@ -901,8 +1059,8 @@ std::string SALOME_ContainerManager::BuildCommandToLaunchLocalContainer(const En #ifndef WIN32 chmod(tmpFileName.c_str(), 0x1ED); #endif - command = tmpFileName; - + + std::string command = tmpFileName; MESSAGE("Command is file ... " << command); MESSAGE("Command is ... " << o.str()); return command; @@ -1242,106 +1400,99 @@ std::string SALOME_ContainerManager::machinesFile(const int nbproc) } -std::string SALOME_ContainerManager::getCommandToRunRemoteProcess(AccessProtocolType protocol, +std::string SALOME_ContainerManager::getCommandToRunRemoteProcessNoAppli(AccessProtocolType protocol, const std::string & hostname, const std::string & username, const std::string & applipath, const std::string & workdir) const +{ + return getCommandToRunRemoteProcessCommon("SALOME_CM_REMOTE","salome shell --",protocol,hostname,username,applipath,workdir); +} + +std::string SALOME_ContainerManager::getCommandToRunRemoteProcess(AccessProtocolType protocol, const std::string & hostname, const std::string & username, const std::string & applipath, const std::string & workdir) const +{ + return getCommandToRunRemoteProcessCommon("SALOME_CM_REMOTE_OLD",this->GetRunRemoteExecutableScript(),protocol,hostname,username,applipath,workdir); +} + +std::string SALOME_ContainerManager::getCommandToRunRemoteProcessCommon(const std::string& templateName, + const std::string& remoteScript, + AccessProtocolType protocol, const std::string & hostname, const std::string & username, const std::string & applipath, const std::string & workdir) const { std::ostringstream command; - bool envd = true; // source the environment + + // Prepare parameters to use in the Python script: + // 1. All parameters are strings. + // 2. For some booleans use "1" = True, "0" = False. + // 3. If a parameter is NULL, then its value is "NULL". + + std::queue script_parameters; + + // ===== Protocol (key = "protocol") + std::string strProtocol; switch (protocol) { - case rsh: - command << "rsh "; - if (username != "") - { - command << "-l " << username << " "; - } - command << hostname << " "; - break; - case ssh: - command << "ssh "; - if (username != "") - { - command << "-l " << username << " "; - } - command << hostname << " "; - break; - case srun: - // no need to redefine the user with srun, the job user is taken by default - // (note: for srun, user id can be specified with " --uid=") - command << "srun -n 1 -N 1 -s --mem-per-cpu=0 --cpu-bind=none --nodelist=" << hostname << " "; - envd = false; - break; - case pbsdsh: - command << "pbsdsh -o -h " << hostname << " "; - break; - case blaunch: - command << "blaunch -no-shell " << hostname << " "; - break; + case rsh: strProtocol = "rsh"; break; + case ssh: strProtocol = "ssh"; break; + case srun: strProtocol = "srun"; break; + case pbsdsh: strProtocol = "pbsdsh"; break; + case blaunch: strProtocol = "blaunch"; break; default: throw SALOME_Exception("Unknown protocol"); } + script_parameters.push(strProtocol); - std::string remoteapplipath; - if (applipath=="") - remoteapplipath = GetenvThreadSafeAsString("APPLI"); - else - remoteapplipath = applipath; + // ===== User name (key = "user") + script_parameters.push(username.empty() ? "NULL" : username); + + // ===== Host name (key = "host") + script_parameters.push(hostname.empty() ? "NULL" : hostname); + + + // ===== Remote APPLI path (key = "appli") + script_parameters.push(applipath.empty() ? GetenvThreadSafeAsString("APPLI") : applipath); + + if(!this->_isSSL) + { + ASSERT(GetenvThreadSafe("NSHOST")); + ASSERT(GetenvThreadSafe("NSPORT")); + } - ASSERT(GetenvThreadSafe("NSHOST")); - ASSERT(GetenvThreadSafe("NSPORT")); + struct stat statbuf; + std::string appli_mode = (stat(GetenvThreadSafe("APPLI"), &statbuf) == 0 && S_ISREG(statbuf.st_mode)) ? "launcher" : "dir"; + // ===== Working directory (key = "workdir") + script_parameters.push(workdir == "$TEMPDIR" ? "\\$TEMPDIR" : workdir); + + // ===== SSL (key = "ssl") + script_parameters.push(this->_isSSL ? "1" : "0"); + + // ===== Hostname of CORBA name server (key = "nshost") + std::string nshost = GetenvThreadSafeAsString("NSHOST"); + script_parameters.push(nshost.empty() ? "NULL" : nshost); + + // ===== Port of CORBA name server (key = "nsport") + std::string nsport = GetenvThreadSafeAsString("NSPORT"); + script_parameters.push(nsport.empty() ? "NULL" : nsport); + + // ===== Remote script (key = "remote_script") + script_parameters.push(remoteScript.empty() ? "NONE" : remoteScript); + + // ===== Naming service (key = "naming_service") + std::string namingService = "NONE"; + if(this->_isSSL) + { + Engines::EmbeddedNamingService_var ns = GetEmbeddedNamingService(); + CORBA::String_var iorNS = _orb->object_to_string(ns); + namingService = iorNS; + } + script_parameters.push(namingService); + + // ===== APPLI mode (key = "appli_mode") // $APPLI points either to an application directory, or to a salome launcher file // we prepare the remote command according to the case - struct stat statbuf; - if (stat(GetenvThreadSafe("APPLI"), &statbuf) ==0 && S_ISREG(statbuf.st_mode)) - { - // if $APPLI is a regular file, we asume it's a salome Launcher - // generate a command with a salome launcher - command << remoteapplipath - << " remote" - << " -m " - << GetenvThreadSafeAsString("NSHOST") // hostname of CORBA name server - << " -p " - << GetenvThreadSafeAsString("NSPORT"); // port of CORBA name server - if (workdir != "") - command << "-d " << workdir; - command << " -- " ; - } - else // we assume it's a salome application directory - { - // generate a command with runRemote.sh - command << remoteapplipath; - command << "/" << this->GetRunRemoteExecutableScript() << " "; - if (!envd) - command << "--noenvd "; + script_parameters.push(appli_mode); - if(this->_isSSL) - { - Engines::EmbeddedNamingService_var ns = GetEmbeddedNamingService(); - CORBA::String_var iorNS = _orb->object_to_string(ns); - command << iorNS; - } - else - { - command << GetenvThreadSafeAsString("NSHOST"); // hostname of CORBA name server - command << " "; - command << GetenvThreadSafeAsString("NSPORT"); // port of CORBA name server - } - - if(workdir != "") - { - command << " WORKINGDIR "; - command << " '"; - if(workdir == "$TEMPDIR") - command << "\\$TEMPDIR"; - else - command << workdir; // requested working directory - command << "'"; - } - } + command << GetCommandFromTemplate(templateName, script_parameters); return command.str(); }