mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-21 19:02:25 +00:00
Add ability to register callback for virCommand dry run
To allow for fault injection of the virCommand dry run, add the ability to register a callback. The callback will be passed the argv, env and stdin buffer and is expected to return the exit status and optionally fill stdout and stderr buffers. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
df3a681c03
commit
7b3f1f8c30
@ -135,6 +135,9 @@ struct _virCommand {
|
||||
|
||||
/* See virCommandSetDryRun for description for this variable */
|
||||
static virBufferPtr dryRunBuffer;
|
||||
static virCommandDryRunCallback dryRunCallback;
|
||||
static void *dryRunOpaque;
|
||||
static int dryRunStatus;
|
||||
|
||||
/*
|
||||
* virCommandFDIsSet:
|
||||
@ -1860,6 +1863,11 @@ virCommandProcessIO(virCommandPtr cmd)
|
||||
size_t inoff = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (dryRunBuffer || dryRunCallback) {
|
||||
VIR_DEBUG("Dry run requested, skipping I/O processing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* With an input buffer, feed data to child
|
||||
* via pipe */
|
||||
if (cmd->inbuf)
|
||||
@ -2267,16 +2275,25 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
|
||||
}
|
||||
|
||||
str = virCommandToString(cmd);
|
||||
if (dryRunBuffer) {
|
||||
if (dryRunBuffer || dryRunCallback) {
|
||||
dryRunStatus = 0;
|
||||
if (!str) {
|
||||
/* error already reported by virCommandToString */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
VIR_DEBUG("Dry run requested, appending stringified "
|
||||
"command to dryRunBuffer=%p", dryRunBuffer);
|
||||
virBufferAdd(dryRunBuffer, str, -1);
|
||||
virBufferAddChar(dryRunBuffer, '\n');
|
||||
if (dryRunBuffer) {
|
||||
VIR_DEBUG("Dry run requested, appending stringified "
|
||||
"command to dryRunBuffer=%p", dryRunBuffer);
|
||||
virBufferAdd(dryRunBuffer, str, -1);
|
||||
virBufferAddChar(dryRunBuffer, '\n');
|
||||
}
|
||||
if (dryRunCallback) {
|
||||
dryRunCallback((const char *const*)cmd->args,
|
||||
(const char *const*)cmd->env,
|
||||
cmd->inbuf, cmd->outbuf, cmd->errbuf,
|
||||
&dryRunStatus, dryRunOpaque);
|
||||
}
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -2356,10 +2373,11 @@ virCommandWait(virCommandPtr cmd, int *exitstatus)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dryRunBuffer) {
|
||||
VIR_DEBUG("Dry run requested, claiming success");
|
||||
if (dryRunBuffer || dryRunCallback) {
|
||||
VIR_DEBUG("Dry run requested, returning status %d",
|
||||
dryRunStatus);
|
||||
if (exitstatus)
|
||||
*exitstatus = 0;
|
||||
*exitstatus = dryRunStatus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2704,6 +2722,7 @@ virCommandDoAsyncIO(virCommandPtr cmd)
|
||||
/**
|
||||
* virCommandSetDryRun:
|
||||
* @buf: buffer to store stringified commands
|
||||
* @callback: callback to process input/output/args
|
||||
*
|
||||
* Sometimes it's desired to not actually run given command, but
|
||||
* see its string representation without having to change the
|
||||
@ -2712,8 +2731,13 @@ virCommandDoAsyncIO(virCommandPtr cmd)
|
||||
* virCommandRun* API. The virCommandSetDryRun allows you to
|
||||
* modify this behavior: once called, every call to
|
||||
* virCommandRun* results in command string representation being
|
||||
* appended to @buf instead of being executed. the strings are
|
||||
* escaped for a shell and separated by a newline. For example:
|
||||
* appended to @buf instead of being executed. If @callback is
|
||||
* provided, then it is invoked with the argv, env and stdin
|
||||
* data string for the command. It is expected to fill the stdout
|
||||
* and stderr data strings and exit status variables.
|
||||
*
|
||||
* The strings stored in @buf are escaped for a shell and
|
||||
* separated by a newline. For example:
|
||||
*
|
||||
* virBuffer buffer = VIR_BUFFER_INITIALIZER;
|
||||
* virCommandSetDryRun(&buffer);
|
||||
@ -2725,10 +2749,14 @@ virCommandDoAsyncIO(virCommandPtr cmd)
|
||||
*
|
||||
* /bin/echo 'Hello world'\n
|
||||
*
|
||||
* To cancel this effect pass NULL.
|
||||
* To cancel this effect pass NULL for @buf and @callback.
|
||||
*/
|
||||
void
|
||||
virCommandSetDryRun(virBufferPtr buf)
|
||||
virCommandSetDryRun(virBufferPtr buf,
|
||||
virCommandDryRunCallback cb,
|
||||
void *opaque)
|
||||
{
|
||||
dryRunBuffer = buf;
|
||||
dryRunCallback = cb;
|
||||
dryRunOpaque = opaque;
|
||||
}
|
||||
|
@ -186,4 +186,5 @@ void virCommandAbort(virCommandPtr cmd);
|
||||
void virCommandFree(virCommandPtr cmd);
|
||||
|
||||
void virCommandDoAsyncIO(virCommandPtr cmd);
|
||||
|
||||
#endif /* __VIR_COMMAND_H__ */
|
||||
|
@ -28,5 +28,16 @@
|
||||
|
||||
# include "vircommand.h"
|
||||
|
||||
void virCommandSetDryRun(virBufferPtr buf);
|
||||
typedef void (*virCommandDryRunCallback)(const char *const*args,
|
||||
const char *const*env,
|
||||
const char *input,
|
||||
char **output,
|
||||
char **error,
|
||||
int *status,
|
||||
void *opaque);
|
||||
|
||||
void virCommandSetDryRun(virBufferPtr buf,
|
||||
virCommandDryRunCallback cb,
|
||||
void *opaque);
|
||||
|
||||
#endif /* __VIR_COMMAND_PRIV_H__ */
|
||||
|
@ -96,7 +96,7 @@ testKModLoad(const void *args)
|
||||
bool useBlacklist = info->useBlacklist;
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
virCommandSetDryRun(&buf);
|
||||
virCommandSetDryRun(&buf, NULL, NULL);
|
||||
|
||||
errbuf = virKModLoad(module, useBlacklist);
|
||||
if (errbuf) {
|
||||
@ -110,7 +110,7 @@ testKModLoad(const void *args)
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virCommandSetDryRun(NULL);
|
||||
virCommandSetDryRun(NULL, NULL, NULL);
|
||||
VIR_FREE(errbuf);
|
||||
return ret;
|
||||
}
|
||||
@ -125,7 +125,7 @@ testKModUnload(const void *args)
|
||||
const char *module = info->module;
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
virCommandSetDryRun(&buf);
|
||||
virCommandSetDryRun(&buf, NULL, NULL);
|
||||
|
||||
errbuf = virKModUnload(module);
|
||||
if (errbuf) {
|
||||
@ -139,7 +139,7 @@ testKModUnload(const void *args)
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virCommandSetDryRun(NULL);
|
||||
virCommandSetDryRun(NULL, NULL, NULL);
|
||||
VIR_FREE(errbuf);
|
||||
return ret;
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ testVirNetDevBandwidthSet(const void *data)
|
||||
if (!iface)
|
||||
iface = "eth0";
|
||||
|
||||
virCommandSetDryRun(&buf);
|
||||
virCommandSetDryRun(&buf, NULL, NULL);
|
||||
|
||||
if (virNetDevBandwidthSet(iface, band, info->hierarchical_class) < 0)
|
||||
goto cleanup;
|
||||
@ -101,6 +101,7 @@ testVirNetDevBandwidthSet(const void *data)
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
virCommandSetDryRun(NULL, NULL, NULL);
|
||||
virNetDevBandwidthFree(band);
|
||||
virBufferFreeAndReset(&buf);
|
||||
VIR_FREE(actual_cmd);
|
||||
|
Loading…
x
Reference in New Issue
Block a user