1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Add remote process shim.

Run the remote process inside a forked child process instead of exec'ing it. This allows coverage to accumulate in the remote process rather than needing to test the remote protocol functions directly, resulting in better end-to-end testing and less test duplication. Another advantage is that the pgbackrest binary does not need to be built for the test and the test does not need to run in a container.
This commit is contained in:
David Steele 2021-05-25 18:16:59 -04:00
parent 441c000b5c
commit 58369c02df
3 changed files with 108 additions and 0 deletions

View File

@ -457,6 +457,7 @@ unit:
protocol/helper:
function:
- protocolLocalExec
- protocolRemoteExec
containerReq: true
binReq: true

View File

@ -29,6 +29,11 @@ static struct
bool localShim;
const ProtocolServerHandler *localHandlerList;
unsigned int localHandlerListSize;
// Remote process shim
bool remoteShim;
const ProtocolServerHandler *remoteHandlerList;
unsigned int remoteHandlerListSize;
} hrnProtocolStatic;
/***********************************************************************************************************************************
@ -127,3 +132,100 @@ hrnProtocolLocalShimUninstall(void)
FUNCTION_HARNESS_RETURN_VOID();
}
/***********************************************************************************************************************************
Shim protocolRemoteExec() to provide coverage as detailed in the hrnProtocolRemoteShimInstall() documentation.
***********************************************************************************************************************************/
static void
protocolRemoteExec(
ProtocolHelperClient *helper, ProtocolStorageType protocolStorageType, unsigned int hostIdx, unsigned int processId)
{
// Call the shim when installed
if (hrnProtocolStatic.remoteShim)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM_P(VOID, helper);
FUNCTION_LOG_PARAM(STRING_ID, protocolStorageType);
FUNCTION_LOG_PARAM(UINT, hostIdx);
FUNCTION_LOG_PARAM(UINT, processId);
FUNCTION_LOG_END();
// Create pipes to communicate with the subprocess. The names of the pipes are from the perspective of the parent process
// since the child process will use them only briefly before exec'ing.
int pipeRead[2];
int pipeWrite[2];
THROW_ON_SYS_ERROR(pipe(pipeRead) == -1, KernelError, "unable to create read pipe");
THROW_ON_SYS_ERROR(pipe(pipeWrite) == -1, KernelError, "unable to create write pipe");
// Exec command in the child process
if (forkSafe() == 0)
{
// Load configuration
StringList *const paramList = protocolRemoteParam(protocolStorageType, hostIdx);
strLstInsert(paramList, 0, cfgExe());
harnessCfgLoadRaw(strLstSize(paramList), strLstPtr(paramList));
// Change log process id to aid in debugging
hrnLogProcessIdSet(processId);
// Run server with provided handlers
String *name = strNewFmt(PROTOCOL_SERVICE_REMOTE "-shim-%u", processId);
IoRead *read = ioFdReadNew(name, pipeWrite[0], 5000);
ioReadOpen(read);
IoWrite *write = ioFdWriteNew(name, pipeRead[1], 5000);
ioWriteOpen(write);
ProtocolServer *server = protocolServerNew(name, PROTOCOL_SERVICE_REMOTE_STR, read, write);
protocolServerProcess(server, NULL, hrnProtocolStatic.remoteHandlerList, hrnProtocolStatic.remoteHandlerListSize);
// Exit when done
exit(0);
}
// Close the unused file descriptors
close(pipeRead[1]);
close(pipeWrite[0]);
// Create protocol object
IoRead *read = ioFdReadNew(strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u shim protocol read", processId), pipeRead[0], 5000);
ioReadOpen(read);
IoWrite *write = ioFdWriteNew(strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u shim protocol write", processId), pipeWrite[1], 5000);
ioWriteOpen(write);
helper->client = protocolClientNew(
strNewFmt(PROTOCOL_SERVICE_REMOTE "-%u shim protocol", processId), PROTOCOL_SERVICE_REMOTE_STR, read, write);
FUNCTION_LOG_RETURN_VOID();
}
// Else call the base function
else
protocolRemoteExec_SHIMMED(helper, protocolStorageType, hostIdx, processId);
}
/**********************************************************************************************************************************/
void
hrnProtocolRemoteShimInstall(const ProtocolServerHandler *const handlerList, const unsigned int handlerListSize)
{
FUNCTION_HARNESS_BEGIN();
FUNCTION_HARNESS_PARAM_P(VOID, handlerList);
FUNCTION_HARNESS_PARAM(UINT, handlerListSize);
FUNCTION_HARNESS_END();
hrnProtocolStatic.remoteShim = true;
hrnProtocolStatic.remoteHandlerList = handlerList;
hrnProtocolStatic.remoteHandlerListSize = handlerListSize;
FUNCTION_HARNESS_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
hrnProtocolRemoteShimUninstall(void)
{
FUNCTION_HARNESS_VOID();
hrnProtocolStatic.remoteShim = false;
FUNCTION_HARNESS_RETURN_VOID();
}

View File

@ -11,3 +11,8 @@ Functions
// functions should be required. A side benefit is that the pgbackrest binary does not need to be built since there is no exec.
void hrnProtocolLocalShimInstall(const ProtocolServerHandler *const handlerList, const unsigned int handlerListSize);
void hrnProtocolLocalShimUninstall(void);
// Install/uninstall the shim that allows protocalRemoteGet() to start a remote in a forked process rather than being exec'd via
// SSH. The benefits are the same as hrnProtocolLocalShimInstall().
void hrnProtocolRemoteShimInstall(const ProtocolServerHandler *const handlerList, const unsigned int handlerListSize);
void hrnProtocolRemoteShimUninstall(void);