[Libvirt-cim] [PATCH 3 of 3] [RFC] Add external check functionality to CheckIsVSMigratable()

Dan Smith danms at us.ibm.com
Wed Mar 12 16:03:37 UTC 2008


# HG changeset patch
# User Dan Smith <danms at us.ibm.com>
# Date 1205337366 25200
# Node ID 39a6d63d6c89d887b68a529a6d7f369c65e6e38b
# Parent  79615aba657b1860f17573d1cac1729a63eb835e
[RFC] Add external check functionality to CheckIsVSMigratable()

Changes:
 - Fetch the array out of the MSD ourselves to avoid adding a special
   case to get_msd_values()

Signed-off-by: Dan Smith <danms at us.ibm.com>

diff -r 79615aba657b -r 39a6d63d6c89 src/Virt_VSMigrationService.c
--- a/src/Virt_VSMigrationService.c	Wed Mar 12 08:55:36 2008 -0700
+++ b/src/Virt_VSMigrationService.c	Wed Mar 12 08:56:06 2008 -0700
@@ -21,6 +21,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
 
 #include <uuid/uuid.h>
 
@@ -39,6 +46,8 @@
 #include "Virt_VSMigrationService.h"
 #include "Virt_HostSystem.h"
 #include "Virt_VSMigrationSettingData.h"
+
+#include "config.h"
 
 #define CIM_JOBSTATE_STARTING 3
 #define CIM_JOBSTATE_RUNNING 4
@@ -262,6 +271,258 @@ static CMPIStatus check_hver(virConnectP
         return s;
 }
 
+static bool is_valid_check(const char *path)
+{
+        struct stat s;
+
+        if (stat(path, &s) != 0)
+                return false;
+
+        if (!S_ISREG(s.st_mode))
+                return false;
+
+        if ((s.st_mode & S_IXUSR) ||
+            (s.st_mode & S_IXGRP) ||
+            (s.st_mode & S_IXOTH))
+                return true;
+        else
+                return false;
+}
+
+static void free_list(char **list, int count)
+{
+        int i;
+
+        if (list == NULL)
+                return;
+
+        for (i = 0; i < count; i++)
+                free(list[i]);
+
+        free(list);
+}
+
+static char **list_migration_checks(int *count)
+{
+        DIR *dir;
+        struct dirent *de;
+        char **list = NULL;
+        int len = 0;
+
+        *count = 0;
+
+        dir = opendir(MIG_CHECKS_DIR);
+        if (dir == NULL) {
+                CU_DEBUG("Unable to open migration checks dir: %s (%s)",
+                         MIG_CHECKS_DIR,
+                         strerror(errno));
+                *count = -1;
+                return NULL;
+        }
+
+        while ((de = readdir(dir)) != NULL) {
+                int ret;
+                char *path = NULL;
+
+                if (de->d_name[0] == '.')
+                        continue;
+
+                if (*count == len) {
+                        char **tmp;
+
+                        len = (len * 2) + 1;
+                        tmp = realloc(list, sizeof(char *) * len);
+                        if (tmp == NULL) {
+                                CU_DEBUG("Failed to alloc check list");
+                                goto error;
+                        }
+
+                        list = tmp;
+                }
+
+                ret = asprintf(&path,
+                               "%s/%s",
+                               MIG_CHECKS_DIR,
+                               de->d_name);
+                if (ret == -1) {
+                        CU_DEBUG("Failed to alloc path for check");
+                        goto error;
+                }
+
+                if (is_valid_check(path)) {
+                        list[*count] = path;
+                        (*count) += 1;
+                } else {
+                        CU_DEBUG("Invalid check program: %s", path);
+                        free(path);
+                }
+        }
+
+        closedir(dir);
+
+        return list;
+ error:
+        closedir(dir);
+
+        free_list(list, *count);
+        *count = 0;
+
+        return NULL;
+}
+
+static CMPIStatus _call_check(virDomainPtr dom,
+                              const char *prog,
+                              const char *param_path)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        pid_t pid;
+        int i;
+        int rc = -1;
+
+        pid = fork();
+        if (pid == 0) {
+                virConnectPtr conn = virDomainGetConnect(dom);
+                const char *name = virDomainGetName(dom);
+                const char *uri = virConnectGetURI(conn);
+
+                if (setpgrp() == -1)
+                        perror("setpgrp");
+
+                execl(prog, prog, name, uri, param_path, NULL);
+                CU_DEBUG("exec(%s) failed: %s", prog, strerror(errno));
+                _exit(1);
+        }
+
+        for (i = 0; i < (MIG_CHECKS_TIMEOUT * 4); i++) {
+                int status;
+                if (waitpid(pid, &status, WNOHANG) != pid) {
+                        usleep(250000);
+                } else {
+                        rc = WEXITSTATUS(status);
+                        break;
+                }
+        }
+
+        if (rc == -1) {
+                CU_DEBUG("Killing off stale child %i", pid);
+                killpg(pid, SIGKILL);
+                waitpid(pid, NULL, WNOHANG);
+        }
+
+        if (rc != 0) {
+                char *name = strdup(prog);
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Migration check `%s' failed",
+                           basename(name));
+                free(name);
+        }
+
+        return s;
+}
+
+static CMPIStatus call_external_checks(virDomainPtr dom,
+                                       const char *param_path)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        char **list = NULL;
+        int count = 0;
+        int i;
+
+        list = list_migration_checks(&count);
+        if (count < 0) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to execute migration checks");
+                goto out;
+        } else if (list == NULL) {
+                goto out;
+        }
+
+        for (i = 0; i < count; i++) {
+                CU_DEBUG("Calling migration check: %s", list[i]);
+                s = _call_check(dom, list[i], param_path);
+                if (s.rc != CMPI_RC_OK) {
+                        CU_DEBUG("...Failed");
+                        break;
+                } else
+                        CU_DEBUG("...OK");
+        }
+ out:
+        free_list(list, count);
+
+        return s;
+}
+
+static char *write_params(CMPIArray *array)
+{
+        int i;
+        int fd;
+        char *filename = strdup("/tmp/libvirtcim_mig.XXXXXX");
+        FILE *file = NULL;
+
+        if (filename == NULL) {
+                CU_DEBUG("Unable to get temporary file");
+                return NULL;
+        }
+
+        fd = mkstemp(filename);
+        if (fd < 0) {
+                CU_DEBUG("Unable to get temporary file: %s", strerror(errno));
+                free(filename);
+                filename = NULL;
+                goto out;
+        }
+
+        file = fdopen(fd, "w");
+        if (file == NULL) {
+                CU_DEBUG("Unable to open temporary file: %s", strerror(errno));
+                free(filename);
+                filename = NULL;
+                goto out;
+        }
+
+        for (i = 0; i < CMGetArrayCount(array, NULL); i++) {
+                CMPIData d;
+                CMPIStatus s;
+
+                d = CMGetArrayElementAt(array, i, &s);
+                if ((s.rc != CMPI_RC_OK) || CMIsNullValue(d)) {
+                        CU_DEBUG("Unable to get array[%i]: %s",
+                                 i,
+                                 CMGetCharPtr(s.msg));
+                        continue;
+                }
+
+                fprintf(file, "%s\n", CMGetCharPtr(d.value.string));
+        }
+
+ out:
+        if (file != NULL)
+                fclose(file);
+
+        close(fd);
+
+        return filename;
+}
+
+static char *get_parms_file(const CMPIObjectPath *ref,
+                            const CMPIArgs *argsin)
+{
+        CMPIStatus s;
+        CMPIArray *array;
+        CMPIInstance *msd;
+
+        s = get_msd(ref, argsin, &msd);
+        if (s.rc != CMPI_RC_OK)
+                return NULL;
+
+        if (cu_get_array_prop(msd, "CheckParameters", &array) == CMPI_RC_OK)
+                return write_params(array);
+        else
+                return NULL;
+}
+
 static CMPIStatus vs_migratable(const CMPIObjectPath *ref,
                                 const char *domain,
                                 const char *destination,
@@ -276,6 +537,7 @@ static CMPIStatus vs_migratable(const CM
         CMPIBoolean isMigratable = 0;
         uint16_t type;
         virDomainPtr dom = NULL;
+        char *path = NULL;
 
         s = get_msd_values(ref, destination, argsin, &type, &dconn);
         if (s.rc != CMPI_RC_OK)
@@ -298,6 +560,11 @@ static CMPIStatus vs_migratable(const CM
         }
 
         s = check_caps(conn, dconn);
+        if (s.rc != CMPI_RC_OK)
+                goto out;
+
+        path = get_parms_file(ref, argsin);
+        s = call_external_checks(dom, path);
         if (s.rc != CMPI_RC_OK)
                 goto out;
 
@@ -315,6 +582,10 @@ static CMPIStatus vs_migratable(const CM
         virDomainFree(dom);
         virConnectClose(conn);
         virConnectClose(dconn);
+
+        if (path != NULL)
+                unlink(path);
+        free(path);
 
         return s;
 }




More information about the Libvirt-cim mailing list