From 9399d716fa7ca28c4983474bbf35d97769efdc05 Mon Sep 17 00:00:00 2001 From: wangkx Date: Fri, 17 Nov 2023 14:29:18 -0500 Subject: [PATCH] HPCC-30809 Add GetVersion/Archive/Restore Signed-off-by: wangkx --- dali/sasha/CMakeLists.txt | 5 +- dali/sasha/saruncmd.cmake | 47 +++++++++ dali/sasha/saruncmd.cpp | 119 ++++++++++++++++++++++ dali/sasha/saruncmd.hpp | 25 +++++ esp/scm/ws_sasha.ecm | 64 ++++++++++++ esp/services/ws_sasha/CMakeLists.txt | 4 + esp/services/ws_sasha/ws_sashaservice.cpp | 118 ++++++++++++++++++++- esp/services/ws_sasha/ws_sashaservice.hpp | 9 ++ esp/smc/SMCLib/eclwatch_errorlist.hpp | 3 +- 9 files changed, 391 insertions(+), 3 deletions(-) create mode 100644 dali/sasha/saruncmd.cmake create mode 100644 dali/sasha/saruncmd.cpp create mode 100644 dali/sasha/saruncmd.hpp create mode 100644 esp/scm/ws_sasha.ecm diff --git a/dali/sasha/CMakeLists.txt b/dali/sasha/CMakeLists.txt index d411836f4eb..1ba66a6e957 100644 --- a/dali/sasha/CMakeLists.txt +++ b/dali/sasha/CMakeLists.txt @@ -24,6 +24,8 @@ project (sasha) +include (saruncmd.cmake) + INCLUDE(CheckLibraryExists) if (NOT WIN32 AND NOT WIN64) @@ -112,7 +114,8 @@ install ( TARGETS sasha RUNTIME DESTINATION ${EXEC_DIR}) target_link_libraries ( sasha ${XALAN_LIBRARIES} ${XERCES_LIBRARIES} jlib - mp + mp + saruncmdlib ) diff --git a/dali/sasha/saruncmd.cmake b/dali/sasha/saruncmd.cmake new file mode 100644 index 00000000000..64eae25e68d --- /dev/null +++ b/dali/sasha/saruncmd.cmake @@ -0,0 +1,47 @@ +################################################################################ +# HPCC SYSTEMS software Copyright (C) 2023 HPCC Systems®. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################ + + +# Component: saruncmdlib +##################################################### +# Description: +# ------------ +# Cmake Input File for saruncmdlib +##################################################### + +project( saruncmdlib ) + +set ( SRCS + sacmd.cpp + saruncmd.cpp + ) + +include_directories ( + . + ${HPCC_SOURCE_DIR}/system/mp + ${HPCC_SOURCE_DIR}/system/include + ${HPCC_SOURCE_DIR}/system/jlib + ) + +ADD_DEFINITIONS ( -D_USRDLL -DSASHACLI_API_EXPORTS ) + +HPCC_ADD_LIBRARY( saruncmdlib SHARED ${SRCS} ) +install ( TARGETS saruncmdlib RUNTIME DESTINATION ${EXEC_DIR} LIBRARY DESTINATION ${LIB_DIR} ) +target_link_libraries ( saruncmdlib + jlib + mp + ) + diff --git a/dali/sasha/saruncmd.cpp b/dali/sasha/saruncmd.cpp new file mode 100644 index 00000000000..864a44515b6 --- /dev/null +++ b/dali/sasha/saruncmd.cpp @@ -0,0 +1,119 @@ +#include "platform.h" +#include "jlib.hpp" +#include "mpbase.hpp" +#include "sacmd.hpp" +#include "saruncmd.hpp" + +class CSashaCmdExecutor : implements ISashaCmdExecutor, public CInterface +{ + Linked node; + unsigned defaultTimeoutMs = 60; + StringBuffer nodeText; + const char *getNodeText() + { + if (0==nodeText.length()) + node->endpoint().getEndpointHostText(nodeText); + return nodeText; + } + bool restoreWorkunit(const char *wuid, bool dfu, StringBuffer &serverResponse) + { + Owned cmd = createSashaCommand(); + cmd->setAction(SCA_RESTORE); + if (dfu) + cmd->setDFU(true); + cmd->addId(wuid); + if (!cmd->send(node, defaultTimeoutMs)) + throw makeStringExceptionV(-1, "Could not connect to Sasha server on %s", getNodeText()); + if (cmd->numIds()==0) + { + // nothing restored + return false; + } + cmd->getId(0, serverResponse); + return true; + } + bool archiveWorkunit(const char *wuid, bool dfu, bool deleteAfterArchiving, StringBuffer &serverResponse) + { + Owned cmd = createSashaCommand(); + cmd->setAction(SCA_ARCHIVE); + if (dfu) + cmd->setDFU(true); + cmd->addId(wuid); + if (!cmd->send(node, defaultTimeoutMs)) + throw makeStringExceptionV(-1, "Could not connect to Sasha server on %s", getNodeText()); + if (cmd->numIds()==0) + { + // nothing archived + return false; + } + cmd->getId(0, serverResponse); + return true; + } + +public: + IMPLEMENT_IINTERFACE; + CSashaCmdExecutor(INode *_node, unsigned _defaultTimeoutSecs=60) : node(_node) + { + defaultTimeoutMs = _defaultTimeoutSecs * 1000; + } + CSashaCmdExecutor(const SocketEndpoint &ep, unsigned _defaultTimeoutSecs = 60) + { + node.setown(createINode(ep)); + defaultTimeoutMs = _defaultTimeoutSecs * 1000; + } + CSashaCmdExecutor(const char *server, unsigned port=0, unsigned _defaultTimeoutSecs = 60) + { + SocketEndpoint ep(server, port); + node.setown(createINode(ep)); + defaultTimeoutMs = _defaultTimeoutSecs * 1000; + } + StringBuffer &getVersion(StringBuffer &version) + { + Owned cmd = createSashaCommand(); + cmd->setAction(SCA_GETVERSION); + if (!cmd->send(node, defaultTimeoutMs)) + throw makeStringExceptionV(-1, "Could not connect to Sasha server on %s", getNodeText()); + if (!cmd->getId(0, version)) + throw makeStringExceptionV(-1, "Sasha server[%s]: Protocol error", getNodeText()); + return version; + } + bool restoreECLWorkUnit(const char *wuid, StringBuffer &serverResponse) + { + return restoreWorkunit(wuid, false, serverResponse); + } + bool restoreDFUWorkUnit(const char *wuid, StringBuffer &serverResponse) + { + return restoreWorkunit(wuid, true, serverResponse); + } + bool archiveECLWorkUnit(const char *wuid, StringBuffer &serverResponse) + { + return archiveWorkunit(wuid, false, true, serverResponse); + } + bool archiveDFUWorkUnit(const char *wuid, StringBuffer &serverResponse) + { + return archiveWorkunit(wuid, true, true, serverResponse); + } + bool backupECLWorkUnit(const char *wuid, StringBuffer &serverResponse) + { + return archiveWorkunit(wuid, true, false, serverResponse); + } + bool backupDFUWorkUnit(const char *wuid, StringBuffer &serverResponse) + { + return archiveWorkunit(wuid, true, false, serverResponse); + } +}; + +ISashaCmdExecutor *createSashaCmdExecutor(INode *node, unsigned defaultTimeoutSecs) +{ + return new CSashaCmdExecutor(node, defaultTimeoutSecs); +} + +ISashaCmdExecutor *createSashaCmdExecutor(const SocketEndpoint &ep, unsigned defaultTimeoutSecs) +{ + return new CSashaCmdExecutor(ep, defaultTimeoutSecs); +} + +ISashaCmdExecutor *createSashaCmdExecutor(const char *server, unsigned port, unsigned defaultTimeoutSecs) +{ + return new CSashaCmdExecutor(server, port, defaultTimeoutSecs); +} \ No newline at end of file diff --git a/dali/sasha/saruncmd.hpp b/dali/sasha/saruncmd.hpp new file mode 100644 index 00000000000..6b6bf3643de --- /dev/null +++ b/dali/sasha/saruncmd.hpp @@ -0,0 +1,25 @@ +#ifndef SARUNCMD_HPP +#define SARUNCMD_HPP + +#ifdef SARUNCMD_API_EXPORTS + #define SARUNCMD_API DECL_EXPORT +#else + #define SARUNCMD_API DECL_IMPORT +#endif + +interface ISashaCmdExecutor : extends IInterface +{ + virtual StringBuffer &getVersion(StringBuffer &version) = 0; + virtual bool restoreECLWorkUnit(const char *wuid, StringBuffer &serverResponse) = 0; + virtual bool restoreDFUWorkUnit(const char *wuid, StringBuffer &serverResponse) = 0; + virtual bool archiveECLWorkUnit(const char *wuid, StringBuffer &serverResponse) = 0; + virtual bool archiveDFUWorkUnit(const char *wuid, StringBuffer &serverResponse) = 0; + virtual bool backupECLWorkUnit(const char *wuid, StringBuffer &serverResponse) = 0; + virtual bool backupDFUWorkUnit(const char *wuid, StringBuffer &serverResponse) = 0; +}; + +extern SARUNCMD_API ISashaCmdExecutor *createSashaCmdExecutor(INode *node, unsigned defaultTimeoutSecs=60); +extern SARUNCMD_API ISashaCmdExecutor *createSashaCmdExecutor(const SocketEndpoint &ep, unsigned defaultTimeoutSecs=60); +extern SARUNCMD_API ISashaCmdExecutor *createSashaCmdExecutor(const char *server, unsigned port=0, unsigned defaultTimeoutSecs=60); + +#endif \ No newline at end of file diff --git a/esp/scm/ws_sasha.ecm b/esp/scm/ws_sasha.ecm new file mode 100644 index 00000000000..f7bce9f9afb --- /dev/null +++ b/esp/scm/ws_sasha.ecm @@ -0,0 +1,64 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2023 HPCC Systems. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +############################################################################## */ + +EspInclude(common); + +ESPenum WUTypes : string +{ + ECL("ECL"), + DFU("DFU"), +}; + +ESPrequest [nil_remove] GetVersionRequest +{ +}; + +ESPresponse [exceptions_inline, nil_remove] ResultResponse +{ + string Result; +}; + +ESPrequest [nil_remove] BackupWURequest +{ + string Wuid; + ESPenum WUTypes WUType; +}; + +ESPrequest [nil_remove] ArchiveWURequest +{ + string Wuid; + ESPenum WUTypes WUType; +}; + +ESPrequest [nil_remove] RestoreWURequest +{ + string Wuid; + ESPenum WUTypes WUType; +}; + +ESPservice [auth_feature("DEFERRED"), //This declares that the method logic handles feature level authorization + version("1.00"), default_client_version("1.00"), exceptions_inline("./smc_xslt/exceptions.xslt")] WSSasha +{ + ESPmethod [auth_feature("SashaAccess:Access")] GetVersion(GetVersionRequest, ResultResponse); + ESPmethod [auth_feature("SashaAccess:FULL")] ArchiveWU(ArchiveWURequest, ResultResponse); //archive ECL WUs or DFU WUs + ESPmethod [auth_feature("SashaAccess:FULL")] RestoreWU(RestoreWURequest, ResultResponse); //restore ECL WUs or DFU WUs + //The ArchiveWU deletes the workunit from Dali whereas BackupWU leave it in place. + ESPmethod [auth_feature("SashaAccess:FULL")] BackupWU(BackupWURequest, ResultResponse); +}; + +SCMexportdef(WSSasha); +SCMapi(WSSasha) IClientWSSasha *createWSSashaClient(); \ No newline at end of file diff --git a/esp/services/ws_sasha/CMakeLists.txt b/esp/services/ws_sasha/CMakeLists.txt index 499efe4f55d..9b553521f69 100644 --- a/esp/services/ws_sasha/CMakeLists.txt +++ b/esp/services/ws_sasha/CMakeLists.txt @@ -26,6 +26,7 @@ project( ws_sasha ) include(${HPCC_SOURCE_DIR}/esp/scm/espscm.cmake) set ( SRCS + ${HPCC_SOURCE_DIR}/dali/sasha/sacmd.cpp ${ESPSCM_GENERATED_DIR}/ws_sasha_esp.cpp ws_sashaplugin.cpp ws_sashaservice.cpp @@ -45,6 +46,7 @@ include_directories ( ${HPCC_SOURCE_DIR}/system/security/shared ${HPCC_SOURCE_DIR}/system/mp ${HPCC_SOURCE_DIR}/common/thorhelper + ${HPCC_SOURCE_DIR}/common/environment ${HPCC_SOURCE_DIR}/dali/base ${HPCC_SOURCE_DIR}/dali/sasha ) @@ -57,6 +59,8 @@ target_link_libraries ( ws_sasha jlib xmllib esphttp + SMCLib + saruncmdlib ${COMMON_ESP_SERVICE_LIBS} ) diff --git a/esp/services/ws_sasha/ws_sashaservice.cpp b/esp/services/ws_sasha/ws_sashaservice.cpp index ef1a51990d6..21cb3e900d9 100644 --- a/esp/services/ws_sasha/ws_sashaservice.cpp +++ b/esp/services/ws_sasha/ws_sashaservice.cpp @@ -21,9 +21,125 @@ #include "ws_sashaservice.hpp" #include "jlib.hpp" +#include "TpWrapper.hpp" -using namespace ws_sasha; +constexpr const char* FEATURE_URL = "SashaAccess"; + +ISashaCmdExecutor* CWSSashaEx::createSashaCommandExecutor(const char* archiverType) +{ + SocketEndpoint ep; + getSashaServiceEP(ep, archiverType, true); + return createSashaCmdExecutor(ep); +} void CWSSashaEx::init(IPropertyTree* cfg, const char* process, const char* service) { } + +bool CWSSashaEx::onGetVersion(IEspContext& context, IEspGetVersionRequest& req, IEspResultResponse& resp) +{ + try + { + context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_SASHA_ACCESS_DENIED, "WSSashaEx.GetVersion: Permission denied."); + + StringBuffer results; + Owned executor = createSashaCommandExecutor(wuArchiverType); + executor->getVersion(results); + resp.setResult(results); + } + catch(IException* e) + { + FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR); + } + + return true; +} + +void CWSSashaEx::setResults(const char* wuid, const char* action, StringBuffer& results) +{ + if (isEmptyString(wuid)) + results.appendf("No workunits %s.", action); + else + results.appendf("Workunit %s not %s", wuid, action); +} + +bool CWSSashaEx::onBackupWU(IEspContext& context, IEspBackupWURequest& req, IEspResultResponse& resp) +{ + try + { + context.ensureFeatureAccess(FEATURE_URL, SecAccess_Full, ECLWATCH_SASHA_ACCESS_DENIED, "WSSashaEx.BackupWU: Permission denied."); + + const char* wuid = req.getWuid(); + CWUTypes wuType = req.getWUType(); + Owned executor = createSashaCommandExecutor(wuType == CWUTypes_ECL ? wuArchiverType : dfuwuArchiverType); + + StringBuffer results; + bool sashaCmdReturn = false; + if (wuType == CWUTypes_ECL) + sashaCmdReturn = executor->backupECLWorkUnit(isEmptyString(wuid) ? "*" : wuid, results); + else + sashaCmdReturn = executor->backupDFUWorkUnit(isEmptyString(wuid) ? "*" : wuid, results); + if (!sashaCmdReturn) + setResults(wuid, "backed up", results); + resp.setResult(results); + } + catch(IException* e) + { + FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR); + } + return true; +} + +bool CWSSashaEx::onArchiveWU(IEspContext& context, IEspArchiveWURequest& req, IEspResultResponse& resp) +{ + try + { + context.ensureFeatureAccess(FEATURE_URL, SecAccess_Full, ECLWATCH_SASHA_ACCESS_DENIED, "WSSashaEx.ArchiveWU: Permission denied."); + + const char* wuid = req.getWuid(); + CWUTypes wuType= req.getWUType(); + Owned executor = createSashaCommandExecutor(wuType == CWUTypes_ECL ? wuArchiverType : dfuwuArchiverType); + + StringBuffer results; + bool sashaCmdReturn = false; + if (wuType == CWUTypes_ECL) + sashaCmdReturn = executor->archiveECLWorkUnit(isEmptyString(wuid) ? "*" : wuid, results); + else + sashaCmdReturn = executor->archiveDFUWorkUnit(isEmptyString(wuid) ? "*" : wuid, results); + if (!sashaCmdReturn) + setResults(wuid, "archived", results); + resp.setResult(results); + } + catch(IException* e) + { + FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR); + } + return true; +} + +bool CWSSashaEx::onRestoreWU(IEspContext& context, IEspRestoreWURequest& req, IEspResultResponse& resp) +{ + try + { + context.ensureFeatureAccess(FEATURE_URL, SecAccess_Full, ECLWATCH_SASHA_ACCESS_DENIED, "WSSashaEx.RestoreWU: Permission denied."); + + const char* wuid = req.getWuid(); + CWUTypes wuType = req.getWUType(); + Owned executor = createSashaCommandExecutor(wuType == CWUTypes_ECL ? wuArchiverType : dfuwuArchiverType); + + StringBuffer results; + bool sashaCmdReturn = false; + if (wuType == CWUTypes_ECL) + sashaCmdReturn = executor->restoreECLWorkUnit(isEmptyString(wuid) ? "*" : wuid, results); + else + sashaCmdReturn = executor->restoreDFUWorkUnit(isEmptyString(wuid) ? "*" : wuid, results); + if (!sashaCmdReturn) + setResults(wuid, "restored", results); + resp.setResult(results); + } + catch(IException* e) + { + FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR); + } + return true; +} diff --git a/esp/services/ws_sasha/ws_sashaservice.hpp b/esp/services/ws_sasha/ws_sashaservice.hpp index 25354498ca3..0c14bb83320 100644 --- a/esp/services/ws_sasha/ws_sashaservice.hpp +++ b/esp/services/ws_sasha/ws_sashaservice.hpp @@ -20,13 +20,22 @@ #include "ws_sasha_esp.ipp" #include "exception_util.hpp" +#include "mpbase.hpp" +#include "saruncmd.hpp" class CWSSashaEx : public CWSSasha { + ISashaCmdExecutor* createSashaCommandExecutor(const char* archiverType); + void setResults(const char* wuid, const char* action, StringBuffer& results); + public: IMPLEMENT_IINTERFACE; virtual void init(IPropertyTree* cfg, const char* process, const char* service) override; + virtual bool onGetVersion(IEspContext& context, IEspGetVersionRequest& req, IEspResultResponse& resp) override; + virtual bool onBackupWU(IEspContext& context, IEspBackupWURequest& req, IEspResultResponse& resp) override; + virtual bool onArchiveWU(IEspContext& context, IEspArchiveWURequest& req, IEspResultResponse& resp) override; + virtual bool onRestoreWU(IEspContext& context, IEspRestoreWURequest& req, IEspResultResponse& resp) override; }; #endif //_ESPWIZ_ws_sasha_HPP__ diff --git a/esp/smc/SMCLib/eclwatch_errorlist.hpp b/esp/smc/SMCLib/eclwatch_errorlist.hpp index 61b38b0d86e..22766d18c63 100644 --- a/esp/smc/SMCLib/eclwatch_errorlist.hpp +++ b/esp/smc/SMCLib/eclwatch_errorlist.hpp @@ -39,7 +39,8 @@ #define ECLWATCH_DFU_WU_ACCESS_DENIED ECLWATCH_ERROR_START+13 #define ECLWATCH_DFU_EX_ACCESS_DENIED ECLWATCH_ERROR_START+14 #define ECLWATCH_FILE_SPRAY_ACCESS_DENIED ECLWATCH_ERROR_START+15 -#define ECLWATCH_FILE_DESPRAY_ACCESS_DENIED ECLWATCH_ERROR_START+16 +#define ECLWATCH_FILE_DESPRAY_ACCESS_DENIED ECLWATCH_ERROR_START+16 +#define ECLWATCH_SASHA_ACCESS_DENIED ECLWATCH_ERROR_START+17 #define ECLWATCH_INVALID_SEC_MANAGER ECLWATCH_ERROR_START+30 #define ECLWATCH_INVALID_ACCOUNT_NAME ECLWATCH_ERROR_START+31