mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +00:00
virhook: support hooks placed in $driver.d/
It is easier for management software (and subsequently distributions) to install hook script under /etc/libvirt/hooks/$driver.d/ and have libvirt execute them in alphabetical order. To maintain backwards compatibility, /etc/libvirt/hooks/$driver hook script is executed the first followed by scripts from the $driver.d directory. The stdio is chained between the scripts. The output of the first script is input of the second and so on. Signed-off-by: Dmitry Nesterenko <dmitry.nesterenko@virtuozzo.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
841910b5de
commit
feb83c1e71
@ -33,6 +33,7 @@
|
||||
#include "virfile.h"
|
||||
#include "configmake.h"
|
||||
#include "vircommand.h"
|
||||
#include "virstring.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_HOOK
|
||||
|
||||
@ -141,7 +142,11 @@ static int virHooksFound = -1;
|
||||
static int
|
||||
virHookCheck(int no, const char *driver)
|
||||
{
|
||||
int ret;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
g_autofree char *path = NULL;
|
||||
g_autofree char *dir_path = NULL;
|
||||
|
||||
if (driver == NULL) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
@ -158,18 +163,41 @@ virHookCheck(int no, const char *driver)
|
||||
|
||||
if (!virFileExists(path)) {
|
||||
VIR_DEBUG("No hook script %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!virFileIsExecutable(path)) {
|
||||
} else if (!virFileIsExecutable(path)) {
|
||||
VIR_WARN("Non-executable hook script %s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
VIR_DEBUG("Found hook script %s", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dir_path = g_strdup_printf("%s.d", path);
|
||||
if ((ret = virDirOpenIfExists(&dir, dir_path)) < 0)
|
||||
return -1;
|
||||
|
||||
if (!ret) {
|
||||
VIR_DEBUG("No hook script dir %s", dir_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((ret = virDirRead(dir, &entry, dir_path)) > 0) {
|
||||
g_autofree char *entry_path = g_build_filename(dir_path,
|
||||
entry->d_name,
|
||||
NULL);
|
||||
if (!virFileIsExecutable(entry_path)) {
|
||||
VIR_WARN("Non-executable hook script %s", entry_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
VIR_DEBUG("Found hook script %s", entry_path);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
VIR_DIR_CLOSE(dir);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* virHookInitialize:
|
||||
*
|
||||
@ -282,12 +310,18 @@ virRunScript(const char *path,
|
||||
* @input: extra input given to the script on stdin
|
||||
* @output: optional address of variable to store malloced result buffer
|
||||
*
|
||||
* Implement a hook call, where the external script for the driver is
|
||||
* Implement a hook call, where the external scripts for the driver are
|
||||
* called with the given information. This is a synchronous call, we wait for
|
||||
* execution completion. If @output is non-NULL, *output is guaranteed to be
|
||||
* allocated after successful virHookCall, and is best-effort allocated after
|
||||
* failed virHookCall; the caller is responsible for freeing *output.
|
||||
*
|
||||
* The script from LIBVIRT_HOOK_DIR is executed the first, followed by scripts
|
||||
* found under "$driver.d/" directory (sorted alphabetically. If output from
|
||||
* the hook script is expected, then the output produced by LIBVIRT_HOOK_DIR
|
||||
* script is fed as input to the first script from the "$driver.d/" directory
|
||||
* and its output is fed as input to the second and so on.
|
||||
*
|
||||
* Returns: 0 if the execution succeeded, 1 if the script was not found or
|
||||
* invalid parameters, and -1 if script returned an error
|
||||
*/
|
||||
@ -300,11 +334,16 @@ virHookCall(int driver,
|
||||
const char *input,
|
||||
char **output)
|
||||
{
|
||||
int ret, script_ret;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
g_autofree char *path = NULL;
|
||||
g_autoptr(virCommand) cmd = NULL;
|
||||
g_autofree char *dir_path = NULL;
|
||||
VIR_AUTOSTRINGLIST entries = NULL;
|
||||
const char *drvstr;
|
||||
const char *opstr;
|
||||
const char *subopstr;
|
||||
size_t i, nentries;
|
||||
|
||||
if (output)
|
||||
*output = NULL;
|
||||
@ -368,6 +407,61 @@ virHookCall(int driver,
|
||||
return -1;
|
||||
}
|
||||
|
||||
return virRunScript(path, id, opstr, subopstr, extra,
|
||||
script_ret = 1;
|
||||
|
||||
if (virFileIsExecutable(path)) {
|
||||
script_ret = virRunScript(path, id, opstr, subopstr, extra,
|
||||
input, output);
|
||||
}
|
||||
|
||||
dir_path = g_strdup_printf("%s.d", path);
|
||||
if ((ret = virDirOpenIfExists(&dir, dir_path)) < 0)
|
||||
return -1;
|
||||
|
||||
if (!ret)
|
||||
return script_ret;
|
||||
|
||||
while ((ret = virDirRead(dir, &entry, dir_path)) > 0) {
|
||||
g_autofree char *entry_path = g_build_filename(dir_path,
|
||||
entry->d_name,
|
||||
NULL);
|
||||
if (!virFileIsExecutable(entry_path))
|
||||
continue;
|
||||
|
||||
virStringListAdd(&entries, entry_path);
|
||||
}
|
||||
|
||||
VIR_DIR_CLOSE(dir);
|
||||
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
if (!entries)
|
||||
return script_ret;
|
||||
|
||||
nentries = virStringListLength((const char **)entries);
|
||||
qsort(entries, nentries, sizeof(*entries), virStringSortCompare);
|
||||
|
||||
for (i = 0; i < nentries; i++) {
|
||||
int entry_ret;
|
||||
const char *entry_input;
|
||||
g_autofree char *entry_output = NULL;
|
||||
|
||||
/* Get input from previous output */
|
||||
entry_input = (!script_ret && output &&
|
||||
!virStringIsEmpty(*output)) ? *output : input;
|
||||
entry_ret = virRunScript(entries[i], id, opstr,
|
||||
subopstr, extra, entry_input,
|
||||
(output) ? &entry_output : NULL);
|
||||
if (entry_ret < script_ret)
|
||||
script_ret = entry_ret;
|
||||
|
||||
/* Replace output to new output from item */
|
||||
if (!entry_ret && output && !virStringIsEmpty(entry_output)) {
|
||||
g_free(*output);
|
||||
*output = g_steal_pointer(&entry_output);
|
||||
}
|
||||
}
|
||||
|
||||
return script_ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user