Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HPCC-31394 WsSMC send roxie control cmd to ssl port if available #18396

Merged
merged 1 commit into from
Jun 13, 2024
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
14 changes: 8 additions & 6 deletions esp/services/ws_ecl/ws_ecl_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "xsdparser.hpp"
#include "httpclient.hpp"
#include "jsonhelpers.hpp"
#include "securesocket.hpp"

#define SDS_LOCK_TIMEOUT (5*60*1000) // 5mins, 30s a bit short

Expand Down Expand Up @@ -211,9 +212,8 @@ class WsEclSocketFactory : public CSmartSocketFactory
{
}

WsEclSocketFactory(const char *_socklist, bool _retry, bool includeTarget, const char *_alias, unsigned _dnsInterval, bool useTls) : CSmartSocketFactory(_socklist, _retry, 60, _dnsInterval), includeTargetInURL(includeTarget), alias(_alias)
WsEclSocketFactory(const char *_socklist, IPropertyTree *_tlsConfig, bool _retry, bool includeTarget, const char *_alias, unsigned _dnsInterval) : CSmartSocketFactory(_socklist, _tlsConfig, _retry, 60, _dnsInterval), includeTargetInURL(includeTarget), alias(_alias)
{
tlsService = useTls;
}
};

Expand Down Expand Up @@ -260,7 +260,8 @@ void initBareMetalRoxieTargets(MapStringToMyClass<ISmartSocketFactory> &connMap,
const char *vip = NULL;
bool includeTargetInURL = true;
unsigned dnsInterval = (unsigned) -1;
bool useTls = false;

Owned<IPropertyTree> tlsConfig;
if (vips)
{
IPropertyTree *pc = vips->queryPropTree(xpath.clear().appendf("ProcessCluster[@name='%s']", process.str()));
Expand All @@ -269,7 +270,8 @@ void initBareMetalRoxieTargets(MapStringToMyClass<ISmartSocketFactory> &connMap,
vip = pc->queryProp("@vip");
includeTargetInURL = pc->getPropBool("@includeTargetInURL", true);
dnsInterval = (unsigned) pc->getPropInt("@dnsInterval", -1);
useTls = pc->getPropBool("@tls", false);
if (pc->getPropBool("@tls", false))
tlsConfig.setown(createSecureSocketConfig(nullptr, nullptr, nullptr));
}
}
StringBuffer list;
Expand Down Expand Up @@ -297,7 +299,7 @@ void initBareMetalRoxieTargets(MapStringToMyClass<ISmartSocketFactory> &connMap,
farmerPort = port;
const char *protocol = farmer.queryProp("@protocol");
if (protocol && streq(protocol, "ssl"))
useTls = true;
tlsConfig.setown(createSecureSocketConfig(farmer.queryProp("@certificateFileName"), farmer.queryProp("@privateKeyFileName"), nullptr));
break; //use the first one without port==0
}
Owned<IPropertyTreeIterator> servers = roxieCluster->getElements("RoxieServerProcess");
Expand All @@ -308,7 +310,7 @@ void initBareMetalRoxieTargets(MapStringToMyClass<ISmartSocketFactory> &connMap,
if (list.length())
{
StringAttr alias(clusterInfo->getAlias());
Owned<ISmartSocketFactory> sf = new WsEclSocketFactory(list.str(), !loadBalanced, includeTargetInURL, loadBalanced ? alias.str() : NULL, dnsInterval, useTls);
Owned<ISmartSocketFactory> sf = new WsEclSocketFactory(list.str(), tlsConfig, !loadBalanced, includeTargetInURL, loadBalanced ? alias.str() : NULL, dnsInterval);
connMap.setValue(target.str(), sf.get());
if (alias.length() && !connMap.getValue(alias.str())) //only need one vip per alias for routing purposes
connMap.setValue(alias.str(), sf.get());
Expand Down
14 changes: 8 additions & 6 deletions esp/services/ws_smc/ws_smcService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ void CWsSMCEx::init(IPropertyTree *cfg, const char *process, const char *service

#ifdef _CONTAINERIZED
initContainerRoxieTargets(roxieConnMap);
#else
initBareMetalRoxieTargets(roxieConnMap);
#endif

xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/ActivityInfoCacheSeconds", process, service);
Expand Down Expand Up @@ -2305,18 +2307,18 @@ bool CWsSMCEx::onRoxieControlCmd(IEspContext &context, IEspRoxieControlCmdReques
if (isEmptyString(process))
throw makeStringException(ECLWATCH_MISSING_PARAMS, "Process cluster not specified.");

SocketEndpointArray addrs;
getRoxieProcessServers(process, addrs);
if (!addrs.length())
throw makeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Process cluster not found.");
Owned<IPropertyTree> controlResp = sendRoxieControlAllNodes(addrs.item(0), controlReq, true, req.getWait());
ISmartSocketFactory *conn = roxieConnMap.getValue(process);
if (!conn)
throw makeStringExceptionV(ECLWATCH_CANNOT_GET_ENV_INFO, "Connection info for '%s' process cluster not found.", process);

Owned<IPropertyTree> controlResp = sendRoxieControlAllNodes(conn, controlReq, true, req.getWait(), ROXIECONNECTIONTIMEOUT);
#else
const char *target = req.getTargetCluster();
if (isEmptyString(target))
target = req.getProcessCluster(); //backward compatible
if (isEmptyString(target))
throw makeStringException(ECLWATCH_MISSING_PARAMS, "Target cluster not specified.");

ISmartSocketFactory *conn = roxieConnMap.getValue(target);
if (!conn)
throw makeStringExceptionV(ECLWATCH_CANNOT_GET_ENV_INFO, "roxie target cluster not mapped: %s", target);
Expand Down
5 changes: 5 additions & 0 deletions esp/smc/SMCLib/TpContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,11 @@ extern TPWRAPPER_API void initContainerRoxieTargets(MapStringToMyClass<ISmartSoc
}
}

extern TPWRAPPER_API void initBareMetalRoxieTargets(MapStringToMyClass<ISmartSocketFactory>& connMap)
{
IWARNLOG("UNIMPLEMENTED: CONTAINERIZED(CTpWrapper::initBareMetalRoxieTargets)");
}

extern TPWRAPPER_API void getRoxieTargetsSupportingPublishedQueries(StringArray& names)
{
Owned<IPropertyTreeIterator> queues = getComponentConfigSP()->getElements("queues[@type='roxie']");
Expand Down
70 changes: 70 additions & 0 deletions esp/smc/SMCLib/TpWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2093,6 +2093,76 @@ extern TPWRAPPER_API void initContainerRoxieTargets(MapStringToMyClass<ISmartSoc
}
}

void appendServerAddress(StringBuffer& list, IPropertyTree& env, IPropertyTree& server, const char* farmerPort)
{
//just in case, for backward compatability with old environment.xml files, allow server rather than farmer to specify port
const char *port = server.queryProp("@port");
if (!port)
port = farmerPort;
if (port && streq(port, "0")) //0 == roxie listening on queue rather than port
return;

const char *netAddress = server.queryProp("@netAddress");
if (!netAddress && server.hasProp("@computer"))
{
VStringBuffer xpath("Hardware/Computer[@name='%s']/@netAddress", server.queryProp("@computer"));
netAddress = env.queryProp(xpath.str());
}
if (!netAddress || !*netAddress)
return;
if (list.length())
list.append('|');
list.append(netAddress).append(':').append(port);
}

extern TPWRAPPER_API void initBareMetalRoxieTargets(MapStringToMyClass<ISmartSocketFactory>& connMap)
{
Owned<IEnvironmentFactory> factory = getEnvironmentFactory(false);
Owned<IConstEnvironment> env = factory->openEnvironment();
Owned<IPropertyTree> envRoot = &env->getPTree();

Owned<IPropertyTreeIterator> roxieClusters = envRoot->getElements("Software/RoxieCluster");
ForEach(*roxieClusters)
{
IPropertyTree& roxieCluster = roxieClusters->query();
const char* name = roxieCluster.queryProp("@name");
if (isEmptyString(name))
continue;

StringBuffer addressList;
StringBuffer port("");
Owned<IPropertyTree> tlsConfig = createPTree("none");

Owned<IPropertyTreeIterator> roxieFarms = roxieCluster.getElements("RoxieFarmProcess");
ForEach(*roxieFarms)
{
IPropertyTree& farm = roxieFarms->query();
const char* farmPort = farm.queryProp("@port");
if (!isEmptyString(farmPort) && !streq(farmPort, "0"))
{
const char *protocol = farm.queryProp("@protocol");
if (!isEmptyString(protocol) && strieq(protocol, "ssl"))
{
port.set(farmPort);
tlsConfig.setown(createSecureSocketConfig(farm.queryProp("@certificateFileName"), farm.queryProp("@privateKeyFileName"), nullptr));
break;
}
else if (isEmptyString(port.str()))
{
port.set(farmPort);
}
}
}

Owned<IPropertyTreeIterator> roxieServers = roxieCluster.getElements("RoxieServerProcess");
ForEach(*roxieServers)
appendServerAddress(addressList, *envRoot, roxieServers->query(), port.str());

Owned<ISmartSocketFactory> sf = streq(tlsConfig->queryName(), "ssl") ? createSecureSmartSocketFactory(addressList, tlsConfig) : createSmartSocketFactory(addressList);
connMap.setValue(name, sf.get());
}
}

extern TPWRAPPER_API void getRoxieTargetsSupportingPublishedQueries(StringArray& names)
{
CConstWUClusterInfoArray clusters;
Expand Down
1 change: 1 addition & 0 deletions esp/smc/SMCLib/TpWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ extern TPWRAPPER_API unsigned getWUClusterInfo(CConstWUClusterInfoArray& cluster
extern TPWRAPPER_API IConstWUClusterInfo* getWUClusterInfoByName(const char* clustName);

extern TPWRAPPER_API void initContainerRoxieTargets(MapStringToMyClass<ISmartSocketFactory>& connMap);
extern TPWRAPPER_API void initBareMetalRoxieTargets(MapStringToMyClass<ISmartSocketFactory>& connMap);
extern TPWRAPPER_API unsigned getThorClusterNames(StringArray& targetNames, StringArray& queueNames);
extern TPWRAPPER_API void getRoxieTargetsSupportingPublishedQueries(StringArray& names);
extern TPWRAPPER_API void validateTargetName(const char* target);
Expand Down
2 changes: 1 addition & 1 deletion roxie/roxiepipe/roxiepipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ int main(int argc, char *argv[])
{
#ifdef _USE_OPENSSL
if (useSSL)
smartSocketFactory = createSecureSmartSocketFactory(hosts.str(), retryMode);
smartSocketFactory = createSecureSmartSocketFactory(hosts.str(), createSecureSocketConfig(nullptr, nullptr, nullptr), retryMode);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createSecureSocketConfig(nullptr, nullptr, nullptr) currently returns null. Is this doing what you expect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I expect but it may not be clear, and I wasn't sure if other changes would make it better. I thought this could be a placeholder until the usage of the smart socket classes is regularized. If it would be better to have an empty rather than null object here I could adjust the createSecureSocketConfig to do so or create an alternate function. I can see how this approach may not be clear and will adjust if you'd like.

The use of the smart sockets and factories isn't entirely consistent. In some cases the users of the classes interrogate the base interface for TLS status, and in others the user knows the TLS state and uses the correct secure/insecure flavor based on its own knowledge. roxiepipe is in the second case and it doesn't rely on the smart socket class itself having a valid config, rather it has already created a secure socket version based on the ssl argument (and compile switch).

else
#endif
smartSocketFactory = createSmartSocketFactory(hosts.str(), retryMode);
Expand Down
12 changes: 9 additions & 3 deletions system/jlib/jsmartsock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,19 @@ CSmartSocketFactory::CSmartSocketFactory(IPropertyTree &service, bool _retry, un
}
}

CSmartSocketFactory::CSmartSocketFactory(const char *_socklist, bool _retry, unsigned _retryInterval, unsigned _dnsInterval)
CSmartSocketFactory::CSmartSocketFactory(const char *_socklist, IPropertyTree* _tlsConfig, bool _retry, unsigned _retryInterval, unsigned _dnsInterval)
{
PROGLOG("CSmartSocketFactory::CSmartSocketFactory(%s)",_socklist?_socklist:"NULL");
PROGLOG("CSmartSocketFactory::CSmartSocketFactory(%s, tlsConfig(%s))",_socklist?_socklist:"NULL", _tlsConfig?"yes":"no");
SmartSocketListParser slp(_socklist);
if (slp.getSockets(sockArray) == 0)
throw createSmartSocketException(0, "no endpoints defined");

if (_tlsConfig != nullptr)
{
tlsService = true;
tlsConfig.setown(createSyncedPropertyTree(_tlsConfig));
}

shuffleEndpoints();

nextEndpointIndex = 0;
Expand Down Expand Up @@ -491,5 +497,5 @@ ISmartSocketFactory *createSmartSocketFactory(IPropertyTree &service, bool _retr

ISmartSocketFactory *createSmartSocketFactory(const char *_socklist, bool _retry, unsigned _retryInterval, unsigned _dnsInterval)
{
return new CSmartSocketFactory(_socklist, _retry, _retryInterval, _dnsInterval);
return new CSmartSocketFactory(_socklist, nullptr, _retry, _retryInterval, _dnsInterval);
}
2 changes: 1 addition & 1 deletion system/jlib/jsmartsock.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ protected:
public:
IMPLEMENT_IINTERFACE_USING(Thread);

CSmartSocketFactory(const char *_socklist, bool _retry = false, unsigned _retryInterval = 60, unsigned _dnsInterval = (unsigned)-1);
CSmartSocketFactory(const char *_socklist, IPropertyTree *_tlsConfig, bool _retry = false, unsigned _retryInterval = 60, unsigned _dnsInterval = (unsigned)-1);
CSmartSocketFactory(IPropertyTree &service, bool _retry = false, unsigned _retryInterval = 60, unsigned _dnsInterval = (unsigned)-1);
~CSmartSocketFactory();
int run();
Expand Down
6 changes: 3 additions & 3 deletions system/security/securesocket/securesocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2188,7 +2188,7 @@ class CSecureSmartSocketFactory : public CSmartSocketFactory
public:
Owned<ISecureSocketContext> secureContext;

CSecureSmartSocketFactory(const char *_socklist, bool _retry, unsigned _retryInterval, unsigned _dnsInterval) : CSmartSocketFactory(_socklist, _retry, _retryInterval, _dnsInterval)
CSecureSmartSocketFactory(const char *_socklist, IPropertyTree *_tlsConfig, bool _retry, unsigned _retryInterval, unsigned _dnsInterval) : CSmartSocketFactory(_socklist, _tlsConfig, _retry, _retryInterval, _dnsInterval)
{
secureContext.setown(createSecureSocketContext(ClientSocket));
}
Expand Down Expand Up @@ -2221,9 +2221,9 @@ class CSecureSmartSocketFactory : public CSmartSocketFactory
}
};

ISmartSocketFactory *createSecureSmartSocketFactory(const char *_socklist, bool _retry, unsigned _retryInterval, unsigned _dnsInterval)
ISmartSocketFactory *createSecureSmartSocketFactory(const char *_socklist, IPropertyTree* _tlsConfig, bool _retry, unsigned _retryInterval, unsigned _dnsInterval)
{
return new CSecureSmartSocketFactory(_socklist, _retry, _retryInterval, _dnsInterval);
return new CSecureSmartSocketFactory(_socklist, _tlsConfig, _retry, _retryInterval, _dnsInterval);
}

ISmartSocketFactory *createSecureSmartSocketFactory(IPropertyTree &service, bool _retry, unsigned _retryInterval, unsigned _dnsInterval)
Expand Down
2 changes: 1 addition & 1 deletion system/security/securesocket/securesocket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ SECURESOCKET_API int signCertificate(const char* csr, const char* ca_certificate
};


SECURESOCKET_API ISmartSocketFactory *createSecureSmartSocketFactory(const char *_socklist, bool _retry = false, unsigned _retryInterval = 60, unsigned _dnsInterval = (unsigned) -1);
SECURESOCKET_API ISmartSocketFactory *createSecureSmartSocketFactory(const char *_socklist, IPropertyTree* _tlsConfig, bool _retry = false, unsigned _retryInterval = 60, unsigned _dnsInterval = (unsigned) -1);
SECURESOCKET_API ISmartSocketFactory *createSecureSmartSocketFactory(IPropertyTree &service, bool _retry = false, unsigned _retryInterval = 60, unsigned _dnsInterval = (unsigned) -1);

SECURESOCKET_API IConversation *createSingletonSecureSocketConnection(unsigned short port,SocketEndpoint *_ep=nullptr);
Expand Down
Loading