On 04/20/2012 10:01 AM, Dmitry Guryanov wrote:
PVS driver is 'stateless', like vmware or openvz drivers.
It collects information about domains during startup using
command-line utility prlctl. VMs in PVS identified by UUIDs
s/identified/are identified/
or unique names, which can be used as respective fields in
virDomainDef structure. Currently only basic info, like
description, virtual cpus number and memory amount implemented.
s/amount implemented/amount, is implemented/
Quering devices information will be added in the next patches.
s/Quering/Querying/
PVS does't support non-persistent domains - you can't run
s/does't/doesn't/
a domain having only disk image, it must always be registered
in system.
Functions for quering domain info have been just copied from
s/quering/querying/
test driver with some changes - they extract needed data from
previouly created list of virDomainObj objects.
s/previouly/previously/
+++ b/po/POTFILES.in
@@ -165,6 +165,7 @@ src/xenapi/xenapi_driver.c
src/xenapi/xenapi_utils.c
src/xenxs/xen_sxpr.c
src/xenxs/xen_xm.c
+src/pvs/pvs_driver.c
tools/console.c
tools/libvirt-guests.init.sh
tools/virsh.c
I think this hunk belongs in 1/9.
@@ -77,6 +78,14 @@ pvsDefaultConsoleType(const char *ostype
ATTRIBUTE_UNUSED)
return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
}
+void
+pvsFreeDomObj(void *p)
+{
+ pvsDomObjPtr pdom = (pvsDomObjPtr) p;
+
+ VIR_FREE(pdom);
Simpler to just write VIR_FREE(p) and avoid the intermediate variable.
Also, this function can safely be marked static.
+/*
+ * Must be called with privconn->lock held
+ */
+static virDomainObjPtr
+pvsLoadDomain(pvsConnPtr privconn, virJSONValuePtr jobj)
+{
Long, but looks okay.
+/*
+ * Must be called with privconn->lock held
+ */
+static int
+pvsLoadDomains(pvsConnPtr privconn, const char *domain_name)
+{
+ int count, i;
+ virJSONValuePtr jobj;
+ virJSONValuePtr jobj2;
+ virDomainObjPtr dom = NULL;
+ int ret = -1;
+
+ jobj = pvsParseOutput(PRLCTL, "list", "-j", "-a",
+ "-i", "-H", domain_name, NULL);
I guess you can call this command with a domain name, to limit to one
output, or with no argument, to list all domains, given...
@@ -150,6 +371,9 @@ pvsOpenDefault(virConnectPtr conn)
if (virDomainObjListInit(&privconn->domains) < 0)
goto error;
+ if (pvsLoadDomains(privconn, NULL))
+ goto error;
this usage.
+static int
+pvsDomainIsPersistent(virDomainPtr dom ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
I'm wondering if we should at least validate that dom still exists in
our hash table. But I can live with this implementation.
+
+static int
+pvsDomainGetState(virDomainPtr domain,
+ int *state, int *reason, unsigned int flags)
+{
+ pvsConnPtr privconn = domain->conn->privateData;
+ virDomainObjPtr privdom;
+ int ret = -1;
+ virCheckFlags(0, -1);
+
+ pvsDriverLock(privconn);
+ privdom = virDomainFindByName(&privconn->domains, domain->name);
+ pvsDriverUnlock(privconn);
+
+ if (privdom == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
Use of __FUNCTION__ as the error message is not a good habit, since
pvsError _already_ adds the function name automatically. You should
instead provide a real message, such as _("Domain '%s' not found"),
domain->name.
+static char *
+pvsDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+ pvsConnPtr privconn = domain->conn->privateData;
+ virDomainDefPtr def;
+ virDomainObjPtr privdom;
+ char *ret = NULL;
+
+ /* Flags checked by virDomainDefFormat */
+
+ pvsDriverLock(privconn);
+ privdom = virDomainFindByName(&privconn->domains, domain->name);
+ pvsDriverUnlock(privconn);
+
+ if (privdom == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
Likewise (and probably throughout the series, so I'll quit pointing it out).
# define pvsError(code, ...)
\
virReportErrorHelper(VIR_FROM_TEST, code, __FILE__, \
__FUNCTION__, __LINE__, __VA_ARGS__)
# define PRLCTL "prlctl"
+# define pvsParseError() \
+ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \
+ __FUNCTION__, __LINE__, "Can't parse prlctl
output")
Mark this string for translation: _("Can't parse prlctl output")
+
+struct pvsDomObj {
+ int id;
+ char *uuid;
+ char *os;
+};
+typedef struct pvsDomObj *pvsDomObjPtr;
struct _pvsConn {
virMutex lock;
@@ -48,4 +60,6 @@ typedef struct _pvsConn *pvsConnPtr;
int pvsRegister(void);
+virJSONValuePtr pvsParseOutput(const char *binary, ...);
Mark this with ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL.
+
+static int
+pvsDoCmdRun(char **outbuf, const char *binary, va_list list)
+{
+ virCommandPtr cmd = virCommandNew(binary);
+ const char *arg;
+ int exitstatus;
+ char *scmd = NULL;
+ char *sstatus = NULL;
+ int ret = -1;
+
+ while ((arg = va_arg(list, const char *)) != NULL)
+ virCommandAddArg(cmd, arg);
+
+ if (outbuf)
+ virCommandSetOutputBuffer(cmd, outbuf);
+
+ scmd = virCommandToString(cmd);
+ if (!scmd)
+ goto cleanup;
+
+ if (virCommandRun(cmd, &exitstatus)) {
If you pass NULL as the second argument here,
+ pvsError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to execute command '%s'"), scmd);
+ goto cleanup;
+ }
+
+ if (exitstatus) {
+ sstatus = virCommandTranslateStatus(exitstatus);
+ pvsError(VIR_ERR_INTERNAL_ERROR,
+ _("Command '%s' finished with errors: %s"), scmd,
sstatus);
then virCommand will take care of ensuring a 0 exit status, and with
more uniform error reporting. No need to reinvent the work that someone
else will do for you :) The only reason to ever pass an &exitstatus
parameter is if you validly expect non-zero exit status.
+/*
+ * Run command and parse its JSON output, return
+ * pointer to virJSONValue or NULL in case of error.
+ */
+virJSONValuePtr
+pvsParseOutput(const char *binary, ...)
+{
+ char *outbuf;
+ virJSONValuePtr jobj = NULL;
+ va_list list;
+ int ret;
+
+ va_start(list, binary);
+ ret = pvsDoCmdRun(&outbuf, binary, list);
+ va_end(list);
+ if (ret)
+ return NULL;
+
+ jobj = virJSONValueFromString(outbuf);
+ if (!jobj)
+ pvsError(VIR_ERR_INTERNAL_ERROR, "%s: %s",
+ _("invalid output from prlctl"), outbuf);
+
+ return jobj;
You leak outbuf if you reach the virJSONValueFromString() call.
--
Eric Blake eblake(a)redhat.com +1-919-301-3266
Libvirt virtualization library
http://libvirt.org