[libvirt] [PATCH v9] bhyve: add a basic driver

Daniel P. Berrange berrange at redhat.com
Mon Feb 17 17:42:55 UTC 2014


On Thu, Feb 13, 2014 at 02:14:32PM +0400, Roman Bogorodskiy wrote:
> +static int
> +bhyveBuildDiskArgStr(const virDomainDef *def, virCommandPtr cmd)
> +{
> +    virDomainDiskDefPtr disk;
> +
> +    if (def->ndisks != 1) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("domain should have one and only one disk defined"));
> +        return -1;
> +    }
> +
> +    disk = def->disks[0];
> +
> +    if (disk->bus != VIR_DOMAIN_DISK_BUS_SATA) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("unsupported disk bus type"));
> +        return -1;
> +    }
> +
> +    if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("unsupported disk type"));
> +        return -1;
> +    }


We still need to validate  disk->type  before accessing disk->src
otherwise you'll crash if someone uses type=network


> +
> +    virCommandAddArg(cmd, "-s");
> +    virCommandAddArgFormat(cmd, "2:0,ahci-hd,%s", disk->src);

What is the '2:0' bit here ?  Is that disk controller/unit
number ?

> +virCommandPtr
> +virBhyveProcessBuildLoadCmd(bhyveConnPtr driver ATTRIBUTE_UNUSED,
> +                            virDomainObjPtr vm)
> +{
> +    virCommandPtr cmd;
> +    virDomainDiskDefPtr disk;
> +
> +    if (vm->def->ndisks != 1) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("domain should have one and only one disk defined"));
> +        return NULL;
> +    }
> +
> +    disk = vm->def->disks[0];
> +
> +    if (disk->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("unsupported disk type"));
> +        return NULL;
> +    }


And validate  disk->type again here

> +
> +    cmd = virCommandNew(BHYVELOAD);
> +
> +    /* Memory */
> +    virCommandAddArg(cmd, "-m");
> +    virCommandAddArgFormat(cmd, "%llu",
> +                           VIR_DIV_UP(vm->def->mem.max_balloon, 1024));
> +
> +    /* Image path */
> +    virCommandAddArg(cmd, "-d");
> +    virCommandAddArgFormat(cmd, disk->src);
> +
> +    /* VM name */
> +    virCommandAddArg(cmd, vm->def->name);
> +
> +    return cmd;
> +}


> +static char *
> +bhyveConnectGetCapabilities(virConnectPtr conn)
> +{
> +    bhyveConnPtr privconn = conn->privateData;
> +    char *xml;
> +
> +    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
> +        return NULL;
> +
> +    bhyveDriverLock(privconn);
> +    if ((xml = virCapabilitiesFormatXML(privconn->caps)) == NULL)
> +        virReportOOMError();
> +    bhyveDriverUnlock(privconn);
> +
> +    return xml;
> +}

Technically the lock/unlock isn't needed since you never
change privconn->caps once you've created it.


> +static virDrvOpenStatus
> +bhyveConnectOpen(virConnectPtr conn,
> +          virConnectAuthPtr auth ATTRIBUTE_UNUSED,
> +          unsigned int flags)
> +{
> +     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
> +
> +     if (conn->uri == NULL) {
> +         if (bhyve_driver == NULL)
> +                return VIR_DRV_OPEN_DECLINED;
> +
> +         if (!(conn->uri = virURIParse("bhyve:///system")))
> +                return VIR_DRV_OPEN_ERROR;

Nitpick indentation is too great in the two 'return' lines

> +     } else {
> +         if (!conn->uri->scheme || STRNEQ(conn->uri->scheme, "bhyve"))
> +             return VIR_DRV_OPEN_DECLINED;
> +
> +         if (conn->uri->server)
> +             return VIR_DRV_OPEN_DECLINED;
> +
> +         if (!STREQ_NULLABLE(conn->uri->path, "/system")) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR,
> +                           _("Unexpected bhyve URI path '%s', try bhyve:///system"),
> +                           conn->uri->path);
> +            return VIR_DRV_OPEN_ERROR;
> +         }
> +
> +         if (bhyve_driver == NULL) {
> +             virReportError(VIR_ERR_INTERNAL_ERROR,
> +                            "%s", _("bhyve state driver is not active"));
> +             return VIR_DRV_OPEN_ERROR;
> +         }
> +     }
> +
> +     if (virConnectOpenEnsureACL(conn) < 0)
> +         return VIR_DRV_OPEN_ERROR;
> +
> +     conn->privateData = bhyve_driver;
> +
> +     return VIR_DRV_OPEN_SUCCESS;
> +}


> +static virDomainPtr
> +bhyveDomainDefineXML(virConnectPtr conn, const char *xml)
> +{
> +    bhyveConnPtr privconn = conn->privateData;
> +    virDomainPtr dom = NULL;
> +    virDomainDefPtr def = NULL;
> +    virDomainDefPtr oldDef = NULL;
> +    virDomainObjPtr vm = NULL;
> +
> +    if ((def = virDomainDefParseString(xml, privconn->caps, privconn->xmlopt,
> +                                       1 << VIR_DOMAIN_VIRT_BHYVE,
> +                                       VIR_DOMAIN_XML_INACTIVE)) == NULL) {
> +        virReportError(VIR_ERR_INVALID_ARG, "%s",
> +                       _("Can't parse XML desc"));

Remove the 'virReportError' call, since that's already done for you
by the parsing code.

> +        goto cleanup;
> +    }
> +
> +    if (virDomainDefineXMLEnsureACL(conn, def) < 0)
> +        goto cleanup;
> +
> +    if (!(vm = virDomainObjListAdd(privconn->domains, def,
> +                                   privconn->xmlopt,
> +                                   0, &oldDef)))
> +       goto cleanup;
> +    def = NULL;
> +
> +    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
> +    if (dom)
> +        dom->id = vm->def->id;
> +
> +    if (virDomainSaveConfig(BHYVE_CONFIG_DIR, vm->def) < 0)
> +        goto cleanup;
> +
> +cleanup:
> +    virDomainDefFree(def);
> +    if (vm)
> +        virObjectUnlock(vm);
> +
> +    return dom;
> +}
> +

> +
> +int
> +virBhyveProcessStart(virConnectPtr conn,
> +                     bhyveConnPtr driver,
> +                     virDomainObjPtr vm,
> +                     virDomainRunningReason reason)
> +{
> +    char *logfile = NULL;
> +    int logfd = -1;
> +    off_t pos = -1;
> +    char ebuf[1024];
> +    virCommandPtr cmd = NULL;
> +    virCommandPtr load_cmd = NULL;
> +    bhyveConnPtr privconn = conn->privateData;
> +    int ret = -1, status;
> +
> +    if (virAsprintf(&logfile, "%s/%s.log",
> +                    BHYVE_LOG_DIR, vm->def->name) < 0)
> +       return -1;
> +
> +
> +    if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT,
> +                      S_IRUSR|S_IWUSR)) < 0) {
> +        virReportSystemError(errno,
> +                             _("Failed to open '%s'"),
> +                             logfile);
> +        goto cleanup;
> +    }
> +
> +    VIR_FREE(privconn->pidfile);
> +    if (!(privconn->pidfile = virPidFileBuildPath(BHYVE_STATE_DIR,
> +                                                  vm->def->name))) {
> +        virReportSystemError(errno,
> +                             "%s", _("Failed to build pidfile path."));
> +        goto cleanup;
> +    }
> +
> +    if (unlink(privconn->pidfile) < 0 &&
> +        errno != ENOENT) {
> +        virReportSystemError(errno,
> +                             _("Cannot remove state PID file %s"),
> +                             privconn->pidfile);
> +        goto cleanup;
> +    }
> +
> +    /* Call bhyve to start the VM */
> +    if (!(cmd = virBhyveProcessBuildBhyveCmd(driver,
> +                                             vm)))
> +        goto cleanup;
> +
> +    virCommandSetOutputFD(cmd, &logfd);
> +    virCommandSetErrorFD(cmd, &logfd);
> +    virCommandWriteArgLog(cmd, logfd);
> +    virCommandSetPidFile(cmd, privconn->pidfile);
> +    virCommandDaemonize(cmd);
> +
> +    /* Now bhyve command is constructed, meaning the
> +     * domain is ready to be started, so we can build
> +     * and execute bhyveload command */
> +    if (!(load_cmd = virBhyveProcessBuildLoadCmd(driver,
> +                                            vm)))
> +        goto cleanup;
> +    virCommandSetOutputFD(load_cmd, &logfd);
> +    virCommandSetErrorFD(load_cmd, &logfd);
> +
> +    /* Log generated command line */
> +    virCommandWriteArgLog(load_cmd, logfd);
> +    if ((pos = lseek(logfd, 0, SEEK_END)) < 0)
> +        VIR_WARN("Unable to seek to end of logfile: %s",
> +                virStrerror(errno, ebuf, sizeof(ebuf)));
> +
> +    VIR_INFO("Loading domain '%s'", vm->def->name);
> +    if (virCommandRun(load_cmd, &status) < 0)
> +        goto cleanup;
> +
> +    if (status != 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Guest failed to load: %d"), status);
> +        goto cleanup;
> +    }
> +
> +    /* Now we can start the domain */
> +    VIR_INFO("Starting domain '%s'", vm->def->name);

I'd suggest  s/INFO/DEBUG/ here and earlier.  If you want user visible
log messages about key operations, then we should talk about what is
needed to make  viraudit.{c,h} work on FreeBSD, and use domain_audit.c
for this.

> +    ret = virCommandRun(cmd, NULL);
> +
> +    if (ret == 0) {
> +        if (virPidFileReadPath(privconn->pidfile, &vm->pid) < 0) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR,
> +                           _("Domain %s didn't show up"), vm->def->name);
> +            goto cleanup;
> +        }
> +
> +        vm->def->id = vm->pid;
> +        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
> +    } else {
> +        goto cleanup;
> +    }
> +
> +cleanup:
> +    if (ret < 0) {
> +        virCommandPtr destroy_cmd;
> +        if ((destroy_cmd = virBhyveProcessBuildDestroyCmd(driver, vm)) != NULL) {
> +            virCommandSetOutputFD(load_cmd, &logfd);
> +            virCommandSetErrorFD(load_cmd, &logfd);
> +            ignore_value(virCommandRun(destroy_cmd, NULL));
> +            virCommandFree(destroy_cmd);
> +        }
> +    }
> +
> +    virCommandFree(load_cmd);
> +    virCommandFree(cmd);
> +    VIR_FREE(logfile);
> +    if (VIR_CLOSE(logfd) < 0) {
> +        virReportSystemError(errno, "%s", _("could not close logfile"));
> +    }

You can use  VIR_FORCE_CLOSE and ignore the error message here.

> +    return ret;
> +}


Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list